Skip to content

Commit

Permalink
io: make port BufReader.readByte() return number | EOF
Browse files Browse the repository at this point in the history
  • Loading branch information
piscisaureus committed May 31, 2019
1 parent 40f55da commit b2786c2
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 26 deletions.
6 changes: 3 additions & 3 deletions io/bufio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ export class BufReader implements Reader {
return p;
}

/** Returns the next byte [0, 255] or -1 if EOF. */
async readByte(): Promise<number> {
/** Returns the next byte [0, 255] or `EOF`. */
async readByte(): Promise<number | EOF> {
while (this.r === this.w) {
if (this.eof) return -1;
if (this.eof) return EOF;
await this._fill(); // buffer is empty.
}
const c = this.buf[this.r];
Expand Down
2 changes: 1 addition & 1 deletion io/bufio_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async function readBytes(buf: BufReader): Promise<string> {
let nb = 0;
while (true) {
let c = await buf.readByte();
if (c < 0) {
if (c === EOF) {
break; // EOF
}
b[nb] = c;
Expand Down
43 changes: 25 additions & 18 deletions io/ioutil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { BufReader } from "./bufio.ts";
import { BufReader, EOF, UnexpectedEOFError } from "./bufio.ts";
type Reader = Deno.Reader;
type Writer = Deno.Writer;
import { assert } from "../testing/asserts.ts";
Expand Down Expand Up @@ -30,36 +30,43 @@ export async function copyN(
}

/** Read big endian 16bit short from BufReader */
export async function readShort(buf: BufReader): Promise<number> {
const [high, low] = [await buf.readByte(), await buf.readByte()];
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();
return (high << 8) | low;
}

/** Read big endian 32bit integer from BufReader */
export async function readInt(buf: BufReader): Promise<number> {
const [high, low] = [await readShort(buf), await readShort(buf)];
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();
return (high << 16) | low;
}

const BIT32 = 0xffffffff;
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);

/** Read big endian 64bit long from BufReader */
export async function readLong(buf: BufReader): Promise<number> {
const [high, low] = [await readInt(buf), await readInt(buf)];
// ECMAScript doesn't support 64bit bit ops.
return high ? high * (BIT32 + 1) + low : low;
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("Value too large.");
return Number(big);
}

/** Slice number into 64bit big endian byte array */
export function sliceLongToBytes(d: number, dest = new Array(8)): number[] {
let mask = 0xff;
let low = (d << 32) >>> 32;
let high = (d - low) / (BIT32 + 1);
let shift = 24;
for (let i = 0; i < 4; i++) {
dest[i] = (high >>> shift) & mask;
dest[i + 4] = (low >>> shift) & mask;
shift -= 8;
let big = BigInt(d);
for (let i = 0; i < 8; i++) {
dest[7 - i] = Number(big & 0xffn);
big >>= 8n;
}
return dest;
}
4 changes: 2 additions & 2 deletions io/ioutil_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ test(async function testReadInt(): Promise<void> {

test(async function testReadLong(): Promise<void> {
const r = new BinaryReader(
new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78])
new Uint8Array([0x00, 0x00, 0x00, 0x78, 0x12, 0x34, 0x56, 0x78])
);
const long = await readLong(new BufReader(r));
assertEquals(long, 0x1234567812345678);
assertEquals(long, 0x7812345678);
});

test(async function testReadLong2(): Promise<void> {
Expand Down
10 changes: 8 additions & 2 deletions ws/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export async function writeFrame(
/** Read websocket frame from given BufReader */
export async function readFrame(buf: BufReader): Promise<WebSocketFrame> {
let b = await buf.readByte();
if (b === EOF) throw new UnexpectedEOFError();
let isLastFrame = false;
switch (b >>> 4) {
case 0b1000:
Expand All @@ -156,12 +157,17 @@ export async function readFrame(buf: BufReader): Promise<WebSocketFrame> {
const opcode = b & 0x0f;
// has_mask & payload
b = await buf.readByte();
if (b === EOF) throw new UnexpectedEOFError();
const hasMask = b >>> 7;
let payloadLength = b & 0b01111111;
if (payloadLength === 126) {
payloadLength = await readShort(buf);
const l = await readShort(buf);
if (l === EOF) throw new UnexpectedEOFError();
payloadLength = l;
} else if (payloadLength === 127) {
payloadLength = await readLong(buf);
const l = await readLong(buf);
if (l === EOF) throw new UnexpectedEOFError();
payloadLength = Number(l);
}
// mask
let mask;
Expand Down

0 comments on commit b2786c2

Please sign in to comment.