2019-01-06 14:26:18 -05:00
|
|
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
2019-05-30 21:19:28 -04:00
|
|
|
import { BufReader, EOF, UnexpectedEOFError } from "./bufio.ts";
|
2019-03-07 19:25:16 -05:00
|
|
|
type Reader = Deno.Reader;
|
|
|
|
type Writer = Deno.Writer;
|
2019-03-06 16:39:50 -05:00
|
|
|
import { assert } from "../testing/asserts.ts";
|
2019-01-06 14:26:18 -05:00
|
|
|
|
2019-02-10 18:49:48 -05:00
|
|
|
/** copy N size at the most. If read size is lesser than N, then returns nread */
|
|
|
|
export async function copyN(
|
|
|
|
dest: Writer,
|
|
|
|
r: Reader,
|
|
|
|
size: number
|
|
|
|
): Promise<number> {
|
|
|
|
let bytesRead = 0;
|
|
|
|
let buf = new Uint8Array(1024);
|
|
|
|
while (bytesRead < size) {
|
|
|
|
if (size - bytesRead < 1024) {
|
|
|
|
buf = new Uint8Array(size - bytesRead);
|
|
|
|
}
|
|
|
|
const { nread, eof } = await r.read(buf);
|
|
|
|
bytesRead += nread;
|
|
|
|
if (nread > 0) {
|
|
|
|
const n = await dest.write(buf.slice(0, nread));
|
2019-03-06 16:39:50 -05:00
|
|
|
assert(n === nread, "could not write");
|
2019-02-10 18:49:48 -05:00
|
|
|
}
|
|
|
|
if (eof) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read big endian 16bit short from BufReader */
|
2019-05-30 21:19:28 -04:00
|
|
|
export async function readShort(buf: BufReader): Promise<number | EOF> {
|
|
|
|
const high = await buf.readByte();
|
|
|
|
if (high === EOF) return EOF;
|
|
|
|
const low = await buf.readByte();
|
|
|
|
if (low === EOF) throw new UnexpectedEOFError();
|
2019-01-06 14:26:18 -05:00
|
|
|
return (high << 8) | low;
|
|
|
|
}
|
|
|
|
|
2019-02-10 18:49:48 -05:00
|
|
|
/** Read big endian 32bit integer from BufReader */
|
2019-05-30 21:19:28 -04:00
|
|
|
export async function readInt(buf: BufReader): Promise<number | EOF> {
|
|
|
|
const high = await readShort(buf);
|
|
|
|
if (high === EOF) return EOF;
|
|
|
|
const low = await readShort(buf);
|
|
|
|
if (low === EOF) throw new UnexpectedEOFError();
|
2019-01-06 14:26:18 -05:00
|
|
|
return (high << 16) | low;
|
|
|
|
}
|
|
|
|
|
2019-05-30 21:19:28 -04:00
|
|
|
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
2019-02-10 18:49:48 -05:00
|
|
|
|
|
|
|
/** Read big endian 64bit long from BufReader */
|
2019-05-30 21:19:28 -04:00
|
|
|
export async function readLong(buf: BufReader): Promise<number | EOF> {
|
|
|
|
const high = await readInt(buf);
|
|
|
|
if (high === EOF) return EOF;
|
|
|
|
const low = await readInt(buf);
|
|
|
|
if (low === EOF) throw new UnexpectedEOFError();
|
|
|
|
const big = (BigInt(high) << 32n) | BigInt(low);
|
|
|
|
// We probably should provide a similar API that returns BigInt values.
|
|
|
|
if (big > MAX_SAFE_INTEGER) {
|
|
|
|
throw new RangeError(
|
|
|
|
"Long value too big to be represented as a Javascript number."
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Number(big);
|
2019-01-06 14:26:18 -05:00
|
|
|
}
|
|
|
|
|
2019-02-10 18:49:48 -05:00
|
|
|
/** Slice number into 64bit big endian byte array */
|
2019-01-06 14:26:18 -05:00
|
|
|
export function sliceLongToBytes(d: number, dest = new Array(8)): number[] {
|
2019-05-30 21:19:28 -04:00
|
|
|
let big = BigInt(d);
|
|
|
|
for (let i = 0; i < 8; i++) {
|
|
|
|
dest[7 - i] = Number(big & 0xffn);
|
|
|
|
big >>= 8n;
|
2019-01-06 14:26:18 -05:00
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|