LZSS.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. // ReSharper disable InconsistentNaming
  6. namespace OpenVIII
  7. {
  8. /// <summary>
  9. /// <para>NEW LZSS</para>
  10. /// <para>LZSS.C -- A Data Compression Program</para>
  11. /// <para>(tab = 4 spaces)</para>
  12. /// <para>4/6/1989 Haruhiko Okumura</para>
  13. /// <para>Use, distribute, and modify this program freely.</para>
  14. /// <para>Please send me your improved versions.</para>
  15. /// <para>PC-VAN SCIENCE</para>
  16. /// <para>NIFTY-Serve PAF01022</para>
  17. /// <para>CompuServe 74050,1022</para>
  18. /// </summary>
  19. public class LZSS
  20. {
  21. #region Fields
  22. private const int EOF = -1;
  23. private const int F = 18;
  24. private const int N = 4096;
  25. private const int THRESHOLD = 2;
  26. #endregion Fields
  27. #region Methods
  28. public static byte[] DecompressAllNew(byte[] data, int uncompressedSize, bool skip = false)
  29. {
  30. if (uncompressedSize < 0) throw new ArgumentOutOfRangeException(nameof(uncompressedSize)); // if 0 ignore checks.
  31. //Memory.Log.WriteLine($"{nameof(LZSS)}::{nameof(DecompressAllNew)} :: decompressing data");
  32. byte[] outFileArray;
  33. using (var infile = new MemoryStream(!skip ? data : data.Skip(4).ToArray()))
  34. {
  35. Decode(infile, out outFileArray);
  36. }
  37. if (uncompressedSize > 0 && outFileArray.Length != uncompressedSize)
  38. throw new InvalidDataException($"{nameof(LZSS)}::{nameof(DecompressAllNew)} Expected size ({uncompressedSize}) != ({outFileArray.Length})");
  39. return outFileArray;
  40. }
  41. //Code borrowed from Java's implementation of LZSS by antiquechrono
  42. private static void Decode(Stream infile, out byte[] outFileArray)
  43. {
  44. var outfile = new List<byte>();
  45. var textBuf = new int[N + F - 1]; // ring buffer of size N, with extra F-1 bytes to facilitate string comparison
  46. var r = N - F; var flags = 0;
  47. for (; ; )
  48. {
  49. int c;
  50. if (((flags >>= 1) & 256) == 0)
  51. {
  52. if ((c = infile.ReadByte()) == EOF) break;
  53. flags = c | 0xff00; // uses higher byte cleverly
  54. } // to Count eight
  55. if ((flags & 1) == 1)
  56. {
  57. if ((c = infile.ReadByte()) == EOF) break;
  58. outfile.Add((byte)c);
  59. textBuf[r++] = c;
  60. r &= (N - 1);
  61. }
  62. else
  63. {
  64. int i;
  65. if ((i = infile.ReadByte()) == EOF) break;
  66. int j;
  67. if ((j = infile.ReadByte()) == EOF) break;
  68. i |= ((j & 0xf0) << 4); j = (j & 0x0f) + THRESHOLD;
  69. int k;
  70. for (k = 0; k <= j; k++)
  71. {
  72. c = textBuf[(i + k) & (N - 1)];
  73. outfile.Add((byte)c);
  74. textBuf[r++] = c;
  75. r &= (N - 1);
  76. }
  77. }
  78. }
  79. outFileArray = outfile.ToArray();
  80. }
  81. #endregion Methods
  82. }
  83. }