Advertisement
Guest User

Yaz0 Decoder/Encoder

a guest
May 27th, 2013
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.18 KB | None | 0 0
  1. /*
  2.  * Yaz0 (de)compression algorithm was found on http://www.amnoid.de and ported to C#
  3.  */
  4. using System;
  5. using System.IO;
  6.  
  7. namespace OcarinaPlayer
  8. {
  9.     public class Yaz0
  10.     {
  11.         /// <summary>
  12.         /// Decompresses a block compressed with the Yaz0 algorithm with respect to a little endian machine
  13.         /// </summary>
  14.         /// <param name="sr"></param>
  15.         /// <param name="yaz0BlockSize">The size of the block without header?</param>
  16.         /// <returns></returns>
  17.         public static byte[] Decode(FileStream sr, int yaz0BlockSize)
  18.         {
  19.             byte[] buf;
  20.             byte[] result;
  21.             int[] size;
  22.  
  23.             buf = new byte[sizeof(Int32)];
  24.             size = new int[1];
  25.  
  26.             sr.Position += 4;
  27.             sr.Read(buf, 0, sizeof(Int32));
  28.             OcarinaPlayer.Endian.ReverseBytes(ref buf, sizeof(Int32));
  29.             Buffer.BlockCopy(buf, 0, size, 0, sizeof(Int32));
  30.             sr.Position += 8;
  31.  
  32.             buf = new byte[yaz0BlockSize];
  33.             sr.Read(buf, 0, yaz0BlockSize);
  34.  
  35.             Decode(buf, out result, size[0]);
  36.             return result;
  37.         }
  38.  
  39.  
  40.  
  41.         #region ConvertedCode
  42.         /// <summary>
  43.         /// Decodes a Yaz0 block
  44.         /// </summary>
  45.         /// <param name="src">points to the yaz0 source data (to the "real" source data, not at the header!)</param>
  46.         /// <param name="dst">points to a buffer uncompressedSize bytes large (you get uncompressedSize from</param>
  47.         /// <param name="uncompressedSize">the second 4 bytes in the Yaz0 header)</param>
  48.         static void Decode(byte[] src, out byte[] dst, int uncompressedSize)
  49.         {
  50.             int srcPlace = 0, dstPlace = 0; //current read/write positions
  51.  
  52.             UInt32 validBitCount = 0; //number of valid bits left in "code" byte
  53.             Byte currCodeByte = 0;//set on first pass
  54.  
  55.             dst = new byte[uncompressedSize];
  56.  
  57.             while (dstPlace < uncompressedSize)
  58.             {
  59.                 //read new "code" byte if the current one is used up
  60.                 if (validBitCount == 0)
  61.                 {
  62.                     currCodeByte = src[srcPlace];
  63.                     ++srcPlace;
  64.                     validBitCount = 8;
  65.                 }
  66.  
  67.                 if ((currCodeByte & 0x80) != 0)
  68.                 {
  69.                     //straight copy
  70.                     dst[dstPlace] = src[srcPlace];
  71.                     dstPlace++;
  72.                     srcPlace++;
  73.                 }
  74.                 else
  75.                 {
  76.                     //RLE part
  77.                     byte byte1 = src[srcPlace];
  78.                     byte byte2 = src[srcPlace + 1];
  79.                     srcPlace += 2;
  80.  
  81.                     UInt32 dist = (UInt32)((byte1 & 0xF) << 8) | byte2;
  82.                     UInt32 copySource = (UInt32)dstPlace - (dist + 1);
  83.  
  84.                     UInt32 numBytes = (UInt32)byte1 >> 4;
  85.                     if (numBytes == 0)
  86.                     {
  87.                         numBytes = (UInt32)src[srcPlace] + 0x12;
  88.                         srcPlace++;
  89.                     }
  90.                     else
  91.                         numBytes += 2;
  92.  
  93.                     //copy run
  94.                     for (int i = 0; i < numBytes; ++i)
  95.                     {
  96.                         dst[dstPlace] = dst[copySource];
  97.                         copySource++;
  98.                         dstPlace++;
  99.                     }
  100.                 }
  101.  
  102.                 //use next bit from "code" byte
  103.                 currCodeByte <<= 1;
  104.                 validBitCount -= 1;
  105.             }
  106.         }
  107.  
  108.         struct Ret
  109.         {
  110.             public int srcPos, dstPos;
  111.             public Ret(int s, int d)
  112.             {
  113.                 srcPos = s;
  114.                 dstPos = d;
  115.             }
  116.         }
  117.  
  118.         /// <summary>
  119.         /// Simple and straight encoding scheme for Yaz0
  120.         /// </summary>
  121.         /// <param name="src"></param>
  122.         /// <param name="size"></param>
  123.         /// <param name="pos"></param>
  124.         /// <param name="pMatchPos"></param>
  125.         /// <returns></returns>
  126.         static UInt32 simpleEnc(byte[] src, int size, int pos, ref UInt32 /* u32* */ pMatchPos)
  127.         //u32 simpleEnc(u8* src, int size, int pos, u32 *pMatchPos)
  128.         {
  129.             int startPos = pos - 0x1000;
  130.             UInt32 numBytes = 1;
  131.             UInt32 matchPos = 0;
  132.  
  133.             if (startPos < 0)
  134.                 startPos = 0;
  135.             for (int i = startPos; i < pos; i++)
  136.             {
  137.                 int j;
  138.                 for (j = 0; j < size - pos; j++)
  139.                 {
  140.                     if (src[i + j] != src[j + pos])
  141.                         break;
  142.                 }
  143.                 if (j > numBytes)
  144.                 {
  145.                     numBytes = (UInt32)j;
  146.                     matchPos = (UInt32)i;
  147.                 }
  148.             }
  149.             pMatchPos = matchPos; //*pMatchPos = matchPos;
  150.             if (numBytes == 2)
  151.                 numBytes = 1;
  152.             return numBytes;
  153.         }
  154.  
  155.         struct StaticEncodeVars
  156.         {
  157.             public UInt32 numBytes1;
  158.             public UInt32 matchPos;
  159.             public int prevFlag;
  160.         }
  161.  
  162.         /// <summary>
  163.         /// a lookahead encoding scheme for ngc Yaz0
  164.         /// </summary>
  165.         /// <param name="src"></param>
  166.         /// <param name="size"></param>
  167.         /// <param name="pos"></param>
  168.         /// <param name="pMatchPos"></param>
  169.         /// <returns></returns>
  170.         static UInt32 nintendoEnc(byte[] src, int size, int pos, ref UInt32 /* u32* */ pMatchPos, StaticEncodeVars var)
  171.         //u32 nintendoEnc(u8* src, int size, int pos, u32 *pMatchPos)
  172.         {
  173.             int startPos = pos - 0x1000;
  174.             UInt32 numBytes = 1;
  175.             var.prevFlag = 0;
  176.  
  177.             // if prevFlag is set, it means that the previous position was determined by look-ahead try.
  178.             // so just use it. this is not the best optimization, but nintendo's choice for speed.
  179.             if (var.prevFlag == 1)
  180.             {
  181.                 pMatchPos = var.matchPos; //*pMatchPos = matchPos;
  182.                 var.prevFlag = 0;
  183.                 return var.numBytes1;
  184.             }
  185.             var.prevFlag = 0;
  186.             numBytes = simpleEnc(src, size, pos, ref var.matchPos); //numBytes = simpleEnc(src, size, pos, &matchPos);
  187.             pMatchPos = var.matchPos; //*pMatchPos = matchPos;
  188.  
  189.             // if this position is RLE encoded, then compare to copying 1 byte and next position(pos+1) encoding
  190.             if (numBytes >= 3)
  191.             {
  192.                 var.numBytes1 = simpleEnc(src, size, pos + 1, ref var.matchPos); //numBytes1 = simpleEnc(src, size, pos+1, &matchPos);
  193.                 // if the next position encoding is +2 longer than current position, choose it.
  194.                 // this does not guarantee the best optimization, but fairly good optimization with speed.
  195.                 if (var.numBytes1 >= numBytes + 2)
  196.                 {
  197.                     numBytes = 1;
  198.                     var.prevFlag = 1;
  199.                 }
  200.             }
  201.             return numBytes;
  202.         }
  203.  
  204.         //public static int EncodeWithHeader(byte[] src,
  205.  
  206.         public static int Encode(byte[] src, int srcSize, FileStream dstFile)
  207.         //int encodeYaz0(u8* src, int srcSize, FILE* dstFile)
  208.         {
  209.             Ret r = new Ret(0, 0);
  210.             byte[] dst = new byte[24]; // 8 codes * 3 bytes maximum
  211.             int dstSize = 0;
  212.             int percent = -1;
  213.  
  214.             UInt32 validBitCount = 0; //number of valid bits left in "code" byte
  215.             byte currCodeByte = 0;
  216.  
  217.             UInt32 numBytes;
  218.             UInt32 matchPos = 0; //uninitialized, modified to compile
  219.             UInt32 srcPosBak;
  220.  
  221.             StaticEncodeVars var = new StaticEncodeVars();
  222.  
  223.             //Write Header
  224.             byte[] srcSizeArr = BitConverter.GetBytes(srcSize);
  225.             byte[] header = new byte[] {0x59, 0x61, 0x7A, 0x30}; //Yaz0
  226.             if (BitConverter.IsLittleEndian)
  227.                 Array.Reverse(srcSizeArr);
  228.  
  229.             dstFile.Write(header, 0, 4);
  230.             dstFile.Write(srcSizeArr, 0, 4);
  231.             for (int i = 0; i < 8; i++)
  232.                 dstFile.WriteByte(0);
  233.  
  234.             while (r.srcPos < srcSize)
  235.             {
  236.                 numBytes = nintendoEnc(src, srcSize, r.srcPos, ref matchPos, var); //matchPos passed ref &matchpos
  237.                 if (numBytes < 3)
  238.                 {
  239.                     //straight copy
  240.                     dst[r.dstPos] = src[r.srcPos];
  241.                     r.dstPos++;
  242.                     r.srcPos++;
  243.                     //set flag for straight copy
  244.                     currCodeByte |= (byte)(0x80 >> (int)validBitCount);
  245.                 }
  246.                 else
  247.                 {
  248.                     //RLE part
  249.                     UInt32 dist = (UInt32)r.srcPos - matchPos - 1;
  250.                     byte byte1, byte2, byte3;
  251.  
  252.                     if (numBytes >= 0x12)  // 3 byte encoding
  253.                     {
  254.                         byte1 = (byte)(0 | (dist >> 8));
  255.                         byte2 = (byte)(dist & 0xff);
  256.                         dst[r.dstPos++] = byte1;
  257.                         dst[r.dstPos++] = byte2;
  258.                         // maximum runlength for 3 byte encoding
  259.                         if (numBytes > 0xff + 0x12)
  260.                             numBytes = 0xff + 0x12;
  261.                         byte3 = (byte)(numBytes - 0x12);
  262.                         dst[r.dstPos++] = byte3;
  263.                     }
  264.                     else  // 2 byte encoding
  265.                     {
  266.                         byte1 = (byte)(((numBytes - 2) << 4) | (dist >> 8));
  267.                         byte2 = (byte)(dist & 0xff);
  268.                         dst[r.dstPos++] = byte1;
  269.                         dst[r.dstPos++] = byte2;
  270.                     }
  271.                     r.srcPos += (int)numBytes;
  272.                 }
  273.                 validBitCount++;
  274.                 //write eight codes
  275.                 if (validBitCount == 8)
  276.                 {
  277.                     dstFile.WriteByte(currCodeByte); //fwrite(&currCodeByte, 1, 1, dstFile);
  278.                     dstFile.Write(dst, 0, r.dstPos); //fwrite(dst, 1, r.dstPos, dstFile);
  279.                     //fflush(dstFile);
  280.                     dstSize += r.dstPos + 1;
  281.  
  282.                     srcPosBak = (UInt32)r.srcPos;
  283.                     currCodeByte = 0;
  284.                     validBitCount = 0;
  285.                     r.dstPos = 0;
  286.                 }
  287.                 if ((r.srcPos + 1) * 100 / srcSize != percent)
  288.                 {
  289.                     percent = (r.srcPos + 1) * 100 / srcSize;
  290.                     //printf("\r %3d%%", percent);
  291.                 }
  292.             }
  293.             if (validBitCount > 0)
  294.             {
  295.                 dstFile.WriteByte(currCodeByte); //fwrite(&currCodeByte, 1, 1, dstFile);
  296.                 dstFile.Write(dst, 0, r.dstPos); //fwrite(dst, 1, r.dstPos, dstFile);
  297.                 dstSize += r.dstPos + 1;
  298.  
  299.                 currCodeByte = 0;
  300.                 validBitCount = 0;
  301.                 r.dstPos = 0;
  302.             }
  303.             //printf("\r done\n", percent);
  304.             dstFile.Close();
  305.             return dstSize;
  306.         }
  307.         #endregion
  308.     }
  309. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement