Skip to main content
Module

std/node/buffer.ts

Deno standard library
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.import * as hex from "../encoding/hex.ts";import * as base64 from "../encoding/base64.ts";import { Encodings, normalizeEncoding, notImplemented } from "./_utils.ts";
const notImplementedEncodings = [ "ascii", "binary", "latin1", "ucs2", "utf16le",];
function checkEncoding(encoding = "utf8", strict = true): Encodings { if (typeof encoding !== "string" || (strict && encoding === "")) { if (!strict) return "utf8"; throw new TypeError(`Unknown encoding: ${encoding}`); }
const normalized = normalizeEncoding(encoding);
if (normalized === undefined) { throw new TypeError(`Unknown encoding: ${encoding}`); }
if (notImplementedEncodings.includes(encoding)) { notImplemented(`"${encoding}" encoding`); }
return normalized;}
interface EncodingOp { byteLength(string: string): number;}
// https://github.com/nodejs/node/blob/56dbe466fdbc598baea3bfce289bf52b97b8b8f7/lib/buffer.js#L598const encodingOps: { [key: string]: EncodingOp } = { utf8: { byteLength: (string: string): number => new TextEncoder().encode(string).byteLength, }, ucs2: { byteLength: (string: string): number => string.length * 2, }, utf16le: { byteLength: (string: string): number => string.length * 2, }, latin1: { byteLength: (string: string): number => string.length, }, ascii: { byteLength: (string: string): number => string.length, }, base64: { byteLength: (string: string): number => base64ByteLength(string, string.length), }, hex: { byteLength: (string: string): number => string.length >>> 1, },};
function base64ByteLength(str: string, bytes: number): number { // Handle padding if (str.charCodeAt(bytes - 1) === 0x3d) bytes--; if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3d) bytes--;
// Base64 ratio: 3/4 return (bytes * 3) >>> 2;}
/** * See also https://nodejs.org/api/buffer.html */export class Buffer extends Uint8Array { /** * Allocates a new Buffer of size bytes. */ static alloc( size: number, fill?: number | string | Uint8Array | Buffer, encoding = "utf8", ): Buffer { if (typeof size !== "number") { throw new TypeError( `The "size" argument must be of type number. Received type ${typeof size}`, ); }
const buf = new Buffer(size); if (size === 0) return buf;
let bufFill; if (typeof fill === "string") { const clearEncoding = checkEncoding(encoding); if ( typeof fill === "string" && fill.length === 1 && clearEncoding === "utf8" ) { buf.fill(fill.charCodeAt(0)); } else bufFill = Buffer.from(fill, clearEncoding); } else if (typeof fill === "number") { buf.fill(fill); } else if (fill instanceof Uint8Array) { if (fill.length === 0) { throw new TypeError( `The argument "value" is invalid. Received ${fill.constructor.name} []`, ); }
bufFill = fill; }
if (bufFill) { if (bufFill.length > buf.length) { bufFill = bufFill.subarray(0, buf.length); }
let offset = 0; while (offset < size) { buf.set(bufFill, offset); offset += bufFill.length; if (offset + bufFill.length >= size) break; } if (offset !== size) { buf.set(bufFill.subarray(0, size - offset), offset); } }
return buf; }
static allocUnsafe(size: number): Buffer { return new Buffer(size); }
/** * Returns the byte length of a string when encoded. This is not the same as * String.prototype.length, which does not account for the encoding that is * used to convert the string into bytes. */ static byteLength( string: string | Buffer | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, encoding = "utf8", ): number { if (typeof string != "string") return string.byteLength;
encoding = normalizeEncoding(encoding) || "utf8"; return encodingOps[encoding].byteLength(string); }
/** * Returns a new Buffer which is the result of concatenating all the Buffer * instances in the list together. */ static concat(list: Buffer[] | Uint8Array[], totalLength?: number): Buffer { if (totalLength == undefined) { totalLength = 0; for (const buf of list) { totalLength += buf.length; } }
const buffer = Buffer.allocUnsafe(totalLength); let pos = 0; for (const item of list) { let buf: Buffer; if (!(item instanceof Buffer)) { buf = Buffer.from(item); } else { buf = item; } buf.copy(buffer, pos); pos += buf.length; }
return buffer; }
/** * Allocates a new Buffer using an array of bytes in the range 0 – 255. Array * entries outside that range will be truncated to fit into it. */ static from(array: number[]): Buffer; /** * This creates a view of the ArrayBuffer without copying the underlying * memory. For example, when passed a reference to the .buffer property of a * TypedArray instance, the newly created Buffer will share the same allocated * memory as the TypedArray. */ static from( arrayBuffer: ArrayBuffer | SharedArrayBuffer, byteOffset?: number, length?: number, ): Buffer; /** * Copies the passed buffer data onto a new Buffer instance. */ static from(buffer: Buffer | Uint8Array): Buffer; /** * Creates a new Buffer containing string. */ static from(string: string, encoding?: string): Buffer; static from( // deno-lint-ignore no-explicit-any value: any, offsetOrEncoding?: number | string, length?: number, ): Buffer { const offset = typeof offsetOrEncoding === "string" ? undefined : offsetOrEncoding; let encoding = typeof offsetOrEncoding === "string" ? offsetOrEncoding : undefined;
if (typeof value == "string") { encoding = checkEncoding(encoding, false); if (encoding === "hex") { return new Buffer(hex.decode(new TextEncoder().encode(value)).buffer); } if (encoding === "base64") return new Buffer(base64.decode(value).buffer); return new Buffer(new TextEncoder().encode(value).buffer); }
// workaround for https://github.com/microsoft/TypeScript/issues/38446 return new Buffer(value, offset!, length); }
/** * Returns true if obj is a Buffer, false otherwise. */ static isBuffer(obj: unknown): obj is Buffer { return obj instanceof Buffer; }
// deno-lint-ignore no-explicit-any static isEncoding(encoding: any): boolean { return ( typeof encoding === "string" && encoding.length !== 0 && normalizeEncoding(encoding) !== undefined ); }
/** * Copies data from a region of buf to a region in target, even if the target * memory region overlaps with buf. */ copy( targetBuffer: Buffer | Uint8Array, targetStart = 0, sourceStart = 0, sourceEnd = this.length, ): number { const sourceBuffer = this .subarray(sourceStart, sourceEnd) .subarray(0, Math.max(0, targetBuffer.length - targetStart));
if (sourceBuffer.length === 0) return 0;
targetBuffer.set(sourceBuffer, targetStart); return sourceBuffer.length; }
/* * Returns true if both buf and otherBuffer have exactly the same bytes, false otherwise. */ equals(otherBuffer: Uint8Array | Buffer): boolean { if (!(otherBuffer instanceof Uint8Array)) { throw new TypeError( `The "otherBuffer" argument must be an instance of Buffer or Uint8Array. Received type ${typeof otherBuffer}`, ); }
if (this === otherBuffer) return true; if (this.byteLength !== otherBuffer.byteLength) return false;
for (let i = 0; i < this.length; i++) { if (this[i] !== otherBuffer[i]) return false; }
return true; }
readBigInt64BE(offset = 0): bigint { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getBigInt64(offset); } readBigInt64LE(offset = 0): bigint { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getBigInt64(offset, true); }
readBigUInt64BE(offset = 0): bigint { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getBigUint64(offset); } readBigUInt64LE(offset = 0): bigint { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getBigUint64(offset, true); }
readDoubleBE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getFloat64(offset); } readDoubleLE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getFloat64(offset, true); }
readFloatBE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getFloat32(offset); } readFloatLE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getFloat32(offset, true); }
readInt8(offset = 0): number { return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt8( offset, ); }
readInt16BE(offset = 0): number { return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16( offset, ); } readInt16LE(offset = 0): number { return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt16( offset, true, ); }
readInt32BE(offset = 0): number { return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32( offset, ); } readInt32LE(offset = 0): number { return new DataView(this.buffer, this.byteOffset, this.byteLength).getInt32( offset, true, ); }
readUInt8(offset = 0): number { return new DataView(this.buffer, this.byteOffset, this.byteLength).getUint8( offset, ); }
readUInt16BE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getUint16(offset); } readUInt16LE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getUint16(offset, true); }
readUInt32BE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getUint32(offset); } readUInt32LE(offset = 0): number { return new DataView( this.buffer, this.byteOffset, this.byteLength, ).getUint32(offset, true); }
/** * Returns a new Buffer that references the same memory as the original, but * offset and cropped by the start and end indices. */ slice(begin = 0, end = this.length): Buffer { // workaround for https://github.com/microsoft/TypeScript/issues/38665 return this.subarray(begin, end) as Buffer; }
/** * Returns a JSON representation of buf. JSON.stringify() implicitly calls * this function when stringifying a Buffer instance. */ toJSON(): Record<string, unknown> { return { type: "Buffer", data: Array.from(this) }; }
/** * Decodes buf to a string according to the specified character encoding in * encoding. start and end may be passed to decode only a subset of buf. */ toString(encoding = "utf8", start = 0, end = this.length): string { encoding = checkEncoding(encoding);
const b = this.subarray(start, end); if (encoding === "hex") return new TextDecoder().decode(hex.encode(b)); if (encoding === "base64") return base64.encode(b);
return new TextDecoder(encoding).decode(b); }
/** * Writes string to buf at offset according to the character encoding in * encoding. The length parameter is the number of bytes to write. If buf did * not contain enough space to fit the entire string, only part of string will * be written. However, partially encoded characters will not be written. */ write(string: string, offset = 0, length = this.length): number | undefined { return new TextEncoder().encodeInto( string, this.subarray(offset, offset + length), ).written; }
writeBigInt64BE(value: bigint, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64( offset, value, ); return offset + 4; } writeBigInt64LE(value: bigint, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setBigInt64( offset, value, true, ); return offset + 4; }
writeBigUInt64BE(value: bigint, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64( offset, value, ); return offset + 4; } writeBigUInt64LE(value: bigint, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setBigUint64( offset, value, true, ); return offset + 4; }
writeDoubleBE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64( offset, value, ); return offset + 8; } writeDoubleLE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat64( offset, value, true, ); return offset + 8; }
writeFloatBE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32( offset, value, ); return offset + 4; } writeFloatLE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setFloat32( offset, value, true, ); return offset + 4; }
writeInt8(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setInt8( offset, value, ); return offset + 1; }
writeInt16BE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16( offset, value, ); return offset + 2; } writeInt16LE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setInt16( offset, value, true, ); return offset + 2; }
writeInt32BE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32( offset, value, ); return offset + 4; } writeInt32LE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setInt32( offset, value, true, ); return offset + 4; }
writeUInt8(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setUint8( offset, value, ); return offset + 1; }
writeUInt16BE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16( offset, value, ); return offset + 2; } writeUInt16LE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setUint16( offset, value, true, ); return offset + 2; }
writeUInt32BE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32( offset, value, ); return offset + 4; } writeUInt32LE(value: number, offset = 0): number { new DataView(this.buffer, this.byteOffset, this.byteLength).setUint32( offset, value, true, ); return offset + 4; }}
export const kMaxLength = 4294967296;export const kStringMaxLength = 536870888;export const constants = { MAX_LENGTH: kMaxLength, MAX_STRING_LENGTH: kStringMaxLength,};
export const atob = globalThis.atob;export const btoa = globalThis.btoa;
export default { Buffer, kMaxLength, kStringMaxLength, constants, atob, btoa,};