Advertisement
charleysdrpepper

GS2 Text Compression

Aug 7th, 2015
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.62 KB | None | 0 0
  1.         public void comptext(byte[] src, byte[] dest) {
  2.             DateTime c = DateTime.Now;//.Ticks;
  3.             //Welcome to my Huffman Hamburger! (Scan text, do complex char tables, compress text.)
  4.             //Scan text to generate frequency table.
  5.             ushort char1 = 0, char2 = 0;
  6.             ushort[] freq = new ushort[0x10000]; //We need to know how often each character combination occurs to determine best bit amounts.
  7.             ushort[] clen = new ushort[0x100]; //How many chars each char has associated with it.
  8.             ushort[] clst = new ushort[0x10000]; //Char list in the order they appear in the text.
  9.             int srcEntry = 0;
  10.             while ((Bits.getInt32(src, srcEntry) != 0) || (srcEntry == 0)) { //Set up frequency table and char list (in order displayed in text.)
  11.                 int srcPos = 0xC300 + Bits.getInt32(src, srcEntry);
  12.                 do {
  13.                     char2 = src[srcPos++];
  14.                     if (freq[char1 * 0x100 + char2]++ == 0) {
  15.                         clst[char1 * 0x100 + clen[char1]++] = char2; //clen[char1]++;// += 1;
  16.                     }
  17.                     //freq[char1 * 0x100 + char2] += 1;
  18.                     char1 = char2;
  19.                 } while (char1 != 0); //Change to while < textArray?-- No, go through offset list instead.
  20.                 srcEntry += 4;
  21.             }
  22.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/clst.dmp", Array.ConvertAll<short, byte>(clst, delegate(short item) { return (byte)item; }));
  23.             byte[] bitLen = new byte[0x10000]; //int[] bitLen = new int[0x10000];
  24.             int[] bitCode = new int[0x10000];
  25.             int addr2 = 0, chrptlen = 0;
  26.             byte[] chrTbl = new byte[0x8000];
  27.             byte[] chrPtrs = new byte[0x200];
  28.             for (int c1 = 0; c1 < 0x100; c1++) {
  29.                 if (clen[c1] == 0) { chrPtrs[(c1 << 1) + 1] = 0x80;  continue; }
  30.                 chrptlen = (c1 + 1) << 1;
  31.                 //if (c1 > 5) { continue; } //For testing.
  32.                 //Sort chars by symbol frequency (simple)
  33.                 //See https://en.wikipedia.org/wiki/Sorting_algorithm - Use a Stable one so same-freq chars stay in order.
  34.                 //I pick simple Insertion Sort for now, since we are dealing with small sets. (https://en.wikipedia.org/wiki/Insertion_sort)
  35.                 for (int i = 1; i < clen[c1]; i++) {
  36.                     ushort x = clst[(c1 << 8) + i];
  37.                     int j = i;
  38.                     while ((j > 0) && (freq[(c1 << 8) + clst[(c1 << 8) + j - 1]] > freq[(c1 << 8) + x])) {
  39.                         clst[(c1 << 8) + j] = clst[(c1 << 8) + j - 1];
  40.                         j = j - 1;
  41.                     }
  42.                     clst[(c1 << 8) + j] = x;
  43.                 }
  44.                 //Sort chars by node frequency (More advanced)
  45.                 int[] symbSort = new int[0x100]; //Basically points to chars in order to be displayed in data.
  46.                 int[] symbBits = new int[0x100];
  47.                 int[] nodeHead = new int[0x100];
  48.                 int[] nodeTail = new int[0x100];
  49.                 int[] nodeFreq = new int[0x100]; nodeFreq[0] = 0x7FFFFFFF; nodeFreq[1] = 0x7FFFFFFF; //Ensure unused/node2 when there is none.
  50.                 int nodeA = 0, nodeI = 0, symbI = 0;
  51.                 if (clen[c1] > 1) {
  52.                     while ((symbI < clen[c1]) || (nodeA < nodeI - 1)) {
  53.                         int symfreq1 = freq[(c1 << 8) + clst[(c1 << 8) + symbI]];
  54.                         int symfreq2 = freq[(c1 << 8) + clst[(c1 << 8) + symbI + 1]];
  55.                         if ((symbI + 1 < clen[c1]) && (symfreq2 <= nodeFreq[nodeA])) { //Symbol - Symbol
  56.                             symbSort[symbI] = symbI + 1;
  57.                             nodeHead[nodeI] = symbI; nodeTail[nodeI] = symbI + 1;
  58.                             nodeFreq[nodeI] = symfreq1 + symfreq2;
  59.                             symbI += 2;
  60.                         } else if ((symbI < clen[c1]) && (symfreq1 <= nodeFreq[nodeA])) { // Symbol - Node
  61.                             symbSort[symbI] = nodeHead[nodeA];
  62.                             nodeHead[nodeI] = symbI; nodeTail[nodeI] = nodeTail[nodeA];
  63.                             nodeFreq[nodeI] = symfreq1 + nodeFreq[nodeA];
  64.                             symbI++; nodeA++;
  65.                         } else if ((nodeA < nodeI - 1) && ((nodeFreq[nodeA + 1] < symfreq1) || ((symbI >= clen[c1])))) { // Node - Node
  66.                             symbSort[nodeTail[nodeA]] = nodeHead[nodeA + 1];
  67.                             nodeHead[nodeI] = nodeHead[nodeA]; nodeTail[nodeI] = nodeTail[nodeA + 1];
  68.                             nodeFreq[nodeI] = nodeFreq[nodeA] + nodeFreq[nodeA + 1];
  69.                             nodeA += 2;
  70.                         } else if (nodeFreq[nodeA] < symfreq1) { // Node - Symbol
  71.                             symbSort[nodeTail[nodeA]] = symbI;
  72.                             nodeHead[nodeI] = nodeHead[nodeA]; nodeTail[nodeI] = symbI;
  73.                             nodeFreq[nodeI] = nodeFreq[nodeA] + symfreq1;
  74.                             symbI++; nodeA++;
  75.                         }
  76.                         symbBits[clst[(c1 << 8) + nodeHead[nodeI++]]] += 1;
  77.                     }
  78.                 }
  79.                 addr2 += (((clen[c1] * 12) + 4) & -8);
  80.                 chrPtrs[(c1 << 1)] = (byte)(addr2 >> 3);
  81.                 chrPtrs[(c1 << 1) + 1] = (byte)(addr2 >> 11);
  82.                 int addr1 = addr2 - 12;
  83.                 byte bitsL = 0;
  84.                 //int val = 0;
  85.                 //int bitnum = (clen[c1] & 1) * 4;
  86.                 int bitC = 0;
  87.                 for (int n = clen[c1]; n > 0; n--) {
  88.                     //List chars
  89.                     chrTbl[(addr1 >> 3)] |= (byte)(clst[(c1 << 8) + nodeHead[nodeA]] << (addr1 & 7));
  90.                     chrTbl[(addr1 >> 3) + 1] |= (byte)(clst[(c1 << 8) + nodeHead[nodeA]] >> (8 - (addr1 & 7)));
  91.                     addr1 -= 12;
  92.                     //val |= clst[(c1 << 8) + nodeHead[nodeA]] << bitnum; bitnum += 12;
  93.                     //while (bitnum >= 8) {
  94.                     //    chrTbl[addr1++] = (byte)val; bitnum -= 8;
  95.                     //}
  96.                     //List the char's tree/flags
  97.                     addr2 += symbBits[clst[(c1 << 8) + nodeHead[nodeA]]];
  98.                     chrTbl[addr2 >> 3] |= (byte)(1 << (addr2++ & 7));
  99.                     //Calculate bit lengths for bit code.
  100.                     bitsL += (byte)symbBits[clst[(c1 << 8) + nodeHead[nodeA]]];
  101.                     //bitLen[clst[(c1 << 8) + nodeHead[nodeA]]] = bitsL;
  102.                     bitLen[(c1 << 8) + clst[(c1 << 8) + nodeHead[nodeA]]] = bitsL;
  103.                     //if (symbBits[clst[(c1 << 8) + nodeHead[nodeA]]] == 0) { bitsL -= 1; }
  104.                     //if (c1 == 0) { Console.WriteLine(bitC.ToString("X8") + "   " + bitsL.ToString("X8") + "   " + (char)clst[(c1 << 8) + nodeHead[nodeA]]); }
  105.                     //Generate bitCode table.
  106.                     bitCode[(c1 << 8) + clst[(c1 << 8) + nodeHead[nodeA]]] = bitC;
  107.                     while (((bitC >> (bitsL - 1)) & 1) == 1) { bitsL -= 1; bitC ^= 1 << bitsL; }
  108.                     bitC |= 1 << (bitsL - 1);
  109.                    
  110.                     nodeHead[nodeA] = symbSort[nodeHead[nodeA]];
  111.                 }
  112.                 addr2 = (addr2 + 8) & -8;
  113.                 //Console.WriteLine("\nLetter by node order");
  114.                 //for (int zz = 0; zz < clen[c1]; zz++) {
  115.                 //    Console.Write(clst[(c1 << 8) + nodeHead[nodeA]].ToString("X4") + " ");
  116.                 //    //Console.Write(symbBits[clst[(c1 << 8) + nodeHead[nodeA]]].ToString("X4") + " ");
  117.                 //    nodeHead[nodeA] = symbSort[nodeHead[nodeA]];
  118.                 //}
  119.                 //Console.WriteLine("\nsymbSort");
  120.                 //for (int zz = 0; zz < clen[c1]; zz++) {
  121.                 //    Console.Write(symbSort[zz].ToString("X4") + " ");
  122.                 //}
  123.             }
  124.             //Finally compress the text.
  125.             int val = 0, bitnum = 0, ctAddr = 0, cstrstart = 0;
  126.             byte[] cText = new byte[src.Length];
  127.             byte[] txtref1 = new byte[0x200]; int tr1Addr = 0;
  128.             byte[] txtref2 = new byte[0x8000]; int tr2Addr = 0;
  129.             srcEntry = 0; char1 = 0;
  130.             while ((Bits.getInt32(src, srcEntry) != 0) || (srcEntry == 0)) {
  131.                 if ((srcEntry & 0x3FC) == 0) {
  132.                     Bits.setInt32(txtref1, tr1Addr, ctAddr); tr1Addr += 4;
  133.                     Bits.setInt32(txtref1, tr1Addr, tr2Addr); tr1Addr += 4;
  134.                 }
  135.                 cstrstart = ctAddr;
  136.                 int srcPos = 0xC300 + Bits.getInt32(src, srcEntry); val = 0;
  137.                 do {
  138.                     char2 = src[srcPos++];
  139.                     val |= bitCode[(char1 << 8) + char2] << bitnum;
  140.                     bitnum += bitLen[(char1 << 8) + char2];
  141.                     while (bitnum >= 8) {
  142.                         cText[ctAddr++] = (byte)val; val >>= 8; bitnum -= 8;
  143.                     }
  144.                     //if (freq[char1 * 0x100 + char2]++ == 0) {
  145.                     //    clst[char1 * 0x100 + clen[char1]++] = char2; //clen[char1]++;// += 1;
  146.                     //}
  147.                     //freq[char1 * 0x100 + char2] += 1;
  148.                     //if (srcEntry == 0) { Console.WriteLine(bitCode[(char1 << 8) + char2].ToString("X8") + "   " + bitLen[(char1 << 8) + char2].ToString("X8")); }
  149.                     char1 = char2;
  150.                 } while (char1 != 0); //Change to while < textArray?-- No, go through offset list instead.
  151.                 srcEntry += 4; if (bitnum != 0) { cText[ctAddr++] = (byte)val; bitnum = 0; }
  152.                 while ((ctAddr - cstrstart) > 0xFE) { txtref2[tr2Addr++] = 0xFF; cstrstart += 0xFF; }
  153.                 txtref2[tr2Addr++] = (byte)(ctAddr - cstrstart); //cstrstart = ctAddr;
  154.             }
  155.             //Now insert everything into the ROM.
  156.             int insAddr = 0xFA0000;
  157.             int loc1 = insAddr;
  158.             Array.Copy(chrTbl, 0, dest, insAddr, addr2 >> 3); insAddr += addr2 >> 3;
  159.             insAddr = (insAddr + 1) & -2;
  160.             int loc2 = insAddr;
  161.             Array.Copy(chrPtrs, 0, dest, insAddr, chrptlen); insAddr += chrptlen;
  162.             Bits.setInt32(dest, 0x38578, 0x08000000 + insAddr);
  163.             Bits.setInt32(dest, insAddr, 0x08000000 + loc1); insAddr += 4;
  164.             Bits.setInt32(dest, insAddr, 0x08000000 + loc2); insAddr += 4;
  165.             loc1 = insAddr;
  166.             Array.Copy(cText, 0, dest, insAddr, ctAddr); insAddr += ctAddr;
  167.             loc2 = insAddr;
  168.             Array.Copy(txtref2, 0, dest, insAddr, tr2Addr); insAddr += tr2Addr;
  169.             insAddr = (insAddr + 3) & -4;
  170.             Bits.setInt32(dest, 0x385DC, 0x08000000 + insAddr);
  171.             for (int a = 0; a < tr1Addr; a += 8) {
  172.                 Bits.setInt32(dest, insAddr + a, 0x08000000 + Bits.getInt32(txtref1, a) + loc1);
  173.                 Bits.setInt32(dest, insAddr + a + 4, 0x08000000 + Bits.getInt32(txtref1, a + 4) + loc2);
  174.             }
  175.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/txtromtest.gba", dest);
  176.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/txtref1.dmp", txtref1);
  177.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/txtref2.dmp", txtref2);
  178.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/cText.dmp", cText);
  179.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/chrPtrs.dmp", chrPtrs);
  180.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/chrTbl.dmp", chrTbl);
  181.             //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/bitLen.dmp", bitLen);
  182.             //DateTime c = DateTime.Now;//.Ticks;
  183.             Console.WriteLine((DateTime.Now - c).ToString());
  184.         }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement