diff --git a/src/lib/cbor-sync.js b/src/lib/cbor-sync.js index a5031c0..4a5309c 100644 --- a/src/lib/cbor-sync.js +++ b/src/lib/cbor-sync.js @@ -1,693 +1,699 @@ (function (global, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module !== 'undefined' && module.exports) { - module.exports = factory(); - } else { - global.CBOR = factory(); - } -})(this, function () { - const { DataItem } = require('./DataItem'); - var CBOR = (function () { - function BinaryHex(hex) { - this.$hex = hex; + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = factory(); + } else { + global.CBOR = factory(); } - BinaryHex.prototype = { - length: function () { - return this.$hex.length / 2; - }, - toString: function (format) { - if (!format || format === 'hex' || format === 16) return this.$hex; - if (format === 'utf-8') { - var encoded = ''; - for (var i = 0; i < this.$hex.length; i += 2) { - encoded += '%' + this.$hex.substring(i, i + 2); - } - return decodeURIComponent(encoded); - } - if (format === 'latin') { - var encoded = []; - for (var i = 0; i < this.$hex.length; i += 2) { - encoded.push(parseInt(this.$hex.substring(i, i + 2), 16)); - } - return String.fromCharCode.apply(String, encoded); - } - throw new Error('Unrecognised format: ' + format); - }, - }; - BinaryHex.fromLatinString = function (latinString) { - var hex = ''; - for (var i = 0; i < latinString.length; i++) { - var pair = latinString.charCodeAt(i).toString(16); - if (pair.length === 1) pair = '0' + pair; - hex += pair; + })(this, function () { + const { DataItem } = require('./DataItem'); + var CBOR = (function () { + function BinaryHex(hex) { + this.$hex = hex; } - return new BinaryHex(hex); - }; - BinaryHex.fromUtf8String = function (utf8String) { - var encoded = encodeURIComponent(utf8String); - var hex = ''; - for (var i = 0; i < encoded.length; i++) { - if (encoded.charAt(i) === '%') { - hex += encoded.substring(i + 1, i + 3); - i += 2; - } else { - var hexPair = encoded.charCodeAt(i).toString(16); - if (hexPair.length < 2) hexPair = '0' + hexPair; - hex += hexPair; - } - } - return new BinaryHex(hex); - }; - - var semanticEncoders = []; - var semanticDecoders = {}; - - var notImplemented = function (label) { - return function () { - throw new Error(label + ' not implemented'); - }; - }; - - function Reader() {} - Reader.prototype = { - peekByte: notImplemented('peekByte'), - readByte: notImplemented('readByte'), - readChunk: notImplemented('readChunk'), - readFloat16: function () { - var half = this.readUint16(); - var exponent = (half & 0x7fff) >> 10; - var mantissa = half & 0x3ff; - var negative = half & 0x8000; - if (exponent === 0x1f) { - if (mantissa === 0) { - return negative ? -Infinity : Infinity; + BinaryHex.prototype = { + length: function () { + return this.$hex.length / 2; + }, + toString: function (format) { + if (!format || format === 'hex' || format === 16) return this.$hex; + if (format === 'utf-8') { + var encoded = ''; + for (var i = 0; i < this.$hex.length; i += 2) { + encoded += '%' + this.$hex.substring(i, i + 2); + } + return decodeURIComponent(encoded); } - return NaN; - } - var magnitude = exponent - ? Math.pow(2, exponent - 25) * (1024 + mantissa) - : Math.pow(2, -24) * mantissa; - return negative ? -magnitude : magnitude; - }, - readFloat32: function () { - var intValue = this.readUint32(); - var exponent = (intValue & 0x7fffffff) >> 23; - var mantissa = intValue & 0x7fffff; - var negative = intValue & 0x80000000; - if (exponent === 0xff) { - if (mantissa === 0) { - return negative ? -Infinity : Infinity; + if (format === 'latin') { + var encoded = []; + for (var i = 0; i < this.$hex.length; i += 2) { + encoded.push(parseInt(this.$hex.substring(i, i + 2), 16)); + } + return String.fromCharCode.apply(String, encoded); } - return NaN; + throw new Error('Unrecognised format: ' + format); + }, + }; + BinaryHex.fromLatinString = function (latinString) { + var hex = ''; + for (var i = 0; i < latinString.length; i++) { + var pair = latinString.charCodeAt(i).toString(16); + if (pair.length === 1) pair = '0' + pair; + hex += pair; } - var magnitude = exponent - ? Math.pow(2, exponent - 23 - 127) * (8388608 + mantissa) - : Math.pow(2, -23 - 126) * mantissa; - return negative ? -magnitude : magnitude; - }, - readFloat64: function () { - var int1 = this.readUint32(), - int2 = this.readUint32(); - var exponent = (int1 >> 20) & 0x7ff; - var mantissa = (int1 & 0xfffff) * 4294967296 + int2; - var negative = int1 & 0x80000000; - if (exponent === 0x7ff) { - if (mantissa === 0) { - return negative ? -Infinity : Infinity; + return new BinaryHex(hex); + }; + BinaryHex.fromUtf8String = function (utf8String) { + var encoded = encodeURIComponent(utf8String); + var hex = ''; + for (var i = 0; i < encoded.length; i++) { + if (encoded.charAt(i) === '%') { + hex += encoded.substring(i + 1, i + 3); + i += 2; + } else { + var hexPair = encoded.charCodeAt(i).toString(16); + if (hexPair.length < 2) hexPair = '0' + hexPair; + hex += hexPair; } - return NaN; } - var magnitude = exponent - ? Math.pow(2, exponent - 52 - 1023) * (4503599627370496 + mantissa) - : Math.pow(2, -52 - 1022) * mantissa; - return negative ? -magnitude : magnitude; - }, - readUint16: function () { - return this.readByte() * 256 + this.readByte(); - }, - readUint32: function () { - return this.readUint16() * 65536 + this.readUint16(); - }, - readUint64: function () { - return this.readUint32() * 4294967296 + this.readUint32(); - }, - }; - function Writer() {} - Writer.prototype = { - writeByte: notImplemented('writeByte'), - result: notImplemented('result'), - writeFloat16: notImplemented('writeFloat16'), - writeFloat32: notImplemented('writeFloat32'), - writeFloat64: notImplemented('writeFloat64'), - writeUint16: function (value) { - this.writeByte((value >> 8) & 0xff); - this.writeByte(value & 0xff); - }, - writeUint32: function (value) { - this.writeUint16((value >> 16) & 0xffff); - this.writeUint16(value & 0xffff); - }, - writeUint64: function (value) { - if (value >= 9007199254740992 || value <= -9007199254740992) { - throw new Error( - 'Cannot encode Uint64 of: ' + - value + - ' magnitude to big (floating point errors)', - ); - } - this.writeUint32(Math.floor(value / 4294967296)); - this.writeUint32(value % 4294967296); - }, - writeString: notImplemented('writeString'), - canWriteBinary: function (chunk) { - return false; - }, - writeBinary: notImplemented('writeChunk'), - }; - - function readHeaderRaw(reader) { - var firstByte = reader.readByte(); - var majorType = firstByte >> 5, - value = firstByte & 0x1f; - return { type: majorType, value: value }; - } - - function valueFromHeader(header, reader) { - var value = header.value; - if (value < 24) { - return value; - } else if (value == 24) { - return reader.readByte(); - } else if (value == 25) { - return reader.readUint16(); - } else if (value == 26) { - return reader.readUint32(); - } else if (value == 27) { - return reader.readUint64(); - } else if (value == 31) { - // special value for non-terminating arrays/objects - return null; - } - notImplemented('Additional info: ' + value)(); - } - - function writeHeaderRaw(type, value, writer) { - writer.writeByte((type << 5) | value); - } - - function writeHeader(type, value, writer) { - var firstByte = type << 5; - if (value < 24) { - writer.writeByte(firstByte | value); - } else if (value < 256) { - writer.writeByte(firstByte | 24); - writer.writeByte(value); - } else if (value < 65536) { - writer.writeByte(firstByte | 25); - writer.writeUint16(value); - } else if (value < 4294967296) { - writer.writeByte(firstByte | 26); - writer.writeUint32(value); - } else { - writer.writeByte(firstByte | 27); - writer.writeUint64(value); - } - } - - var stopCode = new Error(); // Just a unique object, that won't compare strictly equal to anything else - - function decodeReader(reader) { - var header = readHeaderRaw(reader); - switch (header.type) { - case 0: - return valueFromHeader(header, reader); - case 1: - return -1 - valueFromHeader(header, reader); - case 2: - return reader.readChunk(valueFromHeader(header, reader)); - case 3: - var buffer = reader.readChunk(valueFromHeader(header, reader)); - return buffer.toString('utf-8'); - case 4: - case 5: - var arrayLength = valueFromHeader(header, reader); - var result = []; - if (arrayLength !== null) { - if (header.type === 5) { - arrayLength *= 2; - } - for (var i = 0; i < arrayLength; i++) { - result[i] = decodeReader(reader); - } - } else { - var item; - while ((item = decodeReader(reader)) !== stopCode) { - result.push(item); + return new BinaryHex(hex); + }; + + var semanticEncoders = []; + var semanticDecoders = {}; + + var notImplemented = function (label) { + return function () { + throw new Error(label + ' not implemented'); + }; + }; + + function Reader() {} + Reader.prototype = { + peekByte: notImplemented('peekByte'), + readByte: notImplemented('readByte'), + readChunk: notImplemented('readChunk'), + readFloat16: function () { + var half = this.readUint16(); + var exponent = (half & 0x7fff) >> 10; + var mantissa = half & 0x3ff; + var negative = half & 0x8000; + if (exponent === 0x1f) { + if (mantissa === 0) { + return negative ? -Infinity : Infinity; } + return NaN; } - if (header.type === 5) { - var objResult = {}; - for (var i = 0; i < result.length; i += 2) { - objResult[result[i]] = result[i + 1]; + var magnitude = exponent + ? Math.pow(2, exponent - 25) * (1024 + mantissa) + : Math.pow(2, -24) * mantissa; + return negative ? -magnitude : magnitude; + }, + readFloat32: function () { + var intValue = this.readUint32(); + var exponent = (intValue & 0x7fffffff) >> 23; + var mantissa = intValue & 0x7fffff; + var negative = intValue & 0x80000000; + if (exponent === 0xff) { + if (mantissa === 0) { + return negative ? -Infinity : Infinity; } - return objResult; - } else { - return result; + return NaN; } - case 6: - var tag = valueFromHeader(header, reader); - var decoder = semanticDecoders[tag]; - var result = decodeReader(reader); - return decoder ? decoder(result) : result; - case 7: - if (header.value === 25) { - return reader.readFloat16(); - } else if (header.value === 26) { - return reader.readFloat32(); - } else if (header.value === 27) { - return reader.readFloat64(); + var magnitude = exponent + ? Math.pow(2, exponent - 23 - 127) * (8388608 + mantissa) + : Math.pow(2, -23 - 126) * mantissa; + return negative ? -magnitude : magnitude; + }, + readFloat64: function () { + var int1 = this.readUint32(), + int2 = this.readUint32(); + var exponent = (int1 >> 20) & 0x7ff; + var mantissa = (int1 & 0xfffff) * 4294967296 + int2; + var negative = int1 & 0x80000000; + if (exponent === 0x7ff) { + if (mantissa === 0) { + return negative ? -Infinity : Infinity; + } + return NaN; } - switch (valueFromHeader(header, reader)) { - case 20: - return false; - case 21: - return true; - case 22: - return null; - case 23: - return undefined; - case null: - return stopCode; - default: - throw new Error('Unknown fixed value: ' + header.value); + var magnitude = exponent + ? Math.pow(2, exponent - 52 - 1023) * (4503599627370496 + mantissa) + : Math.pow(2, -52 - 1022) * mantissa; + return negative ? -magnitude : magnitude; + }, + readUint16: function () { + return this.readByte() * 256 + this.readByte(); + }, + readUint32: function () { + return this.readUint16() * 65536 + this.readUint16(); + }, + readUint64: function () { + return this.readUint32() * 4294967296 + this.readUint32(); + }, + }; + function Writer() {} + Writer.prototype = { + writeByte: notImplemented('writeByte'), + result: notImplemented('result'), + writeFloat16: notImplemented('writeFloat16'), + writeFloat32: notImplemented('writeFloat32'), + writeFloat64: notImplemented('writeFloat64'), + writeUint16: function (value) { + this.writeByte((value >> 8) & 0xff); + this.writeByte(value & 0xff); + }, + writeUint32: function (value) { + this.writeUint16((value >> 16) & 0xffff); + this.writeUint16(value & 0xffff); + }, + writeUint64: function (value) { + if (value >= 9007199254740992 || value <= -9007199254740992) { + throw new Error( + 'Cannot encode Uint64 of: ' + + value + + ' magnitude to big (floating point errors)', + ); } - default: - throw new Error('Unsupported header: ' + JSON.stringify(header)); + this.writeUint32(Math.floor(value / 4294967296)); + this.writeUint32(value % 4294967296); + }, + writeString: notImplemented('writeString'), + canWriteBinary: function (chunk) { + return false; + }, + writeBinary: notImplemented('writeChunk'), + }; + + function readHeaderRaw(reader) { + var firstByte = reader.readByte(); + var majorType = firstByte >> 5, + value = firstByte & 0x1f; + return { type: majorType, value: value }; } - throw new Error('not implemented yet'); - } - - function encodeWriter(data, writer) { - for (var i = 0; i < semanticEncoders.length; i++) { - var replacement = semanticEncoders[i].fn(data); - if (replacement !== undefined) { - writeHeader(6, semanticEncoders[i].tag, writer); - return encodeWriter(replacement, writer); + + function valueFromHeader(header, reader) { + var value = header.value; + if (value < 24) { + return value; + } else if (value == 24) { + return reader.readByte(); + } else if (value == 25) { + return reader.readUint16(); + } else if (value == 26) { + return reader.readUint32(); + } else if (value == 27) { + return reader.readUint64(); + } else if (value == 31) { + // special value for non-terminating arrays/objects + return null; } + notImplemented('Additional info: ' + value)(); } - - if (data && typeof data.toCBOR === 'function') { - data = data.toCBOR(); + + function writeHeaderRaw(type, value, writer) { + writer.writeByte((type << 5) | value); } - - if (data === false) { - writeHeader(7, 20, writer); - } else if (data === true) { - writeHeader(7, 21, writer); - } else if (data === null) { - writeHeader(7, 22, writer); - } else if (data === undefined) { - writeHeader(7, 23, writer); - } else if (typeof data === 'number') { - if ( - Math.floor(data) === data && - data < 9007199254740992 && - data > -9007199254740992 - ) { - // Integer - if (data < 0) { - writeHeader(1, -1 - data, writer); - } else { - writeHeader(0, data, writer); - } + + function writeHeader(type, value, writer) { + var firstByte = type << 5; + if (value < 24) { + writer.writeByte(firstByte | value); + } else if (value < 256) { + writer.writeByte(firstByte | 24); + writer.writeByte(value); + } else if (value < 65536) { + writer.writeByte(firstByte | 25); + writer.writeUint16(value); + } else if (value < 4294967296) { + writer.writeByte(firstByte | 26); + writer.writeUint32(value); } else { - writeHeaderRaw(7, 27, writer); - writer.writeFloat64(data); + writer.writeByte(firstByte | 27); + writer.writeUint64(value); } - } else if (typeof data === 'string') { - writer.writeString(data, function (length) { - writeHeader(3, length, writer); - }); - } else if (writer.canWriteBinary(data)) { - writer.writeBinary(data, function (length) { - writeHeader(2, length, writer); - }); - } else if (typeof data === 'object') { - if (api.config.useToJSON && typeof data.toJSON === 'function') { - data = data.toJSON(); + } + + var stopCode = new Error(); // Just a unique object, that won't compare strictly equal to anything else + + function decodeReader(reader) { + var header = readHeaderRaw(reader); + switch (header.type) { + case 0: + return valueFromHeader(header, reader); + case 1: + return -1 - valueFromHeader(header, reader); + case 2: + return reader.readChunk(valueFromHeader(header, reader)); + case 3: + var buffer = reader.readChunk(valueFromHeader(header, reader)); + return buffer.toString('utf-8'); + case 4: + case 5: + var arrayLength = valueFromHeader(header, reader); + var result = []; + if (arrayLength !== null) { + if (header.type === 5) { + arrayLength *= 2; + } + for (var i = 0; i < arrayLength; i++) { + result[i] = decodeReader(reader); + } + } else { + var item; + while ((item = decodeReader(reader)) !== stopCode) { + result.push(item); + } + } + if (header.type === 5) { + var objResult = {}; + for (var i = 0; i < result.length; i += 2) { + objResult[result[i]] = result[i + 1]; + } + return objResult; + } else { + return result; + } + case 6: + var tag = valueFromHeader(header, reader); + var decoder = semanticDecoders[tag]; + var result = decodeReader(reader); + return decoder ? decoder(result) : result; + case 7: + if (header.value === 25) { + return reader.readFloat16(); + } else if (header.value === 26) { + return reader.readFloat32(); + } else if (header.value === 27) { + return reader.readFloat64(); + } + switch (valueFromHeader(header, reader)) { + case 20: + return false; + case 21: + return true; + case 22: + return null; + case 23: + return undefined; + case null: + return stopCode; + default: + throw new Error('Unknown fixed value: ' + header.value); + } + default: + throw new Error('Unsupported header: ' + JSON.stringify(header)); } - if (Array.isArray(data)) { - writeHeader(4, data.length, writer); - for (var i = 0; i < data.length; i++) { - encodeWriter(data[i], writer); + throw new Error('not implemented yet'); + } + + function encodeWriter(data, writer) { + for (var i = 0; i < semanticEncoders.length; i++) { + var replacement = semanticEncoders[i].fn(data); + if (replacement !== undefined) { + writeHeader(6, semanticEncoders[i].tag, writer); + return encodeWriter(replacement, writer); } - } else { - var keys = Object.keys(data); - writeHeader(5, keys.length, writer); - for (var i = 0; i < keys.length; i++) { - const number = parseInt(keys[i]); - if (isNaN(number)) { - encodeWriter(keys[i], writer); - encodeWriter(data[keys[i]], writer); + } + + if (data && typeof data.toCBOR === 'function') { + data = data.toCBOR(); + } + + if (data === false) { + writeHeader(7, 20, writer); + } else if (data === true) { + writeHeader(7, 21, writer); + } else if (data === null) { + writeHeader(7, 22, writer); + } else if (data === undefined) { + writeHeader(7, 23, writer); + } else if (typeof data === 'number') { + if ( + Math.floor(data) === data && + data < 9007199254740992 && + data > -9007199254740992 + ) { + // Integer + if (data < 0) { + writeHeader(1, -1 - data, writer); } else { - encodeWriter(number, writer); - encodeWriter(data[keys[i]], writer); + writeHeader(0, data, writer); } + } else { + writeHeaderRaw(7, 27, writer); + writer.writeFloat64(data); } - } - } else { - throw new Error('CBOR encoding not supported: ' + data); - } - } - - var readerFunctions = []; - var writerFunctions = []; - - var api = { - config: { - useToJSON: true, - }, - addWriter: function (format, writerFunction) { - if (typeof format === 'string') { - writerFunctions.push(function (f) { - if (format === f) return writerFunction(f); + } else if (typeof data === 'string') { + writer.writeString(data, function (length) { + writeHeader(3, length, writer); }); - } else { - writerFunctions.push(format); - } - }, - addReader: function (format, readerFunction) { - if (typeof format === 'string') { - readerFunctions.push(function (data, f) { - if (format === f) return readerFunction(data, f); + } else if (writer.canWriteBinary(data)) { + writer.writeBinary(data, function (length) { + writeHeader(2, length, writer); }); + } else if (typeof data === 'object') { + if (api.config.useToJSON && typeof data.toJSON === 'function') { + data = data.toJSON(); + } + if (Array.isArray(data)) { + writeHeader(4, data.length, writer); + for (var i = 0; i < data.length; i++) { + encodeWriter(data[i], writer); + } + } else { + var keys = Object.keys(data); + writeHeader(5, keys.length, writer); + for (var i = 0; i < keys.length; i++) { + const number = parseInt(keys[i]); + if (isNaN(number)) { + encodeWriter(keys[i], writer); + encodeWriter(data[keys[i]], writer); + } else { + encodeWriter(number, writer); + encodeWriter(data[keys[i]], writer); + } + } + } } else { - readerFunctions.push(format); + throw new Error('CBOR encoding not supported: ' + data); } - }, - encode: function (data, format) { - for (var i = 0; i < writerFunctions.length; i++) { - var func = writerFunctions[i]; - var writer = func(format); - if (writer) { - encodeWriter(data, writer); - return writer.result(); + } + + var readerFunctions = []; + var writerFunctions = []; + + var api = { + config: { + useToJSON: true, + }, + addWriter: function (format, writerFunction) { + if (typeof format === 'string') { + writerFunctions.push(function (f) { + if (format === f) return writerFunction(f); + }); + } else { + writerFunctions.push(format); } - } - throw new Error('Unsupported output format: ' + format); - }, - // DataItem: {getData: () => any} - encodeDataItem: function (data, format) { - for (var i = 0; i < writerFunctions.length; i++) { - var func = writerFunctions[i]; - var writer = func(format); - if (writer) { - if (data.getTag() !== undefined) { + }, + addReader: function (format, readerFunction) { + if (typeof format === 'string') { + readerFunctions.push(function (data, f) { + if (format === f) return readerFunction(data, f); + }); + } else { + readerFunctions.push(format); + } + }, + encode: function (data, format) { + console.log('============encode', data, format); + for (var i = 0; i < writerFunctions.length; i++) { + var func = writerFunctions[i]; + var writer = func(format); + if (writer) { encodeWriter(data, writer); return writer.result(); - } else { - encodeWriter(data.getData(), writer); - return writer.result(); } } - } - throw new Error('Unsupported output format: ' + format); - }, - decode: function (data, format) { - for (var i = 0; i < readerFunctions.length; i++) { - var func = readerFunctions[i]; - var reader = func(data, format); - if (reader) { - return decodeReader(reader); + throw new Error('Unsupported output format: ' + format); + }, + // DataItem: {getData: () => any} + encodeDataItem: function (data, format) { + console.log('============encodeDataItem:data', data) + console.log('============encodeDataItem:format', format) + for (var i = 0; i < writerFunctions.length; i++) { + var func = writerFunctions[i]; + var writer = func(format); + console.log('============encodeDataItem:writer', writer) + if (writer) { + if (data.getTag() !== undefined) { + encodeWriter(data, writer); + return writer.result(); + } else { + encodeWriter(data.getData(), writer); + return writer.result(); + } + } } - } - throw new Error('Unsupported input format: ' + format); - }, - decodeToDataItem: function (data, format) { - for (var i = 0; i < readerFunctions.length; i++) { - var func = readerFunctions[i]; - var reader = func(data, format); - if (reader) { - const result = decodeReader(reader); - if (result instanceof DataItem) { - return result; - } else { - return new DataItem(result); + console.log('============encodeDataItem:error', format) + throw new Error('Unsupported output format: ' + format); + }, + decode: function (data, format) { + for (var i = 0; i < readerFunctions.length; i++) { + var func = readerFunctions[i]; + var reader = func(data, format); + if (reader) { + return decodeReader(reader); } } - } - throw new Error('Unsupported input format: ' + format); - }, - addSemanticEncode: function (tag, fn) { - if (typeof tag !== 'number' || tag % 1 !== 0 || tag < 0) { - throw new Error('Tag must be a positive integer'); - } - semanticEncoders.push({ tag: tag, fn: fn }); - return this; - }, - addSemanticDecode: function (tag, fn) { - if (typeof tag !== 'number' || tag % 1 !== 0 || tag < 0) { - throw new Error('Tag must be a positive integer'); - } - semanticDecoders[tag] = fn; - return this; - }, - }; - - /** Node.js Buffers **/ - function BufferReader(buffer) { - this.buffer = buffer; - this.pos = 0; - } - BufferReader.prototype = Object.create(Reader.prototype); - BufferReader.prototype.peekByte = function () { - return this.buffer[this.pos]; - }; - BufferReader.prototype.readByte = function () { - return this.buffer[this.pos++]; - }; - BufferReader.prototype.readUint16 = function () { - var result = this.buffer.readUInt16BE(this.pos); - this.pos += 2; - return result; - }; - BufferReader.prototype.readUint32 = function () { - var result = this.buffer.readUInt32BE(this.pos); - this.pos += 4; - return result; - }; - BufferReader.prototype.readFloat32 = function () { - var result = this.buffer.readFloatBE(this.pos); - this.pos += 4; - return result; - }; - BufferReader.prototype.readFloat64 = function () { - var result = this.buffer.readDoubleBE(this.pos); - this.pos += 8; - return result; - }; - BufferReader.prototype.readChunk = function (length) { - var result = Buffer.alloc(length); - this.buffer.copy(result, 0, this.pos, (this.pos += length)); - return result; - }; - - function BufferWriter(stringFormat) { - this.byteLength = 0; - this.defaultBufferLength = 16384; // 16k - this.latestBuffer = Buffer.alloc(this.defaultBufferLength); - this.latestBufferOffset = 0; - this.completeBuffers = []; - this.stringFormat = stringFormat; - } - BufferWriter.prototype = Object.create(Writer.prototype); - BufferWriter.prototype.writeByte = function (value) { - this.latestBuffer[this.latestBufferOffset++] = value; - if (this.latestBufferOffset >= this.latestBuffer.length) { - this.completeBuffers.push(this.latestBuffer); + throw new Error('Unsupported input format: ' + format); + }, + decodeToDataItem: function (data, format) { + for (var i = 0; i < readerFunctions.length; i++) { + var func = readerFunctions[i]; + var reader = func(data, format); + if (reader) { + const result = decodeReader(reader); + if (result instanceof DataItem) { + return result; + } else { + return new DataItem(result); + } + } + } + throw new Error('Unsupported input format: ' + format); + }, + addSemanticEncode: function (tag, fn) { + if (typeof tag !== 'number' || tag % 1 !== 0 || tag < 0) { + throw new Error('Tag must be a positive integer'); + } + semanticEncoders.push({ tag: tag, fn: fn }); + return this; + }, + addSemanticDecode: function (tag, fn) { + if (typeof tag !== 'number' || tag % 1 !== 0 || tag < 0) { + throw new Error('Tag must be a positive integer'); + } + semanticDecoders[tag] = fn; + return this; + }, + }; + + /** Node.js Buffers **/ + function BufferReader(buffer) { + this.buffer = buffer; + this.pos = 0; + } + BufferReader.prototype = Object.create(Reader.prototype); + BufferReader.prototype.peekByte = function () { + return this.buffer[this.pos]; + }; + BufferReader.prototype.readByte = function () { + return this.buffer[this.pos++]; + }; + BufferReader.prototype.readUint16 = function () { + var result = this.buffer.readUInt16BE(this.pos); + this.pos += 2; + return result; + }; + BufferReader.prototype.readUint32 = function () { + var result = this.buffer.readUInt32BE(this.pos); + this.pos += 4; + return result; + }; + BufferReader.prototype.readFloat32 = function () { + var result = this.buffer.readFloatBE(this.pos); + this.pos += 4; + return result; + }; + BufferReader.prototype.readFloat64 = function () { + var result = this.buffer.readDoubleBE(this.pos); + this.pos += 8; + return result; + }; + BufferReader.prototype.readChunk = function (length) { + var result = Buffer.alloc(length); + this.buffer.copy(result, 0, this.pos, (this.pos += length)); + return result; + }; + + function BufferWriter(stringFormat) { + this.byteLength = 0; + this.defaultBufferLength = 16384; // 16k this.latestBuffer = Buffer.alloc(this.defaultBufferLength); this.latestBufferOffset = 0; + this.completeBuffers = []; + this.stringFormat = stringFormat; } - this.byteLength++; - }; - BufferWriter.prototype.writeFloat32 = function (value) { - var buffer = Buffer.alloc(4); - buffer.writeFloatBE(value, 0); - this.writeBuffer(buffer); - }; - BufferWriter.prototype.writeFloat64 = function (value) { - var buffer = Buffer.alloc(8); - buffer.writeDoubleBE(value, 0); - this.writeBuffer(buffer); - }; - BufferWriter.prototype.writeString = function (string, lengthFunc) { - var buffer = Buffer.from(string, 'utf-8'); - lengthFunc(buffer.length); - this.writeBuffer(buffer); - }; - BufferWriter.prototype.canWriteBinary = function (data) { - return data instanceof Buffer; - }; - BufferWriter.prototype.writeBinary = function (buffer, lengthFunc) { - lengthFunc(buffer.length); - this.writeBuffer(buffer); - }; - BufferWriter.prototype.writeBuffer = function (chunk) { - if (!(chunk instanceof Buffer)) - throw new TypeError('BufferWriter only accepts Buffers'); - if (!this.latestBufferOffset) { - this.completeBuffers.push(chunk); - } else if ( - this.latestBuffer.length - this.latestBufferOffset >= - chunk.length - ) { - chunk.copy(this.latestBuffer, this.latestBufferOffset); - this.latestBufferOffset += chunk.length; + BufferWriter.prototype = Object.create(Writer.prototype); + BufferWriter.prototype.writeByte = function (value) { + this.latestBuffer[this.latestBufferOffset++] = value; if (this.latestBufferOffset >= this.latestBuffer.length) { this.completeBuffers.push(this.latestBuffer); this.latestBuffer = Buffer.alloc(this.defaultBufferLength); this.latestBufferOffset = 0; } - } else { - this.completeBuffers.push( - this.latestBuffer.slice(0, this.latestBufferOffset), - ); - this.completeBuffers.push(chunk); - this.latestBuffer = Buffer.alloc(this.defaultBufferLength); - this.latestBufferOffset = 0; + this.byteLength++; + }; + BufferWriter.prototype.writeFloat32 = function (value) { + var buffer = Buffer.alloc(4); + buffer.writeFloatBE(value, 0); + this.writeBuffer(buffer); + }; + BufferWriter.prototype.writeFloat64 = function (value) { + var buffer = Buffer.alloc(8); + buffer.writeDoubleBE(value, 0); + this.writeBuffer(buffer); + }; + BufferWriter.prototype.writeString = function (string, lengthFunc) { + var buffer = Buffer.from(string, 'utf-8'); + lengthFunc(buffer.length); + this.writeBuffer(buffer); + }; + BufferWriter.prototype.canWriteBinary = function (data) { + return data instanceof Buffer; + }; + BufferWriter.prototype.writeBinary = function (buffer, lengthFunc) { + lengthFunc(buffer.length); + this.writeBuffer(buffer); + }; + BufferWriter.prototype.writeBuffer = function (chunk) { + if (!(chunk instanceof Buffer)) + throw new TypeError('BufferWriter only accepts Buffers'); + if (!this.latestBufferOffset) { + this.completeBuffers.push(chunk); + } else if ( + this.latestBuffer.length - this.latestBufferOffset >= + chunk.length + ) { + chunk.copy(this.latestBuffer, this.latestBufferOffset); + this.latestBufferOffset += chunk.length; + if (this.latestBufferOffset >= this.latestBuffer.length) { + this.completeBuffers.push(this.latestBuffer); + this.latestBuffer = Buffer.alloc(this.defaultBufferLength); + this.latestBufferOffset = 0; + } + } else { + this.completeBuffers.push( + this.latestBuffer.slice(0, this.latestBufferOffset), + ); + this.completeBuffers.push(chunk); + this.latestBuffer = Buffer.alloc(this.defaultBufferLength); + this.latestBufferOffset = 0; + } + this.byteLength += chunk.length; + }; + BufferWriter.prototype.result = function () { + // Copies them all into a single Buffer + var result = Buffer.alloc(this.byteLength); + var offset = 0; + for (var i = 0; i < this.completeBuffers.length; i++) { + var buffer = this.completeBuffers[i]; + buffer.copy(result, offset, 0, buffer.length); + offset += buffer.length; + } + if (this.latestBufferOffset) { + this.latestBuffer.copy(result, offset, 0, this.latestBufferOffset); + } + + if (this.stringFormat) return result.toString(this.stringFormat); + return result; + }; + + if (typeof Buffer === 'function') { + api.addReader(function (data, format) { + if (Buffer.isBuffer(data)) { + return new BufferReader(data); + } + if (format === 'hex' || format === 'base64') { + var buffer = Buffer.from(data, format); + return new BufferReader(buffer); + } + }); + api.addWriter(function (format) { + if (!format || format === 'buffer') { + return new BufferWriter(); + } else if (format === 'hex' || format === 'base64') { + return new BufferWriter(format); + } + }); } - this.byteLength += chunk.length; - }; - BufferWriter.prototype.result = function () { - // Copies them all into a single Buffer - var result = Buffer.alloc(this.byteLength); - var offset = 0; - for (var i = 0; i < this.completeBuffers.length; i++) { - var buffer = this.completeBuffers[i]; - buffer.copy(result, offset, 0, buffer.length); - offset += buffer.length; + + /** Hex-encoding (and Latin1) for browser **/ + function HexReader(hex) { + this.hex = hex; + this.pos = 0; } - if (this.latestBufferOffset) { - this.latestBuffer.copy(result, offset, 0, this.latestBufferOffset); + HexReader.prototype = Object.create(Reader.prototype); + HexReader.prototype.peekByte = function () { + var pair = this.hex.substring(this.pos, 2); + return parseInt(pair, 16); + }; + HexReader.prototype.readByte = function () { + var pair = this.hex.substring(this.pos, this.pos + 2); + this.pos += 2; + return parseInt(pair, 16); + }; + HexReader.prototype.readChunk = function (length) { + var hex = this.hex.substring(this.pos, this.pos + length * 2); + this.pos += length * 2; + if (typeof Buffer === 'function') return Buffer.from(hex, 'hex'); + return new BinaryHex(hex); + }; + + function HexWriter(finalFormat) { + this.$hex = ''; + this.finalFormat = finalFormat || 'hex'; } - - if (this.stringFormat) return result.toString(this.stringFormat); - return result; - }; - - if (typeof Buffer === 'function') { + HexWriter.prototype = Object.create(Writer.prototype); + HexWriter.prototype.writeByte = function (value) { + if (value < 0 || value > 255) + throw new Error('Byte value out of range: ' + value); + var hex = value.toString(16); + if (hex.length == 1) { + hex = '0' + hex; + } + this.$hex += hex; + }; + HexWriter.prototype.canWriteBinary = function (chunk) { + return ( + chunk instanceof BinaryHex || + (typeof Buffer === 'function' && chunk instanceof Buffer) + ); + }; + HexWriter.prototype.writeBinary = function (chunk, lengthFunction) { + if (chunk instanceof BinaryHex) { + lengthFunction(chunk.length()); + this.$hex += chunk.$hex; + } else if (typeof Buffer === 'function' && chunk instanceof Buffer) { + lengthFunction(chunk.length); + this.$hex += chunk.toString('hex'); + } else { + throw new TypeError('HexWriter only accepts BinaryHex or Buffers'); + } + }; + HexWriter.prototype.result = function () { + if (this.finalFormat === 'buffer' && typeof Buffer === 'function') { + return Buffer.from(this.$hex, 'hex'); + } + return new BinaryHex(this.$hex).toString(this.finalFormat); + }; + HexWriter.prototype.writeString = function (string, lengthFunction) { + var buffer = BinaryHex.fromUtf8String(string); + lengthFunction(buffer.length()); + this.$hex += buffer.$hex; + }; + api.addReader(function (data, format) { - if (Buffer.isBuffer(data)) { - return new BufferReader(data); + if (data instanceof BinaryHex || data.$hex) { + return new HexReader(data.$hex); } - if (format === 'hex' || format === 'base64') { - var buffer = Buffer.from(data, format); - return new BufferReader(buffer); + if (format === 'hex') { + return new HexReader(data); } }); api.addWriter(function (format) { - if (!format || format === 'buffer') { - return new BufferWriter(); - } else if (format === 'hex' || format === 'base64') { - return new BufferWriter(format); + if (format === 'hex') { + return new HexWriter(); } }); - } - - /** Hex-encoding (and Latin1) for browser **/ - function HexReader(hex) { - this.hex = hex; - this.pos = 0; - } - HexReader.prototype = Object.create(Reader.prototype); - HexReader.prototype.peekByte = function () { - var pair = this.hex.substring(this.pos, 2); - return parseInt(pair, 16); - }; - HexReader.prototype.readByte = function () { - var pair = this.hex.substring(this.pos, this.pos + 2); - this.pos += 2; - return parseInt(pair, 16); - }; - HexReader.prototype.readChunk = function (length) { - var hex = this.hex.substring(this.pos, this.pos + length * 2); - this.pos += length * 2; - if (typeof Buffer === 'function') return Buffer.from(hex, 'hex'); - return new BinaryHex(hex); - }; - - function HexWriter(finalFormat) { - this.$hex = ''; - this.finalFormat = finalFormat || 'hex'; - } - HexWriter.prototype = Object.create(Writer.prototype); - HexWriter.prototype.writeByte = function (value) { - if (value < 0 || value > 255) - throw new Error('Byte value out of range: ' + value); - var hex = value.toString(16); - if (hex.length == 1) { - hex = '0' + hex; - } - this.$hex += hex; - }; - HexWriter.prototype.canWriteBinary = function (chunk) { - return ( - chunk instanceof BinaryHex || - (typeof Buffer === 'function' && chunk instanceof Buffer) - ); - }; - HexWriter.prototype.writeBinary = function (chunk, lengthFunction) { - if (chunk instanceof BinaryHex) { - lengthFunction(chunk.length()); - this.$hex += chunk.$hex; - } else if (typeof Buffer === 'function' && chunk instanceof Buffer) { - lengthFunction(chunk.length); - this.$hex += chunk.toString('hex'); - } else { - throw new TypeError('HexWriter only accepts BinaryHex or Buffers'); - } - }; - HexWriter.prototype.result = function () { - if (this.finalFormat === 'buffer' && typeof Buffer === 'function') { - return Buffer.from(this.$hex, 'hex'); - } - return new BinaryHex(this.$hex).toString(this.finalFormat); - }; - HexWriter.prototype.writeString = function (string, lengthFunction) { - var buffer = BinaryHex.fromUtf8String(string); - lengthFunction(buffer.length()); - this.$hex += buffer.$hex; - }; - - api.addReader(function (data, format) { - if (data instanceof BinaryHex || data.$hex) { - return new HexReader(data.$hex); + + return api; + })(); + + CBOR.addSemanticEncode(0, function (data) { + if (data instanceof Date) { + return data.toISOString(); } - if (format === 'hex') { - return new HexReader(data); - } - }); - api.addWriter(function (format) { - if (format === 'hex') { - return new HexWriter(); - } - }); - - return api; - })(); - - CBOR.addSemanticEncode(0, function (data) { - if (data instanceof Date) { - return data.toISOString(); - } - }) - .addSemanticDecode(0, function (isoString) { - return new Date(isoString); }) - .addSemanticDecode(1, function (isoString) { - return new Date(isoString); - }); - - return CBOR; -}); + .addSemanticDecode(0, function (isoString) { + return new Date(isoString); + }) + .addSemanticDecode(1, function (isoString) { + return new Date(isoString); + }); + + return CBOR; + }); + \ No newline at end of file