UNPKG

s2-tools

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

1,191 lines 38.1 kB
import * as ieee754 from './ieee754'; const SHIFT_LEFT_32 = 4294967296; // (1 << 16) * (1 << 16); const SHIFT_RIGHT_32 = 2.3283064365386963e-10; // 1 / SHIFT_LEFT_32; /** * # Protobuffer * * ## Description * Create a new PBF instance and either read or write to it. * Follows the early Protobuf spec supporting various types of encoding * including messages (which are usually representative of class objects). * * ## Usage * * ### Reading: * ```ts * const data = fs.readFileSync(path); * const pbf = new Pbf(data); * ``` * * ### Writing: * ```ts * const pbf = new Pbf(); * pbf.writeVarintField(1, 1); * // ... * const result = pbf.commit(); * ``` */ export class Pbf { buf; pos; length; type; static Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum static Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 static Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields static Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 static None = 7; // null value /** * @param buf - an optional Uint8Array to use for reading. otherwise defaults to an empty * Uint8Array for writing */ constructor(buf = new Uint8Array(0)) { this.buf = buf; this.pos = 0; this.type = 0; this.length = this.buf.length; } /** * Destroys the PBF instance. You can still use the Pbf instance after calling * this method. However, the buffer will be emptied. */ destroy() { this.buf = new Uint8Array(0); this.pos = 0; this.type = 0; this.length = 0; } // === READING ================================================================= /** * Reads a tag from the buffer, pulls out the tag and type and returns it. * @returns - {tag: number, type: number} */ readTag() { const input = this.readVarint(); const tag = input >> 3; const type = (this.type = input & 7); return { tag, type }; } /** * If you know you are reading a message, but have already read the length of * the message OR you're reading fields of the top level data, then this method * is the alternative. It's often used by sub-classes So that it can be * instationated prior to reading the message. @see {@link readMessage}. * * Ex. * * ```ts * export class MapboxVectorLayer { * constructor(pbf: Protobuf, end: number) { * this.#pbf = pbf; * pbf.readFields(this.#readLayer, this, end); * } * * #readLayer(tag: number, layer: MapboxVectorLayer, pbf: Protobuf): void { * if (tag === 15) layer.version = pbf.readVarint(); * else if (tag === 1) layer.name = pbf.readString(); * ... * } * } * ``` * @param readField - user defined input function to parse the message fields * @param input - The class to mutate given field data * @param end - the end position of the message in the buffer * @returns - The class we mutated will be returned */ readFields(readField, input, end) { if (end === 0) end = this.length; while (this.pos < end) { const val = this.readVarint(); const tag = val >> 3; const startPos = this.pos; this.type = val & 0x7; readField(tag, input, this); if (this.pos === startPos) this.skip(val); } return input; } /** * Reads a message from the buffer. Sometimes it's easier to manage sub structures * so that the current method can build multiples of an entire structure/class. * If you you are at the top level, or parsing the message inside a class, then * @see {@link readFields}. * * Ex. * * ```ts * class Test { * a: number = 0; * * static read(tag: number, test: Test, pbf: Protobuf): void { * if (tag === 1) test.a = pbf.readVarint(); * // ... * } * } * * const pbf = new Pbf(data); * const t = new Test(); * pbf3.readTag(); * pbf3.readMessage(Test.read, t); * ``` * @param readField - user defined input function * @param input - an instance of the class you are reading into * @returns - The class itself will be returned */ readMessage(readField, input) { return this.readFields(readField, input, this.readVarint() + this.pos); } /** * Read in a 32-bit unsigned integer from the buffer. There are no compression advantages * with this type of encoding. * @returns - 32-bit unsigned integer */ readFixed32() { const val = readUInt32(this.buf, this.pos); this.pos += 4; return val; } /** * Read in a 32-bit signed integer from the buffer. There are no compression advantages * with this type of encoding. * @returns - 32-bit signed integer */ readSFixed32() { const val = readInt32(this.buf, this.pos); this.pos += 4; return val; } // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) /** * Read in a 64-bit unsigned integer from the buffer. There are no compression advantages * with this type of encoding. * @returns - 64-bit unsigned integer */ readFixed64() { const val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; this.pos += 8; return val; } /** * Read in a 64-bit signed integer from the buffer. There are no compression advantages * with this type of encoding. * @returns - 64-bit signed integer */ readSFixed64() { const val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; this.pos += 8; return val; } /** * Read in a 32-bit float from the buffer. There are no compression advantages * with this type of encoding. * @returns - 32-bit float */ readFloat() { const val = ieee754.read(this.buf, this.pos, true, 23, 4); this.pos += 4; return val; } /** * Read in a 64-bit float from the buffer. There are no compression advantages * with this type of encoding. * @returns - 64-bit float */ readDouble() { const val = ieee754.read(this.buf, this.pos, true, 52, 8); this.pos += 8; return val; } /** * @param isSigned - true if the number is signed * @returns - the decoded number */ readVarint(isSigned = false) { const buf = this.buf; let val; let b; b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; b = buf[this.pos]; val |= (b & 0x0f) << 28; return readVarintRemainder(val, isSigned, this); } /** * @see {@link readVarint} for better performance * @returns - the decoded number */ readVarint64() { // for compatibility with v2.0.1 return this.readVarint(true); } /** * @returns - the decoded number as a signed number */ readSVarint() { const num = this.readVarint(); return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding } /** * @returns - parses the varint byte as a boolean expression */ readBoolean() { return Boolean(this.readVarint()); } /** * @returns - the decoded string */ readString() { const end = this.readVarint() + this.pos; const pos = this.pos; this.pos = end; return readUtf8(this.buf, pos, end); } /** * NOTE: bytes is preceeded by a varint dscribing the length of the bytes. * The bytes themselves are presumed to be u8s and therefore don't need to be decoded * @returns - the decoded byte array */ readBytes() { const end = this.readVarint() + this.pos; const buffer = this.buf.subarray(this.pos, end); this.pos = end; return buffer; } // verbose for performance reasons; doesn't affect gzipped size /** * @param arr - the array to write to * @param isSigned - true if the numbers are signed * @returns - the `arr` input with the decoded numbers is also returned */ readPackedVarint(arr = [], isSigned = false) { if (this.type !== Pbf.Bytes) { arr.push(this.readVarint(isSigned)); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readVarint(isSigned)); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded numbers is also returned */ readPackedSVarint(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readSVarint()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readSVarint()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded boolean values is also returned */ readPackedBoolean(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readBoolean()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readBoolean()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded floats is also returned */ readPackedFloat(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readFloat()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readFloat()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded doubles is also returned */ readPackedDouble(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readDouble()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readDouble()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded unsigned integers is also returned */ readPackedFixed32(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readFixed32()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readFixed32()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded signed integers is also returned */ readPackedSFixed32(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readSFixed32()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readSFixed32()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded unsigned 64-bit integers is also returned */ readPackedFixed64(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readFixed64()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readFixed64()); } return arr; } /** * @param arr - the array to write to * @returns - the `arr` input with the decoded signed 64-bit integers is also returned */ readPackedSFixed64(arr = []) { if (this.type !== Pbf.Bytes) { arr.push(this.readSFixed64()); } else { const end = readPackedEnd(this); while (this.pos < end) arr.push(this.readSFixed64()); } return arr; } /** * Skip a value we are not interested in parsing * @param val - the type to skip */ skip(val) { const type = val & 0x7; if (type === Pbf.Varint) { while (this.buf[this.pos++] > 0x7f) { continue; } } else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; else if (type === Pbf.Fixed32) this.pos += 4; else if (type === Pbf.Fixed64) this.pos += 8; else throw new Error('Unimplemented type: ' + String(type)); } // === WRITING ================================================================= /** * Write a tag and its associated type * @param tag - the tag to write * @param type - the type to write (will never be greater than 3 bits) */ writeTag(tag, type) { this.writeVarint((tag << 3) | type); } /** * Allocate more space in the buffer * @param min - the minimum number of bytes to allocate */ realloc(min) { let length = this.length > 0 ? this.length : 16; while (length < this.pos + min) length *= 2; if (length !== this.length) { const buf = new Uint8Array(length); buf.set(this.buf); this.buf = buf; this.length = length; } } /** * @returns - the entire written buffer */ commit() { this.length = this.pos; this.pos = 0; return this.buf.subarray(0, this.length); } /** * Write a 32-bit unsigned integer * @param val - the 32-bit unsigned integer to write */ writeFixed32(val) { this.realloc(4); writeInt32(this.buf, val, this.pos); this.pos += 4; } /** * Write a 32-bit signed integer * @param val - the 32-bit signed integer to write */ writeSFixed32(val) { this.realloc(4); writeInt32(this.buf, val, this.pos); this.pos += 4; } /** * Write a 64-bit unsigned integer * @param val - the 64-bit unsigned integer to write */ writeFixed64(val) { this.realloc(8); writeInt32(this.buf, val & -1, this.pos); writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); this.pos += 8; } /** * Write a 64-bit signed integer * @param val - the 64-bit signed integer to write */ writeSFixed64(val) { this.realloc(8); writeInt32(this.buf, val & -1, this.pos); writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); this.pos += 8; } /** * Write a varint. Can be max 64-bits. Numbers are coerced to an unsigned * while number before using this function. * @param val - any whole unsigned number. It's usually best practice to * not use this function directly unless you know what you're doing. */ writeVarint(val) { if (val > 0xfffffff || val < 0) { writeBigVarint(val, this); return; } this.realloc(4); this.buf[this.pos++] = (val & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; this.buf[this.pos++] = (val >>> 7) & 0x7f; } /** * Write a signed varint. Can be max 64-bits. Numbers can be negative * but must still be a while number. * @param val - any whole signed number. It's usually best practice to * not use this function directly unless you know what you're doing. */ writeSVarint(val) { this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); } /** * Write a boolean value. Can also be a number, in which case * it will be converted to a boolean. 0 is false, anything else is true. * @param val - the boolean to write. */ writeBoolean(val) { const bool = Boolean(val); this.writeVarint(Number(bool)); } /** * Write a string. Strings larger then 128 bytes will be written * in chunks of 128 bytes and are slightly less efficient. * @param str - the string to write */ writeString(str) { str = String(str); this.realloc(str.length * 4); this.pos++; // reserve 1 byte for short string length const startPos = this.pos; // write the string directly to the buffer and see how much was written this.pos = writeUtf8(this.buf, str, this.pos); const len = this.pos - startPos; if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position this.pos = startPos - 1; this.writeVarint(len); this.pos += len; } /** * Write a 32-bit floating point number * @param val - a 32-bit floating point number to write */ writeFloat(val) { this.realloc(4); ieee754.write(this.buf, val, this.pos, true, 23, 4); this.pos += 4; } /** * Write a 64-bit floating point number * @param val - a 64-bit floating point number to write */ writeDouble(val) { this.realloc(8); ieee754.write(this.buf, val, this.pos, true, 52, 8); this.pos += 8; } /** * Write a byte array * @param buf - a Buffer to write. Will write the length of the buffer first. * After that, the buffer will be written byte by byte. */ writeBytes(buf) { const len = buf.length; this.writeVarint(len); this.realloc(len); for (let i = 0; i < len; i++) this.buf[this.pos++] = buf[i]; } /** * Write a message to the buffer. Allows you to pass in an object * with a write function to define how the message should be written. * A good tool to abstract away storing classes or sub-classes. * @param fn - the user defined function to call to write the message * @param obj - the object to pass to the user defined function */ writeRawMessage(fn, obj) { this.pos++; // reserve 1 byte for short message length // write the message directly to the buffer and see how much was written const startPos = this.pos; fn(obj, this); const len = this.pos - startPos; if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position this.pos = startPos - 1; this.writeVarint(len); this.pos += len; } /** * Write a message to the buffer. Allows you to pass in an object * with a write function to define how the message should be written. * A good tool to abstract away storing classes or sub-classes. * @param tag - the tag to write to associate with the message. This will help track how to * read following data. * @param fn - user defined function to call to manually define how to write the object * @param obj - the object to pass to the user defined function */ writeMessage(tag, fn, obj) { this.writeTag(tag, Pbf.Bytes); this.writeRawMessage(fn, obj); } /** * Write a packed repeated unsigned whole number array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of unsigned whole numbers to write. */ writePackedVarint(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); } /** * Write a packed repeated signed whole number array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of signed whole numbers to write. */ writePackedSVarint(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); } /** * Write a packed repeated boolean array to the buffer. * Supports numbers: `0` is false, everything else is true. * @param tag - the tag to write to associate with the value. * @param arr - the array of booleans to write. */ writePackedBoolean(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); } /** * Write a packed repeated 32-bit float array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of floats to write. */ writePackedFloat(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); } /** * Write a packed repeated 64-bit double array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of doubles to write. */ writePackedDouble(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); } /** * Write a packed repeated 32-bit unsigned integer array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of unsigned 32-bit numbers to write. */ writePackedFixed32(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); } /** * Write a packed repeated 32-bit signed integer array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of signed 32-bit numbers to write. */ writePackedSFixed32(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); } /** * Write a packed repeated 64-bit unsigned integer array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of unsigned 64-bit numbers to write. */ writePackedFixed64(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); } /** * Write a packed repeated 64-bit signed integer array to the buffer. * @param tag - the tag to write to associate with the value. * @param arr - the array of signed 64-bit numbers to write. */ writePackedSFixed64(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); } /** * Write a packed repeated byte array to the buffer with * an associated tag. * @param tag - the tag to write to associate with the value. * @param buffer - the buffer of bytes to write. */ writeBytesField(tag, buffer) { this.writeTag(tag, Pbf.Bytes); this.writeBytes(buffer); } /** * write a packed repeated fixed 32-bit integer array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the unsigned 32-bit integer to write. */ writeFixed32Field(tag, val) { this.writeTag(tag, Pbf.Fixed32); this.writeFixed32(val); } /** * Write a packed repeated signed 32-bit integer array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the signed 32-bit integer to write. */ writeSFixed32Field(tag, val) { this.writeTag(tag, Pbf.Fixed32); this.writeSFixed32(val); } /** * Write a packed repeated unsigned 64-bit integer array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the unsigned 64-bit integer to write. */ writeFixed64Field(tag, val) { this.writeTag(tag, Pbf.Fixed64); this.writeFixed64(val); } /** * Write a packed repeated signed 64-bit integer array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the signed 64-bit integer to write. */ writeSFixed64Field(tag, val) { this.writeTag(tag, Pbf.Fixed64); this.writeSFixed64(val); } /** * Write a packed repeated unsigned integer array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the unsigned number to write. */ writeVarintField(tag, val) { this.writeTag(tag, Pbf.Varint); this.writeVarint(val); } /** * Write a packed repeated signed integer array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the signed number to write. */ writeSVarintField(tag, val) { this.writeTag(tag, Pbf.Varint); this.writeSVarint(val); } /** * Write a packed repeated string array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param str - the string to write. */ writeStringField(tag, str) { this.writeTag(tag, Pbf.Bytes); this.writeString(str); } /** * Write a packed repeated float array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the float to write. */ writeFloatField(tag, val) { this.writeTag(tag, Pbf.Fixed32); this.writeFloat(val); } /** * Write a packed repeated double array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the double to write. */ writeDoubleField(tag, val) { this.writeTag(tag, Pbf.Fixed64); this.writeDouble(val); } /** * Write a packed repeated boolean array to the buffer * with an associated tag. * @param tag - the tag to write to associate with the value. * @param val - the boolean to write. */ writeBooleanField(tag, val) { this.writeVarintField(tag, Number(val)); } } /** * Read a varint from the buffer * @param l - the low 32 bits of the number * @param s - the signedness * @param p - the protobuf * @returns - the decoded remainder */ function readVarintRemainder(l, s, p) { const buf = p.buf; let h; let b; b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); throw new Error('Expected varint not more than 10 bytes'); } /** * Read the end of the packed array * @param pbf - the protobuf * @returns - the end of the packed array */ function readPackedEnd(pbf) { return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1; } /** * Decode a varint * @param low - the low 32 bits of the number * @param high - the high 32 bits of the number * @param isSigned - whether the number is signed * @returns - the decoded number */ function toNum(low, high, isSigned) { if (isSigned) { return high * 0x100000000 + (low >>> 0); } return (high >>> 0) * 0x100000000 + (low >>> 0); } /** * Write a varint * @param val - the number * @param pbf - the protobuf */ function writeBigVarint(val, pbf) { let low = val % 0x100000000 | 0; let high = (val / 0x100000000) | 0; if (val < 0) { low = ~(-val % 0x100000000); high = ~(-val / 0x100000000); if ((low ^ 0xffffffff) !== 0) { low = (low + 1) | 0; } else { low = 0; high = (high + 1) | 0; } } if (val >= 0x10000000000000000n || val < -0x10000000000000000n) { throw new Error("Given varint doesn't fit into 10 bytes"); } pbf.realloc(10); writeBigVarintLow(low, high, pbf); writeBigVarintHigh(high, pbf); } /** * Write the low 32 bits of a varint * @param low - lower 32 bits * @param _high - unused "high" bits * @param pbf - the Protobuf class */ function writeBigVarintLow(low, _high, pbf) { pbf.buf[pbf.pos++] = (low & 0x7f) | 0x80; low >>>= 7; pbf.buf[pbf.pos++] = (low & 0x7f) | 0x80; low >>>= 7; pbf.buf[pbf.pos++] = (low & 0x7f) | 0x80; low >>>= 7; pbf.buf[pbf.pos++] = (low & 0x7f) | 0x80; low >>>= 7; pbf.buf[pbf.pos] = low & 0x7f; } /** * Write the high 32 bits of a varint * @param high - the high 32 bits * @param pbf - the Protobuf class */ function writeBigVarintHigh(high, pbf) { const lsb = (high & 0x07) << 4; pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) !== 0 ? 0x80 : 0); if (high === 0) return; pbf.buf[pbf.pos++] = (high & 0x7f) | ((high >>>= 7) !== 0 ? 0x80 : 0); if (high === 0) return; pbf.buf[pbf.pos++] = (high & 0x7f) | ((high >>>= 7) !== 0 ? 0x80 : 0); if (high === 0) return; pbf.buf[pbf.pos++] = (high & 0x7f) | ((high >>>= 7) !== 0 ? 0x80 : 0); if (high === 0) return; pbf.buf[pbf.pos++] = (high & 0x7f) | ((high >>>= 7) !== 0 ? 0x80 : 0); if (high === 0) return; pbf.buf[pbf.pos++] = high & 0x7f; } /** * Make room for extra length * @param startPos - the start position * @param len - the length to make room for * @param pbf - the Protobuf class */ function makeRoomForExtraLength(startPos, len, pbf) { const extraLen = len <= 0x3fff ? 1 : len <= 0x1fffff ? 2 : len <= 0xfffffff ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7)); // if 1 byte isn't enough for encoding message length, shift the data to the right pbf.realloc(extraLen); for (let i = pbf.pos - 1; i >= startPos; i--) { pbf.buf[i + extraLen] = pbf.buf[i]; } } /** * Write a packed varint * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedVarint(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } /** * Write a packed signed varint * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedSVarint(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } /** * Write a packed float * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedFloat(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } /** * Write a packed double * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedDouble(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } /** * Write a packed boolean * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedBoolean(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } /** * Write a packed fixed32 * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedFixed32(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } /** * Write a packed sfixed32 * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedSFixed32(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } /** * Write a packed fixed64 * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedFixed64(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } /** * Write a packed sfixed64 * @param arr - the array of numbers to write * @param pbf - the Protobuf class */ function writePackedSFixed64(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } // Buffer code below from https://github.com/feross/buffer, MIT-licensed /** * Read in a 32-bit unsigned integer from the buffer. There are no compression advantages * @param buf - the buffer of bytes to read * @param pos - the position in the buffer to read from * @returns - the unsigned 32-bit number */ function readUInt32(buf, pos) { return (buf[pos] | (buf[pos + 1] << 8) | (buf[pos + 2] << 16)) + buf[pos + 3] * 0x1000000; } /** * Write a 32-bit unsigned integer to the buffer * @param buf - the buffer of bytes to write * @param val - the unsigned 32-bit number * @param pos - the position in the buffer to write */ function writeInt32(buf, val, pos) { buf[pos] = val; buf[pos + 1] = val >>> 8; buf[pos + 2] = val >>> 16; buf[pos + 3] = val >>> 24; } /** * Read in a 32-bit signed integer from the buffer * @param buf - the buffer of bytes to read * @param pos - the position in the buffer to read from * @returns - the signed 32-bit number */ function readInt32(buf, pos) { return (buf[pos] | (buf[pos + 1] << 8) | (buf[pos + 2] << 16)) + (buf[pos + 3] << 24); } /** * Read UTF-8 string from buffer at "pos" till "end" * @param buf - the buffer of bytes * @param pos - the position in the buffer to read from * @param end - the position in the buffer to stop at * @returns - the utf-8 string */ function readUtf8(buf, pos, end) { let str = ''; let i = pos; while (i < end) { const b0 = buf[i]; let c = null; // codepoint let bytesPerSequence = b0 > 0xef ? 4 : b0 > 0xdf ? 3 : b0 > 0xbf ? 2 : 1; if (i + bytesPerSequence > end) break; let b1, b2, b3; if (bytesPerSequence === 1) { if (b0 < 0x80) { c = b0; } } else if (bytesPerSequence === 2) { b1 = buf[i + 1]; if ((b1 & 0xc0) === 0x80) { c = ((b0 & 0x1f) << 0x6) | (b1 & 0x3f); if (c <= 0x7f) { c = null; } } } else if (bytesPerSequence === 3) { b1 = buf[i + 1]; b2 = buf[i + 2]; if ((b1 & 0xc0) === 0x80 && (b2 & 0xc0) === 0x80) { c = ((b0 & 0xf) << 0xc) | ((b1 & 0x3f) << 0x6) | (b2 & 0x3f); if (c <= 0x7ff || (c >= 0xd800 && c <= 0xdfff)) { c = null; } } } else if (bytesPerSequence === 4) { b1 = buf[i + 1]; b2 = buf[i + 2]; b3 = buf[i + 3]; if ((b1 & 0xc0) === 0x80 && (b2 & 0xc0) === 0x80 && (b3 & 0xc0) === 0x80) { c = ((b0 & 0xf) << 0x12) | ((b1 & 0x3f) << 0xc) | ((b2 & 0x3f) << 0x6) | (b3 & 0x3f); if (c <= 0xffff || c >= 0x110000) { c = null; } } } if (c === null) { c = 0xfffd; bytesPerSequence = 1; } else if (c > 0xffff) { c -= 0x10000; str += String.fromCharCode(((c >>> 10) & 0x3ff) | 0xd800); c = 0xdc00 | (c & 0x3ff); } str += String.fromCharCode(c); i += bytesPerSequence; } return str; } /** * Write a utf8 string to the buffer * @param buf - the buffer of bytes * @param str - the string to write * @param pos - the position in the buffer to start write to * @returns - new position in the buffer */ function writeUtf8(buf, str, pos) { for (let i = 0, c, lead = null; i < str.length; i++) { c = str.charCodeAt(i); // code point if (c > 0xd7ff && c < 0xe000) { if (lead !== null) { if (c < 0xdc00) { buf[pos++] = 0xef; buf[pos++] = 0xbf; buf[pos++] = 0xbd; lead = c; continue; } else { c = ((lead - 0xd800) << 10) | (c - 0xdc00) | 0x10000; lead = null; } } else { if (c > 0xdbff || i + 1 === str.length) { buf[pos++] = 0xef; buf[pos++] = 0xbf; buf[pos++] = 0xbd; } else { lead = c; } continue; } } else if (lead !== null) { buf[pos++] = 0xef; buf[pos++] = 0xbf; buf[pos++] = 0xbd; lead = null; } if (c < 0x80) { buf[pos++] = c; } else { if (c < 0x800) { buf[pos++] = (c >> 0x6) | 0xc0; } else { if (c < 0x10000) { buf[pos++] = (c >> 0xc) | 0xe0; } else { buf[pos++] = (c >> 0x12) | 0xf0; buf[pos++] = ((c >> 0xc) & 0x3f) | 0x80; } buf[pos++] = ((c >> 0x6) & 0x3f) | 0x80; } buf[pos++] = (c & 0x3f) | 0x80; } } return pos; } //# sourceMappingURL=index.js.map