From fbb0f4614ce938aad77eddd6353634b7639fb53e Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Mon, 19 Sep 2022 21:13:58 -0700 Subject: [PATCH] v3 js: varint routines [#41] --- js/index.test.ts | 36 ++++++++++++++++++++++++++---- js/v3.ts | 58 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/js/index.test.ts b/js/index.test.ts index 77fa2bd..7ef451a 100644 --- a/js/index.test.ts +++ b/js/index.test.ts @@ -11,7 +11,13 @@ import { createDirectory, } from "./index"; -import { Entry as EntryV3, zxyToTileId, tileIdToZxy, findTile } from "./v3"; +import { + Entry as EntryV3, + zxyToTileId, + tileIdToZxy, + findTile, + readVarint, +} from "./v3"; test("stub data", (assertion) => { let dataview = createDirectory([ @@ -148,6 +154,22 @@ test("convert spec v1 directory to spec v2 directory", (assertion) => { assertion.ok(entry!.offset === 3); }); +test("varint", (assertion) => { + let b: BufferPosition = { + buf: new Uint8Array([0, 1, 127, 0xe5, 0x8e, 0x26]), + pos: 0, + }; + assertion.eq(readVarint(b), 0); + assertion.eq(readVarint(b), 1); + assertion.eq(readVarint(b), 127); + assertion.eq(readVarint(b), 624485); + b = { + buf: new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f]), + pos: 0, + }; + assertion.eq(readVarint(b), 9007199254740991); +}); + test("zxy to tile id", (assertion) => { assertion.eq(zxyToTileId(0, 0, 0), 0); assertion.eq(zxyToTileId(1, 0, 0), 1); @@ -185,7 +207,9 @@ test("tile search for first entry == id", (assertion) => { }); test("tile search for first entry == id", (assertion) => { - let entries: EntryV3[] = [{ tileId: 100, offset: 1, length: 1, runLength: 1 }]; + let entries: EntryV3[] = [ + { tileId: 100, offset: 1, length: 1, runLength: 1 }, + ]; let entry = findTile(entries, 100)!; assertion.eq(entry.offset, 1); assertion.eq(entry.length, 1); @@ -193,7 +217,9 @@ test("tile search for first entry == id", (assertion) => { }); test("tile search for first entry == id", (assertion) => { - let entries: EntryV3[] = [{ tileId: 100, offset: 1, length: 1, runLength: 2 }]; + let entries: EntryV3[] = [ + { tileId: 100, offset: 1, length: 1, runLength: 2 }, + ]; let entry = findTile(entries, 101)!; assertion.eq(entry.offset, 1); assertion.eq(entry.length, 1); @@ -217,7 +243,9 @@ test("tile search for first entry == id", (assertion) => { }); test("leaf search", (assertion) => { - let entries: EntryV3[] = [{ tileId: 100, offset: 1, length: 1, runLength: 0 }]; + let entries: EntryV3[] = [ + { tileId: 100, offset: 1, length: 1, runLength: 0 }, + ]; let entry = findTile(entries, 150); assertion.eq(entry!.offset, 1); assertion.eq(entry!.length, 1); diff --git a/js/v3.ts b/js/v3.ts index d4855d6..99b4e39 100644 --- a/js/v3.ts +++ b/js/v3.ts @@ -1,3 +1,60 @@ +interface BufferPosition { + buf: Uint8Array; + pos: number; +} + +function toNum(low: number, high: number): number { + return (high >>> 0) * 0x100000000 + (low >>> 0); +} + +function readVarintRemainder(l: number, p: BufferPosition): number { + var buf = p.buf, + h, + b; + b = buf[p.pos++]; + h = (b & 0x70) >> 4; + if (b < 0x80) return toNum(l, h); + b = buf[p.pos++]; + h |= (b & 0x7f) << 3; + if (b < 0x80) return toNum(l, h); + b = buf[p.pos++]; + h |= (b & 0x7f) << 10; + if (b < 0x80) return toNum(l, h); + b = buf[p.pos++]; + h |= (b & 0x7f) << 17; + if (b < 0x80) return toNum(l, h); + b = buf[p.pos++]; + h |= (b & 0x7f) << 24; + if (b < 0x80) return toNum(l, h); + b = buf[p.pos++]; + h |= (b & 0x01) << 31; + if (b < 0x80) return toNum(l, h); + throw new Error("Expected varint not more than 10 bytes"); +} + +export function readVarint(p: BufferPosition): number { + var buf = p.buf, + val, + b; + + b = buf[p.pos++]; + val = b & 0x7f; + if (b < 0x80) return val; + b = buf[p.pos++]; + val |= (b & 0x7f) << 7; + if (b < 0x80) return val; + b = buf[p.pos++]; + val |= (b & 0x7f) << 14; + if (b < 0x80) return val; + b = buf[p.pos++]; + val |= (b & 0x7f) << 21; + if (b < 0x80) return val; + b = buf[p.pos]; + val |= (b & 0x0f) << 28; + + return readVarintRemainder(val, p); +} + function rotate(n: number, xy: number[], rx: number, ry: number): void { if (ry == 0) { if (rx == 1) { @@ -98,4 +155,3 @@ export function findTile(entries: Entry[], tileId: number): Entry | null { } return null; } -