LZSS.cs 5.4 KB

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