BackwardsLz.cs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. namespace Ryujinx.HLE.Loaders.Compression
  3. {
  4. static class BackwardsLz
  5. {
  6. private class BackwardsReader
  7. {
  8. private byte[] _data;
  9. private int _position;
  10. public int Position => _position;
  11. public BackwardsReader(byte[] data, int end)
  12. {
  13. _data = data;
  14. _position = end;
  15. }
  16. public void SeekCurrent(int offset)
  17. {
  18. _position += offset;
  19. }
  20. public byte ReadByte()
  21. {
  22. return _data[--_position];
  23. }
  24. public short ReadInt16()
  25. {
  26. return (short)((ReadByte() << 8) | (ReadByte() << 0));
  27. }
  28. public int ReadInt32()
  29. {
  30. return ((ReadByte() << 24) |
  31. (ReadByte() << 16) |
  32. (ReadByte() << 8) |
  33. (ReadByte() << 0));
  34. }
  35. }
  36. public static void DecompressInPlace(byte[] buffer, int headerEnd)
  37. {
  38. BackwardsReader reader = new BackwardsReader(buffer, headerEnd);
  39. int additionalDecLength = reader.ReadInt32();
  40. int startOffset = reader.ReadInt32();
  41. int compressedLength = reader.ReadInt32();
  42. reader.SeekCurrent(12 - startOffset);
  43. int decBase = headerEnd - compressedLength;
  44. int decPos = compressedLength + additionalDecLength;
  45. byte mask = 0;
  46. byte header = 0;
  47. while (decPos > 0)
  48. {
  49. if ((mask >>= 1) == 0)
  50. {
  51. header = reader.ReadByte();
  52. mask = 0x80;
  53. }
  54. if ((header & mask) == 0)
  55. {
  56. buffer[decBase + --decPos] = reader.ReadByte();
  57. }
  58. else
  59. {
  60. ushort pair = (ushort)reader.ReadInt16();
  61. int length = (pair >> 12) + 3;
  62. int position = (pair & 0xfff) + 3;
  63. if (length > decPos)
  64. {
  65. length = decPos;
  66. }
  67. decPos -= length;
  68. int dstPos = decBase + decPos;
  69. if (length <= position)
  70. {
  71. int srcPos = dstPos + position;
  72. Buffer.BlockCopy(buffer, srcPos, buffer, dstPos, length);
  73. }
  74. else
  75. {
  76. for (int offset = 0; offset < length; offset++)
  77. {
  78. buffer[dstPos + offset] = buffer[dstPos + position + offset];
  79. }
  80. }
  81. }
  82. }
  83. }
  84. }
  85. }