2020-01-02 15:13:47 -05:00
|
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
2020-07-08 05:26:39 -04:00
|
|
|
import type { BufReader } from "./bufio.ts";
|
2019-03-07 19:25:16 -05:00
|
|
|
type Reader = Deno.Reader;
|
|
|
|
type Writer = Deno.Writer;
|
2020-06-07 09:20:33 -04:00
|
|
|
import { assert } from "../_util/assert.ts";
|
2019-01-06 14:26:18 -05:00
|
|
|
|
2020-04-26 16:29:51 -04:00
|
|
|
const DEFAULT_BUFFER_SIZE = 32 * 1024;
|
|
|
|
|
2019-06-19 00:22:01 -04:00
|
|
|
/** copy N size at the most.
|
|
|
|
* If read size is lesser than N, then returns nread
|
|
|
|
* */
|
2019-02-10 18:49:48 -05:00
|
|
|
export async function copyN(
|
|
|
|
r: Reader,
|
2020-04-26 16:26:02 -04:00
|
|
|
dest: Writer,
|
2019-02-10 18:49:48 -05:00
|
|
|
size: number
|
|
|
|
): Promise<number> {
|
|
|
|
let bytesRead = 0;
|
2020-04-26 16:29:51 -04:00
|
|
|
let buf = new Uint8Array(DEFAULT_BUFFER_SIZE);
|
2019-02-10 18:49:48 -05:00
|
|
|
while (bytesRead < size) {
|
2020-04-26 16:29:51 -04:00
|
|
|
if (size - bytesRead < DEFAULT_BUFFER_SIZE) {
|
2019-02-10 18:49:48 -05:00
|
|
|
buf = new Uint8Array(size - bytesRead);
|
|
|
|
}
|
2019-07-07 15:20:41 -04:00
|
|
|
const result = await r.read(buf);
|
2020-04-28 12:40:43 -04:00
|
|
|
const nread = result ?? 0;
|
2019-02-10 18:49:48 -05:00
|
|
|
bytesRead += nread;
|
|
|
|
if (nread > 0) {
|
2020-04-29 06:25:40 -04:00
|
|
|
let n = 0;
|
|
|
|
while (n < nread) {
|
|
|
|
n += await dest.write(buf.slice(n, nread));
|
|
|
|
}
|
2019-03-06 16:39:50 -05:00
|
|
|
assert(n === nread, "could not write");
|
2019-02-10 18:49:48 -05:00
|
|
|
}
|
2020-04-28 12:40:43 -04:00
|
|
|
if (result === null) {
|
2019-02-10 18:49:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read big endian 16bit short from BufReader */
|
2020-04-28 12:40:43 -04:00
|
|
|
export async function readShort(buf: BufReader): Promise<number | null> {
|
2019-05-30 21:19:28 -04:00
|
|
|
const high = await buf.readByte();
|
2020-04-28 12:40:43 -04:00
|
|
|
if (high === null) return null;
|
2019-05-30 21:19:28 -04:00
|
|
|
const low = await buf.readByte();
|
2020-04-28 12:40:43 -04:00
|
|
|
if (low === null) throw new Deno.errors.UnexpectedEof();
|
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 */
|
2020-04-28 12:40:43 -04:00
|
|
|
export async function readInt(buf: BufReader): Promise<number | null> {
|
2019-05-30 21:19:28 -04:00
|
|
|
const high = await readShort(buf);
|
2020-04-28 12:40:43 -04:00
|
|
|
if (high === null) return null;
|
2019-05-30 21:19:28 -04:00
|
|
|
const low = await readShort(buf);
|
2020-04-28 12:40:43 -04:00
|
|
|
if (low === null) throw new Deno.errors.UnexpectedEof();
|
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 */
|
2020-04-28 12:40:43 -04:00
|
|
|
export async function readLong(buf: BufReader): Promise<number | null> {
|
2019-05-30 21:19:28 -04:00
|
|
|
const high = await readInt(buf);
|
2020-04-28 12:40:43 -04:00
|
|
|
if (high === null) return null;
|
2019-05-30 21:19:28 -04:00
|
|
|
const low = await readInt(buf);
|
2020-04-28 12:40:43 -04:00
|
|
|
if (low === null) throw new Deno.errors.UnexpectedEof();
|
2019-05-30 21:19:28 -04:00
|
|
|
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(
|
2020-05-17 13:24:39 -04:00
|
|
|
"Long value too big to be represented as a JavaScript number."
|
2019-05-30 21:19:28 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|