| 62 | } |
| 63 | |
| 64 | uint64_t lzoDecompress(const char* inputAddress, const char* inputLimit, char* outputAddress, |
| 65 | char* outputLimit) { |
| 66 | // nothing compresses to nothing |
| 67 | if (inputAddress == inputLimit) { |
| 68 | return 0; |
| 69 | } |
| 70 | |
| 71 | // maximum offset in buffers to which it's safe to write long-at-a-time |
| 72 | char* const fastOutputLimit = outputLimit - SIZE_OF_LONG; |
| 73 | |
| 74 | // LZO can concat two blocks together so, decode until the input data is |
| 75 | // consumed |
| 76 | const char* input = inputAddress; |
| 77 | char* output = outputAddress; |
| 78 | while (input < inputLimit) { |
| 79 | // |
| 80 | // Note: For safety some of the code below may stop decoding early or |
| 81 | // skip decoding, because input is not available. This makes the code |
| 82 | // safe, and since LZO requires an explicit "stop" command, the decoder |
| 83 | // will still throw a exception. |
| 84 | // |
| 85 | |
| 86 | bool firstCommand = true; |
| 87 | uint32_t lastLiteralLength = 0; |
| 88 | while (true) { |
| 89 | if (input >= inputLimit) { |
| 90 | throw MalformedInputException(input - inputAddress); |
| 91 | } |
| 92 | uint32_t command = *(input++) & 0xFF; |
| 93 | if (command == 0x11) { |
| 94 | break; |
| 95 | } |
| 96 | |
| 97 | // Commands are described using a bit pattern notation: |
| 98 | // 0: bit is not set |
| 99 | // 1: bit is set |
| 100 | // L: part of literal length |
| 101 | // P: part of match offset position |
| 102 | // M: part of match length |
| 103 | // ?: see documentation in command decoder |
| 104 | |
| 105 | int32_t matchLength; |
| 106 | int32_t matchOffset; |
| 107 | uint32_t literalLength; |
| 108 | if ((command & 0xf0) == 0) { |
| 109 | if (lastLiteralLength == 0) { |
| 110 | // 0b0000_LLLL (0bLLLL_LLLL)* |
| 111 | |
| 112 | // copy length :: fixed |
| 113 | // 0 |
| 114 | matchOffset = 0; |
| 115 | |
| 116 | // copy offset :: fixed |
| 117 | // 0 |
| 118 | matchLength = 0; |
| 119 | |
| 120 | // literal length - 3 :: variable bits :: valid range [4..] |
| 121 | // 3 + variableLength(command bits [0..3], 4) |
no test coverage detected