UNPKG

ox

Version:

Ethereum Standard Library

690 lines 24.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ByteStringTooLargeError = exports.ObjectTooLargeError = exports.ArrayTooLargeError = exports.StringTooLargeError = exports.NumberTooLargeError = exports.UnexpectedTokenError = exports.UnsupportedBigIntError = exports.InvalidSimpleValueError = exports.InvalidIndefiniteLengthChunkError = exports.UnsupportedTagError = exports.Unsupported64BitIntegerError = exports.InvalidAdditionalInfoError = exports.InvalidMajorTypeError = void 0; exports.encode = encode; exports.decode = decode; const Bytes = require("./Bytes.js"); const Errors = require("./Errors.js"); const Hex = require("./Hex.js"); const Cursor = require("./internal/cursor.js"); function encode(data, options = {}) { const { as = 'Hex' } = options; const encodable = getEncodable(data); const cursor = Cursor.create(new Uint8Array(encodable.length)); encodable.encode(cursor); if (as === 'Hex') return Hex.fromBytes(cursor.bytes); return cursor.bytes; } function decode(data) { const bytes = (() => { if (typeof data === 'string') { if (data.length > 3 && data.length % 2 !== 0) throw new Hex.InvalidLengthError(data); return Bytes.fromHex(data); } return data; })(); const cursor = Cursor.create(bytes); return decodeCursor(cursor); } class InvalidMajorTypeError extends Errors.BaseError { constructor({ majorType }) { super(`Invalid CBOR major type: ${majorType}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.InvalidMajorTypeError' }); } } exports.InvalidMajorTypeError = InvalidMajorTypeError; class InvalidAdditionalInfoError extends Errors.BaseError { constructor({ additionalInfo }) { super(`Invalid CBOR additional info: ${additionalInfo}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.InvalidAdditionalInfoError' }); } } exports.InvalidAdditionalInfoError = InvalidAdditionalInfoError; class Unsupported64BitIntegerError extends Errors.BaseError { constructor() { super('64-bit integers are not supported in CBOR decoding.'); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.Unsupported64BitIntegerError' }); } } exports.Unsupported64BitIntegerError = Unsupported64BitIntegerError; class UnsupportedTagError extends Errors.BaseError { constructor({ tag }) { super(`CBOR tagged data (tag ${tag}) is not yet supported.`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.UnsupportedTagError' }); } } exports.UnsupportedTagError = UnsupportedTagError; class InvalidIndefiniteLengthChunkError extends Errors.BaseError { constructor({ type }) { super(`Invalid chunk type in indefinite-length ${type}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.InvalidIndefiniteLengthChunkError' }); } } exports.InvalidIndefiniteLengthChunkError = InvalidIndefiniteLengthChunkError; class InvalidSimpleValueError extends Errors.BaseError { constructor({ value }) { super(`Invalid CBOR simple value: ${value}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.InvalidSimpleValueError' }); } } exports.InvalidSimpleValueError = InvalidSimpleValueError; class UnsupportedBigIntError extends Errors.BaseError { constructor() { super('BigInt values are not supported in CBOR encoding.'); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.UnsupportedBigIntError' }); } } exports.UnsupportedBigIntError = UnsupportedBigIntError; class UnexpectedTokenError extends Errors.BaseError { constructor({ token }) { super(`Unexpected token: ${token}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.UnexpectedTokenError' }); } } exports.UnexpectedTokenError = UnexpectedTokenError; class NumberTooLargeError extends Errors.BaseError { constructor({ number }) { super(`Number exceeds maximum safe integer (${Number.MAX_SAFE_INTEGER}): ${number}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.NumberTooLargeError' }); } } exports.NumberTooLargeError = NumberTooLargeError; class StringTooLargeError extends Errors.BaseError { constructor({ size }) { super(`String length exceeds maximum (4294967295): ${size}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.StringTooLargeError' }); } } exports.StringTooLargeError = StringTooLargeError; class ArrayTooLargeError extends Errors.BaseError { constructor({ size }) { super(`Array length exceeds maximum (4294967295): ${size}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.ArrayTooLargeError' }); } } exports.ArrayTooLargeError = ArrayTooLargeError; class ObjectTooLargeError extends Errors.BaseError { constructor({ size }) { super(`Object size exceeds maximum (4294967295): ${size}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.ObjectTooLargeError' }); } } exports.ObjectTooLargeError = ObjectTooLargeError; class ByteStringTooLargeError extends Errors.BaseError { constructor({ size }) { super(`Byte string length exceeds maximum (4294967295): ${size}`); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Cbor.ByteStringTooLargeError' }); } } exports.ByteStringTooLargeError = ByteStringTooLargeError; function getEncodable(value) { if (typeof value === 'undefined') return { length: 1, encode: (cursor) => cursor.pushUint8(0xf7) }; if (value === null) return { length: 1, encode: (cursor) => cursor.pushUint8(0xf6) }; if (typeof value === 'boolean') return { length: 1, encode: (cursor) => cursor.pushUint8(value ? 0xf5 : 0xf4), }; if (typeof value === 'number') return getEncodable.number(value); if (typeof value === 'bigint') throw new UnsupportedBigIntError(); if (typeof value === 'string') return getEncodable.string(value); if (Array.isArray(value)) return getEncodable.array(value); if (value instanceof Uint8Array) return getEncodable.byteString(value); if (value instanceof ArrayBuffer) return getEncodable.byteString(new Uint8Array(value)); if (ArrayBuffer.isView(value)) return getEncodable.byteString(new Uint8Array(value.buffer, value.byteOffset, value.byteLength)); if (typeof value === 'object') return getEncodable.object(value); throw new UnexpectedTokenError({ token: String(value) }); } (function (getEncodable) { function number(value) { if (!Number.isSafeInteger(value)) { const float32 = Math.fround(value); if (Number.isNaN(value) || value === float32) return { length: 5, encode(cursor) { cursor.pushUint8(0xfa); cursor.dataView.setFloat32(cursor.position, value, false); cursor.position += 4; }, }; return { length: 9, encode(cursor) { cursor.pushUint8(0xfb); cursor.dataView.setFloat64(cursor.position, value, false); cursor.position += 8; }, }; } if (value >= 0) { if (value <= 0x17) return { length: 1, encode: (cursor) => cursor.pushUint8(value) }; if (value <= 0xff) return { length: 2, encode: (cursor) => { cursor.pushUint8(0x18); cursor.pushUint8(value); }, }; if (value <= 0xffff) return { length: 3, encode: (cursor) => { cursor.pushUint8(0x19); cursor.pushUint16(value); }, }; if (value <= 0xffffffff) return { length: 5, encode: (cursor) => { cursor.pushUint8(0x1a); cursor.pushUint32(value); }, }; throw new NumberTooLargeError({ number: value.toString(10) }); } const positiveNumber = -1 - value; if (value >= -24) return { length: 1, encode: (cursor) => cursor.pushUint8(0x20 + positiveNumber), }; if (positiveNumber <= 0xff) return { length: 2, encode: (cursor) => { cursor.pushUint8(0x38); cursor.pushUint8(positiveNumber); }, }; if (positiveNumber <= 0xffff) return { length: 3, encode: (cursor) => { cursor.pushUint8(0x39); cursor.pushUint16(positiveNumber); }, }; if (positiveNumber <= 0xffffffff) return { length: 5, encode: (cursor) => { cursor.pushUint8(0x3a); cursor.pushUint32(positiveNumber); }, }; throw new NumberTooLargeError({ number: value.toString(10) }); } getEncodable.number = number; function string(value) { const encoded = Bytes.fromString(value); const size = encoded.length; if (size <= 0x17) return { length: 1 + size, encode(cursor) { cursor.pushUint8(0x60 + size); if (size > 0) cursor.pushBytes(encoded); }, }; if (size <= 0xff) return { length: 2 + size, encode(cursor) { cursor.pushUint8(0x78); cursor.pushUint8(size); cursor.pushBytes(encoded); }, }; if (size <= 0xffff) return { length: 3 + size, encode(cursor) { cursor.pushUint8(0x79); cursor.pushUint16(size); cursor.pushBytes(encoded); }, }; if (size <= 0xffffffff) return { length: 5 + size, encode(cursor) { cursor.pushUint8(0x7a); cursor.pushUint32(size); cursor.pushBytes(encoded); }, }; throw new StringTooLargeError({ size }); } getEncodable.string = string; function array(value) { const items = value.map((item) => getEncodable(item)); const bodyLength = items.reduce((acc, item) => acc + item.length, 0); const size = value.length; if (size <= 0x17) return { length: 1 + bodyLength, encode(cursor) { cursor.pushUint8(0x80 + size); for (const item of items) item.encode(cursor); }, }; if (size <= 0xff) return { length: 2 + bodyLength, encode(cursor) { cursor.pushUint8(0x98); cursor.pushUint8(size); for (const item of items) item.encode(cursor); }, }; if (size <= 0xffff) return { length: 3 + bodyLength, encode(cursor) { cursor.pushUint8(0x99); cursor.pushUint16(size); for (const item of items) item.encode(cursor); }, }; if (size <= 0xffffffff) return { length: 5 + bodyLength, encode(cursor) { cursor.pushUint8(0x9a); cursor.pushUint32(size); for (const item of items) item.encode(cursor); }, }; throw new ArrayTooLargeError({ size }); } getEncodable.array = array; function byteString(value) { const size = value.byteLength; if (size <= 0x17) return { length: 1 + size, encode(cursor) { cursor.pushUint8(0x40 + size); cursor.pushBytes(value); }, }; if (size <= 0xff) return { length: 2 + size, encode(cursor) { cursor.pushUint8(0x58); cursor.pushUint8(size); cursor.pushBytes(value); }, }; if (size <= 0xffff) return { length: 3 + size, encode(cursor) { cursor.pushUint8(0x59); cursor.pushUint16(size); cursor.pushBytes(value); }, }; if (size <= 0xffffffff) return { length: 5 + size, encode(cursor) { cursor.pushUint8(0x5a); cursor.pushUint32(size); cursor.pushBytes(value); }, }; throw new ByteStringTooLargeError({ size }); } getEncodable.byteString = byteString; function object(value) { const keys = Object.keys(value); const entries = keys.map((key) => ({ key: getEncodable(key), value: getEncodable(value[key]), })); const bodyLength = entries.reduce((acc, entry) => acc + entry.key.length + entry.value.length, 0); const size = keys.length; if (size <= 0x17) return { length: 1 + bodyLength, encode(cursor) { cursor.pushUint8(0xa0 + size); for (const entry of entries) { entry.key.encode(cursor); entry.value.encode(cursor); } }, }; if (size <= 0xff) return { length: 2 + bodyLength, encode(cursor) { cursor.pushUint8(0xb8); cursor.pushUint8(size); for (const entry of entries) { entry.key.encode(cursor); entry.value.encode(cursor); } }, }; if (size <= 0xffff) return { length: 3 + bodyLength, encode(cursor) { cursor.pushUint8(0xb9); cursor.pushUint16(size); for (const entry of entries) { entry.key.encode(cursor); entry.value.encode(cursor); } }, }; if (size <= 0xffffffff) return { length: 5 + bodyLength, encode(cursor) { cursor.pushUint8(0xba); cursor.pushUint32(size); for (const entry of entries) { entry.key.encode(cursor); entry.value.encode(cursor); } }, }; throw new ObjectTooLargeError({ size }); } getEncodable.object = object; })(getEncodable || (getEncodable = {})); function decodeCursor(cursor) { const initialByte = cursor.readUint8(); const majorType = initialByte >> 5; const additionalInfo = initialByte & 0b00011111; switch (majorType) { case 0: return decodeCursor.readUnsignedInteger(cursor, additionalInfo); case 1: return decodeCursor.readNegativeInteger(cursor, additionalInfo); case 2: return decodeCursor.readByteString(cursor, additionalInfo); case 3: return decodeCursor.readTextString(cursor, additionalInfo); case 4: return decodeCursor.readArray(cursor, additionalInfo); case 5: return decodeCursor.readMap(cursor, additionalInfo); case 6: throw new UnsupportedTagError({ tag: additionalInfo }); case 7: return decodeCursor.readSimpleOrFloat(cursor, additionalInfo); default: throw new InvalidMajorTypeError({ majorType }); } } (function (decodeCursor) { function readLength(cursor, additionalInfo) { if (additionalInfo < 24) return additionalInfo; if (additionalInfo === 24) return cursor.readUint8(); if (additionalInfo === 25) return cursor.readUint16(); if (additionalInfo === 26) return cursor.readUint32(); if (additionalInfo === 27) throw new Unsupported64BitIntegerError(); throw new InvalidAdditionalInfoError({ additionalInfo }); } function readUnsignedInteger(cursor, additionalInfo) { return readLength(cursor, additionalInfo); } decodeCursor.readUnsignedInteger = readUnsignedInteger; function readNegativeInteger(cursor, additionalInfo) { const value = readLength(cursor, additionalInfo); return -1 - value; } decodeCursor.readNegativeInteger = readNegativeInteger; function readByteString(cursor, additionalInfo) { if (additionalInfo === 31) { const chunks = []; let totalLength = 0; while (true) { const byte = cursor.inspectUint8(); if (byte === 0xff) { cursor.readUint8(); break; } const chunk = decodeCursor(cursor); if (!(chunk instanceof Uint8Array)) throw new InvalidIndefiniteLengthChunkError({ type: 'byte string' }); chunks.push(chunk); totalLength += chunk.length; } const result = new Uint8Array(totalLength); let offset = 0; for (const chunk of chunks) { result.set(chunk, offset); offset += chunk.length; } return result; } const length = readLength(cursor, additionalInfo); return cursor.readBytes(length); } decodeCursor.readByteString = readByteString; function readTextString(cursor, additionalInfo) { if (additionalInfo === 31) { const chunks = []; while (true) { const byte = cursor.inspectUint8(); if (byte === 0xff) { cursor.readUint8(); break; } const chunk = decodeCursor(cursor); if (typeof chunk !== 'string') throw new InvalidIndefiniteLengthChunkError({ type: 'text string' }); chunks.push(chunk); } return chunks.join(''); } const length = readLength(cursor, additionalInfo); const bytes = cursor.readBytes(length); return Bytes.toString(bytes); } decodeCursor.readTextString = readTextString; function readArray(cursor, additionalInfo) { if (additionalInfo === 31) { const result = []; while (true) { const byte = cursor.inspectUint8(); if (byte === 0xff) { cursor.readUint8(); break; } result.push(decodeCursor(cursor)); } return result; } const length = readLength(cursor, additionalInfo); const result = []; for (let i = 0; i < length; i++) { result.push(decodeCursor(cursor)); } return result; } decodeCursor.readArray = readArray; function readMap(cursor, additionalInfo) { if (additionalInfo === 31) { const result = {}; while (true) { const byte = cursor.inspectUint8(); if (byte === 0xff) { cursor.readUint8(); break; } const key = decodeCursor(cursor); const keyStr = typeof key === 'string' ? key : typeof key === 'number' ? String(key) : String(key); const value = decodeCursor(cursor); result[keyStr] = value; } return result; } const length = readLength(cursor, additionalInfo); const result = {}; for (let i = 0; i < length; i++) { const key = decodeCursor(cursor); const keyStr = typeof key === 'string' ? key : typeof key === 'number' ? String(key) : String(key); const value = decodeCursor(cursor); result[keyStr] = value; } return result; } decodeCursor.readMap = readMap; function readSimpleOrFloat(cursor, additionalInfo) { if (additionalInfo === 20) return false; if (additionalInfo === 21) return true; if (additionalInfo === 22) return null; if (additionalInfo === 23) return undefined; if (additionalInfo === 25) { const bits = cursor.readUint16(); return getFloat16(bits); } if (additionalInfo === 26) { const value = cursor.dataView.getFloat32(cursor.position, false); cursor.position += 4; return value; } if (additionalInfo === 27) { const value = cursor.dataView.getFloat64(cursor.position, false); cursor.position += 8; return value; } if (additionalInfo === 24) { const simpleValue = cursor.readUint8(); if (simpleValue < 32) throw new InvalidSimpleValueError({ value: simpleValue }); return undefined; } throw new InvalidAdditionalInfoError({ additionalInfo }); } decodeCursor.readSimpleOrFloat = readSimpleOrFloat; function getFloat16(bits) { const sign = (bits >> 15) & 0x1; const exponent = (bits >> 10) & 0x1f; const fraction = bits & 0x3ff; if (exponent === 0) { if (fraction === 0) return sign ? -0 : 0; const value = 2 ** -14 * (fraction / 1024); return sign ? -value : value; } if (exponent === 0x1f) { if (fraction === 0) return sign ? -Infinity : Infinity; return NaN; } const value = 2 ** (exponent - 15) * (1 + fraction / 1024); return sign ? -value : value; } })(decodeCursor || (decodeCursor = {})); //# sourceMappingURL=Cbor.js.map