| 1 | /** Apply a git delta (as found in OFS_DELTA / REF_DELTA pack entries) to a base. */ |
| 2 | export function applyDelta(base: Uint8Array, delta: Uint8Array): Uint8Array { |
| 3 | let i = 0; |
| 4 | const varint = (): number => { |
| 5 | let result = 0; |
| 6 | let shift = 0; |
| 7 | let c: number; |
| 8 | do { |
| 9 | c = delta[i++]!; |
| 10 | result += (c & 0x7f) * 2 ** shift; |
| 11 | shift += 7; |
| 12 | } while (c & 0x80); |
| 13 | return result; |
| 14 | }; |
| 15 | const srcSize = varint(); |
| 16 | if (srcSize !== base.length) throw new Error(`delta base size mismatch: ${srcSize} != ${base.length}`); |
| 17 | const dstSize = varint(); |
| 18 | const out = new Uint8Array(dstSize); |
| 19 | let o = 0; |
| 20 | while (i < delta.length) { |
| 21 | const op = delta[i++]!; |
| 22 | if (op & 0x80) { |
| 23 | let off = 0; |
| 24 | let size = 0; |
| 25 | if (op & 0x01) off |= delta[i++]!; |
| 26 | if (op & 0x02) off |= delta[i++]! << 8; |
| 27 | if (op & 0x04) off |= delta[i++]! << 16; |
| 28 | if (op & 0x08) off = (off | (delta[i++]! << 24)) >>> 0; |
| 29 | if (op & 0x10) size |= delta[i++]!; |
| 30 | if (op & 0x20) size |= delta[i++]! << 8; |
| 31 | if (op & 0x40) size |= delta[i++]! << 16; |
| 32 | if (size === 0) size = 0x10000; |
| 33 | if (off + size > base.length || o + size > dstSize) throw new Error("delta copy out of range"); |
| 34 | out.set(base.subarray(off, off + size), o); |
| 35 | o += size; |
| 36 | } else if (op > 0) { |
| 37 | if (o + op > dstSize || i + op > delta.length) throw new Error("delta insert out of range"); |
| 38 | out.set(delta.subarray(i, i + op), o); |
| 39 | i += op; |
| 40 | o += op; |
| 41 | } else { |
| 42 | throw new Error("invalid delta opcode 0"); |
| 43 | } |
| 44 | } |
| 45 | if (o !== dstSize) throw new Error(`delta produced ${o} bytes, expected ${dstSize}`); |
| 46 | return out; |
| 47 | } |