lzsa.hpp 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #pragma once
  2. #include <nall/decode/huffman.hpp>
  3. namespace nall::Decode {
  4. inline auto LZSA(array_view<uint8_t> input) -> vector<uint8_t> {
  5. vector<uint8_t> output;
  6. uint index = 0;
  7. uint size = 0;
  8. for(uint byte : range(8)) size |= *input++ << byte * 8;
  9. output.resize(size);
  10. auto load = [&]() -> vector<uint8_t> {
  11. uint size = 0;
  12. for(uint byte : range(8)) size |= *input++ << byte * 8;
  13. vector<uint8_t> buffer;
  14. buffer.reserve(size);
  15. while(size--) buffer.append(*input++);
  16. return buffer;
  17. };
  18. auto flags = Decode::Huffman(load());
  19. auto literals = Decode::Huffman(load());
  20. auto lengths = Decode::Huffman(load());
  21. auto offsets = Decode::Huffman(load());
  22. auto flagData = flags.data();
  23. uint byte = 0, bits = 0;
  24. auto flagRead = [&]() -> bool {
  25. if(bits == 0) bits = 8, byte = *flagData++;
  26. return byte >> --bits & 1;
  27. };
  28. auto literalData = literals.data();
  29. auto literalRead = [&]() -> uint8_t {
  30. return *literalData++;
  31. };
  32. auto lengthData = lengths.data();
  33. auto lengthRead = [&]() -> uint64_t {
  34. uint byte = *lengthData++, bytes = 1;
  35. while(!(byte & 1)) byte >>= 1, bytes++;
  36. uint length = byte >> 1, shift = 8 - bytes;
  37. while(--bytes) length |= *lengthData++ << shift, shift += 8;
  38. return length;
  39. };
  40. auto offsetData = offsets.data();
  41. auto offsetRead = [&]() -> uint {
  42. uint offset = 0;
  43. offset |= *offsetData++ << 0; if(index < 1 << 8) return offset;
  44. offset |= *offsetData++ << 8; if(index < 1 << 16) return offset;
  45. offset |= *offsetData++ << 16; if(index < 1 << 24) return offset;
  46. offset |= *offsetData++ << 24; return offset;
  47. };
  48. while(index < size) {
  49. if(!flagRead()) {
  50. output[index++] = literalRead();
  51. } else {
  52. uint length = lengthRead() + 6;
  53. uint offset = index - offsetRead();
  54. while(length--) output[index++] = output[offset++];
  55. }
  56. }
  57. return output;
  58. }
  59. }