Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { Int64 } from './compat/long';
- export type Double = number;
- export type Float = number;
- export type Int32 = number;
- export type Int64 = Long;
- export type Uint32 = number;
- export type Uint64 = Long;
- export type Sint32 = number;
- export type Sint64 = Long;
- export type Fixed32 = number;
- export type Fixed64 = Long;
- export type Sfixed32 = number;
- export type Sfixed64 = Long;
- export type Bytes = Uint8Array;
- export type Byte = number;
- export interface Long {
- readonly low: Uint32;
- readonly high: Uint32;
- toString(): string;
- unsafeToNumber(): number;
- }
- export interface ByteInputStream {
- hasNext(): boolean;
- take(n: number): () => boolean;
- read(): Byte;
- skip(n: number): void;
- }
- export interface ByteOutputStream {
- write(byte: Byte): void;
- toBytes(): Uint8Array;
- }
- export class Uint8ArrayInputStream implements ByteInputStream {
- private offset = 0;
- private readonly byteLength: number;
- constructor(private readonly bytes: Uint8Array) {
- this.byteLength = bytes.byteLength;
- }
- hasNext(): boolean {
- return this.offset < this.byteLength;
- }
- take(n: number): () => boolean {
- const end = this.offset + n;
- return () => this.offset < end;
- }
- read(): Byte {
- return this.bytes[this.offset++];
- }
- skip(n: number): void {
- this.offset += n;
- }
- }
- export class Uint8ArrayOutputStream implements ByteOutputStream {
- private offset = 0;
- private bytes = new Uint8Array(16);
- write(byte: Byte) {
- this.bytes[this.offset++] = byte;
- }
- toBytes(): Uint8Array {
- return this.bytes.slice(0, this.offset);
- }
- }
- export function readUint32(stream: ByteInputStream): number {
- let byte = stream.read();
- let value = byte & 0x7F;
- if (byte < 0x80) {
- return value;
- }
- byte = stream.read();
- value |= (byte & 0x7F) << 7;
- if (byte < 0x80) {
- return value;
- }
- byte = stream.read();
- value |= (byte & 0x7F) << 14;
- if (byte < 0x80) {
- return value;
- }
- byte = stream.read();
- value |= (byte & 0x7F) << 21;
- if (byte < 0x80) {
- return value;
- }
- byte = stream.read();
- value |= (byte & 0x7F) << 28;
- if (byte < 0x80) {
- return value >>> 0;
- }
- // If we get here, it's a negative integer
- // Since we already read 5 bytes, we will skip over the remaining 5
- stream.skip(5);
- return value;
- }
- export function readSint32(stream: ByteInputStream): number {
- const uint32 = readUint32(stream);
- return (uint32 >>> 1) ^ - (uint32 & 1);
- }
- export function readInt64(stream: ByteInputStream): string {
- let temp;
- let low = 0;
- let high = 0;
- // Read the first four bytes of the varint, stopping at the terminator if we
- // see it.
- for (let i = 0; i < 4; i++) {
- temp = stream.read();
- low |= (temp & 0x7F) << (i * 7);
- if (temp < 128) {
- return new Int64(low >>> 0, 0).toString();
- }
- }
- // Read the fifth byte, which straddles the low and high dwords.
- temp = stream.read();
- low |= (temp & 0x7F) << 28;
- high |= (temp & 0x7F) >> 4;
- if (temp < 128) {
- return new Int64(low >>> 0, high >>> 0).toString();
- }
- // Read the sixth through tenth byte.
- for (let i = 0; i < 5; i++) {
- temp = stream.read();
- high |= (temp & 0x7F) << (i * 7 + 3);
- if (temp < 128) {
- return new Int64(low >>> 0, high >>> 0).toString();
- }
- }
- return new Int64(low, high).toString();
- }
- export function readFixed32(stream: ByteInputStream): number {
- const a = stream.read();
- const b = stream.read();
- const c = stream.read();
- const d = stream.read();
- return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
- }
- export function readFloat(stream: ByteInputStream): number {
- const bits = readFixed32(stream);
- const sign = ((bits >> 31) * 2 + 1);
- const exp = (bits >>> 23) & 0xFF;
- const mantissa = bits & 0x7FFFFF;
- if (exp === 0xFF) {
- if (mantissa) {
- return NaN;
- } else {
- return sign * Infinity;
- }
- }
- if (exp === 0) {
- // Denormal.
- return sign * 1.401298464324817e-45 * mantissa;
- } else {
- return sign * Math.pow(2, exp - 150) *
- (mantissa + 8388608);
- }
- }
- export function readDouble(stream: ByteInputStream): number {
- const low = readFixed32(stream);
- const high = readFixed32(stream);
- const sign = ((high >> 31) * 2 + 1);
- const exp = (high >>> 20) & 0x7FF;
- const mant = 4294967296 * (high & 0xFFFFF) + low;
- if (exp === 0x7FF) {
- if (mant) {
- return NaN;
- } else {
- return sign * Infinity;
- }
- }
- if (exp === 0) {
- // Denormal.
- return sign * 5e-324 * mant;
- } else {
- return sign * Math.pow(2, exp - 1075) * (mant + 4503599627370496);
- }
- }
- export function readBoolean(stream: ByteInputStream): boolean {
- return !!readUint32(stream);
- }
- export function readPackedBoolean(stream: ByteInputStream, array: boolean[]): boolean[] {
- const length = readUint32(stream);
- const next = stream.take(length);
- while (next()) {
- array.push(readBoolean(stream));
- }
- return array;
- }
- export function readString(stream: ByteInputStream): string {
- const length = readUint32(stream);
- const codeUnits = new Array(length);
- let charactersRead = 0;
- let cursor = 0;
- let result = '';
- while (cursor < length) {
- const c = stream.read(); cursor++;
- if (c < 128) { // Regular 7-bit ASCII.
- codeUnits[charactersRead++] = c;
- } else if (c < 192) {
- // UTF-8 continuation mark. We are out of sync. This
- // might happen if we attempted to read a character
- // with more than four bytes.
- continue;
- } else if (c < 224) { // UTF-8 with two bytes.
- const c2 = stream.read(); cursor++;
- codeUnits[charactersRead++] = ((c & 31) << 6) | (c2 & 63);
- } else if (c < 240) { // UTF-8 with three bytes.
- const c2 = stream.read(); cursor++;
- const c3 = stream.read(); cursor++;
- codeUnits[charactersRead++] = ((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63);
- } else if (c < 248) { // UTF-8 with 4 bytes.
- const c2 = stream.read(); cursor++;
- const c3 = stream.read(); cursor++;
- const c4 = stream.read(); cursor++;
- // Characters written on 4 bytes have 21 bits for a codepoint.
- // We can't fit that on 16bit characters, so we use surrogates.
- let codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63);
- // Surrogates formula from wikipedia.
- // 1. Subtract 0x10000 from codepoint
- codepoint -= 0x10000;
- // 2. Split this into the high 10-bit value and the low 10-bit value
- // 3. Add 0xD800 to the high value to form the high surrogate
- // 4. Add 0xDC00 to the low value to form the low surrogate:
- const low = (codepoint & 1023) + 0xDC00;
- const high = ((codepoint >> 10) & 1023) + 0xD800;
- codeUnits[charactersRead++] = high;
- codeUnits[charactersRead++] = low;
- }
- }
- // TODO chunk it if length exceeds 8192
- result += String.fromCharCode.apply(null, codeUnits);
- return result;
- }
- export function writeUint32(value: number, stream: ByteOutputStream) {
- while (value > 0x7F) {
- stream.write((value & 0x7F) | 0x80);
- value = value >>> 7;
- }
- stream.write(value);
- }
- export function writeSint32(value: number, stream: ByteOutputStream) {
- writeUint32(((value << 1) ^ (value >> 31)) >>> 0, stream);
- }
- export function writeInt64(value: string, stream: ByteOutputStream) {
- const int64 = Int64.fromString(value);
- writeInt64FromBits(int64.low, int64.high, stream);
- }
- function writeInt64FromBits(low: number, high: number, stream: ByteOutputStream) {
- // Break the binary representation into chunks of 7 bits, set the 8th bit
- // in each chunk if it's not the final chunk, and append to the result.
- while (high > 0 || low > 127) {
- stream.write((low & 0x7f) | 0x80);
- low = ((low >>> 7) | (high << 25)) >>> 0;
- high = high >>> 7;
- }
- stream.write(low);
- }
- export function writeFloat(value: number, stream: ByteOutputStream) {
- const sign = (value < 0) ? 1 : 0;
- value = sign ? -value : value;
- // Handle zeros.
- if (value === 0) {
- if ((1 / value) > 0) {
- // Positive zero.
- writeFixed32(0x00000000, stream);
- } else {
- // Negative zero.
- writeFixed32(0x80000000, stream);
- }
- return;
- }
- // Handle nans.
- if (isNaN(value)) {
- writeFixed32(0x7FFFFFFF, stream);
- return;
- }
- // Handle infinities.
- if (value > 3.4028234663852886e+38) {
- writeFixed32(((sign << 31) | (0x7F800000)) >>> 0, stream);
- return;
- }
- // Handle denormals.
- if (value < 1.1754943508222875e-38) {
- const mantissa = Math.round(value / 1.401298464324817e-45);
- writeFixed32(((sign << 31) | mantissa) >>> 0, stream);
- } else {
- const exp = Math.floor(Math.log(value) / Math.LN2);
- const mantissa = Math.round(value * Math.pow(2, -exp) * 8388608);
- writeFixed32(((sign << 31) | ((exp + 127) << 23) | mantissa & 0x7FFFFF) >>> 0, stream);
- }
- }
- export function writeDouble(value: number, stream: ByteOutputStream) {
- const sign = (value < 0) ? 1 : 0;
- value = sign ? -value : value;
- // Handle zeros.
- if (value === 0) {
- if ((1 / value) > 0) {
- // Positive zero.
- writeFixed32(0x00000000, stream);
- writeFixed32(0x00000000, stream);
- } else {
- // Negative zero.
- writeFixed32(0x00000000, stream);
- writeFixed32(0x80000000, stream);
- }
- return;
- }
- // Handle nans.
- if (isNaN(value)) {
- writeFixed32(0x7FFFFFFF, stream);
- writeFixed32(0xFFFFFFFF, stream);
- return;
- }
- // Handle infinities.
- if (value > 1.7976931348623157e+308) {
- writeFixed32(0, stream);
- writeFixed32(((sign << 31) | (0x7FF00000)) >>> 0, stream);
- return;
- }
- // Handle denormals.
- if (value < 2.2250738585072014e-308) {
- // Number is a denormal.
- const mant = value / 5e-324;
- const mantHigh = (mant / 8388608);
- writeFixed32(mant >>> 0, stream);
- writeFixed32(((sign << 31) | mantHigh) >>> 0, stream);
- } else {
- const exp = Math.min(Math.floor(Math.log(value) / Math.LN2), 1023);
- const mant = value * Math.pow(2, -exp);
- const mantHigh = (mant * 1048576) & 0xFFFFF;
- const mantLow = (mant * 4503599627370496) >>> 0;
- writeFixed32(mantLow, stream);
- writeFixed32(((sign << 31) | ((exp + 1023) << 20) | mantHigh) >>> 0, stream);
- }
- }
- export function writeFixed32(value: number, stream: ByteOutputStream) {
- stream.write((value >>> 0) & 0xFF);
- stream.write((value >>> 8) & 0xFF);
- stream.write((value >>> 16) & 0xFF);
- stream.write((value >>> 24) & 0xFF);
- }
- export function writeBoolean(value: boolean, stream: ByteOutputStream) {
- writeUint32(value ? 1 : 0, stream);
- }
Add Comment
Please, Sign In to add comment