LZSS.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. namespace FF8
  6. {
  7. internal class LZSS
  8. {
  9. //NEW LZSS
  10. #region License
  11. /**************************************************************
  12. LZSS.C -- A Data Compression Program
  13. (tab = 4 spaces)
  14. ***************************************************************
  15. 4/6/1989 Haruhiko Okumura
  16. Use, distribute, and modify this program freely.
  17. Please send me your improved versions.
  18. PC-VAN SCIENCE
  19. NIFTY-Serve PAF01022
  20. CompuServe 74050,1022
  21. **************************************************************/
  22. #endregion License
  23. private static readonly int N = 4096;
  24. private static readonly int F = 18;
  25. private static readonly int THRESHOLD = 2;
  26. private static readonly int EOF = -1;
  27. public static byte[] DecompressAllNew(byte[] data, bool skip = false)
  28. {
  29. byte[] outfilearray;
  30. using (MemoryStream infile = new MemoryStream(!skip?data:data.Skip(4).ToArray()))
  31. {
  32. Decode(infile, out outfilearray);
  33. }
  34. return outfilearray;
  35. }
  36. //Code borrowed from Java's implementation of LZSS by antiquechrono
  37. private static void Decode(MemoryStream infile, out byte[] outfilearray)
  38. {
  39. int i, j, k, r, c;
  40. List<byte> outfile = new List<byte>();
  41. int[] text_buf = new int[N + F - 1]; /* ring buffer of size N, with extra F-1 bytes to facilitate string comparison */
  42. //unsigned int flags;
  43. int flags;
  44. for (i = 0; i < N - F; i++) text_buf[i] = 0;
  45. r = N - F; flags = 0;
  46. for (; ; )
  47. {
  48. if (((flags >>= 1) & 256) == 0)
  49. {
  50. if ((c = infile.ReadByte()) == EOF) break;
  51. flags = c | 0xff00; /* uses higher byte cleverly */
  52. } /* to count eight */
  53. // if (flags & 1) {
  54. if ((flags & 1) == 1)
  55. {
  56. if ((c = infile.ReadByte()) == EOF) break;
  57. outfile.Add((byte)c);
  58. text_buf[r++] = c;
  59. r &= (N - 1);
  60. }
  61. else
  62. {
  63. if ((i = infile.ReadByte()) == EOF) break;
  64. if ((j = infile.ReadByte()) == EOF) break;
  65. i |= ((j & 0xf0) << 4); j = (j & 0x0f) + THRESHOLD;
  66. for (k = 0; k <= j; k++)
  67. {
  68. c = text_buf[(i + k) & (N - 1)];
  69. outfile.Add((byte)c);
  70. text_buf[r++] = c;
  71. r &= (N - 1);
  72. }
  73. }
  74. }
  75. outfilearray = outfile.ToArray();
  76. }
  77. /// <summary>
  78. /// Decompiles LZSS. You have to know the OutputSize. [DEPRECATED]
  79. /// </summary>
  80. /// <param name="data">buffer</param>
  81. /// <param name="fileSize">Original filesize of compressed file</param>
  82. /// <param name="size">Filesize of final file</param>
  83. /// <returns>Byte array</returns>
  84. [Obsolete("This method proved to be broken. Please use DecompressAllNew")]
  85. public static byte[] DecompressAll(byte[] data, uint fileSize, int size = 0)
  86. {
  87. try
  88. {
  89. bool bDynamic = false;
  90. if (size == 0)
  91. {
  92. size = 0x4000000; //64MB
  93. bDynamic = true;
  94. }
  95. byte[] result = new byte[size];
  96. int curResult = 0;
  97. int curBuff = 4078, flagByte = 0;
  98. int fileData = 4,
  99. endFileData = (int)fileSize;
  100. byte[] textBuf = new byte[4113];
  101. while (true)
  102. {
  103. if (fileData + 1 >= endFileData) return !bDynamic ? result : ReturnDynamic(result, curResult);
  104. if (((flagByte >>= 1) & 256) == 0)
  105. flagByte = data[fileData++] | 0xff00;
  106. if (fileData >= endFileData)
  107. return !bDynamic ? result : ReturnDynamic(result, curResult);
  108. if ((flagByte & 1) > 0)
  109. {
  110. result[curResult] = textBuf[curBuff] = data[fileData++];
  111. curBuff = (curBuff + 1) & 4095;
  112. ++curResult;
  113. }
  114. else
  115. {
  116. if (fileData + 1 >= endFileData)
  117. return !bDynamic ? result : ReturnDynamic(result, curResult);
  118. int offset = (byte)BitConverter.ToChar(data, fileData++);
  119. if (fileData + 1 >= endFileData)
  120. return !bDynamic ? result : ReturnDynamic(result, curResult);
  121. int length = (byte)BitConverter.ToChar(data, fileData++);
  122. offset |= (length & 0xF0) << 4;
  123. length = (length & 0xF) + 2 + offset;
  124. int e;
  125. for (e = offset; e <= length; e++)
  126. {
  127. textBuf[curBuff] = result[curResult] = textBuf[e & 4095];
  128. curBuff = (curBuff + 1) & 4095;
  129. ++curResult;
  130. }
  131. }
  132. }
  133. }
  134. catch
  135. {
  136. return null;
  137. }
  138. }
  139. private static byte[] ReturnDynamic(byte[] result, int curResult)
  140. {
  141. byte[] buffer = new byte[curResult];
  142. Array.Copy(result, buffer, buffer.Length);
  143. return buffer;
  144. }
  145. }
  146. }