| |
| |
| |
| |
| |
|
|
| const WORD_MASK = [0, 0xff, 0xffff, 0xffffff, 0xffffffff] |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function copyBytes(fromArray, fromPos, toArray, toPos, length) { |
| for (let i = 0; i < length; i++) { |
| toArray[toPos + i] = fromArray[fromPos + i] |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function snappyUncompress(input, output) { |
| const inputLength = input.byteLength |
| const outputLength = output.byteLength |
| let pos = 0 |
| let outPos = 0 |
|
|
| |
| while (pos < inputLength) { |
| const c = input[pos] |
| pos++ |
| if (c < 128) { |
| break |
| } |
| } |
| if (outputLength && pos >= inputLength) { |
| throw new Error('invalid snappy length header') |
| } |
|
|
| while (pos < inputLength) { |
| const c = input[pos] |
| let len = 0 |
| pos++ |
|
|
| if (pos >= inputLength) { |
| throw new Error('missing eof marker') |
| } |
|
|
| |
| if ((c & 0x3) === 0) { |
| |
| let len = (c >>> 2) + 1 |
| |
| if (len > 60) { |
| if (pos + 3 >= inputLength) { |
| throw new Error('snappy error literal pos + 3 >= inputLength') |
| } |
| const lengthSize = len - 60 |
| len = input[pos] |
| + (input[pos + 1] << 8) |
| + (input[pos + 2] << 16) |
| + (input[pos + 3] << 24) |
| len = (len & WORD_MASK[lengthSize]) + 1 |
| pos += lengthSize |
| } |
| if (pos + len > inputLength) { |
| throw new Error('snappy error literal exceeds input length') |
| } |
| copyBytes(input, pos, output, outPos, len) |
| pos += len |
| outPos += len |
| } else { |
| |
| let offset = 0 |
| switch (c & 0x3) { |
| case 1: |
| |
| len = (c >>> 2 & 0x7) + 4 |
| offset = input[pos] + (c >>> 5 << 8) |
| pos++ |
| break |
| case 2: |
| |
| if (inputLength <= pos + 1) { |
| throw new Error('snappy error end of input') |
| } |
| len = (c >>> 2) + 1 |
| offset = input[pos] + (input[pos + 1] << 8) |
| pos += 2 |
| break |
| case 3: |
| |
| if (inputLength <= pos + 3) { |
| throw new Error('snappy error end of input') |
| } |
| len = (c >>> 2) + 1 |
| offset = input[pos] |
| + (input[pos + 1] << 8) |
| + (input[pos + 2] << 16) |
| + (input[pos + 3] << 24) |
| pos += 4 |
| break |
| default: |
| break |
| } |
| if (offset === 0 || isNaN(offset)) { |
| throw new Error(`invalid offset ${offset} pos ${pos} inputLength ${inputLength}`) |
| } |
| if (offset > outPos) { |
| throw new Error('cannot copy from before start of buffer') |
| } |
| copyBytes(output, outPos - offset, output, outPos, len) |
| outPos += len |
| } |
| } |
|
|
| if (outPos !== outputLength) throw new Error('premature end of input') |
| } |
|
|