Skip to content

Instantly share code, notes, and snippets.

@char
Last active January 4, 2020 08:07
Show Gist options
  • Save char/0986190c94165d063d8c6f26e49d5223 to your computer and use it in GitHub Desktop.
Save char/0986190c94165d063d8c6f26e49d5223 to your computer and use it in GitHub Desktop.
Git delta parser in pure TypeScript
// A git delta parser in TypeScript for deno
// Author: Anthony Som
// MIT License.
function copy(source, target, targetOffset, sourcePos, length) {
for (let i = 0; i < length; i++) {
target[targetOffset + i] = source[sourcePos + i]
}
}
function readHeader(buffer) {
let offset = 0;
function readSize() {
let byte = buffer[offset++],
rv = byte & 0x7F,ts
shift = 7;
while (byte & 0x80) {
byte = buffer[offset++]
rv |= (byte & 0x7F) << shift;
shift += 7;
}
return rv;
}
return [readSize(), readSize(), offset];
}
export function applyDelta(base: Uint8Array, delta: Uint8Array) {
let rv, opcode, baseOffset, copyLength;
let rvOffset = 0;
const header = readHeader(delta);
let offset = header[2];
if (header[0] != base.length) {
throw new Error("Invalid base buffer length in header")
}
rv = new Uint8Array(header[1]);
while (offset < delta.length) {
opcode = delta[offset++]
if (opcode & 0x80) {
// Copy
baseOffset = 0;
copyLength = 0;
// Base offset:
if (opcode & 0x01) baseOffset = delta[offset++];
if (opcode & 0x02) baseOffset |= delta[offset++] << 8;
if (opcode & 0x04) baseOffset |= delta[offset++] << 16;
if (opcode & 0x08) baseOffset |= delta[offset++] << 24
// Copy length
if (opcode & 0x10) copyLength = delta[offset++];
if (opcode & 0x20) copyLength |= delta[offset++] << 8;
if (opcode & 0x40) copyLength |= delta[offset++] << 16;
if (copyLength === 0) copyLength = 1 << 16;
copy(base, rv, rvOffset, baseOffset, copyLength);
} else if (opcode) {
copyLength = opcode;
copy(delta, rv, rvOffset, offset, offset + copyLength);
offset += copyLength;
} else {
throw new Error("Invalid opcode in delta")
}
rvOffset += copyLength;
}
if (rvOffset !== rv.length) {
throw new Error("Error patching the base buffer")
}
return rv
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment