Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+643
View File
@@ -0,0 +1,643 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const fixtures = [
{
cbor: 'AA==',
hex: '00',
roundtrip: true,
decoded: 0
},
{
cbor: 'AQ==',
hex: '01',
roundtrip: true,
decoded: 1
},
{
cbor: 'Cg==',
hex: '0a',
roundtrip: true,
decoded: 10
},
{
cbor: 'Fw==',
hex: '17',
roundtrip: true,
decoded: 23
},
{
cbor: 'GBg=',
hex: '1818',
roundtrip: true,
decoded: 24
},
{
cbor: 'GBk=',
hex: '1819',
roundtrip: true,
decoded: 25
},
{
cbor: 'GGQ=',
hex: '1864',
roundtrip: true,
decoded: 100
},
{
cbor: 'GQPo',
hex: '1903e8',
roundtrip: true,
decoded: 1000
},
{
cbor: 'GgAPQkA=',
hex: '1a000f4240',
roundtrip: true,
decoded: 1000000
},
{
cbor: 'GwAAAOjUpRAA',
hex: '1b000000e8d4a51000',
roundtrip: true,
decoded: 1000000000000
},
{
cbor: 'G///////////',
hex: '1bffffffffffffffff',
roundtrip: true,
decoded: BigInt('18446744073709551615')
},
{
cbor: 'wkkBAAAAAAAAAAA=',
hex: 'c249010000000000000000',
roundtrip: true,
decoded: BigInt('18446744073709551616'),
noTagDecodeError: /tag not supported \(2\)/,
noTagEncodeError: /BigInt larger than allowable range/
},
{
cbor: 'O///////////',
hex: '3bffffffffffffffff',
roundtrip: true,
decoded: BigInt('-18446744073709551616')
},
{
cbor: 'w0kBAAAAAAAAAAA=',
hex: 'c349010000000000000000',
roundtrip: true,
decoded: BigInt('-18446744073709551617'),
noTagDecodeError: /tag not supported \(3\)/,
noTagEncodeError: /BigInt larger than allowable range/
},
{
cbor: 'IA==',
hex: '20',
roundtrip: true,
decoded: -1
},
{
cbor: 'KQ==',
hex: '29',
roundtrip: true,
decoded: -10
},
{
cbor: 'OGM=',
hex: '3863',
roundtrip: true,
decoded: -100
},
{
cbor: 'OQPn',
hex: '3903e7',
roundtrip: true,
decoded: -1000
},
{
cbor: '+QAA',
hex: 'f90000',
roundtrip: false,
decoded: 0
},
{
cbor: '+YAA',
hex: 'f98000',
roundtrip: false,
decoded: -0
},
{
cbor: '+TwA',
hex: 'f93c00',
roundtrip: false,
decoded: 1
},
{
cbor: '+z/xmZmZmZma',
hex: 'fb3ff199999999999a',
roundtrip: true,
decoded: 1.1
},
{
cbor: '+T4A',
hex: 'f93e00',
roundtrip: true,
decoded: 1.5
},
{
cbor: '+Xv/',
hex: 'f97bff',
roundtrip: false,
decoded: 65504
},
{
cbor: '+kfDUAA=',
hex: 'fa47c35000',
roundtrip: false,
decoded: 100000
},
{
cbor: '+n9///8=',
hex: 'fa7f7fffff',
roundtrip: true,
decoded: 3.4028234663852886e+38
},
{
cbor: '+3435DyIAHWc',
hex: 'fb7e37e43c8800759c',
roundtrip: true,
decoded: 1e+300
},
{
cbor: '+QAB',
hex: 'f90001',
roundtrip: true,
decoded: 5.960464477539063e-8
},
{
cbor: '+QQA',
hex: 'f90400',
roundtrip: true,
decoded: 0.00006103515625
},
{
cbor: '+cQA',
hex: 'f9c400',
roundtrip: false,
decoded: -4
},
{
cbor: '+8AQZmZmZmZm',
hex: 'fbc010666666666666',
roundtrip: true,
decoded: -4.1
},
{
cbor: '+XwA',
hex: 'f97c00',
roundtrip: true,
diagnostic: Infinity
},
{
cbor: '+X4A',
hex: 'f97e00',
roundtrip: true,
diagnostic: NaN
},
{
cbor: '+fwA',
hex: 'f9fc00',
roundtrip: true,
diagnostic: -Infinity
},
{
cbor: '+n+AAAA=',
hex: 'fa7f800000',
roundtrip: false,
diagnostic: Infinity
},
{
cbor: '+n/AAAA=',
hex: 'fa7fc00000',
roundtrip: false,
diagnostic: NaN
},
{
cbor: '+v+AAAA=',
hex: 'faff800000',
roundtrip: false,
diagnostic: -Infinity
},
{
cbor: '+3/wAAAAAAAA',
hex: 'fb7ff0000000000000',
roundtrip: false,
diagnostic: Infinity
},
{
cbor: '+3/4AAAAAAAA',
hex: 'fb7ff8000000000000',
roundtrip: false,
diagnostic: NaN
},
{
cbor: '+//wAAAAAAAA',
hex: 'fbfff0000000000000',
roundtrip: false,
diagnostic: -Infinity
},
{
cbor: '9A==',
hex: 'f4',
roundtrip: true,
decoded: false
},
{
cbor: '9Q==',
hex: 'f5',
roundtrip: true,
decoded: true
},
{
cbor: '9g==',
hex: 'f6',
roundtrip: true,
decoded: null
},
{
cbor: '9w==',
hex: 'f7',
roundtrip: true,
diagnostic: undefined
},
{
cbor: '8A==',
hex: 'f0',
roundtrip: true,
diagnostic: 'simple(16)',
error: /simple values are not supported/
},
{
cbor: '+Bg=',
hex: 'f818',
roundtrip: true,
diagnostic: 'simple(24)',
error: /simple values are not supported/
},
{
cbor: '+P8=',
hex: 'f8ff',
roundtrip: true,
diagnostic: 'simple(255)',
error: /simple values are not supported/
},
{
cbor: 'wHQyMDEzLTAzLTIxVDIwOjA0OjAwWg==',
hex: 'c074323031332d30332d32315432303a30343a30305a',
roundtrip: false,
diagnostic: '0("2013-03-21T20:04:00Z")'
},
{
cbor: 'wRpRS2ew',
hex: 'c11a514b67b0',
roundtrip: false,
diagnostic: '1(1363896240)'
},
{
cbor: 'wftB1FLZ7CAAAA==',
hex: 'c1fb41d452d9ec200000',
roundtrip: false,
diagnostic: '1(1363896240.5)'
},
{
cbor: '10QBAgME',
hex: 'd74401020304',
roundtrip: false,
diagnostic: '23(h\'01020304\')'
},
{
cbor: '2BhFZElFVEY=',
hex: 'd818456449455446',
roundtrip: false,
diagnostic: '24(h\'6449455446\')'
},
{
cbor: '2CB2aHR0cDovL3d3dy5leGFtcGxlLmNvbQ==',
hex: 'd82076687474703a2f2f7777772e6578616d706c652e636f6d',
roundtrip: false,
diagnostic: '32("http://www.example.com")'
},
{
cbor: 'QA==',
hex: '40',
roundtrip: true,
diagnostic: 'h\'\''
},
{
cbor: 'RAECAwQ=',
hex: '4401020304',
roundtrip: true,
diagnostic: 'h\'01020304\''
},
{
cbor: 'YA==',
hex: '60',
roundtrip: true,
decoded: ''
},
{
cbor: 'YWE=',
hex: '6161',
roundtrip: true,
decoded: 'a'
},
{
cbor: 'ZElFVEY=',
hex: '6449455446',
roundtrip: true,
decoded: 'IETF'
},
{
cbor: 'YiJc',
hex: '62225c',
roundtrip: true,
decoded: '"\\'
},
{
cbor: 'YsO8',
hex: '62c3bc',
roundtrip: true,
decoded: 'ü'
},
{
cbor: 'Y+awtA==',
hex: '63e6b0b4',
roundtrip: true,
decoded: '水'
},
{
cbor: 'ZPCQhZE=',
hex: '64f0908591',
roundtrip: true,
decoded: '\uD800\uDD51'
},
{
cbor: 'gA==',
hex: '80',
roundtrip: true,
decoded: []
},
{
cbor: 'gwECAw==',
hex: '83010203',
roundtrip: true,
decoded: [
1,
2,
3
]
},
{
cbor: 'gwGCAgOCBAU=',
hex: '8301820203820405',
roundtrip: true,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'mBkBAgMEBQYHCAkKCwwNDg8QERITFBUWFxgYGBk=',
hex: '98190102030405060708090a0b0c0d0e0f101112131415161718181819',
roundtrip: true,
decoded: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
]
},
{
cbor: 'oA==',
hex: 'a0',
roundtrip: true,
decoded: {}
},
{
cbor: 'ogECAwQ=',
hex: 'a201020304',
roundtrip: true,
diagnostic: '{1: 2, 3: 4}',
error: /non-string keys not supported/
},
{
cbor: 'omFhAWFiggID',
hex: 'a26161016162820203',
roundtrip: true,
decoded: {
a: 1,
b: [
2,
3
]
}
},
{
cbor: 'gmFhoWFiYWM=',
hex: '826161a161626163',
roundtrip: true,
decoded: [
'a',
{ b: 'c' }
]
},
{
cbor: 'pWFhYUFhYmFCYWNhQ2FkYURhZWFF',
hex: 'a56161614161626142616361436164614461656145',
roundtrip: true,
decoded: {
a: 'A',
b: 'B',
c: 'C',
d: 'D',
e: 'E'
}
},
{
cbor: 'X0IBAkMDBAX/',
hex: '5f42010243030405ff',
roundtrip: false,
diagnostic: '(_ h\'0102\', h\'030405\')',
error: /indefinite length bytes\/strings are not supported/
},
{
cbor: 'f2VzdHJlYWRtaW5n/w==',
hex: '7f657374726561646d696e67ff',
roundtrip: false,
decoded: 'streaming',
error: /indefinite length bytes\/strings are not supported/
},
{
cbor: 'n/8=',
hex: '9fff',
roundtrip: false,
decoded: []
},
{
cbor: 'nwGCAgOfBAX//w==',
hex: '9f018202039f0405ffff',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'nwGCAgOCBAX/',
hex: '9f01820203820405ff',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'gwGCAgOfBAX/',
hex: '83018202039f0405ff',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'gwGfAgP/ggQF',
hex: '83019f0203ff820405',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'nwECAwQFBgcICQoLDA0ODxAREhMUFRYXGBgYGf8=',
hex: '9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff',
roundtrip: false,
decoded: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
]
},
{
cbor: 'v2FhAWFinwID//8=',
hex: 'bf61610161629f0203ffff',
roundtrip: false,
decoded: {
a: 1,
b: [
2,
3
]
}
},
{
cbor: 'gmFhv2FiYWP/',
hex: '826161bf61626163ff',
roundtrip: false,
decoded: [
'a',
{ b: 'c' }
]
},
{
cbor: 'v2NGdW71Y0FtdCH/',
hex: 'bf6346756ef563416d7421ff',
roundtrip: false,
decoded: {
Fun: true,
Amt: -2
}
}
];
exports.fixtures = fixtures;
+24
View File
@@ -0,0 +1,24 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('../lib/token.js');
function dateDecoder(obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 1');
}
return new Date(obj);
}
function dateEncoder(obj) {
if (!(obj instanceof Date)) {
throw new Error('expected Date for "Date" encoder');
}
return [
new token.Token(token.Type.tag, 0),
new token.Token(token.Type.string, obj.toISOString().replace(/\.000Z$/, 'Z'))
];
}
exports.dateDecoder = dateDecoder;
exports.dateEncoder = dateEncoder;
+348
View File
@@ -0,0 +1,348 @@
'use strict';
var chai = require('chai');
var child_process = require('child_process');
var process = require('process');
var path = require('path');
var os = require('os');
var url = require('url');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
var process__default = /*#__PURE__*/_interopDefaultLegacy(process);
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
const {assert} = chai__default["default"];
const fixture1JsonString = '{"a":1,"b":[2,3],"smile":"\uD83D\uDE00"}';
const fixture1JsonPrettyString = `{
"a": 1,
"b": [
2,
3
],
"smile": "😀"
}
`;
const fixture1HexString = 'a3616101616282020365736d696c6564f09f9880';
const fixture1Bin = fromHex(fixture1HexString);
const fixture1BinString = new TextDecoder().decode(fixture1Bin);
const fixture1DiagnosticString = `a3 # map(3)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
82 # array(2)
02 # uint(2)
03 # uint(3)
65 # string(5)
736d696c65 # "smile"
64 # string(2)
f09f9880 # "😀"
`;
const fixture2HexString = 'a4616101616282020363627566440102036165736d696c6564f09f9880';
const fixture2DiagnosticString = `a4 # map(4)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
82 # array(2)
02 # uint(2)
03 # uint(3)
63 # string(3)
627566 # "buf"
44 # bytes(4)
01020361 # "\\x01\\x02\\x03a"
65 # string(5)
736d696c65 # "smile"
64 # string(2)
f09f9880 # "😀"
`;
const binPath = path__default["default"].join(path__default["default"].dirname(url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('browser-test/node-test-bin.js', document.baseURI).href)))), '../lib/bin.js');
function fromHex(hex) {
return new Uint8Array(hex.split('').map((c, i, d) => i % 2 === 0 ? `0x${ c }${ d[i + 1] }` : '').filter(Boolean).map(e => parseInt(e, 16)));
}
async function execBin(cmd, stdin) {
return new Promise((resolve, reject) => {
const cp = child_process.exec(`"${ process__default["default"].execPath }" "${ binPath }" ${ cmd }`, (err, stdout, stderr) => {
if (err) {
err.stdout = stdout;
err.stderr = stderr;
return reject(err);
}
resolve({
stdout,
stderr
});
});
if (stdin != null) {
cp.on('spawn', () => {
cp.stdin.write(stdin);
cp.stdin.end();
});
}
});
}
describe('Bin', () => {
it('usage', async () => {
try {
await execBin('');
assert.fail('should have errored');
} catch (e) {
assert.strictEqual(e.stdout, '');
assert.strictEqual(e.stderr, `Usage: cborg <command> <args>
Valid commands:
\tbin2diag [binary input]
\tbin2hex [binary input]
\tbin2json [--pretty] [binary input]
\tdiag2bin [diagnostic input]
\tdiag2hex [diagnostic input]
\tdiag2json [--pretty] [diagnostic input]
\thex2bin [hex input]
\thex2diag [hex input]
\thex2json [--pretty] [hex input]
\tjson2bin '[json input]'
\tjson2diag '[json input]'
\tjson2hex '[json input]'
Input may either be supplied as an argument or piped via stdin
`);
}
});
it('bad cmd', async () => {
try {
await execBin('blip');
assert.fail('should have errored');
} catch (e) {
assert.strictEqual(e.stdout, '');
assert.strictEqual(e.stderr, `Unknown command: 'blip'
Usage: cborg <command> <args>
Valid commands:
\tbin2diag [binary input]
\tbin2hex [binary input]
\tbin2json [--pretty] [binary input]
\tdiag2bin [diagnostic input]
\tdiag2hex [diagnostic input]
\tdiag2json [--pretty] [diagnostic input]
\thex2bin [hex input]
\thex2diag [hex input]
\thex2json [--pretty] [hex input]
\tjson2bin '[json input]'
\tjson2diag '[json input]'
\tjson2hex '[json input]'
Input may either be supplied as an argument or piped via stdin
`);
}
});
it('help', async () => {
const {stdout, stderr} = await execBin('help');
assert.strictEqual(stdout, '');
assert.strictEqual(stderr, `Usage: cborg <command> <args>
Valid commands:
\tbin2diag [binary input]
\tbin2hex [binary input]
\tbin2json [--pretty] [binary input]
\tdiag2bin [diagnostic input]
\tdiag2hex [diagnostic input]
\tdiag2json [--pretty] [diagnostic input]
\thex2bin [hex input]
\thex2diag [hex input]
\thex2json [--pretty] [hex input]
\tjson2bin '[json input]'
\tjson2diag '[json input]'
\tjson2hex '[json input]'
Input may either be supplied as an argument or piped via stdin
`);
});
it('bin2diag (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2diag', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1DiagnosticString);
});
it('bin2hex (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2hex', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1HexString }\n`);
});
it('bin2json (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2json', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1JsonString }\n`);
});
it('bin2json pretty (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2json --pretty', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1JsonPrettyString);
});
for (const stdin of [
true,
false
]) {
if (os.platform() !== 'win32' || stdin) {
it(`diag2bin${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2bin '${ fixture1DiagnosticString }'`) : await execBin('diag2bin', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1BinString);
});
it(`diag2hex${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2hex '${ fixture1DiagnosticString }'`) : await execBin('diag2hex', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1HexString }\n`);
});
it(`diag2json${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2json '${ fixture1DiagnosticString }'`) : await execBin('diag2json', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1JsonString }\n`);
});
it(`diag2json pretty${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2json --pretty '${ fixture1DiagnosticString }'`) : await execBin('diag2json --pretty', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1JsonPrettyString);
});
}
it(`hex2bin${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2bin ${ fixture1HexString }`) : await execBin('hex2bin', fixture1HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1BinString);
});
it(`hex2diag${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2diag ${ fixture2HexString }`) : await execBin('hex2diag', fixture2HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture2DiagnosticString);
});
it(`hex2json${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2json ${ fixture1HexString }`) : await execBin('hex2json', fixture1HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1JsonString }\n`);
});
it(`hex2json pretty${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2json --pretty ${ fixture1HexString }`) : await execBin('hex2json --pretty', fixture1HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1JsonPrettyString);
});
it(`json2bin${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin('json2bin "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"\uD83D\uDE00\\"}"') : await execBin('json2bin', fixture1JsonString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1BinString);
});
it(`json2diag${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin('json2diag "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"\uD83D\uDE00\\"}"') : await execBin('json2diag', fixture1JsonString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1DiagnosticString);
});
it(`json2hex${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`json2hex "${ fixture1JsonString.replace(/"/g, '\\"') }"`) : await execBin('json2hex', fixture1JsonString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1HexString }\n`);
});
}
it('diag indenting', async () => {
const {stdout, stderr} = await execBin('json2diag', '{"a":[],"b":{},"c":{"a":1,"b":{"a":{"a":{}}}},"d":{"a":{"a":{"a":1},"b":2,"c":[]}},"e":[[[[{"a":{}}]]]],"f":1}');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `a6 # map(6)
61 # string(1)
61 # "a"
80 # array(0)
61 # string(1)
62 # "b"
a0 # map(0)
61 # string(1)
63 # "c"
a2 # map(2)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
a1 # map(1)
61 # string(1)
61 # "a"
a1 # map(1)
61 # string(1)
61 # "a"
a0 # map(0)
61 # string(1)
64 # "d"
a1 # map(1)
61 # string(1)
61 # "a"
a3 # map(3)
61 # string(1)
61 # "a"
a1 # map(1)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
02 # uint(2)
61 # string(1)
63 # "c"
80 # array(0)
61 # string(1)
65 # "e"
81 # array(1)
81 # array(1)
81 # array(1)
81 # array(1)
a1 # map(1)
61 # string(1)
61 # "a"
a0 # map(0)
61 # string(1)
66 # "f"
01 # uint(1)
`);
});
describe('diag length bytes', () => {
it('compact', async () => {
const {stdout, stderr} = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaa"');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `77 # string(23)
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
`);
});
it('1-byte', async () => {
const {stdout, stderr} = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `78 23 # string(35)
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
616161616161616161616161 # "aaaaaaaaaaaa"
`);
});
it('2-byte', async () => {
const {stdout, stderr} = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `79 0100 # string(256)
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
616161 # "aaa"
`);
});
});
it('diag non-utf8 and non-printable ascii', async () => {
const input = '7864f55ff8f12508b63ef2bfeca7557ae90df6311a5ec1631b4a1fa843310bd9c3a710eaace5a1bdd72ad0bfe049771c11e756338bd93865e645f1adec9b9c99ef407fbd4fc6859e7904c5ad7dc9bd10a5cc16973d5b28ec1a6dd43d9f82f9f18c3d03418e35';
let {stdout, stderr} = await execBin(`hex2diag ${ input }`);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `78 64 # string(86)
f55ff8f12508b63ef2bfeca7557ae90df6311a5ec1631b # "õ_øñ%\\x08¶>ò¿ì§Uzé\\x0dö1\\x1a^Ác\\x1b"
4a1fa843310bd9c3a710eaace5a1bdd72ad0bfe049771c # "J\\x1f¨C1\\x0bÙç\\x10ê¬å¡½×*пàIw\\x1c"
11e756338bd93865e645f1adec9b9c99ef407fbd4fc685 # "\\x11çV3\\x8bÙ8eæEñ\\xadì\\x9b\\x9c\\x99ï@\\x7f½OÆ\\x85"
9e7904c5ad7dc9bd10a5cc16973d5b28ec1a6dd43d9f82 # "\\x9ey\\x04Å\\xad}ɽ\\x10¥Ì\\x16\\x97=[(ì\\x1amÔ=\\x9f\\x82"
f9f18c3d03418e35 # "ùñ\\x8c=\\x03A\\x8e5"
`);
({stdout, stderr} = await execBin('diag2hex', stdout));
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ input }\n`);
});
});
+4
View File
@@ -0,0 +1,4 @@
'use strict';
require('../lib/bin.js');
+158
View File
@@ -0,0 +1,158 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '00',
expected: 0,
type: 'uint8'
},
{
data: '02',
expected: 2,
type: 'uint8'
},
{
data: '18ff',
expected: 255,
type: 'uint8'
},
{
data: '1901f4',
expected: 500,
type: 'uint16'
},
{
data: '1900ff',
expected: 255,
type: 'uint16',
strict: false
},
{
data: '19ffff',
expected: 65535,
type: 'uint16'
},
{
data: '1a000000ff',
expected: 255,
type: 'uint32',
strict: false
},
{
data: '1a00010000',
expected: 65536,
type: 'uint32'
},
{
data: '1a000f4240',
expected: 1000000,
type: 'uint32'
},
{
data: '1aa5f702b3',
expected: 2784428723,
type: 'uint32'
},
{
data: '1b00000000000000ff',
expected: 255,
type: 'uint64',
strict: false
},
{
data: '1b0016db6db6db6db7',
expected: Number.MAX_SAFE_INTEGER / 1.4,
type: 'uint64'
},
{
data: '1b001fffffffffffff',
expected: Number.MAX_SAFE_INTEGER,
type: 'uint64'
},
{
data: '1ba5f702b3a5f702b3',
expected: BigInt('11959030306112471731'),
type: 'uint64'
},
{
data: '1bffffffffffffffff',
expected: BigInt('18446744073709551615'),
type: 'uint64'
}
];
describe('uint', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(data) === fixture.expected, `decode ${ fixture.type } ${ decode.decode(data) } != ${ fixture.expected }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.ok(decode.decode(data, { strict: true }) === fixture.expected, `decode ${ fixture.type }`);
}
});
}
});
it('should throw error', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('1ca5f702b3a5f702b3')), Error, 'CBOR decode error: encountered invalid minor (28) for major 0');
assert.throws(() => decode.decode(byteUtils.fromHex('1ba5f702b3a5f702')), Error, 'CBOR decode error: not enough data for type');
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(encode.encode(fixture.expected)) === fixture.expected, `roundtrip ${ fixture.type }`);
});
}
}
});
describe('toobig', () => {
it('bigger than 64-bit', () => {
assert.doesNotThrow(() => encode.encode(BigInt('18446744073709551615')));
assert.throws(() => encode.encode(BigInt('18446744073709551616')), /BigInt larger than allowable range/);
});
it('disallow BigInt', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
if (!Number.isSafeInteger(fixture.expected)) {
assert.throws(() => decode.decode(data, { allowBigInt: false }), /safe integer range/);
} else {
assert.ok(decode.decode(data, { allowBigInt: false }) === fixture.expected, `decode ${ fixture.type }`);
}
}
});
});
describe('toosmall', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false && typeof fixture.expected === 'number') {
const small = BigInt(fixture.expected);
it(`should encode ${ small }n`, () => {
assert.strictEqual(byteUtils.toHex(encode.encode(BigInt(small))), fixture.data, `encode ${ small }`);
});
}
}
});
});
+152
View File
@@ -0,0 +1,152 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '20',
expected: -1,
type: 'negint8'
},
{
data: '22',
expected: -3,
type: 'negint8'
},
{
data: '3863',
expected: -100,
type: 'negint8'
},
{
data: '38ff',
expected: -256,
type: 'negint8'
},
{
data: '3900ff',
expected: -256,
type: 'negint16',
strict: false
},
{
data: '3901f4',
expected: -501,
type: 'negint16'
},
{
data: '3a000000ff',
expected: -256,
type: 'negint32',
strict: false
},
{
data: '3aa5f702b3',
expected: -2784428724,
type: 'negint32'
},
{
data: '3b00000000000000ff',
expected: -256,
type: 'negint32',
strict: false
},
{
data: '3b0016db6db6db6db7',
expected: Number.MIN_SAFE_INTEGER / 1.4 - 1,
type: 'negint64'
},
{
data: '3b001ffffffffffffe',
expected: Number.MIN_SAFE_INTEGER,
type: 'negint64'
},
{
data: '3b001fffffffffffff',
expected: BigInt('-9007199254740992'),
type: 'negint64'
},
{
data: '3b0020000000000000',
expected: BigInt('-9007199254740993'),
type: 'negint64'
},
{
data: '3ba5f702b3a5f702b3',
expected: BigInt('-11959030306112471732'),
type: 'negint64'
},
{
data: '3bffffffffffffffff',
expected: BigInt('-18446744073709551616'),
type: 'negint64'
}
];
describe('negint', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(data) === fixture.expected, `decode ${ fixture.type } (${ decode.decode(data) } != ${ fixture.expected })`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.strictEqual(decode.decode(data, { strict: true }), fixture.expected, `decode ${ fixture.type }`);
}
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
it(`should roundtrip ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(encode.encode(fixture.expected)) === fixture.expected, `roundtrip ${ fixture.type }`);
});
}
});
describe('toobig', () => {
it('bigger than 64-bit', () => {
assert.doesNotThrow(() => encode.encode(BigInt('-18446744073709551616')));
assert.throws(() => encode.encode(BigInt('-18446744073709551617')), /BigInt larger than allowable range/);
});
it('disallow BigInt', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
if (!Number.isSafeInteger(fixture.expected)) {
assert.throws(() => decode.decode(data, { allowBigInt: false }), /safe integer range/);
} else {
assert.ok(decode.decode(data, { allowBigInt: false }) === fixture.expected, `decode ${ fixture.type }`);
}
}
});
});
describe('toosmall', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false && typeof fixture.expected === 'number') {
const small = BigInt(fixture.expected);
it(`should encode ${ small }n`, () => {
assert.strictEqual(byteUtils.toHex(encode.encode(BigInt(small))), fixture.data, `encode ${ small }`);
});
}
}
});
});
+254
View File
@@ -0,0 +1,254 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '40',
expected: '',
type: 'bytes'
},
{
data: '41a1',
expected: 'a1',
type: 'bytes'
},
{
data: '5801a1',
expected: 'a1',
type: 'bytes',
strict: false
},
{
data: '58ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 8-bit length'
},
{
data: '5900ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 16-bit length',
strict: false
},
{
data: '5a000000ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 32-bit length',
strict: false
},
{
data: '5b00000000000000ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 64-bit length',
strict: false
}
];
(() => {
function rnd(length) {
return new Uint8Array(Array.from({ length }, () => Math.floor(Math.random() * 255)));
}
const expected16 = rnd(256);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('590100'),
...expected16
]),
expected: expected16,
type: 'bytes',
label: 'long bytes, 16-bit length strict-compat'
});
const expected32 = rnd(65536);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('5a00010000'),
...expected32
]),
expected: expected32,
type: 'bytes',
label: 'long bytes, 32-bit length strict-compat'
});
})();
describe('bytes', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
let actual = decode.decode(data);
assert.strictEqual(byteUtils.toHex(actual), byteUtils.toHex(byteUtils.fromHex(fixture.expected)), `decode ${ fixture.type }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
actual = decode.decode(data, { strict: true });
assert.strictEqual(byteUtils.toHex(actual), byteUtils.toHex(byteUtils.fromHex(fixture.expected)), `decode ${ fixture.type } strict`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('5ba5f702b3a5f702b3000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe')), /CBOR decode error: 64-bit integer bytes lengths not supported/);
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
if (fixture.data.length >= 100000000) {
it.skip(`(TODO) skipping encode of very large bytes ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
});
continue;
}
const data = byteUtils.fromHex(fixture.expected);
const expectedHex = byteUtils.toHex(fixture.data);
it(`should encode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
if (fixture.unsafe) {
assert.throws(() => encode.encode(data), Error, /^CBOR encode error: number too large to encode \(-\d+\)$/);
} else if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type }`);
}
});
}
});
describe('typedarrays', () => {
const cases = [
{
obj: Uint8Array.from([
1,
2,
3
]),
hex: '43010203'
},
{
obj: Uint8ClampedArray.from([
1,
2,
3
]),
hex: '43010203'
},
{
obj: Uint16Array.from([
1,
2,
3
]),
hex: '46010002000300'
},
{
obj: Uint32Array.from([
1,
2,
3
]),
hex: '4c010000000200000003000000'
},
{
obj: Int8Array.from([
1,
2,
-3
]),
hex: '430102fd'
},
{
obj: Int16Array.from([
1,
2,
-3
]),
hex: '4601000200fdff'
},
{
obj: Int32Array.from([
1,
2,
-3
]),
hex: '4c0100000002000000fdffffff'
},
{
obj: Float32Array.from([
1,
2,
-3
]),
hex: '4c0000803f00000040000040c0'
},
{
obj: Float64Array.from([
1,
2,
-3
]),
hex: '5818000000000000f03f000000000000004000000000000008c0'
},
{
obj: BigUint64Array.from([
BigInt(1),
BigInt(2),
BigInt(3)
]),
hex: '5818010000000000000002000000000000000300000000000000'
},
{
obj: BigInt64Array.from([
BigInt(1),
BigInt(2),
BigInt(-3)
]),
hex: '581801000000000000000200000000000000fdffffffffffffff'
},
{
obj: new DataView(Uint8Array.from([
1,
2,
3
]).buffer),
hex: '43010203'
},
{
obj: Uint8Array.from([
1,
2,
3
]).buffer,
hex: '43010203'
}
];
for (const testCase of cases) {
it(testCase.obj.constructor.name, () => {
assert.equal(byteUtils.toHex(encode.encode(testCase.obj)), testCase.hex);
const decoded = decode.decode(byteUtils.fromHex(testCase.hex));
assert.instanceOf(decoded, Uint8Array);
assert.equal(byteUtils.toHex(decoded), byteUtils.toHex(testCase.obj));
});
}
});
if (byteUtils.useBuffer) {
describe('buffer', () => {
it('can encode Node.js Buffers', () => {
const obj = global.Buffer.from([
1,
2,
3
]);
assert.equal(byteUtils.toHex(encode.encode(obj)), '43010203');
const decoded = decode.decode(byteUtils.fromHex('43010203'));
assert.instanceOf(decoded, Uint8Array);
assert.equal(byteUtils.toHex(decoded), byteUtils.toHex(obj));
});
});
}
});
+144
View File
@@ -0,0 +1,144 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '60',
expected: '',
type: 'string'
},
{
data: '6161',
expected: 'a',
type: 'string'
},
{
data: '780161',
expected: 'a',
type: 'string',
strict: false
},
{
data: '6c48656c6c6f20776f726c6421',
expected: 'Hello world!',
type: 'string'
},
{
data: '6fc48c6175657320c39f76c49b746521',
expected: 'Čaues ßvěte!',
type: 'string'
},
{
data: '78964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 8-bit length'
},
{
data: '7900964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 16-bit length',
strict: false
},
{
data: '7a000000964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 32-bit length',
strict: false
},
{
data: '7b00000000000000964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 64-bit length',
strict: false
}
];
(() => {
function rnd(length) {
const sa = [];
let l = 0;
while (l < length) {
const ascii = length - l < 3;
const base = ascii ? 32 : 126976;
const max = ascii ? 126 : 130816;
const cc = Math.floor(Math.random() * (max - base)) + base;
const s = String.fromCharCode(cc);
l += new TextEncoder().encode(s).length;
sa.push(s);
}
return sa.join('');
}
const expected16 = rnd(256);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('790100'),
...new TextEncoder().encode(expected16)
]),
expected: expected16,
type: 'string',
label: 'long string, 16-bit length strict-compat'
});
const expected32 = rnd(65536);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('7a00010000'),
...new TextEncoder().encode(expected32)
]),
expected: expected32,
type: 'string',
label: 'long string, 32-bit length strict-compat'
});
})();
describe('string', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
let actual = decode.decode(data);
assert.strictEqual(actual, fixture.expected, `decode ${ fixture.type }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
actual = decode.decode(data, { strict: true });
assert.strictEqual(actual, fixture.expected, `decode ${ fixture.type } strict`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('7ba5f702b3a5f702b34c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e')), /CBOR decode error: 64-bit integer string lengths not supported/);
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
if (fixture.data.length >= 100000000) {
it.skip(`(TODO) skipping encode of very large string ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
});
continue;
}
const data = fixture.expected;
const expectedHex = byteUtils.toHex(fixture.data);
it(`should encode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
if (fixture.unsafe) {
assert.throws(() => encode.encode(data), Error, /^CBOR encode error: number too large to encode \(-\d+\)$/);
} else if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type }`);
}
});
}
});
});
+200
View File
@@ -0,0 +1,200 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '80',
expected: [],
type: 'array empty'
},
{
data: '8102',
expected: [2],
type: 'array 1 compact uint'
},
{
data: '8118ff',
expected: [255],
type: 'array 1 uint8'
},
{
data: '811901f4',
expected: [500],
type: 'array 1 uint16'
},
{
data: '811a00010000',
expected: [65536],
type: 'array 1 uint32'
},
{
data: '811b00000000000000ff',
expected: [255],
type: 'array 1 uint64',
strict: false
},
{
data: '811b0016db6db6db6db7',
expected: [Number.MAX_SAFE_INTEGER / 1.4],
type: 'array 1 uint64'
},
{
data: '811b001fffffffffffff',
expected: [Number.MAX_SAFE_INTEGER],
type: 'array 1 uint64'
},
{
data: '8403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints'
},
{
data: '8c1b0016db6db6db6db71a000100001901f40200202238ff3aa5f702b33b0016db6db6db6db74261316fc48c6175657320c39f76c49b746521',
expected: [
Number.MAX_SAFE_INTEGER / 1.4,
65536,
500,
2,
0,
-1,
-3,
-256,
-2784428724,
Number.MIN_SAFE_INTEGER / 1.4 - 1,
new TextEncoder().encode('a1'),
'Čaues ßvěte!'
],
type: 'array mixed terminals',
label: '[]'
},
{
data: '8265617272617982626f66820582666e657374656482666172726179736121',
expected: [
'array',
[
'of',
[
5,
[
'nested',
[
'arrays',
'!'
]
]
]
]
],
type: 'array nested'
},
{
data: '980403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length8',
strict: false
},
{
data: '99000403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length16',
strict: false
},
{
data: '9a0000000403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length32',
strict: false
},
{
data: '9b000000000000000403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length64',
strict: false
}
];
describe('array', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(data), fixture.expected, `decode ${ fixture.type }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.deepStrictEqual(decode.decode(data, { strict: true }), fixture.expected, `decode ${ fixture.type }`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('9ba5f702b3a5f7020403040506')), /CBOR decode error: 64-bit integer array lengths not supported/);
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
if (fixture.unsafe) {
assert.throws(encode.encode.bind(null, fixture.expected), Error, /^CBOR encode error: number too large to encode \(\d+\)$/);
} else if (fixture.strict === false) {
assert.notDeepEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (!fixture.unsafe && fixture.strict !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(encode.encode(fixture.expected)), fixture.expected, `roundtrip ${ fixture.type }`);
});
}
}
});
describe('specials', () => {
it('can decode indefinite length items', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('9f616f6174ff')), [
'o',
't'
]);
});
it('can switch off indefinite length support', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('9f616f6174ff'), { allowIndefinite: false }), /indefinite/);
});
});
});
+667
View File
@@ -0,0 +1,667 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: 'a0',
expected: {},
type: 'map empty'
},
{
data: 'a0',
expected: new Map(),
type: 'map empty (useMaps)',
useMaps: true
},
{
data: 'a1616101',
expected: { a: 1 },
type: 'map 1 pair'
},
{
data: 'a161316161',
expected: { 1: 'a' },
type: 'map 1 pair (rev)'
},
{
data: 'a1016161',
expected: toMap([[
1,
'a'
]]),
type: 'map 1 pair (int key as Map w/ useMaps)',
useMaps: true
},
{
data: 'a243010203633132334302030463323334',
expected: toMap([
[
Uint8Array.from([
1,
2,
3
]),
'123'
],
[
Uint8Array.from([
2,
3,
4
]),
'234'
]
]),
type: 'map 2 pair (bytes keys Map w/ useMaps)',
useMaps: true
},
{
data: 'a1666f626a656374a16477697468a26134666e6573746564676f626a65637473a161216121',
expected: {
object: {
with: {
4: 'nested',
objects: { '!': '!' }
}
}
},
type: 'map nested'
},
{
data: 'a1666f626a656374a16477697468a204666e6573746564676f626a65637473a161216121',
expected: toMap([[
'object',
toMap([[
'with',
toMap([
[
4,
'nested'
],
[
'objects',
toMap([[
'!',
'!'
]])
]
])
]])
]]),
type: 'map nested w/ useMaps',
useMaps: true
},
{
data: 'ae636f6e651b0016db6db6db6db763736978206374656e3b0016db6db6db6db76374776f1a0001000064666976650064666f757202646e696e653aa5f702b365656967687438ff65736576656e226574687265651901f466656c6576656e426131667477656c76656fc48c6175657320c39f76c49b74652168666f75727465656ea4616664666f7572616f016174026274680368746869727465656e840203046466697665',
encode: {
one: Number.MAX_SAFE_INTEGER / 1.4,
two: 65536,
three: 500,
four: 2,
five: 0,
six: -1,
seven: -3,
eight: -256,
nine: -2784428724,
ten: Number.MIN_SAFE_INTEGER / 1.4 - 1,
eleven: new TextEncoder().encode('a1'),
twelve: 'Čaues ßvěte!',
thirteen: [
2,
3,
4,
'five'
],
fourteen: {
o: 1,
t: 2,
th: 3,
f: 'four'
}
},
expected: {
one: Number.MAX_SAFE_INTEGER / 1.4,
six: -1,
ten: Number.MIN_SAFE_INTEGER / 1.4 - 1,
two: 65536,
five: 0,
four: 2,
nine: -2784428724,
eight: -256,
seven: -3,
three: 500,
eleven: new TextEncoder().encode('a1'),
twelve: 'Čaues ßvěte!',
fourteen: {
f: 'four',
o: 1,
t: 2,
th: 3
},
thirteen: [
2,
3,
4,
'five'
]
},
type: 'map with complex entries',
label: '{}'
},
{
data: 'ad01636f6e65026374776f1901f46c666976652068756e647265641902586b7369782068756e647265641a00010000636269671b0016db6db6db6db76662696767657220696d696e7573206f6e6521696d696e75732074776f38ff781f6d696e75732074776f2068756e6472656420616e64206669667479207369783901f4781a6d696e757820666976652068756e6472656420616e64206f6e653901f5781a6d696e757820666976652068756e6472656420616e642074776f3aa5f702b367626967206e65673b0016db6db6db6db76a626967676572206e6567',
encode: toMap([
[
2,
'two'
],
[
1,
'one'
],
[
-2,
'minus two'
],
[
-1,
'minus one'
],
[
600,
'six hundred'
],
[
500,
'five hundred'
],
[
-256,
'minus two hundred and fifty six'
],
[
-502,
'minux five hundred and two'
],
[
-501,
'minux five hundred and one'
],
[
65536,
'big'
],
[
-2784428724,
'big neg'
],
[
6433713753386423,
'bigger'
],
[
-6433713753386424,
'bigger neg'
]
]),
expected: toMap([
[
1,
'one'
],
[
2,
'two'
],
[
500,
'five hundred'
],
[
600,
'six hundred'
],
[
65536,
'big'
],
[
6433713753386423,
'bigger'
],
[
-1,
'minus one'
],
[
-2,
'minus two'
],
[
-256,
'minus two hundred and fifty six'
],
[
-501,
'minux five hundred and one'
],
[
-502,
'minux five hundred and two'
],
[
-2784428724,
'big neg'
],
[
-6433713753386424,
'bigger neg'
]
]),
type: 'map with ints and negints',
useMaps: true
},
{
data: 'a44104636f6e65430102026374776f430102036574687265654301020464666f7572',
encode: toMap([
[
Uint8Array.from([
1,
2,
3
]),
'three'
],
[
Uint8Array.from([4]),
'one'
],
[
Uint8Array.from([
1,
2,
4
]),
'four'
],
[
Uint8Array.from([
1,
2,
2
]),
'two'
]
]),
expected: toMap([
[
Uint8Array.from([4]),
'one'
],
[
Uint8Array.from([
1,
2,
2
]),
'two'
],
[
Uint8Array.from([
1,
2,
3
]),
'three'
],
[
Uint8Array.from([
1,
2,
4
]),
'four'
]
]),
type: 'map with bytes keys',
useMaps: true
},
{
data: 'b801616101',
expected: { a: 1 },
type: 'map 1 pair, length8',
strict: false
},
{
data: 'b90001616101',
expected: { a: 1 },
type: 'map 1 pair, length16',
strict: false
},
{
data: 'ba00000001616101',
expected: { a: 1 },
type: 'map 1 pair, length32',
strict: false
},
{
data: 'bb0000000000000001616101',
expected: { a: 1 },
type: 'map 1 pair, length64',
strict: false
}
];
function toMap(arr) {
const m = new Map();
for (const [key, value] of arr) {
m.set(key, value);
}
return m;
}
function entries(map) {
function nest(a) {
for (const e of a) {
e[0] = entries(e[0]);
e[1] = entries(e[1]);
}
return a;
}
if (Object.getPrototypeOf(map) === Map.prototype) {
return nest([...map.entries()]);
}
if (typeof map === 'object') {
return nest([...Object.entries(map)]);
}
return map;
}
describe('map', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || JSON.stringify(fixture.expected) }`, () => {
let options = fixture.useMaps ? { useMaps: true } : undefined;
const decoded = decode.decode(data, options);
if (fixture.useMaps) {
assert.strictEqual(Object.getPrototypeOf(decoded), Map.prototype, 'is Map');
} else {
assert.isObject(decoded, 'is object');
}
assert.deepStrictEqual(entries(decoded), entries(fixture.expected), `decode ${ fixture.type }`);
options = Object.assign({ strict: true }, options);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, options), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.deepStrictEqual(entries(decode.decode(data, options)), entries(fixture.expected), `decode ${ fixture.type }`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('bba5f702b3a5f70201616101')), /CBOR decode error: 64-bit integer map lengths not supported/);
});
}
it('errors', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a1016161')), /non-string keys not supported \(got number\)/);
});
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.label || JSON.stringify(fixture.expected) }`, () => {
const toEncode = fixture.encode || fixture.expected;
if (fixture.unsafe) {
assert.throws(encode.encode.bind(null, toEncode), Error, /^CBOR encode error: number too large to encode \(\d+\)$/);
} else if (fixture.strict === false || fixture.roundtrip === false) {
assert.notDeepEqual(byteUtils.toHex(encode.encode(toEncode)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(toEncode)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (!fixture.unsafe && fixture.strict !== false && fixture.roundtrip !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.label || JSON.stringify(fixture.expected) }`, () => {
const toEncode = fixture.encode || fixture.expected;
const options = fixture.useMaps ? { useMaps: true } : undefined;
const rt = decode.decode(encode.encode(toEncode), options);
if (fixture.useMaps) {
assert.strictEqual(Object.getPrototypeOf(rt), Map.prototype, 'is Map');
} else {
assert.isObject(rt, 'is object');
}
assert.deepStrictEqual(entries(rt), entries(fixture.expected), `roundtrip ${ fixture.type }`);
});
}
}
});
describe('specials', () => {
it('can decode indefinite length items', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('bf616f01617402ff')), {
o: 1,
t: 2
});
});
it('can switch off indefinite length support', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('bf616f01617402ff'), { allowIndefinite: false }), /indefinite/);
});
});
describe('sorting', () => {
it('sorts int map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
1,
1
],
[
2,
2
]
]))), 'a201010202');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
2,
1
],
[
1,
2
]
]))), 'a201020201');
});
it('sorts negint map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
-1,
1
],
[
-2,
2
]
]))), 'a220012102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
-2,
1
],
[
-1,
2
]
]))), 'a220022101');
});
it('sorts bytes map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
]
]))), 'a24201020142020102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
2,
1
]),
1
],
[
Uint8Array.from([
1,
2
]),
2
]
]))), 'a24201020242020101');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
],
[
Uint8Array.from([200]),
3
]
]))), 'a341c8034201020142020102');
});
it('sorts bytes map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
]
]))), 'a24201020142020102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
2,
1
]),
1
],
[
Uint8Array.from([
1,
2
]),
2
]
]))), 'a24201020242020101');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
],
[
Uint8Array.from([200]),
3
]
]))), 'a341c8034201020142020102');
});
it('sorts array map keys (length only)', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
[1],
1
],
[
[
1,
1
],
2
]
]))), 'a281010182010102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
[
1,
1
],
1
],
[
[1],
2
]
]))), 'a281010282010101');
});
it('sorts map map keys (length only)', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
{ a: 1 },
1
],
[
{
a: 1,
b: 1
},
2
]
]))), 'a2a161610101a261610161620102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
{
a: 1,
b: 1
},
1
],
[
{ a: 1 },
2
]
]))), 'a2a161610102a261610161620101');
});
});
});
+75
View File
@@ -0,0 +1,75 @@
'use strict';
var chai = require('chai');
var token = require('../lib/token.js');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var common = require('./common.js');
var encode = require('../lib/encode.js');
var decode = require('../lib/decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
function Uint16ArrayDecoder(obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 23');
}
const u8a = byteUtils.fromHex(obj);
return new Uint16Array(u8a.buffer, u8a.byteOffset, u8a.length / 2);
}
function Uint16ArrayEncoder(obj) {
if (!(obj instanceof Uint16Array)) {
throw new Error('expected Uint16Array for "Uint16Array" encoder');
}
return [
new token.Token(token.Type.tag, 23),
new token.Token(token.Type.string, byteUtils.toHex(obj))
];
}
describe('tag', () => {
it('date', () => {
assert.throws(() => encode.encode({ d: new Date() }), /unsupported type: Date/);
assert.equal(byteUtils.toHex(encode.encode(new Date('2013-03-21T20:04:00Z'), { typeEncoders: { Date: common.dateEncoder } })), 'c074323031332d30332d32315432303a30343a30305a');
const decodedDate = decode.decode(byteUtils.fromHex('c074323031332d30332d32315432303a30343a30305a'), { tags: { 0: common.dateDecoder } });
assert.instanceOf(decodedDate, Date);
assert.equal(decodedDate.toISOString(), new Date('2013-03-21T20:04:00Z').toISOString());
});
it('Uint16Array as hex/23 (overide existing type)', () => {
assert.equal(byteUtils.toHex(encode.encode(Uint16Array.from([
1,
2,
3
]), { typeEncoders: { Uint16Array: Uint16ArrayEncoder } })), 'd76c303130303032303030333030');
const decoded = decode.decode(byteUtils.fromHex('d76c303130303032303030333030'), { tags: { 23: Uint16ArrayDecoder } });
assert.instanceOf(decoded, Uint16Array);
assert.equal(byteUtils.toHex(decoded), byteUtils.toHex(Uint16Array.from([
1,
2,
3
])));
});
it('tag int too large', () => {
const verify = (hex, strict) => {
if (!strict) {
assert.throws(() => decode.decode(byteUtils.fromHex(hex), {
tags: { 8: common.dateDecoder },
strict: true
}), /integer encoded in more bytes than necessary/);
}
const decodedDate = decode.decode(byteUtils.fromHex(hex), {
tags: { 8: common.dateDecoder },
strict
});
assert.instanceOf(decodedDate, Date);
assert.equal(decodedDate.toISOString(), new Date('2013-03-21T20:04:00Z').toISOString());
};
verify('c874323031332d30332d32315432303a30343a30305a', true);
verify('d80874323031332d30332d32315432303a30343a30305a', false);
verify('d9000874323031332d30332d32315432303a30343a30305a', false);
verify('da0000000874323031332d30332d32315432303a30343a30305a', false);
verify('db000000000000000874323031332d30332d32315432303a30343a30305a', false);
});
});
+253
View File
@@ -0,0 +1,253 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '8601f5f4f6f720',
expected: [
1,
true,
false,
null,
undefined,
-1
],
type: 'array of float specials'
},
{
data: 'f93800',
expected: 0.5,
type: 'float16'
},
{
data: 'f9b800',
expected: -0.5,
type: 'float16'
},
{
data: 'fa33c00000',
expected: 8.940696716308594e-8,
type: 'float32'
},
{
data: 'fab3c00000',
expected: -8.940696716308594e-8,
type: 'float32'
},
{
data: 'fb3ff199999999999a',
expected: 1.1,
type: 'float64'
},
{
data: 'fbbff199999999999a',
expected: -1.1,
type: 'float64'
},
{
data: 'fb3ff1c71c71c71c72',
expected: 1.1111111111111112,
type: 'float64'
},
{
data: 'fb0000000000000002',
expected: 1e-323,
type: 'float64'
},
{
data: 'fb8000000000000002',
expected: -1e-323,
type: 'float64'
},
{
data: 'fb3fefffffffffffff',
expected: 0.9999999999999999,
type: 'float64'
},
{
data: 'fbbfefffffffffffff',
expected: -0.9999999999999999,
type: 'float64'
},
{
data: 'f97c00',
expected: Infinity,
type: 'Infinity'
},
{
data: 'fb7ff0000000000000',
expected: Infinity,
type: 'Infinity',
strict: false
},
{
data: 'f9fc00',
expected: -Infinity,
type: '-Infinity'
},
{
data: 'fbfff0000000000000',
expected: -Infinity,
type: '-Infinity',
strict: false
},
{
data: 'f97e00',
expected: NaN,
type: 'NaN'
},
{
data: 'f97ff8',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fa7ff80000',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fb7ff8000000000000',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fb7ff8cafedeadbeef',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fb40f4241a31a5a515',
expected: 82497.63712086187,
type: 'float64'
}
];
describe('float', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(data), fixture.expected, `decode ${ fixture.type }`);
assert.deepStrictEqual(decode.decode(data, { strict: true }), fixture.expected, `decode ${ fixture.type }`);
});
}
});
it('error', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('f80000')), Error, 'simple values are not supported');
assert.throws(() => decode.decode(byteUtils.fromHex('f900')), Error, 'not enough data for float16');
assert.throws(() => decode.decode(byteUtils.fromHex('fa0000')), Error, 'not enough data for float32');
assert.throws(() => decode.decode(byteUtils.fromHex('fb00000000')), Error, 'not enough data for float64');
});
describe('encode', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
});
}
}
});
describe('encode float64', () => {
for (const fixture of fixtures) {
if (fixture.type.startsWith('float')) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
const encoded = encode.encode(fixture.expected, { float64: true });
assert.strictEqual(encoded.length, 9);
assert.strictEqual(encoded[0], 251);
assert.strictEqual(decode.decode(encoded), fixture.expected, `encode float64 ${ fixture.type }`);
});
}
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (!fixture.unsafe && fixture.strict !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(encode.encode(fixture.expected)), fixture.expected, `roundtrip ${ fixture.type }`);
});
}
}
});
describe('specials', () => {
it('indefinite length switch fails on BREAK', () => {
assert.throws(() => decode.decode(Uint8Array.from([
131,
1,
2,
255
])), /unexpected break to lengthed array/);
assert.throws(() => decode.decode(Uint8Array.from([
131,
1,
2,
255
]), { allowIndefinite: false }), /indefinite/);
});
it('can switch off undefined support', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('f7')), undefined);
assert.throws(() => decode.decode(byteUtils.fromHex('f7'), { allowUndefined: false }), /undefined/);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f7')), [
1,
2,
undefined
]);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f7'), { allowUndefined: false }), /undefined/);
});
it('can coerce undefined to null', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('f7'), { coerceUndefinedToNull: false }), undefined);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('f7'), { coerceUndefinedToNull: true }), null);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f7'), { coerceUndefinedToNull: false }), [
1,
2,
undefined
]);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f7'), { coerceUndefinedToNull: true }), [
1,
2,
null
]);
});
it('can switch off Infinity support', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f97c00')), [
1,
2,
Infinity
]);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f9fc00')), [
1,
2,
-Infinity
]);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f97c00'), { allowInfinity: false }), /Infinity/);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f9fc00'), { allowInfinity: false }), /Infinity/);
for (const fixture of fixtures.filter(f => f.type.endsWith('Infinity'))) {
assert.throws(() => decode.decode(byteUtils.fromHex(fixture.data), { allowInfinity: false }), /Infinity/);
}
});
it('can switch off NaN support', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f97e00')), [
1,
2,
NaN
]);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f97e00'), { allowNaN: false }), /NaN/);
for (const fixture of fixtures.filter(f => f.type === 'NaN')) {
assert.throws(() => decode.decode(byteUtils.fromHex(fixture.data), { allowNaN: false }), /NaN/);
}
});
});
});
+91
View File
@@ -0,0 +1,91 @@
'use strict';
var chai = require('chai');
var bl = require('../lib/bl.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
describe('Internal bytes list', () => {
describe('push', () => {
it('push bits', () => {
const bl$1 = new bl.Bl(10);
const expected = [];
for (let i = 0; i < 25; i++) {
bl$1.push([i + 1]);
expected.push(i + 1);
}
assert.deepEqual([...bl$1.toBytes()], expected);
});
for (let i = 4; i < 21; i++) {
it(`push Bl(${ i })`, () => {
const bl$1 = new bl.Bl(i);
const expected = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
100,
110,
120,
11,
12,
130,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23
];
for (let i = 0; i < 5; i++) {
bl$1.push([i + 1]);
}
bl$1.push(Uint8Array.from([
6,
7,
8,
9,
10
]));
bl$1.push([100]);
bl$1.push(Uint8Array.from([
110,
120
]));
bl$1.push(Uint8Array.from([
11,
12
]));
bl$1.push([130]);
bl$1.push(Uint8Array.from([
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23
]));
assert.deepEqual([...bl$1.toBytes()], expected);
});
}
});
});
+98
View File
@@ -0,0 +1,98 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var taglib = require('../taglib.js');
var byteUtils = require('../lib/byte-utils.js');
var appendix_a = require('./appendix_a.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const tags = [];
const typeEncoders = {};
tags[0] = function (obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 1');
}
return `0("${ new Date(obj).toISOString().replace(/\.000Z$/, 'Z') }")`;
};
tags[1] = function (obj) {
if (typeof obj !== 'number') {
throw new Error('expected number for tag 1');
}
return `1(${ obj })`;
};
tags[2] = taglib.bigIntDecoder;
typeEncoders.bigint = taglib.bigIntEncoder;
tags[3] = taglib.bigNegIntDecoder;
tags[23] = function (obj) {
if (!(obj instanceof Uint8Array)) {
throw new Error('expected byte array for tag 23');
}
return `23(h'${ byteUtils.toHex(obj) }')`;
};
tags[24] = function (obj) {
return tags[23](obj).replace(/^23/, '24');
};
tags[32] = function (obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 32');
}
;
(() => new URL(obj))();
return `32("${ obj }")`;
};
describe('cbor/test-vectors', () => {
let i = 0;
for (const fixture of appendix_a.fixtures) {
const u8a = byteUtils.fromHex(fixture.hex);
let expected = fixture.decoded !== undefined ? fixture.decoded : fixture.diagnostic;
if (typeof expected === 'string' && expected.startsWith('h\'')) {
expected = byteUtils.fromHex(expected.replace(/(^h)'|('$)/g, ''));
}
it(`test vector #${ i }: ${ inspect(expected).replace(/\n\s*/g, '') }`, () => {
if (fixture.error) {
assert.throws(() => decode.decode(u8a, { tags }), fixture.error);
} else {
if (fixture.noTagDecodeError) {
assert.throws(() => decode.decode(u8a), fixture.noTagDecodeError);
}
let actual = decode.decode(u8a, { tags });
if (typeof actual === 'bigint') {
actual = inspect(actual);
}
if (typeof expected === 'bigint') {
expected = inspect(expected);
}
assert.deepEqual(actual, expected);
if (fixture.roundtrip) {
if (fixture.noTagEncodeError) {
assert.throws(() => encode.encode(decode.decode(u8a, { tags })), fixture.noTagEncodeError);
}
const reencoded = encode.encode(decode.decode(u8a, { tags }), { typeEncoders });
assert.equal(byteUtils.toHex(reencoded), fixture.hex);
}
}
});
i++;
}
it.skip('encode w/ tags', () => {
});
});
function inspect(o) {
if (typeof o === 'string') {
return `'${ o }'`;
}
if (o instanceof Uint8Array) {
return `Uint8Array<${ o.join(',') }>`;
}
if (o == null || typeof o !== 'object') {
return String(o);
}
return JSON.stringify(o);
}
@@ -0,0 +1,77 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
describe('decode errors', () => {
it('not Uint8Array', () => {
for (const arg of [
true,
false,
null,
undefined,
'string',
{ obj: 'ect' },
{},
['array'],
[],
[
1,
2,
3
],
0,
100,
1.1,
-1,
Symbol.for('nope')
]) {
assert.throws(() => decode.decode(arg), /CBOR decode error.*must be a Uint8Array/);
}
});
it('no data', () => {
assert.throws(() => decode.decode(new Uint8Array('')), /CBOR decode error.*content/);
});
it('break only', () => {
assert.throws(() => decode.decode(new Uint8Array([255])), /CBOR decode error.*break/);
});
it('not enough map entries (value)', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a2616f016174')), /map.*not enough entries.*value/);
});
it('not enough map entries (key)', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a2616f01')), /map.*not enough entries.*key/);
});
it('break in lengthed map', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a2616f01ff740f')), /unexpected break to lengthed map/);
});
it('not enough array entries', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('82616f')), /array.*not enough entries/);
});
it('break in lengthed array', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('82ff')), /unexpected break to lengthed array/);
});
it('no such decoder', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('82ff')), /unexpected break to lengthed array/);
});
it('too many terminals', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('0101')), /too many terminals/);
});
it('rejectDuplicateMapKeys enabled on duplicate keys', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('a3636261720363666f6f0163666f6f02')), {
foo: 2,
bar: 3
});
assert.throws(() => decode.decode(byteUtils.fromHex('a3636261720363666f6f0163666f6f02'), { rejectDuplicateMapKeys: true }), /CBOR decode error: found repeat map key "foo"/);
assert.throws(() => decode.decode(byteUtils.fromHex('a3636261720363666f6f0163666f6f02'), {
useMaps: true,
rejectDuplicateMapKeys: true
}), /CBOR decode error: found repeat map key "foo"/);
});
});
+56
View File
@@ -0,0 +1,56 @@
'use strict';
var ipldGarbage = require('ipld-garbage');
require('../cborg.js');
var chai = require('chai');
var encode = require('../lib/encode.js');
var decode = require('../lib/decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
describe('Fuzz round-trip', () => {
it('random objects', function () {
this.timeout(5000);
for (let i = 0; i < 1000; i++) {
const obj = ipldGarbage.garbage(300, { weights: { CID: 0 } });
const byts = encode.encode(obj);
const decoded = decode.decode(byts);
assert.deepEqual(decoded, obj);
}
});
it('circular references error', () => {
let obj = {};
obj.obj = obj;
assert.throws(() => encode.encode(obj), /circular references/);
obj = {
blip: [
1,
2,
{ blop: {} }
]
};
obj.blip[2].blop.boop = obj;
assert.throws(() => encode.encode(obj), /circular references/);
obj = {
blip: [
1,
2,
{ blop: {} }
]
};
obj.blip[2].blop.boop = obj.blip;
assert.throws(() => encode.encode(obj), /circular references/);
obj = {
blip: {},
bloop: {}
};
obj.bloop = obj.blip;
assert.doesNotThrow(() => encode.encode(obj));
const arr = [];
arr[0] = arr;
assert.throws(() => encode.encode(arr), /circular references/);
});
});
+281
View File
@@ -0,0 +1,281 @@
'use strict';
var chai = require('chai');
require('../lib/json/json.js');
var encode = require('../lib/json/encode.js');
var decode = require('../lib/json/decode.js');
const toBytes = str => new TextEncoder().encode(str);
function verifyRoundTrip(obj, sorting) {
const encoded = new TextDecoder().decode(encode.encode(obj, sorting === false ? { mapSorter: null } : undefined));
const json = JSON.stringify(obj);
chai.assert.strictEqual(encoded, json);
const decoded = decode.decode(toBytes(JSON.stringify(obj)));
chai.assert.deepStrictEqual(decoded, obj);
}
function verifyEncodedForm(testCase) {
const obj = JSON.parse(testCase);
const encoded = encode.encode(obj);
chai.assert.strictEqual(new TextDecoder().decode(encoded), JSON.stringify(obj));
const decoded = decode.decode(encoded);
chai.assert.deepStrictEqual(decoded, obj);
const decoded2 = decode.decode(toBytes(testCase));
chai.assert.deepStrictEqual(decoded2, obj);
}
describe('json basics', () => {
it('can round-trip basic literals', () => {
const testCases = [
'null',
'true',
'false',
'0',
'9007199254740991',
'-9007199254740991',
JSON.stringify(Number.MAX_VALUE),
JSON.stringify(Number.MIN_VALUE)
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
chai.assert.strictEqual(decode.decode(toBytes('1E1')), 10);
chai.assert.strictEqual(decode.decode(toBytes('0.1e1')), 1);
chai.assert.strictEqual(decode.decode(toBytes('1e-1')), 0.1);
chai.assert.strictEqual(decode.decode(toBytes('1e+00')), 1);
chai.assert.strictEqual(decode.decode(toBytes('10.0')), 10);
chai.assert.deepStrictEqual(decode.decode(toBytes('[-10.0,1.0,0.0,100.0]')), [
-10,
1,
0,
100
]);
verifyRoundTrip(true);
verifyRoundTrip(false);
verifyRoundTrip(null);
verifyRoundTrip(100);
verifyRoundTrip(-100);
verifyRoundTrip(1.11);
verifyRoundTrip(-100.11111);
verifyRoundTrip(11100000000);
verifyRoundTrip(1.0011111e-18);
});
it('handles large integers as BigInt', () => {
const verify = (inp, str) => {
if (str === undefined) {
str = String(inp);
}
chai.assert.strictEqual(decode.decode(toBytes(str), { allowBigInt: true }), inp);
chai.assert.strictEqual(decode.decode(toBytes(str)), parseFloat(str));
};
verify(Number.MAX_SAFE_INTEGER);
verify(-Number.MAX_SAFE_INTEGER);
verify(BigInt('9007199254740992'));
verify(BigInt('9007199254740993'));
verify(BigInt('11959030306112471731'));
verify(BigInt('18446744073709551615'));
verify(BigInt('9223372036854775807'));
verify(BigInt('-9007199254740992'));
verify(BigInt('-9007199254740993'));
verify(BigInt('-9223372036854776000'));
verify(BigInt('-11959030306112471732'));
verify(BigInt('-18446744073709551616'));
verify(-9007199254740992, '-9007199254740992.0');
verify(-9223372036854776000, '-9223372036854776000.0');
verify(-18446744073709552000, '-18446744073709551616.0');
});
it('can round-trip string literals', () => {
const testCases = [
JSON.stringify(''),
JSON.stringify(' '),
JSON.stringify('"'),
JSON.stringify('\\'),
JSON.stringify('\b\f\n\r\t'),
JSON.stringify('"'),
JSON.stringify('&#34; %22 0x22 034 &#x22;'),
'"\uD83D\uDE00"'
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
chai.assert.strictEqual(decode.decode(toBytes('"/ & \\/"')), '/ & /');
verifyRoundTrip('this is a string');
verifyRoundTrip('this \uD834\uDD1E is a \u263A\u263A \u2663 string ̐ ̀\n\r');
verifyRoundTrip('');
verifyRoundTrip('foo\\bar\nbaz\tbop\rbing"bip\'bang');
});
it('can round-trip array literals', () => {
const testCases = [
'[]',
'[null]',
'[true, false]',
'[ \n 0,1, 2\n , 3,\n4] \n ',
'[-10.0, 1.0, 0.0, 100.0]',
'[["2 deep"]]'
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
verifyRoundTrip([
1,
2,
3,
'string',
true,
4
]);
verifyRoundTrip([
1,
2,
3,
'string',
true,
[
'and',
'a',
'nested',
'array',
true
],
4
]);
});
it('can round-trip object literals', () => {
const testCases = [
'{}',
'\n {\n "\\b"\n :\n""\n }\n ',
'{"":""}',
'{"1":{"2":0,"3":"deep"}}'
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
});
it('will sort map keys', () => {
const unsorted = {
one: 1,
two: 2,
three: 3.1,
str: 'string',
bool: true,
four: 4
};
verifyRoundTrip(unsorted, false);
chai.assert.strictEqual(new TextDecoder().decode(encode.encode(unsorted)), '{"bool":true,"four":4,"one":1,"str":"string","three":3.1,"two":2}');
});
it('can handle novel cases', () => {
chai.assert.strictEqual(decode.decode(toBytes('"this \\uD834\\uDD1E is a \\u263a\\u263a string"')), 'this \uD834\uDD1E is a \u263A\u263A string');
verifyRoundTrip({
one: 1,
two: 2,
three: 3.1,
str: 'string',
arr: [
'and',
'a',
'nested',
[],
'array',
[
true,
1
],
false
],
bool: true,
obj: {
nested: 'object',
a: [],
o: {}
},
four: 4
}, false);
verifyRoundTrip([
false,
[
{
'#nFzU': {},
'\\w>': -0.9441451951197325,
'\t\'': '\'JB+2Wg\tw"IrM*#e^L/d&4rrzUuwq(1mH6aVRredB&Bfs]S"KqK(Tz1Q"URBAfw',
'\n@FrfM': 'M[D]q&'
},
'J4>\'Xdc+u2$%',
4227406737130333
]
], false);
verifyRoundTrip([
0.12995619865708727,
-4973404279772543,
{
drG2: [true],
';#K^Qf>V': null,
'`2=': 'ecc<e/$+-.;U>Gr5RdZDJ\n5+:{=QHNN.tVVN~dX$FWFwu`6>"&=tW!*1*^\u263A)JFM1p|}&X.B|${*\\f@!w2\u263A+'
}
], false);
chai.assert.strictEqual(`${ decode.decode(encode.encode(9007199254740991)) }`, '9007199254740991');
chai.assert.strictEqual(`${ decode.decode(encode.encode(9007199254740992)) }`, '9007199254740992');
chai.assert.strictEqual(`${ decode.decode(encode.encode(900719925474099100n)) }`, '900719925474099100');
});
it('should throw on bad types', () => {
chai.assert.throws(() => encode.encode(new Uint8Array([
1,
2
])), /CBOR encode error: unsupported type: Uint8Array/);
chai.assert.throws(() => encode.encode({
boop: new Uint8Array([
1,
2
])
}), /CBOR encode error: unsupported type: Uint8Array/);
chai.assert.throws(() => encode.encode(undefined), /CBOR encode error: unsupported type: undefined/);
chai.assert.throws(() => encode.encode(new Map([
[
1,
2
],
[
2,
3
]
])), /CBOR encode error: non-string map keys are not supported/);
chai.assert.throws(() => encode.encode(new Map([
[
[
'foo',
'bar'
],
2
],
[
[
'bar',
'foo'
],
3
]
])), /CBOR encode error: complex map keys are not supported/);
});
it('should throw on bad decode failure modes', () => {
chai.assert.throws(() => decode.decode(toBytes('{"a":1 & "b":2}')), 'CBOR decode error: unexpected character at position 7, was expecting object delimiter but found \'&\'');
chai.assert.throws(() => decode.decode(toBytes('{"a":1,"b"!2}')), 'CBOR decode error: unexpected character at position 10, was expecting key/value delimiter \':\' but found \'!\'');
chai.assert.throws(() => decode.decode(toBytes('[1,2&3]')), 'CBOR decode error: unexpected character at position 4, was expecting array delimiter but found \'&\'');
chai.assert.throws(() => decode.decode(toBytes('{"a":!}')), 'CBOR decode error: unexpected character at position 5');
chai.assert.throws(() => decode.decode(toBytes('"abc')), 'CBOR decode error: unexpected end of string at position 4');
chai.assert.throws(() => decode.decode(toBytes('"ab\\xc"')), 'CBOR decode error: unexpected string escape character at position 5');
chai.assert.throws(() => decode.decode(toBytes('"ab\x1Ec"')), 'CBOR decode error: invalid control character at position 3');
chai.assert.throws(() => decode.decode(toBytes('"ab\\')), 'CBOR decode error: unexpected string termination at position 4');
chai.assert.throws(() => decode.decode(toBytes('"\u263A').subarray(0, 3)), 'CBOR decode error: unexpected unicode sequence at position 1');
chai.assert.throws(() => decode.decode(toBytes('"\\uxyza"')), 'CBOR decode error: unexpected unicode escape character at position 3');
chai.assert.throws(() => decode.decode(toBytes('"\\u11"')), 'CBOR decode error: unexpected end of unicode escape sequence at position 3');
chai.assert.throws(() => decode.decode(toBytes('-boop')), 'CBOR decode error: unexpected token at position 1');
chai.assert.throws(() => decode.decode(toBytes('{"v":nope}')), 'CBOR decode error: unexpected token at position 7, expected to find \'null\'');
chai.assert.throws(() => decode.decode(toBytes('[n]')), 'CBOR decode error: unexpected end of input at position 1');
chai.assert.throws(() => decode.decode(toBytes('{"v":truu}')), 'CBOR decode error: unexpected token at position 9, expected to find \'true\'');
chai.assert.throws(() => decode.decode(toBytes('[tr]')), 'CBOR decode error: unexpected end of input at position 1');
chai.assert.throws(() => decode.decode(toBytes('{"v":flase}')), 'CBOR decode error: unexpected token at position 7, expected to find \'false\'');
chai.assert.throws(() => decode.decode(toBytes('[fa]')), 'CBOR decode error: unexpected end of input at position 1');
chai.assert.throws(() => decode.decode(toBytes('-0..1')), 'CBOR decode error: unexpected token at position 3');
});
it('should throw when rejectDuplicateMapKeys enabled on duplicate keys', () => {
chai.assert.deepStrictEqual(decode.decode(toBytes('{"foo":1,"foo":2}')), { foo: 2 });
chai.assert.throws(() => decode.decode(toBytes('{"foo":1,"foo":2}'), { rejectDuplicateMapKeys: true }), /CBOR decode error: found repeat map key "foo"/);
});
});
+63
View File
@@ -0,0 +1,63 @@
'use strict';
var chai = require('chai');
var ipldGarbage = require('ipld-garbage');
var _0uint = require('../lib/0uint.js');
require('../cborg.js');
var length = require('../lib/length.js');
var common = require('./common.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
function verifyLength(object, options) {
const len = length.encodedLength(object, options);
const encoded = encode.encode(object, options);
const actual = encoded.length;
assert.strictEqual(actual, len, JSON.stringify(object));
}
describe('encodedLength', () => {
it('int boundaries', () => {
for (let ii = 0; ii < 4; ii++) {
verifyLength(_0uint.uintBoundaries[ii]);
verifyLength(_0uint.uintBoundaries[ii] - 1);
verifyLength(_0uint.uintBoundaries[ii] + 1);
verifyLength(-1 * _0uint.uintBoundaries[ii]);
verifyLength(-1 * _0uint.uintBoundaries[ii] - 1);
verifyLength(-1 * _0uint.uintBoundaries[ii] + 1);
}
});
it('tags', () => {
verifyLength({ date: new Date('2013-03-21T20:04:00Z') }, { typeEncoders: { Date: common.dateEncoder } });
});
it('floats', () => {
verifyLength(0.5);
verifyLength(0.5, { float64: true });
verifyLength(8.940696716308594e-8);
verifyLength(8.940696716308594e-8, { float64: true });
});
it('small garbage', function () {
this.timeout(10000);
for (let ii = 0; ii < 1000; ii++) {
const gbg = ipldGarbage.garbage(1 << 6, { weights: { CID: 0 } });
verifyLength(gbg);
}
});
it('medium garbage', function () {
this.timeout(10000);
for (let ii = 0; ii < 100; ii++) {
const gbg = ipldGarbage.garbage(1 << 16, { weights: { CID: 0 } });
verifyLength(gbg);
}
});
it('large garbage', function () {
this.timeout(10000);
for (let ii = 0; ii < 10; ii++) {
const gbg = ipldGarbage.garbage(1 << 20, { weights: { CID: 0 } });
verifyLength(gbg);
}
});
});
+14
View File
@@ -0,0 +1,14 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var encode = require('./lib/encode.js');
var decode = require('./lib/decode.js');
var token = require('./lib/token.js');
exports.encode = encode.encode;
exports.decode = decode.decode;
exports.Token = token.Token;
exports.Type = token.Type;
+163
View File
@@ -0,0 +1,163 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var common = require('./common.js');
const uintBoundaries = [
24,
256,
65536,
4294967296,
BigInt('18446744073709551616')
];
function readUint8(data, offset, options) {
common.assertEnoughData(data, offset, 1);
const value = data[offset];
if (options.strict === true && value < uintBoundaries[0]) {
throw new Error(`${ common.decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`);
}
return value;
}
function readUint16(data, offset, options) {
common.assertEnoughData(data, offset, 2);
const value = data[offset] << 8 | data[offset + 1];
if (options.strict === true && value < uintBoundaries[1]) {
throw new Error(`${ common.decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`);
}
return value;
}
function readUint32(data, offset, options) {
common.assertEnoughData(data, offset, 4);
const value = data[offset] * 16777216 + (data[offset + 1] << 16) + (data[offset + 2] << 8) + data[offset + 3];
if (options.strict === true && value < uintBoundaries[2]) {
throw new Error(`${ common.decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`);
}
return value;
}
function readUint64(data, offset, options) {
common.assertEnoughData(data, offset, 8);
const hi = data[offset] * 16777216 + (data[offset + 1] << 16) + (data[offset + 2] << 8) + data[offset + 3];
const lo = data[offset + 4] * 16777216 + (data[offset + 5] << 16) + (data[offset + 6] << 8) + data[offset + 7];
const value = (BigInt(hi) << BigInt(32)) + BigInt(lo);
if (options.strict === true && value < uintBoundaries[3]) {
throw new Error(`${ common.decodeErrPrefix } integer encoded in more bytes than necessary (strict decode)`);
}
if (value <= Number.MAX_SAFE_INTEGER) {
return Number(value);
}
if (options.allowBigInt === true) {
return value;
}
throw new Error(`${ common.decodeErrPrefix } integers outside of the safe integer range are not supported`);
}
function decodeUint8(data, pos, _minor, options) {
return new token.Token(token.Type.uint, readUint8(data, pos + 1, options), 2);
}
function decodeUint16(data, pos, _minor, options) {
return new token.Token(token.Type.uint, readUint16(data, pos + 1, options), 3);
}
function decodeUint32(data, pos, _minor, options) {
return new token.Token(token.Type.uint, readUint32(data, pos + 1, options), 5);
}
function decodeUint64(data, pos, _minor, options) {
return new token.Token(token.Type.uint, readUint64(data, pos + 1, options), 9);
}
function encodeUint(buf, token) {
return encodeUintValue(buf, 0, token.value);
}
function encodeUintValue(buf, major, uint) {
if (uint < uintBoundaries[0]) {
const nuint = Number(uint);
buf.push([major | nuint]);
} else if (uint < uintBoundaries[1]) {
const nuint = Number(uint);
buf.push([
major | 24,
nuint
]);
} else if (uint < uintBoundaries[2]) {
const nuint = Number(uint);
buf.push([
major | 25,
nuint >>> 8,
nuint & 255
]);
} else if (uint < uintBoundaries[3]) {
const nuint = Number(uint);
buf.push([
major | 26,
nuint >>> 24 & 255,
nuint >>> 16 & 255,
nuint >>> 8 & 255,
nuint & 255
]);
} else {
const buint = BigInt(uint);
if (buint < uintBoundaries[4]) {
const set = [
major | 27,
0,
0,
0,
0,
0,
0,
0
];
let lo = Number(buint & BigInt(4294967295));
let hi = Number(buint >> BigInt(32) & BigInt(4294967295));
set[8] = lo & 255;
lo = lo >> 8;
set[7] = lo & 255;
lo = lo >> 8;
set[6] = lo & 255;
lo = lo >> 8;
set[5] = lo & 255;
set[4] = hi & 255;
hi = hi >> 8;
set[3] = hi & 255;
hi = hi >> 8;
set[2] = hi & 255;
hi = hi >> 8;
set[1] = hi & 255;
buf.push(set);
} else {
throw new Error(`${ common.decodeErrPrefix } encountered BigInt larger than allowable range`);
}
}
}
encodeUint.encodedSize = function encodedSize(token) {
return encodeUintValue.encodedSize(token.value);
};
encodeUintValue.encodedSize = function encodedSize(uint) {
if (uint < uintBoundaries[0]) {
return 1;
}
if (uint < uintBoundaries[1]) {
return 2;
}
if (uint < uintBoundaries[2]) {
return 3;
}
if (uint < uintBoundaries[3]) {
return 5;
}
return 9;
};
encodeUint.compareTokens = function compareTokens(tok1, tok2) {
return tok1.value < tok2.value ? -1 : tok1.value > tok2.value ? 1 : 0;
};
exports.decodeUint16 = decodeUint16;
exports.decodeUint32 = decodeUint32;
exports.decodeUint64 = decodeUint64;
exports.decodeUint8 = decodeUint8;
exports.encodeUint = encodeUint;
exports.encodeUintValue = encodeUintValue;
exports.readUint16 = readUint16;
exports.readUint32 = readUint32;
exports.readUint64 = readUint64;
exports.readUint8 = readUint8;
exports.uintBoundaries = uintBoundaries;
+63
View File
@@ -0,0 +1,63 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var _0uint = require('./0uint.js');
var common = require('./common.js');
function decodeNegint8(data, pos, _minor, options) {
return new token.Token(token.Type.negint, -1 - _0uint.readUint8(data, pos + 1, options), 2);
}
function decodeNegint16(data, pos, _minor, options) {
return new token.Token(token.Type.negint, -1 - _0uint.readUint16(data, pos + 1, options), 3);
}
function decodeNegint32(data, pos, _minor, options) {
return new token.Token(token.Type.negint, -1 - _0uint.readUint32(data, pos + 1, options), 5);
}
const neg1b = BigInt(-1);
const pos1b = BigInt(1);
function decodeNegint64(data, pos, _minor, options) {
const int = _0uint.readUint64(data, pos + 1, options);
if (typeof int !== 'bigint') {
const value = -1 - int;
if (value >= Number.MIN_SAFE_INTEGER) {
return new token.Token(token.Type.negint, value, 9);
}
}
if (options.allowBigInt !== true) {
throw new Error(`${ common.decodeErrPrefix } integers outside of the safe integer range are not supported`);
}
return new token.Token(token.Type.negint, neg1b - BigInt(int), 9);
}
function encodeNegint(buf, token) {
const negint = token.value;
const unsigned = typeof negint === 'bigint' ? negint * neg1b - pos1b : negint * -1 - 1;
_0uint.encodeUintValue(buf, token.type.majorEncoded, unsigned);
}
encodeNegint.encodedSize = function encodedSize(token) {
const negint = token.value;
const unsigned = typeof negint === 'bigint' ? negint * neg1b - pos1b : negint * -1 - 1;
if (unsigned < _0uint.uintBoundaries[0]) {
return 1;
}
if (unsigned < _0uint.uintBoundaries[1]) {
return 2;
}
if (unsigned < _0uint.uintBoundaries[2]) {
return 3;
}
if (unsigned < _0uint.uintBoundaries[3]) {
return 5;
}
return 9;
};
encodeNegint.compareTokens = function compareTokens(tok1, tok2) {
return tok1.value < tok2.value ? 1 : tok1.value > tok2.value ? -1 : 0;
};
exports.decodeNegint16 = decodeNegint16;
exports.decodeNegint32 = decodeNegint32;
exports.decodeNegint64 = decodeNegint64;
exports.decodeNegint8 = decodeNegint8;
exports.encodeNegint = encodeNegint;
+62
View File
@@ -0,0 +1,62 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var common = require('./common.js');
var _0uint = require('./0uint.js');
var byteUtils = require('./byte-utils.js');
function toToken(data, pos, prefix, length) {
common.assertEnoughData(data, pos, prefix + length);
const buf = byteUtils.slice(data, pos + prefix, pos + prefix + length);
return new token.Token(token.Type.bytes, buf, prefix + length);
}
function decodeBytesCompact(data, pos, minor, _options) {
return toToken(data, pos, 1, minor);
}
function decodeBytes8(data, pos, _minor, options) {
return toToken(data, pos, 2, _0uint.readUint8(data, pos + 1, options));
}
function decodeBytes16(data, pos, _minor, options) {
return toToken(data, pos, 3, _0uint.readUint16(data, pos + 1, options));
}
function decodeBytes32(data, pos, _minor, options) {
return toToken(data, pos, 5, _0uint.readUint32(data, pos + 1, options));
}
function decodeBytes64(data, pos, _minor, options) {
const l = _0uint.readUint64(data, pos + 1, options);
if (typeof l === 'bigint') {
throw new Error(`${ common.decodeErrPrefix } 64-bit integer bytes lengths not supported`);
}
return toToken(data, pos, 9, l);
}
function tokenBytes(token$1) {
if (token$1.encodedBytes === undefined) {
token$1.encodedBytes = token$1.type === token.Type.string ? byteUtils.fromString(token$1.value) : token$1.value;
}
return token$1.encodedBytes;
}
function encodeBytes(buf, token) {
const bytes = tokenBytes(token);
_0uint.encodeUintValue(buf, token.type.majorEncoded, bytes.length);
buf.push(bytes);
}
encodeBytes.encodedSize = function encodedSize(token) {
const bytes = tokenBytes(token);
return _0uint.encodeUintValue.encodedSize(bytes.length) + bytes.length;
};
encodeBytes.compareTokens = function compareTokens(tok1, tok2) {
return compareBytes(tokenBytes(tok1), tokenBytes(tok2));
};
function compareBytes(b1, b2) {
return b1.length < b2.length ? -1 : b1.length > b2.length ? 1 : byteUtils.compare(b1, b2);
}
exports.compareBytes = compareBytes;
exports.decodeBytes16 = decodeBytes16;
exports.decodeBytes32 = decodeBytes32;
exports.decodeBytes64 = decodeBytes64;
exports.decodeBytes8 = decodeBytes8;
exports.decodeBytesCompact = decodeBytesCompact;
exports.encodeBytes = encodeBytes;
+46
View File
@@ -0,0 +1,46 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var common = require('./common.js');
var _0uint = require('./0uint.js');
var _2bytes = require('./2bytes.js');
var byteUtils = require('./byte-utils.js');
function toToken(data, pos, prefix, length, options) {
const totLength = prefix + length;
common.assertEnoughData(data, pos, totLength);
const tok = new token.Token(token.Type.string, byteUtils.toString(data, pos + prefix, pos + totLength), totLength);
if (options.retainStringBytes === true) {
tok.byteValue = byteUtils.slice(data, pos + prefix, pos + totLength);
}
return tok;
}
function decodeStringCompact(data, pos, minor, options) {
return toToken(data, pos, 1, minor, options);
}
function decodeString8(data, pos, _minor, options) {
return toToken(data, pos, 2, _0uint.readUint8(data, pos + 1, options), options);
}
function decodeString16(data, pos, _minor, options) {
return toToken(data, pos, 3, _0uint.readUint16(data, pos + 1, options), options);
}
function decodeString32(data, pos, _minor, options) {
return toToken(data, pos, 5, _0uint.readUint32(data, pos + 1, options), options);
}
function decodeString64(data, pos, _minor, options) {
const l = _0uint.readUint64(data, pos + 1, options);
if (typeof l === 'bigint') {
throw new Error(`${ common.decodeErrPrefix } 64-bit integer string lengths not supported`);
}
return toToken(data, pos, 9, l, options);
}
const encodeString = _2bytes.encodeBytes;
exports.decodeString16 = decodeString16;
exports.decodeString32 = decodeString32;
exports.decodeString64 = decodeString64;
exports.decodeString8 = decodeString8;
exports.decodeStringCompact = decodeStringCompact;
exports.encodeString = encodeString;
+51
View File
@@ -0,0 +1,51 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var _0uint = require('./0uint.js');
var common = require('./common.js');
function toToken(_data, _pos, prefix, length) {
return new token.Token(token.Type.array, length, prefix);
}
function decodeArrayCompact(data, pos, minor, _options) {
return toToken(data, pos, 1, minor);
}
function decodeArray8(data, pos, _minor, options) {
return toToken(data, pos, 2, _0uint.readUint8(data, pos + 1, options));
}
function decodeArray16(data, pos, _minor, options) {
return toToken(data, pos, 3, _0uint.readUint16(data, pos + 1, options));
}
function decodeArray32(data, pos, _minor, options) {
return toToken(data, pos, 5, _0uint.readUint32(data, pos + 1, options));
}
function decodeArray64(data, pos, _minor, options) {
const l = _0uint.readUint64(data, pos + 1, options);
if (typeof l === 'bigint') {
throw new Error(`${ common.decodeErrPrefix } 64-bit integer array lengths not supported`);
}
return toToken(data, pos, 9, l);
}
function decodeArrayIndefinite(data, pos, _minor, options) {
if (options.allowIndefinite === false) {
throw new Error(`${ common.decodeErrPrefix } indefinite length items not allowed`);
}
return toToken(data, pos, 1, Infinity);
}
function encodeArray(buf, token$1) {
_0uint.encodeUintValue(buf, token.Type.array.majorEncoded, token$1.value);
}
encodeArray.compareTokens = _0uint.encodeUint.compareTokens;
encodeArray.encodedSize = function encodedSize(token) {
return _0uint.encodeUintValue.encodedSize(token.value);
};
exports.decodeArray16 = decodeArray16;
exports.decodeArray32 = decodeArray32;
exports.decodeArray64 = decodeArray64;
exports.decodeArray8 = decodeArray8;
exports.decodeArrayCompact = decodeArrayCompact;
exports.decodeArrayIndefinite = decodeArrayIndefinite;
exports.encodeArray = encodeArray;
+51
View File
@@ -0,0 +1,51 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var _0uint = require('./0uint.js');
var common = require('./common.js');
function toToken(_data, _pos, prefix, length) {
return new token.Token(token.Type.map, length, prefix);
}
function decodeMapCompact(data, pos, minor, _options) {
return toToken(data, pos, 1, minor);
}
function decodeMap8(data, pos, _minor, options) {
return toToken(data, pos, 2, _0uint.readUint8(data, pos + 1, options));
}
function decodeMap16(data, pos, _minor, options) {
return toToken(data, pos, 3, _0uint.readUint16(data, pos + 1, options));
}
function decodeMap32(data, pos, _minor, options) {
return toToken(data, pos, 5, _0uint.readUint32(data, pos + 1, options));
}
function decodeMap64(data, pos, _minor, options) {
const l = _0uint.readUint64(data, pos + 1, options);
if (typeof l === 'bigint') {
throw new Error(`${ common.decodeErrPrefix } 64-bit integer map lengths not supported`);
}
return toToken(data, pos, 9, l);
}
function decodeMapIndefinite(data, pos, _minor, options) {
if (options.allowIndefinite === false) {
throw new Error(`${ common.decodeErrPrefix } indefinite length items not allowed`);
}
return toToken(data, pos, 1, Infinity);
}
function encodeMap(buf, token$1) {
_0uint.encodeUintValue(buf, token.Type.map.majorEncoded, token$1.value);
}
encodeMap.compareTokens = _0uint.encodeUint.compareTokens;
encodeMap.encodedSize = function encodedSize(token) {
return _0uint.encodeUintValue.encodedSize(token.value);
};
exports.decodeMap16 = decodeMap16;
exports.decodeMap32 = decodeMap32;
exports.decodeMap64 = decodeMap64;
exports.decodeMap8 = decodeMap8;
exports.decodeMapCompact = decodeMapCompact;
exports.decodeMapIndefinite = decodeMapIndefinite;
exports.encodeMap = encodeMap;
+36
View File
@@ -0,0 +1,36 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var _0uint = require('./0uint.js');
function decodeTagCompact(_data, _pos, minor, _options) {
return new token.Token(token.Type.tag, minor, 1);
}
function decodeTag8(data, pos, _minor, options) {
return new token.Token(token.Type.tag, _0uint.readUint8(data, pos + 1, options), 2);
}
function decodeTag16(data, pos, _minor, options) {
return new token.Token(token.Type.tag, _0uint.readUint16(data, pos + 1, options), 3);
}
function decodeTag32(data, pos, _minor, options) {
return new token.Token(token.Type.tag, _0uint.readUint32(data, pos + 1, options), 5);
}
function decodeTag64(data, pos, _minor, options) {
return new token.Token(token.Type.tag, _0uint.readUint64(data, pos + 1, options), 9);
}
function encodeTag(buf, token$1) {
_0uint.encodeUintValue(buf, token.Type.tag.majorEncoded, token$1.value);
}
encodeTag.compareTokens = _0uint.encodeUint.compareTokens;
encodeTag.encodedSize = function encodedSize(token) {
return _0uint.encodeUintValue.encodedSize(token.value);
};
exports.decodeTag16 = decodeTag16;
exports.decodeTag32 = decodeTag32;
exports.decodeTag64 = decodeTag64;
exports.decodeTag8 = decodeTag8;
exports.decodeTagCompact = decodeTagCompact;
exports.encodeTag = encodeTag;
+188
View File
@@ -0,0 +1,188 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var common = require('./common.js');
var _0uint = require('./0uint.js');
const MINOR_FALSE = 20;
const MINOR_TRUE = 21;
const MINOR_NULL = 22;
const MINOR_UNDEFINED = 23;
function decodeUndefined(_data, _pos, _minor, options) {
if (options.allowUndefined === false) {
throw new Error(`${ common.decodeErrPrefix } undefined values are not supported`);
} else if (options.coerceUndefinedToNull === true) {
return new token.Token(token.Type.null, null, 1);
}
return new token.Token(token.Type.undefined, undefined, 1);
}
function decodeBreak(_data, _pos, _minor, options) {
if (options.allowIndefinite === false) {
throw new Error(`${ common.decodeErrPrefix } indefinite length items not allowed`);
}
return new token.Token(token.Type.break, undefined, 1);
}
function createToken(value, bytes, options) {
if (options) {
if (options.allowNaN === false && Number.isNaN(value)) {
throw new Error(`${ common.decodeErrPrefix } NaN values are not supported`);
}
if (options.allowInfinity === false && (value === Infinity || value === -Infinity)) {
throw new Error(`${ common.decodeErrPrefix } Infinity values are not supported`);
}
}
return new token.Token(token.Type.float, value, bytes);
}
function decodeFloat16(data, pos, _minor, options) {
return createToken(readFloat16(data, pos + 1), 3, options);
}
function decodeFloat32(data, pos, _minor, options) {
return createToken(readFloat32(data, pos + 1), 5, options);
}
function decodeFloat64(data, pos, _minor, options) {
return createToken(readFloat64(data, pos + 1), 9, options);
}
function encodeFloat(buf, token$1, options) {
const float = token$1.value;
if (float === false) {
buf.push([token.Type.float.majorEncoded | MINOR_FALSE]);
} else if (float === true) {
buf.push([token.Type.float.majorEncoded | MINOR_TRUE]);
} else if (float === null) {
buf.push([token.Type.float.majorEncoded | MINOR_NULL]);
} else if (float === undefined) {
buf.push([token.Type.float.majorEncoded | MINOR_UNDEFINED]);
} else {
let decoded;
let success = false;
if (!options || options.float64 !== true) {
encodeFloat16(float);
decoded = readFloat16(ui8a, 1);
if (float === decoded || Number.isNaN(float)) {
ui8a[0] = 249;
buf.push(ui8a.slice(0, 3));
success = true;
} else {
encodeFloat32(float);
decoded = readFloat32(ui8a, 1);
if (float === decoded) {
ui8a[0] = 250;
buf.push(ui8a.slice(0, 5));
success = true;
}
}
}
if (!success) {
encodeFloat64(float);
decoded = readFloat64(ui8a, 1);
ui8a[0] = 251;
buf.push(ui8a.slice(0, 9));
}
}
}
encodeFloat.encodedSize = function encodedSize(token, options) {
const float = token.value;
if (float === false || float === true || float === null || float === undefined) {
return 1;
}
if (!options || options.float64 !== true) {
encodeFloat16(float);
let decoded = readFloat16(ui8a, 1);
if (float === decoded || Number.isNaN(float)) {
return 3;
}
encodeFloat32(float);
decoded = readFloat32(ui8a, 1);
if (float === decoded) {
return 5;
}
}
return 9;
};
const buffer = new ArrayBuffer(9);
const dataView = new DataView(buffer, 1);
const ui8a = new Uint8Array(buffer, 0);
function encodeFloat16(inp) {
if (inp === Infinity) {
dataView.setUint16(0, 31744, false);
} else if (inp === -Infinity) {
dataView.setUint16(0, 64512, false);
} else if (Number.isNaN(inp)) {
dataView.setUint16(0, 32256, false);
} else {
dataView.setFloat32(0, inp);
const valu32 = dataView.getUint32(0);
const exponent = (valu32 & 2139095040) >> 23;
const mantissa = valu32 & 8388607;
if (exponent === 255) {
dataView.setUint16(0, 31744, false);
} else if (exponent === 0) {
dataView.setUint16(0, (inp & 2147483648) >> 16 | mantissa >> 13, false);
} else {
const logicalExponent = exponent - 127;
if (logicalExponent < -24) {
dataView.setUint16(0, 0);
} else if (logicalExponent < -14) {
dataView.setUint16(0, (valu32 & 2147483648) >> 16 | 1 << 24 + logicalExponent, false);
} else {
dataView.setUint16(0, (valu32 & 2147483648) >> 16 | logicalExponent + 15 << 10 | mantissa >> 13, false);
}
}
}
}
function readFloat16(ui8a, pos) {
if (ui8a.length - pos < 2) {
throw new Error(`${ common.decodeErrPrefix } not enough data for float16`);
}
const half = (ui8a[pos] << 8) + ui8a[pos + 1];
if (half === 31744) {
return Infinity;
}
if (half === 64512) {
return -Infinity;
}
if (half === 32256) {
return NaN;
}
const exp = half >> 10 & 31;
const mant = half & 1023;
let val;
if (exp === 0) {
val = mant * 2 ** -24;
} else if (exp !== 31) {
val = (mant + 1024) * 2 ** (exp - 25);
} else {
val = mant === 0 ? Infinity : NaN;
}
return half & 32768 ? -val : val;
}
function encodeFloat32(inp) {
dataView.setFloat32(0, inp, false);
}
function readFloat32(ui8a, pos) {
if (ui8a.length - pos < 4) {
throw new Error(`${ common.decodeErrPrefix } not enough data for float32`);
}
const offset = (ui8a.byteOffset || 0) + pos;
return new DataView(ui8a.buffer, offset, 4).getFloat32(0, false);
}
function encodeFloat64(inp) {
dataView.setFloat64(0, inp, false);
}
function readFloat64(ui8a, pos) {
if (ui8a.length - pos < 8) {
throw new Error(`${ common.decodeErrPrefix } not enough data for float64`);
}
const offset = (ui8a.byteOffset || 0) + pos;
return new DataView(ui8a.buffer, offset, 8).getFloat64(0, false);
}
encodeFloat.compareTokens = _0uint.encodeUint.compareTokens;
exports.decodeBreak = decodeBreak;
exports.decodeFloat16 = decodeFloat16;
exports.decodeFloat32 = decodeFloat32;
exports.decodeFloat64 = decodeFloat64;
exports.decodeUndefined = decodeUndefined;
exports.encodeFloat = encodeFloat;
+139
View File
@@ -0,0 +1,139 @@
'use strict';
var process = require('process');
require('../cborg.js');
var diagnostic = require('./diagnostic.js');
var byteUtils = require('./byte-utils.js');
var encode = require('./encode.js');
var decode = require('./decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var process__default = /*#__PURE__*/_interopDefaultLegacy(process);
function usage(code) {
console.error('Usage: cborg <command> <args>');
console.error('Valid commands:');
console.error('\tbin2diag [binary input]');
console.error('\tbin2hex [binary input]');
console.error('\tbin2json [--pretty] [binary input]');
console.error('\tdiag2bin [diagnostic input]');
console.error('\tdiag2hex [diagnostic input]');
console.error('\tdiag2json [--pretty] [diagnostic input]');
console.error('\thex2bin [hex input]');
console.error('\thex2diag [hex input]');
console.error('\thex2json [--pretty] [hex input]');
console.error('\tjson2bin \'[json input]\'');
console.error('\tjson2diag \'[json input]\'');
console.error('\tjson2hex \'[json input]\'');
console.error('Input may either be supplied as an argument or piped via stdin');
process__default["default"].exit(code || 0);
}
async function fromStdin() {
const chunks = [];
for await (const chunk of process__default["default"].stdin) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
}
function fromHex(str) {
str = str.replace(/\r?\n/g, '');
if (!/^([0-9a-f]{2})*$/i.test(str)) {
throw new Error('Input string is not hexadecimal format');
}
return byteUtils.fromHex(str);
}
function argvPretty() {
const argv = process__default["default"].argv.filter(s => s !== '--pretty');
const pretty = argv.length !== process__default["default"].argv.length;
return {
argv,
pretty
};
}
async function run() {
const cmd = process__default["default"].argv[2];
switch (cmd) {
case 'help': {
return usage(0);
}
case 'bin2diag': {
const bin = process__default["default"].argv.length < 4 ? await fromStdin() : new TextEncoder().encode(process__default["default"].argv[3]);
for (const line of diagnostic.tokensToDiagnostic(bin)) {
console.log(line);
}
return;
}
case 'bin2hex': {
const bin = process__default["default"].argv.length < 4 ? await fromStdin() : new TextEncoder().encode(process__default["default"].argv[3]);
return console.log(byteUtils.toHex(bin));
}
case 'bin2json': {
const {argv, pretty} = argvPretty();
const bin = argv.length < 4 ? await fromStdin() : new TextEncoder().encode(argv[3]);
return console.log(JSON.stringify(decode.decode(bin), undefined, pretty ? 2 : undefined));
}
case 'diag2bin': {
const bin = diagnostic.fromDiag(process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3]);
return process__default["default"].stdout.write(bin);
}
case 'diag2hex': {
const bin = diagnostic.fromDiag(process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3]);
return console.log(byteUtils.toHex(bin));
}
case 'diag2json': {
const {argv, pretty} = argvPretty();
const bin = diagnostic.fromDiag(argv.length < 4 ? (await fromStdin()).toString() : argv[3]);
return console.log(JSON.stringify(decode.decode(bin), undefined, pretty ? 2 : undefined));
}
case 'hex2bin': {
const bin = fromHex(process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3]);
return process__default["default"].stdout.write(bin);
}
case 'hex2diag': {
const bin = fromHex(process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3]);
for (const line of diagnostic.tokensToDiagnostic(bin)) {
console.log(line);
}
return;
}
case 'hex2json': {
const {argv, pretty} = argvPretty();
const bin = fromHex(argv.length < 4 ? (await fromStdin()).toString() : argv[3]);
return console.log(JSON.stringify(decode.decode(bin), undefined, pretty ? 2 : undefined));
}
case 'json2bin': {
const inp = process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3];
const obj = JSON.parse(inp);
return process__default["default"].stdout.write(encode.encode(obj));
}
case 'json2diag': {
const inp = process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3];
const obj = JSON.parse(inp);
for (const line of diagnostic.tokensToDiagnostic(encode.encode(obj))) {
console.log(line);
}
return;
}
case 'json2hex': {
const inp = process__default["default"].argv.length < 4 ? (await fromStdin()).toString() : process__default["default"].argv[3];
const obj = JSON.parse(inp);
return console.log(byteUtils.toHex(encode.encode(obj)));
}
default: {
if (process__default["default"].argv.findIndex(a => a.endsWith('mocha')) === -1) {
if (cmd) {
console.error(`Unknown command: '${ cmd }'`);
}
usage(1);
}
}
}
}
run().catch(err => {
console.error(err);
process__default["default"].exit(1);
});
var bin = true;
module.exports = bin;
+77
View File
@@ -0,0 +1,77 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var byteUtils = require('./byte-utils.js');
const defaultChunkSize = 256;
class Bl {
constructor(chunkSize = defaultChunkSize) {
this.chunkSize = chunkSize;
this.cursor = 0;
this.maxCursor = -1;
this.chunks = [];
this._initReuseChunk = null;
}
reset() {
this.cursor = 0;
this.maxCursor = -1;
if (this.chunks.length) {
this.chunks = [];
}
if (this._initReuseChunk !== null) {
this.chunks.push(this._initReuseChunk);
this.maxCursor = this._initReuseChunk.length - 1;
}
}
push(bytes) {
let topChunk = this.chunks[this.chunks.length - 1];
const newMax = this.cursor + bytes.length;
if (newMax <= this.maxCursor + 1) {
const chunkPos = topChunk.length - (this.maxCursor - this.cursor) - 1;
topChunk.set(bytes, chunkPos);
} else {
if (topChunk) {
const chunkPos = topChunk.length - (this.maxCursor - this.cursor) - 1;
if (chunkPos < topChunk.length) {
this.chunks[this.chunks.length - 1] = topChunk.subarray(0, chunkPos);
this.maxCursor = this.cursor - 1;
}
}
if (bytes.length < 64 && bytes.length < this.chunkSize) {
topChunk = byteUtils.alloc(this.chunkSize);
this.chunks.push(topChunk);
this.maxCursor += topChunk.length;
if (this._initReuseChunk === null) {
this._initReuseChunk = topChunk;
}
topChunk.set(bytes, 0);
} else {
this.chunks.push(bytes);
this.maxCursor += bytes.length;
}
}
this.cursor += bytes.length;
}
toBytes(reset = false) {
let byts;
if (this.chunks.length === 1) {
const chunk = this.chunks[0];
if (reset && this.cursor > chunk.length / 2) {
byts = this.cursor === chunk.length ? chunk : chunk.subarray(0, this.cursor);
this._initReuseChunk = null;
this.chunks = [];
} else {
byts = byteUtils.slice(chunk, 0, this.cursor);
}
} else {
byts = byteUtils.concat(this.chunks, this.cursor);
}
if (reset) {
this.reset();
}
return byts;
}
}
exports.Bl = Bl;
+245
View File
@@ -0,0 +1,245 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const useBuffer = globalThis.process && !globalThis.process.browser && globalThis.Buffer && typeof globalThis.Buffer.isBuffer === 'function';
const textDecoder = new TextDecoder();
const textEncoder = new TextEncoder();
function isBuffer(buf) {
return useBuffer && globalThis.Buffer.isBuffer(buf);
}
function asU8A(buf) {
if (!(buf instanceof Uint8Array)) {
return Uint8Array.from(buf);
}
return isBuffer(buf) ? new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength) : buf;
}
const toString = useBuffer ? (bytes, start, end) => {
return end - start > 64 ? globalThis.Buffer.from(bytes.subarray(start, end)).toString('utf8') : utf8Slice(bytes, start, end);
} : (bytes, start, end) => {
return end - start > 64 ? textDecoder.decode(bytes.subarray(start, end)) : utf8Slice(bytes, start, end);
};
const fromString = useBuffer ? string => {
return string.length > 64 ? globalThis.Buffer.from(string) : utf8ToBytes(string);
} : string => {
return string.length > 64 ? textEncoder.encode(string) : utf8ToBytes(string);
};
const fromArray = arr => {
return Uint8Array.from(arr);
};
const slice = useBuffer ? (bytes, start, end) => {
if (isBuffer(bytes)) {
return new Uint8Array(bytes.subarray(start, end));
}
return bytes.slice(start, end);
} : (bytes, start, end) => {
return bytes.slice(start, end);
};
const concat = useBuffer ? (chunks, length) => {
chunks = chunks.map(c => c instanceof Uint8Array ? c : globalThis.Buffer.from(c));
return asU8A(globalThis.Buffer.concat(chunks, length));
} : (chunks, length) => {
const out = new Uint8Array(length);
let off = 0;
for (let b of chunks) {
if (off + b.length > out.length) {
b = b.subarray(0, out.length - off);
}
out.set(b, off);
off += b.length;
}
return out;
};
const alloc = useBuffer ? size => {
return globalThis.Buffer.allocUnsafe(size);
} : size => {
return new Uint8Array(size);
};
const toHex = useBuffer ? d => {
if (typeof d === 'string') {
return d;
}
return globalThis.Buffer.from(toBytes(d)).toString('hex');
} : d => {
if (typeof d === 'string') {
return d;
}
return Array.prototype.reduce.call(toBytes(d), (p, c) => `${ p }${ c.toString(16).padStart(2, '0') }`, '');
};
const fromHex = useBuffer ? hex => {
if (hex instanceof Uint8Array) {
return hex;
}
return globalThis.Buffer.from(hex, 'hex');
} : hex => {
if (hex instanceof Uint8Array) {
return hex;
}
if (!hex.length) {
return new Uint8Array(0);
}
return new Uint8Array(hex.split('').map((c, i, d) => i % 2 === 0 ? `0x${ c }${ d[i + 1] }` : '').filter(Boolean).map(e => parseInt(e, 16)));
};
function toBytes(obj) {
if (obj instanceof Uint8Array && obj.constructor.name === 'Uint8Array') {
return obj;
}
if (obj instanceof ArrayBuffer) {
return new Uint8Array(obj);
}
if (ArrayBuffer.isView(obj)) {
return new Uint8Array(obj.buffer, obj.byteOffset, obj.byteLength);
}
throw new Error('Unknown type, must be binary type');
}
function compare(b1, b2) {
if (isBuffer(b1) && isBuffer(b2)) {
return b1.compare(b2);
}
for (let i = 0; i < b1.length; i++) {
if (b1[i] === b2[i]) {
continue;
}
return b1[i] < b2[i] ? -1 : 1;
}
return 0;
}
function utf8ToBytes(string, units = Infinity) {
let codePoint;
const length = string.length;
let leadSurrogate = null;
const bytes = [];
for (let i = 0; i < length; ++i) {
codePoint = string.charCodeAt(i);
if (codePoint > 55295 && codePoint < 57344) {
if (!leadSurrogate) {
if (codePoint > 56319) {
if ((units -= 3) > -1)
bytes.push(239, 191, 189);
continue;
} else if (i + 1 === length) {
if ((units -= 3) > -1)
bytes.push(239, 191, 189);
continue;
}
leadSurrogate = codePoint;
continue;
}
if (codePoint < 56320) {
if ((units -= 3) > -1)
bytes.push(239, 191, 189);
leadSurrogate = codePoint;
continue;
}
codePoint = (leadSurrogate - 55296 << 10 | codePoint - 56320) + 65536;
} else if (leadSurrogate) {
if ((units -= 3) > -1)
bytes.push(239, 191, 189);
}
leadSurrogate = null;
if (codePoint < 128) {
if ((units -= 1) < 0)
break;
bytes.push(codePoint);
} else if (codePoint < 2048) {
if ((units -= 2) < 0)
break;
bytes.push(codePoint >> 6 | 192, codePoint & 63 | 128);
} else if (codePoint < 65536) {
if ((units -= 3) < 0)
break;
bytes.push(codePoint >> 12 | 224, codePoint >> 6 & 63 | 128, codePoint & 63 | 128);
} else if (codePoint < 1114112) {
if ((units -= 4) < 0)
break;
bytes.push(codePoint >> 18 | 240, codePoint >> 12 & 63 | 128, codePoint >> 6 & 63 | 128, codePoint & 63 | 128);
} else {
throw new Error('Invalid code point');
}
}
return bytes;
}
function utf8Slice(buf, offset, end) {
const res = [];
while (offset < end) {
const firstByte = buf[offset];
let codePoint = null;
let bytesPerSequence = firstByte > 239 ? 4 : firstByte > 223 ? 3 : firstByte > 191 ? 2 : 1;
if (offset + bytesPerSequence <= end) {
let secondByte, thirdByte, fourthByte, tempCodePoint;
switch (bytesPerSequence) {
case 1:
if (firstByte < 128) {
codePoint = firstByte;
}
break;
case 2:
secondByte = buf[offset + 1];
if ((secondByte & 192) === 128) {
tempCodePoint = (firstByte & 31) << 6 | secondByte & 63;
if (tempCodePoint > 127) {
codePoint = tempCodePoint;
}
}
break;
case 3:
secondByte = buf[offset + 1];
thirdByte = buf[offset + 2];
if ((secondByte & 192) === 128 && (thirdByte & 192) === 128) {
tempCodePoint = (firstByte & 15) << 12 | (secondByte & 63) << 6 | thirdByte & 63;
if (tempCodePoint > 2047 && (tempCodePoint < 55296 || tempCodePoint > 57343)) {
codePoint = tempCodePoint;
}
}
break;
case 4:
secondByte = buf[offset + 1];
thirdByte = buf[offset + 2];
fourthByte = buf[offset + 3];
if ((secondByte & 192) === 128 && (thirdByte & 192) === 128 && (fourthByte & 192) === 128) {
tempCodePoint = (firstByte & 15) << 18 | (secondByte & 63) << 12 | (thirdByte & 63) << 6 | fourthByte & 63;
if (tempCodePoint > 65535 && tempCodePoint < 1114112) {
codePoint = tempCodePoint;
}
}
}
}
if (codePoint === null) {
codePoint = 65533;
bytesPerSequence = 1;
} else if (codePoint > 65535) {
codePoint -= 65536;
res.push(codePoint >>> 10 & 1023 | 55296);
codePoint = 56320 | codePoint & 1023;
}
res.push(codePoint);
offset += bytesPerSequence;
}
return decodeCodePointsArray(res);
}
const MAX_ARGUMENTS_LENGTH = 4096;
function decodeCodePointsArray(codePoints) {
const len = codePoints.length;
if (len <= MAX_ARGUMENTS_LENGTH) {
return String.fromCharCode.apply(String, codePoints);
}
let res = '';
let i = 0;
while (i < len) {
res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH));
}
return res;
}
exports.alloc = alloc;
exports.asU8A = asU8A;
exports.compare = compare;
exports.concat = concat;
exports.decodeCodePointsArray = decodeCodePointsArray;
exports.fromArray = fromArray;
exports.fromHex = fromHex;
exports.fromString = fromString;
exports.slice = slice;
exports.toHex = toHex;
exports.toString = toString;
exports.useBuffer = useBuffer;
+22
View File
@@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const decodeErrPrefix = 'CBOR decode error:';
const encodeErrPrefix = 'CBOR encode error:';
const uintMinorPrefixBytes = [];
uintMinorPrefixBytes[23] = 1;
uintMinorPrefixBytes[24] = 2;
uintMinorPrefixBytes[25] = 3;
uintMinorPrefixBytes[26] = 5;
uintMinorPrefixBytes[27] = 9;
function assertEnoughData(data, pos, need) {
if (data.length - pos < need) {
throw new Error(`${ decodeErrPrefix } not enough data for type`);
}
}
exports.assertEnoughData = assertEnoughData;
exports.decodeErrPrefix = decodeErrPrefix;
exports.encodeErrPrefix = encodeErrPrefix;
exports.uintMinorPrefixBytes = uintMinorPrefixBytes;
+140
View File
@@ -0,0 +1,140 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var common = require('./common.js');
var token = require('./token.js');
var jump = require('./jump.js');
const defaultDecodeOptions = {
strict: false,
allowIndefinite: true,
allowUndefined: true,
allowBigInt: true
};
class Tokeniser {
constructor(data, options = {}) {
this.pos = 0;
this.data = data;
this.options = options;
}
done() {
return this.pos >= this.data.length;
}
next() {
const byt = this.data[this.pos];
let token = jump.quick[byt];
if (token === undefined) {
const decoder = jump.jump[byt];
if (!decoder) {
throw new Error(`${ common.decodeErrPrefix } no decoder for major type ${ byt >>> 5 } (byte 0x${ byt.toString(16).padStart(2, '0') })`);
}
const minor = byt & 31;
token = decoder(this.data, this.pos, minor, this.options);
}
this.pos += token.encodedLength;
return token;
}
}
const DONE = Symbol.for('DONE');
const BREAK = Symbol.for('BREAK');
function tokenToArray(token, tokeniser, options) {
const arr = [];
for (let i = 0; i < token.value; i++) {
const value = tokensToObject(tokeniser, options);
if (value === BREAK) {
if (token.value === Infinity) {
break;
}
throw new Error(`${ common.decodeErrPrefix } got unexpected break to lengthed array`);
}
if (value === DONE) {
throw new Error(`${ common.decodeErrPrefix } found array but not enough entries (got ${ i }, expected ${ token.value })`);
}
arr[i] = value;
}
return arr;
}
function tokenToMap(token, tokeniser, options) {
const useMaps = options.useMaps === true;
const obj = useMaps ? undefined : {};
const m = useMaps ? new Map() : undefined;
for (let i = 0; i < token.value; i++) {
const key = tokensToObject(tokeniser, options);
if (key === BREAK) {
if (token.value === Infinity) {
break;
}
throw new Error(`${ common.decodeErrPrefix } got unexpected break to lengthed map`);
}
if (key === DONE) {
throw new Error(`${ common.decodeErrPrefix } found map but not enough entries (got ${ i } [no key], expected ${ token.value })`);
}
if (useMaps !== true && typeof key !== 'string') {
throw new Error(`${ common.decodeErrPrefix } non-string keys not supported (got ${ typeof key })`);
}
if (options.rejectDuplicateMapKeys === true) {
if (useMaps && m.has(key) || !useMaps && key in obj) {
throw new Error(`${ common.decodeErrPrefix } found repeat map key "${ key }"`);
}
}
const value = tokensToObject(tokeniser, options);
if (value === DONE) {
throw new Error(`${ common.decodeErrPrefix } found map but not enough entries (got ${ i } [no value], expected ${ token.value })`);
}
if (useMaps) {
m.set(key, value);
} else {
obj[key] = value;
}
}
return useMaps ? m : obj;
}
function tokensToObject(tokeniser, options) {
if (tokeniser.done()) {
return DONE;
}
const token$1 = tokeniser.next();
if (token$1.type === token.Type.break) {
return BREAK;
}
if (token$1.type.terminal) {
return token$1.value;
}
if (token$1.type === token.Type.array) {
return tokenToArray(token$1, tokeniser, options);
}
if (token$1.type === token.Type.map) {
return tokenToMap(token$1, tokeniser, options);
}
if (token$1.type === token.Type.tag) {
if (options.tags && typeof options.tags[token$1.value] === 'function') {
const tagged = tokensToObject(tokeniser, options);
return options.tags[token$1.value](tagged);
}
throw new Error(`${ common.decodeErrPrefix } tag not supported (${ token$1.value })`);
}
throw new Error('unsupported');
}
function decode(data, options) {
if (!(data instanceof Uint8Array)) {
throw new Error(`${ common.decodeErrPrefix } data to decode must be a Uint8Array`);
}
options = Object.assign({}, defaultDecodeOptions, options);
const tokeniser = options.tokenizer || new Tokeniser(data, options);
const decoded = tokensToObject(tokeniser, options);
if (decoded === DONE) {
throw new Error(`${ common.decodeErrPrefix } did not find any content to decode`);
}
if (decoded === BREAK) {
throw new Error(`${ common.decodeErrPrefix } got unexpected break`);
}
if (!tokeniser.done()) {
throw new Error(`${ common.decodeErrPrefix } too many terminals, data makes no sense`);
}
return decoded;
}
exports.Tokeniser = Tokeniser;
exports.decode = decode;
exports.tokensToObject = tokensToObject;
+124
View File
@@ -0,0 +1,124 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var decode = require('./decode.js');
var byteUtils = require('./byte-utils.js');
var _0uint = require('./0uint.js');
const utf8Encoder = new TextEncoder();
const utf8Decoder = new TextDecoder();
function* tokensToDiagnostic(inp, width = 100) {
const tokeniser = new decode.Tokeniser(inp, {
retainStringBytes: true,
allowBigInt: true
});
let pos = 0;
const indent = [];
const slc = (start, length) => {
return byteUtils.toHex(inp.slice(pos + start, pos + start + length));
};
while (!tokeniser.done()) {
const token = tokeniser.next();
let margin = ''.padStart(indent.length * 2, ' ');
let vLength = token.encodedLength - 1;
let v = String(token.value);
let outp = `${ margin }${ slc(0, 1) }`;
const str = token.type.name === 'bytes' || token.type.name === 'string';
if (token.type.name === 'string') {
v = v.length;
vLength -= v;
} else if (token.type.name === 'bytes') {
v = token.value.length;
vLength -= v;
}
let multilen;
switch (token.type.name) {
case 'string':
case 'bytes':
case 'map':
case 'array':
multilen = token.type.name === 'string' ? utf8Encoder.encode(token.value).length : token.value.length;
if (multilen >= _0uint.uintBoundaries[0]) {
if (multilen < _0uint.uintBoundaries[1]) {
outp += ` ${ slc(1, 1) }`;
} else if (multilen < _0uint.uintBoundaries[2]) {
outp += ` ${ slc(1, 2) }`;
} else if (multilen < _0uint.uintBoundaries[3]) {
outp += ` ${ slc(1, 4) }`;
} else if (multilen < _0uint.uintBoundaries[4]) {
outp += ` ${ slc(1, 8) }`;
}
}
break;
default:
outp += ` ${ slc(1, vLength) }`;
break;
}
outp = outp.padEnd(width / 2, ' ');
outp += `# ${ margin }${ token.type.name }`;
if (token.type.name !== v) {
outp += `(${ v })`;
}
yield outp;
if (str) {
let asString = token.type.name === 'string';
margin += ' ';
let repr = asString ? utf8Encoder.encode(token.value) : token.value;
if (asString && token.byteValue !== undefined) {
if (repr.length !== token.byteValue.length) {
repr = token.byteValue;
asString = false;
}
}
const wh = (width / 2 - margin.length - 1) / 2;
let snip = 0;
while (repr.length - snip > 0) {
const piece = repr.slice(snip, snip + wh);
snip += piece.length;
const st = asString ? utf8Decoder.decode(piece) : piece.reduce((p, c) => {
if (c < 32 || c >= 127 && c < 161 || c === 173) {
return `${ p }\\x${ c.toString(16).padStart(2, '0') }`;
}
return `${ p }${ String.fromCharCode(c) }`;
}, '');
yield `${ margin }${ byteUtils.toHex(piece) }`.padEnd(width / 2, ' ') + `# ${ margin }"${ st }"`;
}
}
if (indent.length) {
indent[indent.length - 1]--;
}
if (!token.type.terminal) {
switch (token.type.name) {
case 'map':
indent.push(token.value * 2);
break;
case 'array':
indent.push(token.value);
break;
case 'tag':
indent.push(1);
break;
default:
throw new Error(`Unknown token type '${ token.type.name }'`);
}
}
while (indent.length && indent[indent.length - 1] <= 0) {
indent.pop();
}
pos += token.encodedLength;
}
}
function fromDiag(input) {
if (typeof input !== 'string') {
throw new TypeError('Expected string input');
}
input = input.replace(/#.*?$/mg, '').replace(/[\s\r\n]+/mg, '');
if (/[^a-f0-9]/i.test(input)) {
throw new TypeError('Input string was not CBOR diagnostic format');
}
return byteUtils.fromHex(input);
}
exports.fromDiag = fromDiag;
exports.tokensToDiagnostic = tokensToDiagnostic;
+248
View File
@@ -0,0 +1,248 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var is = require('./is.js');
var token = require('./token.js');
var bl = require('./bl.js');
var common = require('./common.js');
var jump = require('./jump.js');
var byteUtils = require('./byte-utils.js');
var _0uint = require('./0uint.js');
var _1negint = require('./1negint.js');
var _2bytes = require('./2bytes.js');
var _3string = require('./3string.js');
var _4array = require('./4array.js');
var _5map = require('./5map.js');
var _6tag = require('./6tag.js');
var _7float = require('./7float.js');
const defaultEncodeOptions = {
float64: false,
mapSorter,
quickEncodeToken: jump.quickEncodeToken
};
function makeCborEncoders() {
const encoders = [];
encoders[token.Type.uint.major] = _0uint.encodeUint;
encoders[token.Type.negint.major] = _1negint.encodeNegint;
encoders[token.Type.bytes.major] = _2bytes.encodeBytes;
encoders[token.Type.string.major] = _3string.encodeString;
encoders[token.Type.array.major] = _4array.encodeArray;
encoders[token.Type.map.major] = _5map.encodeMap;
encoders[token.Type.tag.major] = _6tag.encodeTag;
encoders[token.Type.float.major] = _7float.encodeFloat;
return encoders;
}
const cborEncoders = makeCborEncoders();
const buf = new bl.Bl();
class Ref {
constructor(obj, parent) {
this.obj = obj;
this.parent = parent;
}
includes(obj) {
let p = this;
do {
if (p.obj === obj) {
return true;
}
} while (p = p.parent);
return false;
}
static createCheck(stack, obj) {
if (stack && stack.includes(obj)) {
throw new Error(`${ common.encodeErrPrefix } object contains circular references`);
}
return new Ref(obj, stack);
}
}
const simpleTokens = {
null: new token.Token(token.Type.null, null),
undefined: new token.Token(token.Type.undefined, undefined),
true: new token.Token(token.Type.true, true),
false: new token.Token(token.Type.false, false),
emptyArray: new token.Token(token.Type.array, 0),
emptyMap: new token.Token(token.Type.map, 0)
};
const typeEncoders = {
number(obj, _typ, _options, _refStack) {
if (!Number.isInteger(obj) || !Number.isSafeInteger(obj)) {
return new token.Token(token.Type.float, obj);
} else if (obj >= 0) {
return new token.Token(token.Type.uint, obj);
} else {
return new token.Token(token.Type.negint, obj);
}
},
bigint(obj, _typ, _options, _refStack) {
if (obj >= BigInt(0)) {
return new token.Token(token.Type.uint, obj);
} else {
return new token.Token(token.Type.negint, obj);
}
},
Uint8Array(obj, _typ, _options, _refStack) {
return new token.Token(token.Type.bytes, obj);
},
string(obj, _typ, _options, _refStack) {
return new token.Token(token.Type.string, obj);
},
boolean(obj, _typ, _options, _refStack) {
return obj ? simpleTokens.true : simpleTokens.false;
},
null(_obj, _typ, _options, _refStack) {
return simpleTokens.null;
},
undefined(_obj, _typ, _options, _refStack) {
return simpleTokens.undefined;
},
ArrayBuffer(obj, _typ, _options, _refStack) {
return new token.Token(token.Type.bytes, new Uint8Array(obj));
},
DataView(obj, _typ, _options, _refStack) {
return new token.Token(token.Type.bytes, new Uint8Array(obj.buffer, obj.byteOffset, obj.byteLength));
},
Array(obj, _typ, options, refStack) {
if (!obj.length) {
if (options.addBreakTokens === true) {
return [
simpleTokens.emptyArray,
new token.Token(token.Type.break)
];
}
return simpleTokens.emptyArray;
}
refStack = Ref.createCheck(refStack, obj);
const entries = [];
let i = 0;
for (const e of obj) {
entries[i++] = objectToTokens(e, options, refStack);
}
if (options.addBreakTokens) {
return [
new token.Token(token.Type.array, obj.length),
entries,
new token.Token(token.Type.break)
];
}
return [
new token.Token(token.Type.array, obj.length),
entries
];
},
Object(obj, typ, options, refStack) {
const isMap = typ !== 'Object';
const keys = isMap ? obj.keys() : Object.keys(obj);
const length = isMap ? obj.size : keys.length;
if (!length) {
if (options.addBreakTokens === true) {
return [
simpleTokens.emptyMap,
new token.Token(token.Type.break)
];
}
return simpleTokens.emptyMap;
}
refStack = Ref.createCheck(refStack, obj);
const entries = [];
let i = 0;
for (const key of keys) {
entries[i++] = [
objectToTokens(key, options, refStack),
objectToTokens(isMap ? obj.get(key) : obj[key], options, refStack)
];
}
sortMapEntries(entries, options);
if (options.addBreakTokens) {
return [
new token.Token(token.Type.map, length),
entries,
new token.Token(token.Type.break)
];
}
return [
new token.Token(token.Type.map, length),
entries
];
}
};
typeEncoders.Map = typeEncoders.Object;
typeEncoders.Buffer = typeEncoders.Uint8Array;
for (const typ of 'Uint8Clamped Uint16 Uint32 Int8 Int16 Int32 BigUint64 BigInt64 Float32 Float64'.split(' ')) {
typeEncoders[`${ typ }Array`] = typeEncoders.DataView;
}
function objectToTokens(obj, options = {}, refStack) {
const typ = is.is(obj);
const customTypeEncoder = options && options.typeEncoders && options.typeEncoders[typ] || typeEncoders[typ];
if (typeof customTypeEncoder === 'function') {
const tokens = customTypeEncoder(obj, typ, options, refStack);
if (tokens != null) {
return tokens;
}
}
const typeEncoder = typeEncoders[typ];
if (!typeEncoder) {
throw new Error(`${ common.encodeErrPrefix } unsupported type: ${ typ }`);
}
return typeEncoder(obj, typ, options, refStack);
}
function sortMapEntries(entries, options) {
if (options.mapSorter) {
entries.sort(options.mapSorter);
}
}
function mapSorter(e1, e2) {
const keyToken1 = Array.isArray(e1[0]) ? e1[0][0] : e1[0];
const keyToken2 = Array.isArray(e2[0]) ? e2[0][0] : e2[0];
if (keyToken1.type !== keyToken2.type) {
return keyToken1.type.compare(keyToken2.type);
}
const major = keyToken1.type.major;
const tcmp = cborEncoders[major].compareTokens(keyToken1, keyToken2);
if (tcmp === 0) {
console.warn('WARNING: complex key types used, CBOR key sorting guarantees are gone');
}
return tcmp;
}
function tokensToEncoded(buf, tokens, encoders, options) {
if (Array.isArray(tokens)) {
for (const token of tokens) {
tokensToEncoded(buf, token, encoders, options);
}
} else {
encoders[tokens.type.major](buf, tokens, options);
}
}
function encodeCustom(data, encoders, options) {
const tokens = objectToTokens(data, options);
if (!Array.isArray(tokens) && options.quickEncodeToken) {
const quickBytes = options.quickEncodeToken(tokens);
if (quickBytes) {
return quickBytes;
}
const encoder = encoders[tokens.type.major];
if (encoder.encodedSize) {
const size = encoder.encodedSize(tokens, options);
const buf = new bl.Bl(size);
encoder(buf, tokens, options);
if (buf.chunks.length !== 1) {
throw new Error(`Unexpected error: pre-calculated length for ${ tokens } was wrong`);
}
return byteUtils.asU8A(buf.chunks[0]);
}
}
buf.reset();
tokensToEncoded(buf, tokens, encoders, options);
return buf.toBytes(true);
}
function encode(data, options) {
options = Object.assign({}, defaultEncodeOptions, options);
return encodeCustom(data, cborEncoders, options);
}
exports.Ref = Ref;
exports.encode = encode;
exports.encodeCustom = encodeCustom;
exports.makeCborEncoders = makeCborEncoders;
exports.objectToTokens = objectToTokens;
+87
View File
@@ -0,0 +1,87 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const typeofs = [
'string',
'number',
'bigint',
'symbol'
];
const objectTypeNames = [
'Function',
'Generator',
'AsyncGenerator',
'GeneratorFunction',
'AsyncGeneratorFunction',
'AsyncFunction',
'Observable',
'Array',
'Buffer',
'Object',
'RegExp',
'Date',
'Error',
'Map',
'Set',
'WeakMap',
'WeakSet',
'ArrayBuffer',
'SharedArrayBuffer',
'DataView',
'Promise',
'URL',
'HTMLElement',
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array',
'BigInt64Array',
'BigUint64Array'
];
function is(value) {
if (value === null) {
return 'null';
}
if (value === undefined) {
return 'undefined';
}
if (value === true || value === false) {
return 'boolean';
}
const typeOf = typeof value;
if (typeofs.includes(typeOf)) {
return typeOf;
}
if (typeOf === 'function') {
return 'Function';
}
if (Array.isArray(value)) {
return 'Array';
}
if (isBuffer(value)) {
return 'Buffer';
}
const objectType = getObjectType(value);
if (objectType) {
return objectType;
}
return 'Object';
}
function isBuffer(value) {
return value && value.constructor && value.constructor.isBuffer && value.constructor.isBuffer.call(null, value);
}
function getObjectType(value) {
const objectTypeName = Object.prototype.toString.call(value).slice(8, -1);
if (objectTypeNames.includes(objectTypeName)) {
return objectTypeName;
}
return undefined;
}
exports.is = is;
+414
View File
@@ -0,0 +1,414 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var decode$1 = require('../decode.js');
var token = require('../token.js');
var byteUtils = require('../byte-utils.js');
var common = require('../common.js');
class Tokenizer {
constructor(data, options = {}) {
this.pos = 0;
this.data = data;
this.options = options;
this.modeStack = ['value'];
this.lastToken = '';
}
done() {
return this.pos >= this.data.length;
}
ch() {
return this.data[this.pos];
}
currentMode() {
return this.modeStack[this.modeStack.length - 1];
}
skipWhitespace() {
let c = this.ch();
while (c === 32 || c === 9 || c === 13 || c === 10) {
c = this.data[++this.pos];
}
}
expect(str) {
if (this.data.length - this.pos < str.length) {
throw new Error(`${ common.decodeErrPrefix } unexpected end of input at position ${ this.pos }`);
}
for (let i = 0; i < str.length; i++) {
if (this.data[this.pos++] !== str[i]) {
throw new Error(`${ common.decodeErrPrefix } unexpected token at position ${ this.pos }, expected to find '${ String.fromCharCode(...str) }'`);
}
}
}
parseNumber() {
const startPos = this.pos;
let negative = false;
let float = false;
const swallow = chars => {
while (!this.done()) {
const ch = this.ch();
if (chars.includes(ch)) {
this.pos++;
} else {
break;
}
}
};
if (this.ch() === 45) {
negative = true;
this.pos++;
}
if (this.ch() === 48) {
this.pos++;
if (this.ch() === 46) {
this.pos++;
float = true;
} else {
return new token.Token(token.Type.uint, 0, this.pos - startPos);
}
}
swallow([
48,
49,
50,
51,
52,
53,
54,
55,
56,
57
]);
if (negative && this.pos === startPos + 1) {
throw new Error(`${ common.decodeErrPrefix } unexpected token at position ${ this.pos }`);
}
if (!this.done() && this.ch() === 46) {
if (float) {
throw new Error(`${ common.decodeErrPrefix } unexpected token at position ${ this.pos }`);
}
float = true;
this.pos++;
swallow([
48,
49,
50,
51,
52,
53,
54,
55,
56,
57
]);
}
if (!this.done() && (this.ch() === 101 || this.ch() === 69)) {
float = true;
this.pos++;
if (!this.done() && (this.ch() === 43 || this.ch() === 45)) {
this.pos++;
}
swallow([
48,
49,
50,
51,
52,
53,
54,
55,
56,
57
]);
}
const numStr = String.fromCharCode.apply(null, this.data.subarray(startPos, this.pos));
const num = parseFloat(numStr);
if (float) {
return new token.Token(token.Type.float, num, this.pos - startPos);
}
if (this.options.allowBigInt !== true || Number.isSafeInteger(num)) {
return new token.Token(num >= 0 ? token.Type.uint : token.Type.negint, num, this.pos - startPos);
}
return new token.Token(num >= 0 ? token.Type.uint : token.Type.negint, BigInt(numStr), this.pos - startPos);
}
parseString() {
if (this.ch() !== 34) {
throw new Error(`${ common.decodeErrPrefix } unexpected character at position ${ this.pos }; this shouldn't happen`);
}
this.pos++;
for (let i = this.pos, l = 0; i < this.data.length && l < 65536; i++, l++) {
const ch = this.data[i];
if (ch === 92 || ch < 32 || ch >= 128) {
break;
}
if (ch === 34) {
const str = String.fromCharCode.apply(null, this.data.subarray(this.pos, i));
this.pos = i + 1;
return new token.Token(token.Type.string, str, l);
}
}
const startPos = this.pos;
const chars = [];
const readu4 = () => {
if (this.pos + 4 >= this.data.length) {
throw new Error(`${ common.decodeErrPrefix } unexpected end of unicode escape sequence at position ${ this.pos }`);
}
let u4 = 0;
for (let i = 0; i < 4; i++) {
let ch = this.ch();
if (ch >= 48 && ch <= 57) {
ch -= 48;
} else if (ch >= 97 && ch <= 102) {
ch = ch - 97 + 10;
} else if (ch >= 65 && ch <= 70) {
ch = ch - 65 + 10;
} else {
throw new Error(`${ common.decodeErrPrefix } unexpected unicode escape character at position ${ this.pos }`);
}
u4 = u4 * 16 + ch;
this.pos++;
}
return u4;
};
const readUtf8Char = () => {
const firstByte = this.ch();
let codePoint = null;
let bytesPerSequence = firstByte > 239 ? 4 : firstByte > 223 ? 3 : firstByte > 191 ? 2 : 1;
if (this.pos + bytesPerSequence > this.data.length) {
throw new Error(`${ common.decodeErrPrefix } unexpected unicode sequence at position ${ this.pos }`);
}
let secondByte, thirdByte, fourthByte, tempCodePoint;
switch (bytesPerSequence) {
case 1:
if (firstByte < 128) {
codePoint = firstByte;
}
break;
case 2:
secondByte = this.data[this.pos + 1];
if ((secondByte & 192) === 128) {
tempCodePoint = (firstByte & 31) << 6 | secondByte & 63;
if (tempCodePoint > 127) {
codePoint = tempCodePoint;
}
}
break;
case 3:
secondByte = this.data[this.pos + 1];
thirdByte = this.data[this.pos + 2];
if ((secondByte & 192) === 128 && (thirdByte & 192) === 128) {
tempCodePoint = (firstByte & 15) << 12 | (secondByte & 63) << 6 | thirdByte & 63;
if (tempCodePoint > 2047 && (tempCodePoint < 55296 || tempCodePoint > 57343)) {
codePoint = tempCodePoint;
}
}
break;
case 4:
secondByte = this.data[this.pos + 1];
thirdByte = this.data[this.pos + 2];
fourthByte = this.data[this.pos + 3];
if ((secondByte & 192) === 128 && (thirdByte & 192) === 128 && (fourthByte & 192) === 128) {
tempCodePoint = (firstByte & 15) << 18 | (secondByte & 63) << 12 | (thirdByte & 63) << 6 | fourthByte & 63;
if (tempCodePoint > 65535 && tempCodePoint < 1114112) {
codePoint = tempCodePoint;
}
}
}
if (codePoint === null) {
codePoint = 65533;
bytesPerSequence = 1;
} else if (codePoint > 65535) {
codePoint -= 65536;
chars.push(codePoint >>> 10 & 1023 | 55296);
codePoint = 56320 | codePoint & 1023;
}
chars.push(codePoint);
this.pos += bytesPerSequence;
};
while (!this.done()) {
const ch = this.ch();
let ch1;
switch (ch) {
case 92:
this.pos++;
if (this.done()) {
throw new Error(`${ common.decodeErrPrefix } unexpected string termination at position ${ this.pos }`);
}
ch1 = this.ch();
this.pos++;
switch (ch1) {
case 34:
case 39:
case 92:
case 47:
chars.push(ch1);
break;
case 98:
chars.push(8);
break;
case 116:
chars.push(9);
break;
case 110:
chars.push(10);
break;
case 102:
chars.push(12);
break;
case 114:
chars.push(13);
break;
case 117:
chars.push(readu4());
break;
default:
throw new Error(`${ common.decodeErrPrefix } unexpected string escape character at position ${ this.pos }`);
}
break;
case 34:
this.pos++;
return new token.Token(token.Type.string, byteUtils.decodeCodePointsArray(chars), this.pos - startPos);
default:
if (ch < 32) {
throw new Error(`${ common.decodeErrPrefix } invalid control character at position ${ this.pos }`);
} else if (ch < 128) {
chars.push(ch);
this.pos++;
} else {
readUtf8Char();
}
}
}
throw new Error(`${ common.decodeErrPrefix } unexpected end of string at position ${ this.pos }`);
}
parseValue() {
switch (this.ch()) {
case 123:
this.modeStack.push('obj-start');
this.pos++;
return new token.Token(token.Type.map, Infinity, 1);
case 91:
this.modeStack.push('array-start');
this.pos++;
return new token.Token(token.Type.array, Infinity, 1);
case 34: {
return this.parseString();
}
case 110:
this.expect([
110,
117,
108,
108
]);
return new token.Token(token.Type.null, null, 4);
case 102:
this.expect([
102,
97,
108,
115,
101
]);
return new token.Token(token.Type.false, false, 5);
case 116:
this.expect([
116,
114,
117,
101
]);
return new token.Token(token.Type.true, true, 4);
case 45:
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
case 56:
case 57:
return this.parseNumber();
default:
throw new Error(`${ common.decodeErrPrefix } unexpected character at position ${ this.pos }`);
}
}
next() {
this.skipWhitespace();
switch (this.currentMode()) {
case 'value':
this.modeStack.pop();
return this.parseValue();
case 'array-value': {
this.modeStack.pop();
if (this.ch() === 93) {
this.pos++;
this.skipWhitespace();
return new token.Token(token.Type.break, undefined, 1);
}
if (this.ch() !== 44) {
throw new Error(`${ common.decodeErrPrefix } unexpected character at position ${ this.pos }, was expecting array delimiter but found '${ String.fromCharCode(this.ch()) }'`);
}
this.pos++;
this.modeStack.push('array-value');
this.skipWhitespace();
return this.parseValue();
}
case 'array-start': {
this.modeStack.pop();
if (this.ch() === 93) {
this.pos++;
this.skipWhitespace();
return new token.Token(token.Type.break, undefined, 1);
}
this.modeStack.push('array-value');
this.skipWhitespace();
return this.parseValue();
}
case 'obj-key':
if (this.ch() === 125) {
this.modeStack.pop();
this.pos++;
this.skipWhitespace();
return new token.Token(token.Type.break, undefined, 1);
}
if (this.ch() !== 44) {
throw new Error(`${ common.decodeErrPrefix } unexpected character at position ${ this.pos }, was expecting object delimiter but found '${ String.fromCharCode(this.ch()) }'`);
}
this.pos++;
this.skipWhitespace();
case 'obj-start': {
this.modeStack.pop();
if (this.ch() === 125) {
this.pos++;
this.skipWhitespace();
return new token.Token(token.Type.break, undefined, 1);
}
const token$1 = this.parseString();
this.skipWhitespace();
if (this.ch() !== 58) {
throw new Error(`${ common.decodeErrPrefix } unexpected character at position ${ this.pos }, was expecting key/value delimiter ':' but found '${ String.fromCharCode(this.ch()) }'`);
}
this.pos++;
this.modeStack.push('obj-value');
return token$1;
}
case 'obj-value': {
this.modeStack.pop();
this.modeStack.push('obj-key');
this.skipWhitespace();
return this.parseValue();
}
default:
throw new Error(`${ common.decodeErrPrefix } unexpected parse state at position ${ this.pos }; this shouldn't happen`);
}
}
}
function decode(data, options) {
options = Object.assign({ tokenizer: new Tokenizer(data, options) }, options);
return decode$1.decode(data, options);
}
exports.Tokenizer = Tokenizer;
exports.decode = decode;
+161
View File
@@ -0,0 +1,161 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('../token.js');
var encode$1 = require('../encode.js');
var common = require('../common.js');
var byteUtils = require('../byte-utils.js');
class JSONEncoder extends Array {
constructor() {
super();
this.inRecursive = [];
}
prefix(buf) {
const recurs = this.inRecursive[this.inRecursive.length - 1];
if (recurs) {
if (recurs.type === token.Type.array) {
recurs.elements++;
if (recurs.elements !== 1) {
buf.push([44]);
}
}
if (recurs.type === token.Type.map) {
recurs.elements++;
if (recurs.elements !== 1) {
if (recurs.elements % 2 === 1) {
buf.push([44]);
} else {
buf.push([58]);
}
}
}
}
}
[token.Type.uint.major](buf, token) {
this.prefix(buf);
const is = String(token.value);
const isa = [];
for (let i = 0; i < is.length; i++) {
isa[i] = is.charCodeAt(i);
}
buf.push(isa);
}
[token.Type.negint.major](buf, token$1) {
this[token.Type.uint.major](buf, token$1);
}
[token.Type.bytes.major](_buf, _token) {
throw new Error(`${ common.encodeErrPrefix } unsupported type: Uint8Array`);
}
[token.Type.string.major](buf, token) {
this.prefix(buf);
const byts = byteUtils.fromString(JSON.stringify(token.value));
buf.push(byts.length > 32 ? byteUtils.asU8A(byts) : byts);
}
[token.Type.array.major](buf, _token) {
this.prefix(buf);
this.inRecursive.push({
type: token.Type.array,
elements: 0
});
buf.push([91]);
}
[token.Type.map.major](buf, _token) {
this.prefix(buf);
this.inRecursive.push({
type: token.Type.map,
elements: 0
});
buf.push([123]);
}
[token.Type.tag.major](_buf, _token) {
}
[token.Type.float.major](buf, token$1) {
if (token$1.type.name === 'break') {
const recurs = this.inRecursive.pop();
if (recurs) {
if (recurs.type === token.Type.array) {
buf.push([93]);
} else if (recurs.type === token.Type.map) {
buf.push([125]);
} else {
throw new Error('Unexpected recursive type; this should not happen!');
}
return;
}
throw new Error('Unexpected break; this should not happen!');
}
if (token$1.value === undefined) {
throw new Error(`${ common.encodeErrPrefix } unsupported type: undefined`);
}
this.prefix(buf);
if (token$1.type.name === 'true') {
buf.push([
116,
114,
117,
101
]);
return;
} else if (token$1.type.name === 'false') {
buf.push([
102,
97,
108,
115,
101
]);
return;
} else if (token$1.type.name === 'null') {
buf.push([
110,
117,
108,
108
]);
return;
}
const is = String(token$1.value);
const isa = [];
let dp = false;
for (let i = 0; i < is.length; i++) {
isa[i] = is.charCodeAt(i);
if (!dp && (isa[i] === 46 || isa[i] === 101 || isa[i] === 69)) {
dp = true;
}
}
if (!dp) {
isa.push(46);
isa.push(48);
}
buf.push(isa);
}
}
function mapSorter(e1, e2) {
if (Array.isArray(e1[0]) || Array.isArray(e2[0])) {
throw new Error(`${ common.encodeErrPrefix } complex map keys are not supported`);
}
const keyToken1 = e1[0];
const keyToken2 = e2[0];
if (keyToken1.type !== token.Type.string || keyToken2.type !== token.Type.string) {
throw new Error(`${ common.encodeErrPrefix } non-string map keys are not supported`);
}
if (keyToken1 < keyToken2) {
return -1;
}
if (keyToken1 > keyToken2) {
return 1;
}
throw new Error(`${ common.encodeErrPrefix } unexpected duplicate map keys, this is not supported`);
}
const defaultEncodeOptions = {
addBreakTokens: true,
mapSorter
};
function encode(data, options) {
options = Object.assign({}, defaultEncodeOptions, options);
return encode$1.encodeCustom(data, new JSONEncoder(), options);
}
exports.encode = encode;
+12
View File
@@ -0,0 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var encode = require('./encode.js');
var decode = require('./decode.js');
exports.encode = encode.encode;
exports.Tokenizer = decode.Tokenizer;
exports.decode = decode.decode;
+174
View File
@@ -0,0 +1,174 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('./token.js');
var _0uint = require('./0uint.js');
var _1negint = require('./1negint.js');
var _2bytes = require('./2bytes.js');
var _3string = require('./3string.js');
var _4array = require('./4array.js');
var _5map = require('./5map.js');
var _6tag = require('./6tag.js');
var _7float = require('./7float.js');
var common = require('./common.js');
var byteUtils = require('./byte-utils.js');
function invalidMinor(data, pos, minor) {
throw new Error(`${ common.decodeErrPrefix } encountered invalid minor (${ minor }) for major ${ data[pos] >>> 5 }`);
}
function errorer(msg) {
return () => {
throw new Error(`${ common.decodeErrPrefix } ${ msg }`);
};
}
const jump = [];
for (let i = 0; i <= 23; i++) {
jump[i] = invalidMinor;
}
jump[24] = _0uint.decodeUint8;
jump[25] = _0uint.decodeUint16;
jump[26] = _0uint.decodeUint32;
jump[27] = _0uint.decodeUint64;
jump[28] = invalidMinor;
jump[29] = invalidMinor;
jump[30] = invalidMinor;
jump[31] = invalidMinor;
for (let i = 32; i <= 55; i++) {
jump[i] = invalidMinor;
}
jump[56] = _1negint.decodeNegint8;
jump[57] = _1negint.decodeNegint16;
jump[58] = _1negint.decodeNegint32;
jump[59] = _1negint.decodeNegint64;
jump[60] = invalidMinor;
jump[61] = invalidMinor;
jump[62] = invalidMinor;
jump[63] = invalidMinor;
for (let i = 64; i <= 87; i++) {
jump[i] = _2bytes.decodeBytesCompact;
}
jump[88] = _2bytes.decodeBytes8;
jump[89] = _2bytes.decodeBytes16;
jump[90] = _2bytes.decodeBytes32;
jump[91] = _2bytes.decodeBytes64;
jump[92] = invalidMinor;
jump[93] = invalidMinor;
jump[94] = invalidMinor;
jump[95] = errorer('indefinite length bytes/strings are not supported');
for (let i = 96; i <= 119; i++) {
jump[i] = _3string.decodeStringCompact;
}
jump[120] = _3string.decodeString8;
jump[121] = _3string.decodeString16;
jump[122] = _3string.decodeString32;
jump[123] = _3string.decodeString64;
jump[124] = invalidMinor;
jump[125] = invalidMinor;
jump[126] = invalidMinor;
jump[127] = errorer('indefinite length bytes/strings are not supported');
for (let i = 128; i <= 151; i++) {
jump[i] = _4array.decodeArrayCompact;
}
jump[152] = _4array.decodeArray8;
jump[153] = _4array.decodeArray16;
jump[154] = _4array.decodeArray32;
jump[155] = _4array.decodeArray64;
jump[156] = invalidMinor;
jump[157] = invalidMinor;
jump[158] = invalidMinor;
jump[159] = _4array.decodeArrayIndefinite;
for (let i = 160; i <= 183; i++) {
jump[i] = _5map.decodeMapCompact;
}
jump[184] = _5map.decodeMap8;
jump[185] = _5map.decodeMap16;
jump[186] = _5map.decodeMap32;
jump[187] = _5map.decodeMap64;
jump[188] = invalidMinor;
jump[189] = invalidMinor;
jump[190] = invalidMinor;
jump[191] = _5map.decodeMapIndefinite;
for (let i = 192; i <= 215; i++) {
jump[i] = _6tag.decodeTagCompact;
}
jump[216] = _6tag.decodeTag8;
jump[217] = _6tag.decodeTag16;
jump[218] = _6tag.decodeTag32;
jump[219] = _6tag.decodeTag64;
jump[220] = invalidMinor;
jump[221] = invalidMinor;
jump[222] = invalidMinor;
jump[223] = invalidMinor;
for (let i = 224; i <= 243; i++) {
jump[i] = errorer('simple values are not supported');
}
jump[244] = invalidMinor;
jump[245] = invalidMinor;
jump[246] = invalidMinor;
jump[247] = _7float.decodeUndefined;
jump[248] = errorer('simple values are not supported');
jump[249] = _7float.decodeFloat16;
jump[250] = _7float.decodeFloat32;
jump[251] = _7float.decodeFloat64;
jump[252] = invalidMinor;
jump[253] = invalidMinor;
jump[254] = invalidMinor;
jump[255] = _7float.decodeBreak;
const quick = [];
for (let i = 0; i < 24; i++) {
quick[i] = new token.Token(token.Type.uint, i, 1);
}
for (let i = -1; i >= -24; i--) {
quick[31 - i] = new token.Token(token.Type.negint, i, 1);
}
quick[64] = new token.Token(token.Type.bytes, new Uint8Array(0), 1);
quick[96] = new token.Token(token.Type.string, '', 1);
quick[128] = new token.Token(token.Type.array, 0, 1);
quick[160] = new token.Token(token.Type.map, 0, 1);
quick[244] = new token.Token(token.Type.false, false, 1);
quick[245] = new token.Token(token.Type.true, true, 1);
quick[246] = new token.Token(token.Type.null, null, 1);
function quickEncodeToken(token$1) {
switch (token$1.type) {
case token.Type.false:
return byteUtils.fromArray([244]);
case token.Type.true:
return byteUtils.fromArray([245]);
case token.Type.null:
return byteUtils.fromArray([246]);
case token.Type.bytes:
if (!token$1.value.length) {
return byteUtils.fromArray([64]);
}
return;
case token.Type.string:
if (token$1.value === '') {
return byteUtils.fromArray([96]);
}
return;
case token.Type.array:
if (token$1.value === 0) {
return byteUtils.fromArray([128]);
}
return;
case token.Type.map:
if (token$1.value === 0) {
return byteUtils.fromArray([160]);
}
return;
case token.Type.uint:
if (token$1.value < 24) {
return byteUtils.fromArray([Number(token$1.value)]);
}
return;
case token.Type.negint:
if (token$1.value >= -24) {
return byteUtils.fromArray([31 - Number(token$1.value)]);
}
}
}
exports.jump = jump;
exports.quick = quick;
exports.quickEncodeToken = quickEncodeToken;
+36
View File
@@ -0,0 +1,36 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var encode = require('./encode.js');
var jump = require('./jump.js');
const cborEncoders = encode.makeCborEncoders();
const defaultEncodeOptions = {
float64: false,
quickEncodeToken: jump.quickEncodeToken
};
function encodedLength(data, options) {
options = Object.assign({}, defaultEncodeOptions, options);
options.mapSorter = undefined;
const tokens = encode.objectToTokens(data, options);
return tokensToLength(tokens, cborEncoders, options);
}
function tokensToLength(tokens, encoders = cborEncoders, options = defaultEncodeOptions) {
if (Array.isArray(tokens)) {
let len = 0;
for (const token of tokens) {
len += tokensToLength(token, encoders, options);
}
return len;
} else {
const encoder = encoders[tokens.type.major];
if (encoder.encodedSize === undefined || typeof encoder.encodedSize !== 'function') {
throw new Error(`Encoder for ${ tokens.type.name } does not have an encodedSize()`);
}
return encoder.encodedSize(tokens, options);
}
}
exports.encodedLength = encodedLength;
exports.tokensToLength = tokensToLength;
+46
View File
@@ -0,0 +1,46 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
class Type {
constructor(major, name, terminal) {
this.major = major;
this.majorEncoded = major << 5;
this.name = name;
this.terminal = terminal;
}
toString() {
return `Type[${ this.major }].${ this.name }`;
}
compare(typ) {
return this.major < typ.major ? -1 : this.major > typ.major ? 1 : 0;
}
}
Type.uint = new Type(0, 'uint', true);
Type.negint = new Type(1, 'negint', true);
Type.bytes = new Type(2, 'bytes', true);
Type.string = new Type(3, 'string', true);
Type.array = new Type(4, 'array', false);
Type.map = new Type(5, 'map', false);
Type.tag = new Type(6, 'tag', false);
Type.float = new Type(7, 'float', true);
Type.false = new Type(7, 'false', true);
Type.true = new Type(7, 'true', true);
Type.null = new Type(7, 'null', true);
Type.undefined = new Type(7, 'undefined', true);
Type.break = new Type(7, 'break', true);
class Token {
constructor(type, value, encodedLength) {
this.type = type;
this.value = value;
this.encodedLength = encodedLength;
this.encodedBytes = undefined;
this.byteValue = undefined;
}
toString() {
return `Token[${ this.type }].${ this.value }`;
}
}
exports.Token = Token;
exports.Type = Type;
+643
View File
@@ -0,0 +1,643 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const fixtures = [
{
cbor: 'AA==',
hex: '00',
roundtrip: true,
decoded: 0
},
{
cbor: 'AQ==',
hex: '01',
roundtrip: true,
decoded: 1
},
{
cbor: 'Cg==',
hex: '0a',
roundtrip: true,
decoded: 10
},
{
cbor: 'Fw==',
hex: '17',
roundtrip: true,
decoded: 23
},
{
cbor: 'GBg=',
hex: '1818',
roundtrip: true,
decoded: 24
},
{
cbor: 'GBk=',
hex: '1819',
roundtrip: true,
decoded: 25
},
{
cbor: 'GGQ=',
hex: '1864',
roundtrip: true,
decoded: 100
},
{
cbor: 'GQPo',
hex: '1903e8',
roundtrip: true,
decoded: 1000
},
{
cbor: 'GgAPQkA=',
hex: '1a000f4240',
roundtrip: true,
decoded: 1000000
},
{
cbor: 'GwAAAOjUpRAA',
hex: '1b000000e8d4a51000',
roundtrip: true,
decoded: 1000000000000
},
{
cbor: 'G///////////',
hex: '1bffffffffffffffff',
roundtrip: true,
decoded: BigInt('18446744073709551615')
},
{
cbor: 'wkkBAAAAAAAAAAA=',
hex: 'c249010000000000000000',
roundtrip: true,
decoded: BigInt('18446744073709551616'),
noTagDecodeError: /tag not supported \(2\)/,
noTagEncodeError: /BigInt larger than allowable range/
},
{
cbor: 'O///////////',
hex: '3bffffffffffffffff',
roundtrip: true,
decoded: BigInt('-18446744073709551616')
},
{
cbor: 'w0kBAAAAAAAAAAA=',
hex: 'c349010000000000000000',
roundtrip: true,
decoded: BigInt('-18446744073709551617'),
noTagDecodeError: /tag not supported \(3\)/,
noTagEncodeError: /BigInt larger than allowable range/
},
{
cbor: 'IA==',
hex: '20',
roundtrip: true,
decoded: -1
},
{
cbor: 'KQ==',
hex: '29',
roundtrip: true,
decoded: -10
},
{
cbor: 'OGM=',
hex: '3863',
roundtrip: true,
decoded: -100
},
{
cbor: 'OQPn',
hex: '3903e7',
roundtrip: true,
decoded: -1000
},
{
cbor: '+QAA',
hex: 'f90000',
roundtrip: false,
decoded: 0
},
{
cbor: '+YAA',
hex: 'f98000',
roundtrip: false,
decoded: -0
},
{
cbor: '+TwA',
hex: 'f93c00',
roundtrip: false,
decoded: 1
},
{
cbor: '+z/xmZmZmZma',
hex: 'fb3ff199999999999a',
roundtrip: true,
decoded: 1.1
},
{
cbor: '+T4A',
hex: 'f93e00',
roundtrip: true,
decoded: 1.5
},
{
cbor: '+Xv/',
hex: 'f97bff',
roundtrip: false,
decoded: 65504
},
{
cbor: '+kfDUAA=',
hex: 'fa47c35000',
roundtrip: false,
decoded: 100000
},
{
cbor: '+n9///8=',
hex: 'fa7f7fffff',
roundtrip: true,
decoded: 3.4028234663852886e+38
},
{
cbor: '+3435DyIAHWc',
hex: 'fb7e37e43c8800759c',
roundtrip: true,
decoded: 1e+300
},
{
cbor: '+QAB',
hex: 'f90001',
roundtrip: true,
decoded: 5.960464477539063e-8
},
{
cbor: '+QQA',
hex: 'f90400',
roundtrip: true,
decoded: 0.00006103515625
},
{
cbor: '+cQA',
hex: 'f9c400',
roundtrip: false,
decoded: -4
},
{
cbor: '+8AQZmZmZmZm',
hex: 'fbc010666666666666',
roundtrip: true,
decoded: -4.1
},
{
cbor: '+XwA',
hex: 'f97c00',
roundtrip: true,
diagnostic: Infinity
},
{
cbor: '+X4A',
hex: 'f97e00',
roundtrip: true,
diagnostic: NaN
},
{
cbor: '+fwA',
hex: 'f9fc00',
roundtrip: true,
diagnostic: -Infinity
},
{
cbor: '+n+AAAA=',
hex: 'fa7f800000',
roundtrip: false,
diagnostic: Infinity
},
{
cbor: '+n/AAAA=',
hex: 'fa7fc00000',
roundtrip: false,
diagnostic: NaN
},
{
cbor: '+v+AAAA=',
hex: 'faff800000',
roundtrip: false,
diagnostic: -Infinity
},
{
cbor: '+3/wAAAAAAAA',
hex: 'fb7ff0000000000000',
roundtrip: false,
diagnostic: Infinity
},
{
cbor: '+3/4AAAAAAAA',
hex: 'fb7ff8000000000000',
roundtrip: false,
diagnostic: NaN
},
{
cbor: '+//wAAAAAAAA',
hex: 'fbfff0000000000000',
roundtrip: false,
diagnostic: -Infinity
},
{
cbor: '9A==',
hex: 'f4',
roundtrip: true,
decoded: false
},
{
cbor: '9Q==',
hex: 'f5',
roundtrip: true,
decoded: true
},
{
cbor: '9g==',
hex: 'f6',
roundtrip: true,
decoded: null
},
{
cbor: '9w==',
hex: 'f7',
roundtrip: true,
diagnostic: undefined
},
{
cbor: '8A==',
hex: 'f0',
roundtrip: true,
diagnostic: 'simple(16)',
error: /simple values are not supported/
},
{
cbor: '+Bg=',
hex: 'f818',
roundtrip: true,
diagnostic: 'simple(24)',
error: /simple values are not supported/
},
{
cbor: '+P8=',
hex: 'f8ff',
roundtrip: true,
diagnostic: 'simple(255)',
error: /simple values are not supported/
},
{
cbor: 'wHQyMDEzLTAzLTIxVDIwOjA0OjAwWg==',
hex: 'c074323031332d30332d32315432303a30343a30305a',
roundtrip: false,
diagnostic: '0("2013-03-21T20:04:00Z")'
},
{
cbor: 'wRpRS2ew',
hex: 'c11a514b67b0',
roundtrip: false,
diagnostic: '1(1363896240)'
},
{
cbor: 'wftB1FLZ7CAAAA==',
hex: 'c1fb41d452d9ec200000',
roundtrip: false,
diagnostic: '1(1363896240.5)'
},
{
cbor: '10QBAgME',
hex: 'd74401020304',
roundtrip: false,
diagnostic: '23(h\'01020304\')'
},
{
cbor: '2BhFZElFVEY=',
hex: 'd818456449455446',
roundtrip: false,
diagnostic: '24(h\'6449455446\')'
},
{
cbor: '2CB2aHR0cDovL3d3dy5leGFtcGxlLmNvbQ==',
hex: 'd82076687474703a2f2f7777772e6578616d706c652e636f6d',
roundtrip: false,
diagnostic: '32("http://www.example.com")'
},
{
cbor: 'QA==',
hex: '40',
roundtrip: true,
diagnostic: 'h\'\''
},
{
cbor: 'RAECAwQ=',
hex: '4401020304',
roundtrip: true,
diagnostic: 'h\'01020304\''
},
{
cbor: 'YA==',
hex: '60',
roundtrip: true,
decoded: ''
},
{
cbor: 'YWE=',
hex: '6161',
roundtrip: true,
decoded: 'a'
},
{
cbor: 'ZElFVEY=',
hex: '6449455446',
roundtrip: true,
decoded: 'IETF'
},
{
cbor: 'YiJc',
hex: '62225c',
roundtrip: true,
decoded: '"\\'
},
{
cbor: 'YsO8',
hex: '62c3bc',
roundtrip: true,
decoded: 'ü'
},
{
cbor: 'Y+awtA==',
hex: '63e6b0b4',
roundtrip: true,
decoded: '水'
},
{
cbor: 'ZPCQhZE=',
hex: '64f0908591',
roundtrip: true,
decoded: '\uD800\uDD51'
},
{
cbor: 'gA==',
hex: '80',
roundtrip: true,
decoded: []
},
{
cbor: 'gwECAw==',
hex: '83010203',
roundtrip: true,
decoded: [
1,
2,
3
]
},
{
cbor: 'gwGCAgOCBAU=',
hex: '8301820203820405',
roundtrip: true,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'mBkBAgMEBQYHCAkKCwwNDg8QERITFBUWFxgYGBk=',
hex: '98190102030405060708090a0b0c0d0e0f101112131415161718181819',
roundtrip: true,
decoded: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
]
},
{
cbor: 'oA==',
hex: 'a0',
roundtrip: true,
decoded: {}
},
{
cbor: 'ogECAwQ=',
hex: 'a201020304',
roundtrip: true,
diagnostic: '{1: 2, 3: 4}',
error: /non-string keys not supported/
},
{
cbor: 'omFhAWFiggID',
hex: 'a26161016162820203',
roundtrip: true,
decoded: {
a: 1,
b: [
2,
3
]
}
},
{
cbor: 'gmFhoWFiYWM=',
hex: '826161a161626163',
roundtrip: true,
decoded: [
'a',
{ b: 'c' }
]
},
{
cbor: 'pWFhYUFhYmFCYWNhQ2FkYURhZWFF',
hex: 'a56161614161626142616361436164614461656145',
roundtrip: true,
decoded: {
a: 'A',
b: 'B',
c: 'C',
d: 'D',
e: 'E'
}
},
{
cbor: 'X0IBAkMDBAX/',
hex: '5f42010243030405ff',
roundtrip: false,
diagnostic: '(_ h\'0102\', h\'030405\')',
error: /indefinite length bytes\/strings are not supported/
},
{
cbor: 'f2VzdHJlYWRtaW5n/w==',
hex: '7f657374726561646d696e67ff',
roundtrip: false,
decoded: 'streaming',
error: /indefinite length bytes\/strings are not supported/
},
{
cbor: 'n/8=',
hex: '9fff',
roundtrip: false,
decoded: []
},
{
cbor: 'nwGCAgOfBAX//w==',
hex: '9f018202039f0405ffff',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'nwGCAgOCBAX/',
hex: '9f01820203820405ff',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'gwGCAgOfBAX/',
hex: '83018202039f0405ff',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'gwGfAgP/ggQF',
hex: '83019f0203ff820405',
roundtrip: false,
decoded: [
1,
[
2,
3
],
[
4,
5
]
]
},
{
cbor: 'nwECAwQFBgcICQoLDA0ODxAREhMUFRYXGBgYGf8=',
hex: '9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff',
roundtrip: false,
decoded: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
]
},
{
cbor: 'v2FhAWFinwID//8=',
hex: 'bf61610161629f0203ffff',
roundtrip: false,
decoded: {
a: 1,
b: [
2,
3
]
}
},
{
cbor: 'gmFhv2FiYWP/',
hex: '826161bf61626163ff',
roundtrip: false,
decoded: [
'a',
{ b: 'c' }
]
},
{
cbor: 'v2NGdW71Y0FtdCH/',
hex: 'bf6346756ef563416d7421ff',
roundtrip: false,
decoded: {
Fun: true,
Amt: -2
}
}
];
exports.fixtures = fixtures;
+24
View File
@@ -0,0 +1,24 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var token = require('../lib/token.js');
function dateDecoder(obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 1');
}
return new Date(obj);
}
function dateEncoder(obj) {
if (!(obj instanceof Date)) {
throw new Error('expected Date for "Date" encoder');
}
return [
new token.Token(token.Type.tag, 0),
new token.Token(token.Type.string, obj.toISOString().replace(/\.000Z$/, 'Z'))
];
}
exports.dateDecoder = dateDecoder;
exports.dateEncoder = dateEncoder;
+348
View File
@@ -0,0 +1,348 @@
'use strict';
var chai = require('chai');
var child_process = require('child_process');
var process = require('process');
var path = require('path');
var os = require('os');
var url = require('url');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
var process__default = /*#__PURE__*/_interopDefaultLegacy(process);
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
const {assert} = chai__default["default"];
const fixture1JsonString = '{"a":1,"b":[2,3],"smile":"\uD83D\uDE00"}';
const fixture1JsonPrettyString = `{
"a": 1,
"b": [
2,
3
],
"smile": "😀"
}
`;
const fixture1HexString = 'a3616101616282020365736d696c6564f09f9880';
const fixture1Bin = fromHex(fixture1HexString);
const fixture1BinString = new TextDecoder().decode(fixture1Bin);
const fixture1DiagnosticString = `a3 # map(3)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
82 # array(2)
02 # uint(2)
03 # uint(3)
65 # string(5)
736d696c65 # "smile"
64 # string(2)
f09f9880 # "😀"
`;
const fixture2HexString = 'a4616101616282020363627566440102036165736d696c6564f09f9880';
const fixture2DiagnosticString = `a4 # map(4)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
82 # array(2)
02 # uint(2)
03 # uint(3)
63 # string(3)
627566 # "buf"
44 # bytes(4)
01020361 # "\\x01\\x02\\x03a"
65 # string(5)
736d696c65 # "smile"
64 # string(2)
f09f9880 # "😀"
`;
const binPath = path__default["default"].join(path__default["default"].dirname(url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('node-test/node-test-bin.js', document.baseURI).href)))), '../lib/bin.js');
function fromHex(hex) {
return new Uint8Array(hex.split('').map((c, i, d) => i % 2 === 0 ? `0x${ c }${ d[i + 1] }` : '').filter(Boolean).map(e => parseInt(e, 16)));
}
async function execBin(cmd, stdin) {
return new Promise((resolve, reject) => {
const cp = child_process.exec(`"${ process__default["default"].execPath }" "${ binPath }" ${ cmd }`, (err, stdout, stderr) => {
if (err) {
err.stdout = stdout;
err.stderr = stderr;
return reject(err);
}
resolve({
stdout,
stderr
});
});
if (stdin != null) {
cp.on('spawn', () => {
cp.stdin.write(stdin);
cp.stdin.end();
});
}
});
}
describe('Bin', () => {
it('usage', async () => {
try {
await execBin('');
assert.fail('should have errored');
} catch (e) {
assert.strictEqual(e.stdout, '');
assert.strictEqual(e.stderr, `Usage: cborg <command> <args>
Valid commands:
\tbin2diag [binary input]
\tbin2hex [binary input]
\tbin2json [--pretty] [binary input]
\tdiag2bin [diagnostic input]
\tdiag2hex [diagnostic input]
\tdiag2json [--pretty] [diagnostic input]
\thex2bin [hex input]
\thex2diag [hex input]
\thex2json [--pretty] [hex input]
\tjson2bin '[json input]'
\tjson2diag '[json input]'
\tjson2hex '[json input]'
Input may either be supplied as an argument or piped via stdin
`);
}
});
it('bad cmd', async () => {
try {
await execBin('blip');
assert.fail('should have errored');
} catch (e) {
assert.strictEqual(e.stdout, '');
assert.strictEqual(e.stderr, `Unknown command: 'blip'
Usage: cborg <command> <args>
Valid commands:
\tbin2diag [binary input]
\tbin2hex [binary input]
\tbin2json [--pretty] [binary input]
\tdiag2bin [diagnostic input]
\tdiag2hex [diagnostic input]
\tdiag2json [--pretty] [diagnostic input]
\thex2bin [hex input]
\thex2diag [hex input]
\thex2json [--pretty] [hex input]
\tjson2bin '[json input]'
\tjson2diag '[json input]'
\tjson2hex '[json input]'
Input may either be supplied as an argument or piped via stdin
`);
}
});
it('help', async () => {
const {stdout, stderr} = await execBin('help');
assert.strictEqual(stdout, '');
assert.strictEqual(stderr, `Usage: cborg <command> <args>
Valid commands:
\tbin2diag [binary input]
\tbin2hex [binary input]
\tbin2json [--pretty] [binary input]
\tdiag2bin [diagnostic input]
\tdiag2hex [diagnostic input]
\tdiag2json [--pretty] [diagnostic input]
\thex2bin [hex input]
\thex2diag [hex input]
\thex2json [--pretty] [hex input]
\tjson2bin '[json input]'
\tjson2diag '[json input]'
\tjson2hex '[json input]'
Input may either be supplied as an argument or piped via stdin
`);
});
it('bin2diag (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2diag', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1DiagnosticString);
});
it('bin2hex (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2hex', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1HexString }\n`);
});
it('bin2json (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2json', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1JsonString }\n`);
});
it('bin2json pretty (stdin)', async () => {
const {stdout, stderr} = await execBin('bin2json --pretty', fixture1Bin);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1JsonPrettyString);
});
for (const stdin of [
true,
false
]) {
if (os.platform() !== 'win32' || stdin) {
it(`diag2bin${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2bin '${ fixture1DiagnosticString }'`) : await execBin('diag2bin', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1BinString);
});
it(`diag2hex${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2hex '${ fixture1DiagnosticString }'`) : await execBin('diag2hex', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1HexString }\n`);
});
it(`diag2json${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2json '${ fixture1DiagnosticString }'`) : await execBin('diag2json', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1JsonString }\n`);
});
it(`diag2json pretty${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`diag2json --pretty '${ fixture1DiagnosticString }'`) : await execBin('diag2json --pretty', fixture1DiagnosticString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1JsonPrettyString);
});
}
it(`hex2bin${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2bin ${ fixture1HexString }`) : await execBin('hex2bin', fixture1HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1BinString);
});
it(`hex2diag${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2diag ${ fixture2HexString }`) : await execBin('hex2diag', fixture2HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture2DiagnosticString);
});
it(`hex2json${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2json ${ fixture1HexString }`) : await execBin('hex2json', fixture1HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1JsonString }\n`);
});
it(`hex2json pretty${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`hex2json --pretty ${ fixture1HexString }`) : await execBin('hex2json --pretty', fixture1HexString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1JsonPrettyString);
});
it(`json2bin${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin('json2bin "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"\uD83D\uDE00\\"}"') : await execBin('json2bin', fixture1JsonString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1BinString);
});
it(`json2diag${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin('json2diag "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"\uD83D\uDE00\\"}"') : await execBin('json2diag', fixture1JsonString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, fixture1DiagnosticString);
});
it(`json2hex${ stdin ? ' (stdin)' : '' }`, async () => {
const {stdout, stderr} = !stdin ? await execBin(`json2hex "${ fixture1JsonString.replace(/"/g, '\\"') }"`) : await execBin('json2hex', fixture1JsonString);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ fixture1HexString }\n`);
});
}
it('diag indenting', async () => {
const {stdout, stderr} = await execBin('json2diag', '{"a":[],"b":{},"c":{"a":1,"b":{"a":{"a":{}}}},"d":{"a":{"a":{"a":1},"b":2,"c":[]}},"e":[[[[{"a":{}}]]]],"f":1}');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `a6 # map(6)
61 # string(1)
61 # "a"
80 # array(0)
61 # string(1)
62 # "b"
a0 # map(0)
61 # string(1)
63 # "c"
a2 # map(2)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
a1 # map(1)
61 # string(1)
61 # "a"
a1 # map(1)
61 # string(1)
61 # "a"
a0 # map(0)
61 # string(1)
64 # "d"
a1 # map(1)
61 # string(1)
61 # "a"
a3 # map(3)
61 # string(1)
61 # "a"
a1 # map(1)
61 # string(1)
61 # "a"
01 # uint(1)
61 # string(1)
62 # "b"
02 # uint(2)
61 # string(1)
63 # "c"
80 # array(0)
61 # string(1)
65 # "e"
81 # array(1)
81 # array(1)
81 # array(1)
81 # array(1)
a1 # map(1)
61 # string(1)
61 # "a"
a0 # map(0)
61 # string(1)
66 # "f"
01 # uint(1)
`);
});
describe('diag length bytes', () => {
it('compact', async () => {
const {stdout, stderr} = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaa"');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `77 # string(23)
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
`);
});
it('1-byte', async () => {
const {stdout, stderr} = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `78 23 # string(35)
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
616161616161616161616161 # "aaaaaaaaaaaa"
`);
});
it('2-byte', async () => {
const {stdout, stderr} = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"');
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `79 0100 # string(256)
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
616161 # "aaa"
`);
});
});
it('diag non-utf8 and non-printable ascii', async () => {
const input = '7864f55ff8f12508b63ef2bfeca7557ae90df6311a5ec1631b4a1fa843310bd9c3a710eaace5a1bdd72ad0bfe049771c11e756338bd93865e645f1adec9b9c99ef407fbd4fc6859e7904c5ad7dc9bd10a5cc16973d5b28ec1a6dd43d9f82f9f18c3d03418e35';
let {stdout, stderr} = await execBin(`hex2diag ${ input }`);
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `78 64 # string(86)
f55ff8f12508b63ef2bfeca7557ae90df6311a5ec1631b # "õ_øñ%\\x08¶>ò¿ì§Uzé\\x0dö1\\x1a^Ác\\x1b"
4a1fa843310bd9c3a710eaace5a1bdd72ad0bfe049771c # "J\\x1f¨C1\\x0bÙç\\x10ê¬å¡½×*пàIw\\x1c"
11e756338bd93865e645f1adec9b9c99ef407fbd4fc685 # "\\x11çV3\\x8bÙ8eæEñ\\xadì\\x9b\\x9c\\x99ï@\\x7f½OÆ\\x85"
9e7904c5ad7dc9bd10a5cc16973d5b28ec1a6dd43d9f82 # "\\x9ey\\x04Å\\xad}ɽ\\x10¥Ì\\x16\\x97=[(ì\\x1amÔ=\\x9f\\x82"
f9f18c3d03418e35 # "ùñ\\x8c=\\x03A\\x8e5"
`);
({stdout, stderr} = await execBin('diag2hex', stdout));
assert.strictEqual(stderr, '');
assert.strictEqual(stdout, `${ input }\n`);
});
});
+4
View File
@@ -0,0 +1,4 @@
'use strict';
require('../lib/bin.js');
+158
View File
@@ -0,0 +1,158 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '00',
expected: 0,
type: 'uint8'
},
{
data: '02',
expected: 2,
type: 'uint8'
},
{
data: '18ff',
expected: 255,
type: 'uint8'
},
{
data: '1901f4',
expected: 500,
type: 'uint16'
},
{
data: '1900ff',
expected: 255,
type: 'uint16',
strict: false
},
{
data: '19ffff',
expected: 65535,
type: 'uint16'
},
{
data: '1a000000ff',
expected: 255,
type: 'uint32',
strict: false
},
{
data: '1a00010000',
expected: 65536,
type: 'uint32'
},
{
data: '1a000f4240',
expected: 1000000,
type: 'uint32'
},
{
data: '1aa5f702b3',
expected: 2784428723,
type: 'uint32'
},
{
data: '1b00000000000000ff',
expected: 255,
type: 'uint64',
strict: false
},
{
data: '1b0016db6db6db6db7',
expected: Number.MAX_SAFE_INTEGER / 1.4,
type: 'uint64'
},
{
data: '1b001fffffffffffff',
expected: Number.MAX_SAFE_INTEGER,
type: 'uint64'
},
{
data: '1ba5f702b3a5f702b3',
expected: BigInt('11959030306112471731'),
type: 'uint64'
},
{
data: '1bffffffffffffffff',
expected: BigInt('18446744073709551615'),
type: 'uint64'
}
];
describe('uint', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(data) === fixture.expected, `decode ${ fixture.type } ${ decode.decode(data) } != ${ fixture.expected }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.ok(decode.decode(data, { strict: true }) === fixture.expected, `decode ${ fixture.type }`);
}
});
}
});
it('should throw error', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('1ca5f702b3a5f702b3')), Error, 'CBOR decode error: encountered invalid minor (28) for major 0');
assert.throws(() => decode.decode(byteUtils.fromHex('1ba5f702b3a5f702')), Error, 'CBOR decode error: not enough data for type');
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(encode.encode(fixture.expected)) === fixture.expected, `roundtrip ${ fixture.type }`);
});
}
}
});
describe('toobig', () => {
it('bigger than 64-bit', () => {
assert.doesNotThrow(() => encode.encode(BigInt('18446744073709551615')));
assert.throws(() => encode.encode(BigInt('18446744073709551616')), /BigInt larger than allowable range/);
});
it('disallow BigInt', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
if (!Number.isSafeInteger(fixture.expected)) {
assert.throws(() => decode.decode(data, { allowBigInt: false }), /safe integer range/);
} else {
assert.ok(decode.decode(data, { allowBigInt: false }) === fixture.expected, `decode ${ fixture.type }`);
}
}
});
});
describe('toosmall', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false && typeof fixture.expected === 'number') {
const small = BigInt(fixture.expected);
it(`should encode ${ small }n`, () => {
assert.strictEqual(byteUtils.toHex(encode.encode(BigInt(small))), fixture.data, `encode ${ small }`);
});
}
}
});
});
+152
View File
@@ -0,0 +1,152 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '20',
expected: -1,
type: 'negint8'
},
{
data: '22',
expected: -3,
type: 'negint8'
},
{
data: '3863',
expected: -100,
type: 'negint8'
},
{
data: '38ff',
expected: -256,
type: 'negint8'
},
{
data: '3900ff',
expected: -256,
type: 'negint16',
strict: false
},
{
data: '3901f4',
expected: -501,
type: 'negint16'
},
{
data: '3a000000ff',
expected: -256,
type: 'negint32',
strict: false
},
{
data: '3aa5f702b3',
expected: -2784428724,
type: 'negint32'
},
{
data: '3b00000000000000ff',
expected: -256,
type: 'negint32',
strict: false
},
{
data: '3b0016db6db6db6db7',
expected: Number.MIN_SAFE_INTEGER / 1.4 - 1,
type: 'negint64'
},
{
data: '3b001ffffffffffffe',
expected: Number.MIN_SAFE_INTEGER,
type: 'negint64'
},
{
data: '3b001fffffffffffff',
expected: BigInt('-9007199254740992'),
type: 'negint64'
},
{
data: '3b0020000000000000',
expected: BigInt('-9007199254740993'),
type: 'negint64'
},
{
data: '3ba5f702b3a5f702b3',
expected: BigInt('-11959030306112471732'),
type: 'negint64'
},
{
data: '3bffffffffffffffff',
expected: BigInt('-18446744073709551616'),
type: 'negint64'
}
];
describe('negint', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(data) === fixture.expected, `decode ${ fixture.type } (${ decode.decode(data) } != ${ fixture.expected })`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.strictEqual(decode.decode(data, { strict: true }), fixture.expected, `decode ${ fixture.type }`);
}
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
it(`should roundtrip ${ fixture.type }=${ fixture.expected }`, () => {
assert.ok(decode.decode(encode.encode(fixture.expected)) === fixture.expected, `roundtrip ${ fixture.type }`);
});
}
});
describe('toobig', () => {
it('bigger than 64-bit', () => {
assert.doesNotThrow(() => encode.encode(BigInt('-18446744073709551616')));
assert.throws(() => encode.encode(BigInt('-18446744073709551617')), /BigInt larger than allowable range/);
});
it('disallow BigInt', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
if (!Number.isSafeInteger(fixture.expected)) {
assert.throws(() => decode.decode(data, { allowBigInt: false }), /safe integer range/);
} else {
assert.ok(decode.decode(data, { allowBigInt: false }) === fixture.expected, `decode ${ fixture.type }`);
}
}
});
});
describe('toosmall', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false && typeof fixture.expected === 'number') {
const small = BigInt(fixture.expected);
it(`should encode ${ small }n`, () => {
assert.strictEqual(byteUtils.toHex(encode.encode(BigInt(small))), fixture.data, `encode ${ small }`);
});
}
}
});
});
+254
View File
@@ -0,0 +1,254 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '40',
expected: '',
type: 'bytes'
},
{
data: '41a1',
expected: 'a1',
type: 'bytes'
},
{
data: '5801a1',
expected: 'a1',
type: 'bytes',
strict: false
},
{
data: '58ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 8-bit length'
},
{
data: '5900ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 16-bit length',
strict: false
},
{
data: '5a000000ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 32-bit length',
strict: false
},
{
data: '5b00000000000000ff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
expected: '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe',
type: 'bytes',
label: 'long bytes, 64-bit length',
strict: false
}
];
(() => {
function rnd(length) {
return new Uint8Array(Array.from({ length }, () => Math.floor(Math.random() * 255)));
}
const expected16 = rnd(256);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('590100'),
...expected16
]),
expected: expected16,
type: 'bytes',
label: 'long bytes, 16-bit length strict-compat'
});
const expected32 = rnd(65536);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('5a00010000'),
...expected32
]),
expected: expected32,
type: 'bytes',
label: 'long bytes, 32-bit length strict-compat'
});
})();
describe('bytes', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
let actual = decode.decode(data);
assert.strictEqual(byteUtils.toHex(actual), byteUtils.toHex(byteUtils.fromHex(fixture.expected)), `decode ${ fixture.type }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
actual = decode.decode(data, { strict: true });
assert.strictEqual(byteUtils.toHex(actual), byteUtils.toHex(byteUtils.fromHex(fixture.expected)), `decode ${ fixture.type } strict`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('5ba5f702b3a5f702b3000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe')), /CBOR decode error: 64-bit integer bytes lengths not supported/);
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
if (fixture.data.length >= 100000000) {
it.skip(`(TODO) skipping encode of very large bytes ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
});
continue;
}
const data = byteUtils.fromHex(fixture.expected);
const expectedHex = byteUtils.toHex(fixture.data);
it(`should encode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
if (fixture.unsafe) {
assert.throws(() => encode.encode(data), Error, /^CBOR encode error: number too large to encode \(-\d+\)$/);
} else if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type }`);
}
});
}
});
describe('typedarrays', () => {
const cases = [
{
obj: Uint8Array.from([
1,
2,
3
]),
hex: '43010203'
},
{
obj: Uint8ClampedArray.from([
1,
2,
3
]),
hex: '43010203'
},
{
obj: Uint16Array.from([
1,
2,
3
]),
hex: '46010002000300'
},
{
obj: Uint32Array.from([
1,
2,
3
]),
hex: '4c010000000200000003000000'
},
{
obj: Int8Array.from([
1,
2,
-3
]),
hex: '430102fd'
},
{
obj: Int16Array.from([
1,
2,
-3
]),
hex: '4601000200fdff'
},
{
obj: Int32Array.from([
1,
2,
-3
]),
hex: '4c0100000002000000fdffffff'
},
{
obj: Float32Array.from([
1,
2,
-3
]),
hex: '4c0000803f00000040000040c0'
},
{
obj: Float64Array.from([
1,
2,
-3
]),
hex: '5818000000000000f03f000000000000004000000000000008c0'
},
{
obj: BigUint64Array.from([
BigInt(1),
BigInt(2),
BigInt(3)
]),
hex: '5818010000000000000002000000000000000300000000000000'
},
{
obj: BigInt64Array.from([
BigInt(1),
BigInt(2),
BigInt(-3)
]),
hex: '581801000000000000000200000000000000fdffffffffffffff'
},
{
obj: new DataView(Uint8Array.from([
1,
2,
3
]).buffer),
hex: '43010203'
},
{
obj: Uint8Array.from([
1,
2,
3
]).buffer,
hex: '43010203'
}
];
for (const testCase of cases) {
it(testCase.obj.constructor.name, () => {
assert.equal(byteUtils.toHex(encode.encode(testCase.obj)), testCase.hex);
const decoded = decode.decode(byteUtils.fromHex(testCase.hex));
assert.instanceOf(decoded, Uint8Array);
assert.equal(byteUtils.toHex(decoded), byteUtils.toHex(testCase.obj));
});
}
});
if (byteUtils.useBuffer) {
describe('buffer', () => {
it('can encode Node.js Buffers', () => {
const obj = global.Buffer.from([
1,
2,
3
]);
assert.equal(byteUtils.toHex(encode.encode(obj)), '43010203');
const decoded = decode.decode(byteUtils.fromHex('43010203'));
assert.instanceOf(decoded, Uint8Array);
assert.equal(byteUtils.toHex(decoded), byteUtils.toHex(obj));
});
});
}
});
+144
View File
@@ -0,0 +1,144 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '60',
expected: '',
type: 'string'
},
{
data: '6161',
expected: 'a',
type: 'string'
},
{
data: '780161',
expected: 'a',
type: 'string',
strict: false
},
{
data: '6c48656c6c6f20776f726c6421',
expected: 'Hello world!',
type: 'string'
},
{
data: '6fc48c6175657320c39f76c49b746521',
expected: 'Čaues ßvěte!',
type: 'string'
},
{
data: '78964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 8-bit length'
},
{
data: '7900964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 16-bit length',
strict: false
},
{
data: '7a000000964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 32-bit length',
strict: false
},
{
data: '7b00000000000000964c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e',
expected: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.',
type: 'string',
label: 'long string, 64-bit length',
strict: false
}
];
(() => {
function rnd(length) {
const sa = [];
let l = 0;
while (l < length) {
const ascii = length - l < 3;
const base = ascii ? 32 : 126976;
const max = ascii ? 126 : 130816;
const cc = Math.floor(Math.random() * (max - base)) + base;
const s = String.fromCharCode(cc);
l += new TextEncoder().encode(s).length;
sa.push(s);
}
return sa.join('');
}
const expected16 = rnd(256);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('790100'),
...new TextEncoder().encode(expected16)
]),
expected: expected16,
type: 'string',
label: 'long string, 16-bit length strict-compat'
});
const expected32 = rnd(65536);
fixtures.push({
data: new Uint8Array([
...byteUtils.fromHex('7a00010000'),
...new TextEncoder().encode(expected32)
]),
expected: expected32,
type: 'string',
label: 'long string, 32-bit length strict-compat'
});
})();
describe('string', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
let actual = decode.decode(data);
assert.strictEqual(actual, fixture.expected, `decode ${ fixture.type }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
actual = decode.decode(data, { strict: true });
assert.strictEqual(actual, fixture.expected, `decode ${ fixture.type } strict`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('7ba5f702b3a5f702b34c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e6563206d692074656c6c75732c20696163756c6973206e656320766573746962756c756d20717569732c206665726d656e74756d206e6f6e2066656c69732e204d616563656e6173207574206a7573746f20706f73756572652e')), /CBOR decode error: 64-bit integer string lengths not supported/);
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
if (fixture.data.length >= 100000000) {
it.skip(`(TODO) skipping encode of very large string ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
});
continue;
}
const data = fixture.expected;
const expectedHex = byteUtils.toHex(fixture.data);
it(`should encode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
if (fixture.unsafe) {
assert.throws(() => encode.encode(data), Error, /^CBOR encode error: number too large to encode \(-\d+\)$/);
} else if (fixture.strict === false) {
assert.notStrictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(data)), expectedHex, `encode ${ fixture.type }`);
}
});
}
});
});
+200
View File
@@ -0,0 +1,200 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '80',
expected: [],
type: 'array empty'
},
{
data: '8102',
expected: [2],
type: 'array 1 compact uint'
},
{
data: '8118ff',
expected: [255],
type: 'array 1 uint8'
},
{
data: '811901f4',
expected: [500],
type: 'array 1 uint16'
},
{
data: '811a00010000',
expected: [65536],
type: 'array 1 uint32'
},
{
data: '811b00000000000000ff',
expected: [255],
type: 'array 1 uint64',
strict: false
},
{
data: '811b0016db6db6db6db7',
expected: [Number.MAX_SAFE_INTEGER / 1.4],
type: 'array 1 uint64'
},
{
data: '811b001fffffffffffff',
expected: [Number.MAX_SAFE_INTEGER],
type: 'array 1 uint64'
},
{
data: '8403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints'
},
{
data: '8c1b0016db6db6db6db71a000100001901f40200202238ff3aa5f702b33b0016db6db6db6db74261316fc48c6175657320c39f76c49b746521',
expected: [
Number.MAX_SAFE_INTEGER / 1.4,
65536,
500,
2,
0,
-1,
-3,
-256,
-2784428724,
Number.MIN_SAFE_INTEGER / 1.4 - 1,
new TextEncoder().encode('a1'),
'Čaues ßvěte!'
],
type: 'array mixed terminals',
label: '[]'
},
{
data: '8265617272617982626f66820582666e657374656482666172726179736121',
expected: [
'array',
[
'of',
[
5,
[
'nested',
[
'arrays',
'!'
]
]
]
]
],
type: 'array nested'
},
{
data: '980403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length8',
strict: false
},
{
data: '99000403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length16',
strict: false
},
{
data: '9a0000000403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length32',
strict: false
},
{
data: '9b000000000000000403040506',
expected: [
3,
4,
5,
6
],
type: 'array 4 ints, length64',
strict: false
}
];
describe('array', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(data), fixture.expected, `decode ${ fixture.type }`);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, { strict: true }), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.deepStrictEqual(decode.decode(data, { strict: true }), fixture.expected, `decode ${ fixture.type }`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('9ba5f702b3a5f7020403040506')), /CBOR decode error: 64-bit integer array lengths not supported/);
});
}
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
if (fixture.unsafe) {
assert.throws(encode.encode.bind(null, fixture.expected), Error, /^CBOR encode error: number too large to encode \(\d+\)$/);
} else if (fixture.strict === false) {
assert.notDeepEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (!fixture.unsafe && fixture.strict !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.label || fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(encode.encode(fixture.expected)), fixture.expected, `roundtrip ${ fixture.type }`);
});
}
}
});
describe('specials', () => {
it('can decode indefinite length items', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('9f616f6174ff')), [
'o',
't'
]);
});
it('can switch off indefinite length support', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('9f616f6174ff'), { allowIndefinite: false }), /indefinite/);
});
});
});
+667
View File
@@ -0,0 +1,667 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: 'a0',
expected: {},
type: 'map empty'
},
{
data: 'a0',
expected: new Map(),
type: 'map empty (useMaps)',
useMaps: true
},
{
data: 'a1616101',
expected: { a: 1 },
type: 'map 1 pair'
},
{
data: 'a161316161',
expected: { 1: 'a' },
type: 'map 1 pair (rev)'
},
{
data: 'a1016161',
expected: toMap([[
1,
'a'
]]),
type: 'map 1 pair (int key as Map w/ useMaps)',
useMaps: true
},
{
data: 'a243010203633132334302030463323334',
expected: toMap([
[
Uint8Array.from([
1,
2,
3
]),
'123'
],
[
Uint8Array.from([
2,
3,
4
]),
'234'
]
]),
type: 'map 2 pair (bytes keys Map w/ useMaps)',
useMaps: true
},
{
data: 'a1666f626a656374a16477697468a26134666e6573746564676f626a65637473a161216121',
expected: {
object: {
with: {
4: 'nested',
objects: { '!': '!' }
}
}
},
type: 'map nested'
},
{
data: 'a1666f626a656374a16477697468a204666e6573746564676f626a65637473a161216121',
expected: toMap([[
'object',
toMap([[
'with',
toMap([
[
4,
'nested'
],
[
'objects',
toMap([[
'!',
'!'
]])
]
])
]])
]]),
type: 'map nested w/ useMaps',
useMaps: true
},
{
data: 'ae636f6e651b0016db6db6db6db763736978206374656e3b0016db6db6db6db76374776f1a0001000064666976650064666f757202646e696e653aa5f702b365656967687438ff65736576656e226574687265651901f466656c6576656e426131667477656c76656fc48c6175657320c39f76c49b74652168666f75727465656ea4616664666f7572616f016174026274680368746869727465656e840203046466697665',
encode: {
one: Number.MAX_SAFE_INTEGER / 1.4,
two: 65536,
three: 500,
four: 2,
five: 0,
six: -1,
seven: -3,
eight: -256,
nine: -2784428724,
ten: Number.MIN_SAFE_INTEGER / 1.4 - 1,
eleven: new TextEncoder().encode('a1'),
twelve: 'Čaues ßvěte!',
thirteen: [
2,
3,
4,
'five'
],
fourteen: {
o: 1,
t: 2,
th: 3,
f: 'four'
}
},
expected: {
one: Number.MAX_SAFE_INTEGER / 1.4,
six: -1,
ten: Number.MIN_SAFE_INTEGER / 1.4 - 1,
two: 65536,
five: 0,
four: 2,
nine: -2784428724,
eight: -256,
seven: -3,
three: 500,
eleven: new TextEncoder().encode('a1'),
twelve: 'Čaues ßvěte!',
fourteen: {
f: 'four',
o: 1,
t: 2,
th: 3
},
thirteen: [
2,
3,
4,
'five'
]
},
type: 'map with complex entries',
label: '{}'
},
{
data: 'ad01636f6e65026374776f1901f46c666976652068756e647265641902586b7369782068756e647265641a00010000636269671b0016db6db6db6db76662696767657220696d696e7573206f6e6521696d696e75732074776f38ff781f6d696e75732074776f2068756e6472656420616e64206669667479207369783901f4781a6d696e757820666976652068756e6472656420616e64206f6e653901f5781a6d696e757820666976652068756e6472656420616e642074776f3aa5f702b367626967206e65673b0016db6db6db6db76a626967676572206e6567',
encode: toMap([
[
2,
'two'
],
[
1,
'one'
],
[
-2,
'minus two'
],
[
-1,
'minus one'
],
[
600,
'six hundred'
],
[
500,
'five hundred'
],
[
-256,
'minus two hundred and fifty six'
],
[
-502,
'minux five hundred and two'
],
[
-501,
'minux five hundred and one'
],
[
65536,
'big'
],
[
-2784428724,
'big neg'
],
[
6433713753386423,
'bigger'
],
[
-6433713753386424,
'bigger neg'
]
]),
expected: toMap([
[
1,
'one'
],
[
2,
'two'
],
[
500,
'five hundred'
],
[
600,
'six hundred'
],
[
65536,
'big'
],
[
6433713753386423,
'bigger'
],
[
-1,
'minus one'
],
[
-2,
'minus two'
],
[
-256,
'minus two hundred and fifty six'
],
[
-501,
'minux five hundred and one'
],
[
-502,
'minux five hundred and two'
],
[
-2784428724,
'big neg'
],
[
-6433713753386424,
'bigger neg'
]
]),
type: 'map with ints and negints',
useMaps: true
},
{
data: 'a44104636f6e65430102026374776f430102036574687265654301020464666f7572',
encode: toMap([
[
Uint8Array.from([
1,
2,
3
]),
'three'
],
[
Uint8Array.from([4]),
'one'
],
[
Uint8Array.from([
1,
2,
4
]),
'four'
],
[
Uint8Array.from([
1,
2,
2
]),
'two'
]
]),
expected: toMap([
[
Uint8Array.from([4]),
'one'
],
[
Uint8Array.from([
1,
2,
2
]),
'two'
],
[
Uint8Array.from([
1,
2,
3
]),
'three'
],
[
Uint8Array.from([
1,
2,
4
]),
'four'
]
]),
type: 'map with bytes keys',
useMaps: true
},
{
data: 'b801616101',
expected: { a: 1 },
type: 'map 1 pair, length8',
strict: false
},
{
data: 'b90001616101',
expected: { a: 1 },
type: 'map 1 pair, length16',
strict: false
},
{
data: 'ba00000001616101',
expected: { a: 1 },
type: 'map 1 pair, length32',
strict: false
},
{
data: 'bb0000000000000001616101',
expected: { a: 1 },
type: 'map 1 pair, length64',
strict: false
}
];
function toMap(arr) {
const m = new Map();
for (const [key, value] of arr) {
m.set(key, value);
}
return m;
}
function entries(map) {
function nest(a) {
for (const e of a) {
e[0] = entries(e[0]);
e[1] = entries(e[1]);
}
return a;
}
if (Object.getPrototypeOf(map) === Map.prototype) {
return nest([...map.entries()]);
}
if (typeof map === 'object') {
return nest([...Object.entries(map)]);
}
return map;
}
describe('map', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.label || JSON.stringify(fixture.expected) }`, () => {
let options = fixture.useMaps ? { useMaps: true } : undefined;
const decoded = decode.decode(data, options);
if (fixture.useMaps) {
assert.strictEqual(Object.getPrototypeOf(decoded), Map.prototype, 'is Map');
} else {
assert.isObject(decoded, 'is object');
}
assert.deepStrictEqual(entries(decoded), entries(fixture.expected), `decode ${ fixture.type }`);
options = Object.assign({ strict: true }, options);
if (fixture.strict === false) {
assert.throws(() => decode.decode(data, options), Error, 'CBOR decode error: integer encoded in more bytes than necessary (strict decode)');
} else {
assert.deepStrictEqual(entries(decode.decode(data, options)), entries(fixture.expected), `decode ${ fixture.type }`);
}
});
it('should fail to decode very large length', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('bba5f702b3a5f70201616101')), /CBOR decode error: 64-bit integer map lengths not supported/);
});
}
it('errors', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a1016161')), /non-string keys not supported \(got number\)/);
});
});
describe('encode', () => {
for (const fixture of fixtures) {
it(`should encode ${ fixture.type }=${ fixture.label || JSON.stringify(fixture.expected) }`, () => {
const toEncode = fixture.encode || fixture.expected;
if (fixture.unsafe) {
assert.throws(encode.encode.bind(null, toEncode), Error, /^CBOR encode error: number too large to encode \(\d+\)$/);
} else if (fixture.strict === false || fixture.roundtrip === false) {
assert.notDeepEqual(byteUtils.toHex(encode.encode(toEncode)), fixture.data, `encode ${ fixture.type } !strict`);
} else {
assert.strictEqual(byteUtils.toHex(encode.encode(toEncode)), fixture.data, `encode ${ fixture.type }`);
}
});
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (!fixture.unsafe && fixture.strict !== false && fixture.roundtrip !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.label || JSON.stringify(fixture.expected) }`, () => {
const toEncode = fixture.encode || fixture.expected;
const options = fixture.useMaps ? { useMaps: true } : undefined;
const rt = decode.decode(encode.encode(toEncode), options);
if (fixture.useMaps) {
assert.strictEqual(Object.getPrototypeOf(rt), Map.prototype, 'is Map');
} else {
assert.isObject(rt, 'is object');
}
assert.deepStrictEqual(entries(rt), entries(fixture.expected), `roundtrip ${ fixture.type }`);
});
}
}
});
describe('specials', () => {
it('can decode indefinite length items', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('bf616f01617402ff')), {
o: 1,
t: 2
});
});
it('can switch off indefinite length support', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('bf616f01617402ff'), { allowIndefinite: false }), /indefinite/);
});
});
describe('sorting', () => {
it('sorts int map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
1,
1
],
[
2,
2
]
]))), 'a201010202');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
2,
1
],
[
1,
2
]
]))), 'a201020201');
});
it('sorts negint map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
-1,
1
],
[
-2,
2
]
]))), 'a220012102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
-2,
1
],
[
-1,
2
]
]))), 'a220022101');
});
it('sorts bytes map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
]
]))), 'a24201020142020102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
2,
1
]),
1
],
[
Uint8Array.from([
1,
2
]),
2
]
]))), 'a24201020242020101');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
],
[
Uint8Array.from([200]),
3
]
]))), 'a341c8034201020142020102');
});
it('sorts bytes map keys', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
]
]))), 'a24201020142020102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
2,
1
]),
1
],
[
Uint8Array.from([
1,
2
]),
2
]
]))), 'a24201020242020101');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
Uint8Array.from([
1,
2
]),
1
],
[
Uint8Array.from([
2,
1
]),
2
],
[
Uint8Array.from([200]),
3
]
]))), 'a341c8034201020142020102');
});
it('sorts array map keys (length only)', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
[1],
1
],
[
[
1,
1
],
2
]
]))), 'a281010182010102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
[
1,
1
],
1
],
[
[1],
2
]
]))), 'a281010282010101');
});
it('sorts map map keys (length only)', () => {
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
{ a: 1 },
1
],
[
{
a: 1,
b: 1
},
2
]
]))), 'a2a161610101a261610161620102');
assert.strictEqual(byteUtils.toHex(encode.encode(new Map([
[
{
a: 1,
b: 1
},
1
],
[
{ a: 1 },
2
]
]))), 'a2a161610102a261610161620101');
});
});
});
+75
View File
@@ -0,0 +1,75 @@
'use strict';
var chai = require('chai');
var token = require('../lib/token.js');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var common = require('./common.js');
var encode = require('../lib/encode.js');
var decode = require('../lib/decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
function Uint16ArrayDecoder(obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 23');
}
const u8a = byteUtils.fromHex(obj);
return new Uint16Array(u8a.buffer, u8a.byteOffset, u8a.length / 2);
}
function Uint16ArrayEncoder(obj) {
if (!(obj instanceof Uint16Array)) {
throw new Error('expected Uint16Array for "Uint16Array" encoder');
}
return [
new token.Token(token.Type.tag, 23),
new token.Token(token.Type.string, byteUtils.toHex(obj))
];
}
describe('tag', () => {
it('date', () => {
assert.throws(() => encode.encode({ d: new Date() }), /unsupported type: Date/);
assert.equal(byteUtils.toHex(encode.encode(new Date('2013-03-21T20:04:00Z'), { typeEncoders: { Date: common.dateEncoder } })), 'c074323031332d30332d32315432303a30343a30305a');
const decodedDate = decode.decode(byteUtils.fromHex('c074323031332d30332d32315432303a30343a30305a'), { tags: { 0: common.dateDecoder } });
assert.instanceOf(decodedDate, Date);
assert.equal(decodedDate.toISOString(), new Date('2013-03-21T20:04:00Z').toISOString());
});
it('Uint16Array as hex/23 (overide existing type)', () => {
assert.equal(byteUtils.toHex(encode.encode(Uint16Array.from([
1,
2,
3
]), { typeEncoders: { Uint16Array: Uint16ArrayEncoder } })), 'd76c303130303032303030333030');
const decoded = decode.decode(byteUtils.fromHex('d76c303130303032303030333030'), { tags: { 23: Uint16ArrayDecoder } });
assert.instanceOf(decoded, Uint16Array);
assert.equal(byteUtils.toHex(decoded), byteUtils.toHex(Uint16Array.from([
1,
2,
3
])));
});
it('tag int too large', () => {
const verify = (hex, strict) => {
if (!strict) {
assert.throws(() => decode.decode(byteUtils.fromHex(hex), {
tags: { 8: common.dateDecoder },
strict: true
}), /integer encoded in more bytes than necessary/);
}
const decodedDate = decode.decode(byteUtils.fromHex(hex), {
tags: { 8: common.dateDecoder },
strict
});
assert.instanceOf(decodedDate, Date);
assert.equal(decodedDate.toISOString(), new Date('2013-03-21T20:04:00Z').toISOString());
};
verify('c874323031332d30332d32315432303a30343a30305a', true);
verify('d80874323031332d30332d32315432303a30343a30305a', false);
verify('d9000874323031332d30332d32315432303a30343a30305a', false);
verify('da0000000874323031332d30332d32315432303a30343a30305a', false);
verify('db000000000000000874323031332d30332d32315432303a30343a30305a', false);
});
});
+253
View File
@@ -0,0 +1,253 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const fixtures = [
{
data: '8601f5f4f6f720',
expected: [
1,
true,
false,
null,
undefined,
-1
],
type: 'array of float specials'
},
{
data: 'f93800',
expected: 0.5,
type: 'float16'
},
{
data: 'f9b800',
expected: -0.5,
type: 'float16'
},
{
data: 'fa33c00000',
expected: 8.940696716308594e-8,
type: 'float32'
},
{
data: 'fab3c00000',
expected: -8.940696716308594e-8,
type: 'float32'
},
{
data: 'fb3ff199999999999a',
expected: 1.1,
type: 'float64'
},
{
data: 'fbbff199999999999a',
expected: -1.1,
type: 'float64'
},
{
data: 'fb3ff1c71c71c71c72',
expected: 1.1111111111111112,
type: 'float64'
},
{
data: 'fb0000000000000002',
expected: 1e-323,
type: 'float64'
},
{
data: 'fb8000000000000002',
expected: -1e-323,
type: 'float64'
},
{
data: 'fb3fefffffffffffff',
expected: 0.9999999999999999,
type: 'float64'
},
{
data: 'fbbfefffffffffffff',
expected: -0.9999999999999999,
type: 'float64'
},
{
data: 'f97c00',
expected: Infinity,
type: 'Infinity'
},
{
data: 'fb7ff0000000000000',
expected: Infinity,
type: 'Infinity',
strict: false
},
{
data: 'f9fc00',
expected: -Infinity,
type: '-Infinity'
},
{
data: 'fbfff0000000000000',
expected: -Infinity,
type: '-Infinity',
strict: false
},
{
data: 'f97e00',
expected: NaN,
type: 'NaN'
},
{
data: 'f97ff8',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fa7ff80000',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fb7ff8000000000000',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fb7ff8cafedeadbeef',
expected: NaN,
type: 'NaN',
strict: false
},
{
data: 'fb40f4241a31a5a515',
expected: 82497.63712086187,
type: 'float64'
}
];
describe('float', () => {
describe('decode', () => {
for (const fixture of fixtures) {
const data = byteUtils.fromHex(fixture.data);
it(`should decode ${ fixture.type }=${ fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(data), fixture.expected, `decode ${ fixture.type }`);
assert.deepStrictEqual(decode.decode(data, { strict: true }), fixture.expected, `decode ${ fixture.type }`);
});
}
});
it('error', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('f80000')), Error, 'simple values are not supported');
assert.throws(() => decode.decode(byteUtils.fromHex('f900')), Error, 'not enough data for float16');
assert.throws(() => decode.decode(byteUtils.fromHex('fa0000')), Error, 'not enough data for float32');
assert.throws(() => decode.decode(byteUtils.fromHex('fb00000000')), Error, 'not enough data for float64');
});
describe('encode', () => {
for (const fixture of fixtures) {
if (fixture.strict !== false) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
assert.strictEqual(byteUtils.toHex(encode.encode(fixture.expected)), fixture.data, `encode ${ fixture.type }`);
});
}
}
});
describe('encode float64', () => {
for (const fixture of fixtures) {
if (fixture.type.startsWith('float')) {
it(`should encode ${ fixture.type }=${ fixture.expected }`, () => {
const encoded = encode.encode(fixture.expected, { float64: true });
assert.strictEqual(encoded.length, 9);
assert.strictEqual(encoded[0], 251);
assert.strictEqual(decode.decode(encoded), fixture.expected, `encode float64 ${ fixture.type }`);
});
}
}
});
describe('roundtrip', () => {
for (const fixture of fixtures) {
if (!fixture.unsafe && fixture.strict !== false) {
it(`should roundtrip ${ fixture.type }=${ fixture.expected }`, () => {
assert.deepStrictEqual(decode.decode(encode.encode(fixture.expected)), fixture.expected, `roundtrip ${ fixture.type }`);
});
}
}
});
describe('specials', () => {
it('indefinite length switch fails on BREAK', () => {
assert.throws(() => decode.decode(Uint8Array.from([
131,
1,
2,
255
])), /unexpected break to lengthed array/);
assert.throws(() => decode.decode(Uint8Array.from([
131,
1,
2,
255
]), { allowIndefinite: false }), /indefinite/);
});
it('can switch off undefined support', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('f7')), undefined);
assert.throws(() => decode.decode(byteUtils.fromHex('f7'), { allowUndefined: false }), /undefined/);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f7')), [
1,
2,
undefined
]);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f7'), { allowUndefined: false }), /undefined/);
});
it('can coerce undefined to null', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('f7'), { coerceUndefinedToNull: false }), undefined);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('f7'), { coerceUndefinedToNull: true }), null);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f7'), { coerceUndefinedToNull: false }), [
1,
2,
undefined
]);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f7'), { coerceUndefinedToNull: true }), [
1,
2,
null
]);
});
it('can switch off Infinity support', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f97c00')), [
1,
2,
Infinity
]);
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f9fc00')), [
1,
2,
-Infinity
]);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f97c00'), { allowInfinity: false }), /Infinity/);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f9fc00'), { allowInfinity: false }), /Infinity/);
for (const fixture of fixtures.filter(f => f.type.endsWith('Infinity'))) {
assert.throws(() => decode.decode(byteUtils.fromHex(fixture.data), { allowInfinity: false }), /Infinity/);
}
});
it('can switch off NaN support', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('830102f97e00')), [
1,
2,
NaN
]);
assert.throws(() => decode.decode(byteUtils.fromHex('830102f97e00'), { allowNaN: false }), /NaN/);
for (const fixture of fixtures.filter(f => f.type === 'NaN')) {
assert.throws(() => decode.decode(byteUtils.fromHex(fixture.data), { allowNaN: false }), /NaN/);
}
});
});
});
+91
View File
@@ -0,0 +1,91 @@
'use strict';
var chai = require('chai');
var bl = require('../lib/bl.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
describe('Internal bytes list', () => {
describe('push', () => {
it('push bits', () => {
const bl$1 = new bl.Bl(10);
const expected = [];
for (let i = 0; i < 25; i++) {
bl$1.push([i + 1]);
expected.push(i + 1);
}
assert.deepEqual([...bl$1.toBytes()], expected);
});
for (let i = 4; i < 21; i++) {
it(`push Bl(${ i })`, () => {
const bl$1 = new bl.Bl(i);
const expected = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
100,
110,
120,
11,
12,
130,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23
];
for (let i = 0; i < 5; i++) {
bl$1.push([i + 1]);
}
bl$1.push(Uint8Array.from([
6,
7,
8,
9,
10
]));
bl$1.push([100]);
bl$1.push(Uint8Array.from([
110,
120
]));
bl$1.push(Uint8Array.from([
11,
12
]));
bl$1.push([130]);
bl$1.push(Uint8Array.from([
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23
]));
assert.deepEqual([...bl$1.toBytes()], expected);
});
}
});
});
+98
View File
@@ -0,0 +1,98 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var taglib = require('../taglib.js');
var byteUtils = require('../lib/byte-utils.js');
var appendix_a = require('./appendix_a.js');
var decode = require('../lib/decode.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
const tags = [];
const typeEncoders = {};
tags[0] = function (obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 1');
}
return `0("${ new Date(obj).toISOString().replace(/\.000Z$/, 'Z') }")`;
};
tags[1] = function (obj) {
if (typeof obj !== 'number') {
throw new Error('expected number for tag 1');
}
return `1(${ obj })`;
};
tags[2] = taglib.bigIntDecoder;
typeEncoders.bigint = taglib.bigIntEncoder;
tags[3] = taglib.bigNegIntDecoder;
tags[23] = function (obj) {
if (!(obj instanceof Uint8Array)) {
throw new Error('expected byte array for tag 23');
}
return `23(h'${ byteUtils.toHex(obj) }')`;
};
tags[24] = function (obj) {
return tags[23](obj).replace(/^23/, '24');
};
tags[32] = function (obj) {
if (typeof obj !== 'string') {
throw new Error('expected string for tag 32');
}
;
(() => new URL(obj))();
return `32("${ obj }")`;
};
describe('cbor/test-vectors', () => {
let i = 0;
for (const fixture of appendix_a.fixtures) {
const u8a = byteUtils.fromHex(fixture.hex);
let expected = fixture.decoded !== undefined ? fixture.decoded : fixture.diagnostic;
if (typeof expected === 'string' && expected.startsWith('h\'')) {
expected = byteUtils.fromHex(expected.replace(/(^h)'|('$)/g, ''));
}
it(`test vector #${ i }: ${ inspect(expected).replace(/\n\s*/g, '') }`, () => {
if (fixture.error) {
assert.throws(() => decode.decode(u8a, { tags }), fixture.error);
} else {
if (fixture.noTagDecodeError) {
assert.throws(() => decode.decode(u8a), fixture.noTagDecodeError);
}
let actual = decode.decode(u8a, { tags });
if (typeof actual === 'bigint') {
actual = inspect(actual);
}
if (typeof expected === 'bigint') {
expected = inspect(expected);
}
assert.deepEqual(actual, expected);
if (fixture.roundtrip) {
if (fixture.noTagEncodeError) {
assert.throws(() => encode.encode(decode.decode(u8a, { tags })), fixture.noTagEncodeError);
}
const reencoded = encode.encode(decode.decode(u8a, { tags }), { typeEncoders });
assert.equal(byteUtils.toHex(reencoded), fixture.hex);
}
}
});
i++;
}
it.skip('encode w/ tags', () => {
});
});
function inspect(o) {
if (typeof o === 'string') {
return `'${ o }'`;
}
if (o instanceof Uint8Array) {
return `Uint8Array<${ o.join(',') }>`;
}
if (o == null || typeof o !== 'object') {
return String(o);
}
return JSON.stringify(o);
}
+77
View File
@@ -0,0 +1,77 @@
'use strict';
var chai = require('chai');
require('../cborg.js');
var byteUtils = require('../lib/byte-utils.js');
var decode = require('../lib/decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
describe('decode errors', () => {
it('not Uint8Array', () => {
for (const arg of [
true,
false,
null,
undefined,
'string',
{ obj: 'ect' },
{},
['array'],
[],
[
1,
2,
3
],
0,
100,
1.1,
-1,
Symbol.for('nope')
]) {
assert.throws(() => decode.decode(arg), /CBOR decode error.*must be a Uint8Array/);
}
});
it('no data', () => {
assert.throws(() => decode.decode(new Uint8Array('')), /CBOR decode error.*content/);
});
it('break only', () => {
assert.throws(() => decode.decode(new Uint8Array([255])), /CBOR decode error.*break/);
});
it('not enough map entries (value)', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a2616f016174')), /map.*not enough entries.*value/);
});
it('not enough map entries (key)', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a2616f01')), /map.*not enough entries.*key/);
});
it('break in lengthed map', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('a2616f01ff740f')), /unexpected break to lengthed map/);
});
it('not enough array entries', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('82616f')), /array.*not enough entries/);
});
it('break in lengthed array', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('82ff')), /unexpected break to lengthed array/);
});
it('no such decoder', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('82ff')), /unexpected break to lengthed array/);
});
it('too many terminals', () => {
assert.throws(() => decode.decode(byteUtils.fromHex('0101')), /too many terminals/);
});
it('rejectDuplicateMapKeys enabled on duplicate keys', () => {
assert.deepStrictEqual(decode.decode(byteUtils.fromHex('a3636261720363666f6f0163666f6f02')), {
foo: 2,
bar: 3
});
assert.throws(() => decode.decode(byteUtils.fromHex('a3636261720363666f6f0163666f6f02'), { rejectDuplicateMapKeys: true }), /CBOR decode error: found repeat map key "foo"/);
assert.throws(() => decode.decode(byteUtils.fromHex('a3636261720363666f6f0163666f6f02'), {
useMaps: true,
rejectDuplicateMapKeys: true
}), /CBOR decode error: found repeat map key "foo"/);
});
});
+56
View File
@@ -0,0 +1,56 @@
'use strict';
var ipldGarbage = require('ipld-garbage');
require('../cborg.js');
var chai = require('chai');
var encode = require('../lib/encode.js');
var decode = require('../lib/decode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
describe('Fuzz round-trip', () => {
it('random objects', function () {
this.timeout(5000);
for (let i = 0; i < 1000; i++) {
const obj = ipldGarbage.garbage(300, { weights: { CID: 0 } });
const byts = encode.encode(obj);
const decoded = decode.decode(byts);
assert.deepEqual(decoded, obj);
}
});
it('circular references error', () => {
let obj = {};
obj.obj = obj;
assert.throws(() => encode.encode(obj), /circular references/);
obj = {
blip: [
1,
2,
{ blop: {} }
]
};
obj.blip[2].blop.boop = obj;
assert.throws(() => encode.encode(obj), /circular references/);
obj = {
blip: [
1,
2,
{ blop: {} }
]
};
obj.blip[2].blop.boop = obj.blip;
assert.throws(() => encode.encode(obj), /circular references/);
obj = {
blip: {},
bloop: {}
};
obj.bloop = obj.blip;
assert.doesNotThrow(() => encode.encode(obj));
const arr = [];
arr[0] = arr;
assert.throws(() => encode.encode(arr), /circular references/);
});
});
+281
View File
@@ -0,0 +1,281 @@
'use strict';
var chai = require('chai');
require('../lib/json/json.js');
var encode = require('../lib/json/encode.js');
var decode = require('../lib/json/decode.js');
const toBytes = str => new TextEncoder().encode(str);
function verifyRoundTrip(obj, sorting) {
const encoded = new TextDecoder().decode(encode.encode(obj, sorting === false ? { mapSorter: null } : undefined));
const json = JSON.stringify(obj);
chai.assert.strictEqual(encoded, json);
const decoded = decode.decode(toBytes(JSON.stringify(obj)));
chai.assert.deepStrictEqual(decoded, obj);
}
function verifyEncodedForm(testCase) {
const obj = JSON.parse(testCase);
const encoded = encode.encode(obj);
chai.assert.strictEqual(new TextDecoder().decode(encoded), JSON.stringify(obj));
const decoded = decode.decode(encoded);
chai.assert.deepStrictEqual(decoded, obj);
const decoded2 = decode.decode(toBytes(testCase));
chai.assert.deepStrictEqual(decoded2, obj);
}
describe('json basics', () => {
it('can round-trip basic literals', () => {
const testCases = [
'null',
'true',
'false',
'0',
'9007199254740991',
'-9007199254740991',
JSON.stringify(Number.MAX_VALUE),
JSON.stringify(Number.MIN_VALUE)
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
chai.assert.strictEqual(decode.decode(toBytes('1E1')), 10);
chai.assert.strictEqual(decode.decode(toBytes('0.1e1')), 1);
chai.assert.strictEqual(decode.decode(toBytes('1e-1')), 0.1);
chai.assert.strictEqual(decode.decode(toBytes('1e+00')), 1);
chai.assert.strictEqual(decode.decode(toBytes('10.0')), 10);
chai.assert.deepStrictEqual(decode.decode(toBytes('[-10.0,1.0,0.0,100.0]')), [
-10,
1,
0,
100
]);
verifyRoundTrip(true);
verifyRoundTrip(false);
verifyRoundTrip(null);
verifyRoundTrip(100);
verifyRoundTrip(-100);
verifyRoundTrip(1.11);
verifyRoundTrip(-100.11111);
verifyRoundTrip(11100000000);
verifyRoundTrip(1.0011111e-18);
});
it('handles large integers as BigInt', () => {
const verify = (inp, str) => {
if (str === undefined) {
str = String(inp);
}
chai.assert.strictEqual(decode.decode(toBytes(str), { allowBigInt: true }), inp);
chai.assert.strictEqual(decode.decode(toBytes(str)), parseFloat(str));
};
verify(Number.MAX_SAFE_INTEGER);
verify(-Number.MAX_SAFE_INTEGER);
verify(BigInt('9007199254740992'));
verify(BigInt('9007199254740993'));
verify(BigInt('11959030306112471731'));
verify(BigInt('18446744073709551615'));
verify(BigInt('9223372036854775807'));
verify(BigInt('-9007199254740992'));
verify(BigInt('-9007199254740993'));
verify(BigInt('-9223372036854776000'));
verify(BigInt('-11959030306112471732'));
verify(BigInt('-18446744073709551616'));
verify(-9007199254740992, '-9007199254740992.0');
verify(-9223372036854776000, '-9223372036854776000.0');
verify(-18446744073709552000, '-18446744073709551616.0');
});
it('can round-trip string literals', () => {
const testCases = [
JSON.stringify(''),
JSON.stringify(' '),
JSON.stringify('"'),
JSON.stringify('\\'),
JSON.stringify('\b\f\n\r\t'),
JSON.stringify('"'),
JSON.stringify('&#34; %22 0x22 034 &#x22;'),
'"\uD83D\uDE00"'
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
chai.assert.strictEqual(decode.decode(toBytes('"/ & \\/"')), '/ & /');
verifyRoundTrip('this is a string');
verifyRoundTrip('this \uD834\uDD1E is a \u263A\u263A \u2663 string ̐ ̀\n\r');
verifyRoundTrip('');
verifyRoundTrip('foo\\bar\nbaz\tbop\rbing"bip\'bang');
});
it('can round-trip array literals', () => {
const testCases = [
'[]',
'[null]',
'[true, false]',
'[ \n 0,1, 2\n , 3,\n4] \n ',
'[-10.0, 1.0, 0.0, 100.0]',
'[["2 deep"]]'
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
verifyRoundTrip([
1,
2,
3,
'string',
true,
4
]);
verifyRoundTrip([
1,
2,
3,
'string',
true,
[
'and',
'a',
'nested',
'array',
true
],
4
]);
});
it('can round-trip object literals', () => {
const testCases = [
'{}',
'\n {\n "\\b"\n :\n""\n }\n ',
'{"":""}',
'{"1":{"2":0,"3":"deep"}}'
];
for (const testCase of testCases) {
verifyEncodedForm(testCase);
}
});
it('will sort map keys', () => {
const unsorted = {
one: 1,
two: 2,
three: 3.1,
str: 'string',
bool: true,
four: 4
};
verifyRoundTrip(unsorted, false);
chai.assert.strictEqual(new TextDecoder().decode(encode.encode(unsorted)), '{"bool":true,"four":4,"one":1,"str":"string","three":3.1,"two":2}');
});
it('can handle novel cases', () => {
chai.assert.strictEqual(decode.decode(toBytes('"this \\uD834\\uDD1E is a \\u263a\\u263a string"')), 'this \uD834\uDD1E is a \u263A\u263A string');
verifyRoundTrip({
one: 1,
two: 2,
three: 3.1,
str: 'string',
arr: [
'and',
'a',
'nested',
[],
'array',
[
true,
1
],
false
],
bool: true,
obj: {
nested: 'object',
a: [],
o: {}
},
four: 4
}, false);
verifyRoundTrip([
false,
[
{
'#nFzU': {},
'\\w>': -0.9441451951197325,
'\t\'': '\'JB+2Wg\tw"IrM*#e^L/d&4rrzUuwq(1mH6aVRredB&Bfs]S"KqK(Tz1Q"URBAfw',
'\n@FrfM': 'M[D]q&'
},
'J4>\'Xdc+u2$%',
4227406737130333
]
], false);
verifyRoundTrip([
0.12995619865708727,
-4973404279772543,
{
drG2: [true],
';#K^Qf>V': null,
'`2=': 'ecc<e/$+-.;U>Gr5RdZDJ\n5+:{=QHNN.tVVN~dX$FWFwu`6>"&=tW!*1*^\u263A)JFM1p|}&X.B|${*\\f@!w2\u263A+'
}
], false);
chai.assert.strictEqual(`${ decode.decode(encode.encode(9007199254740991)) }`, '9007199254740991');
chai.assert.strictEqual(`${ decode.decode(encode.encode(9007199254740992)) }`, '9007199254740992');
chai.assert.strictEqual(`${ decode.decode(encode.encode(900719925474099100n)) }`, '900719925474099100');
});
it('should throw on bad types', () => {
chai.assert.throws(() => encode.encode(new Uint8Array([
1,
2
])), /CBOR encode error: unsupported type: Uint8Array/);
chai.assert.throws(() => encode.encode({
boop: new Uint8Array([
1,
2
])
}), /CBOR encode error: unsupported type: Uint8Array/);
chai.assert.throws(() => encode.encode(undefined), /CBOR encode error: unsupported type: undefined/);
chai.assert.throws(() => encode.encode(new Map([
[
1,
2
],
[
2,
3
]
])), /CBOR encode error: non-string map keys are not supported/);
chai.assert.throws(() => encode.encode(new Map([
[
[
'foo',
'bar'
],
2
],
[
[
'bar',
'foo'
],
3
]
])), /CBOR encode error: complex map keys are not supported/);
});
it('should throw on bad decode failure modes', () => {
chai.assert.throws(() => decode.decode(toBytes('{"a":1 & "b":2}')), 'CBOR decode error: unexpected character at position 7, was expecting object delimiter but found \'&\'');
chai.assert.throws(() => decode.decode(toBytes('{"a":1,"b"!2}')), 'CBOR decode error: unexpected character at position 10, was expecting key/value delimiter \':\' but found \'!\'');
chai.assert.throws(() => decode.decode(toBytes('[1,2&3]')), 'CBOR decode error: unexpected character at position 4, was expecting array delimiter but found \'&\'');
chai.assert.throws(() => decode.decode(toBytes('{"a":!}')), 'CBOR decode error: unexpected character at position 5');
chai.assert.throws(() => decode.decode(toBytes('"abc')), 'CBOR decode error: unexpected end of string at position 4');
chai.assert.throws(() => decode.decode(toBytes('"ab\\xc"')), 'CBOR decode error: unexpected string escape character at position 5');
chai.assert.throws(() => decode.decode(toBytes('"ab\x1Ec"')), 'CBOR decode error: invalid control character at position 3');
chai.assert.throws(() => decode.decode(toBytes('"ab\\')), 'CBOR decode error: unexpected string termination at position 4');
chai.assert.throws(() => decode.decode(toBytes('"\u263A').subarray(0, 3)), 'CBOR decode error: unexpected unicode sequence at position 1');
chai.assert.throws(() => decode.decode(toBytes('"\\uxyza"')), 'CBOR decode error: unexpected unicode escape character at position 3');
chai.assert.throws(() => decode.decode(toBytes('"\\u11"')), 'CBOR decode error: unexpected end of unicode escape sequence at position 3');
chai.assert.throws(() => decode.decode(toBytes('-boop')), 'CBOR decode error: unexpected token at position 1');
chai.assert.throws(() => decode.decode(toBytes('{"v":nope}')), 'CBOR decode error: unexpected token at position 7, expected to find \'null\'');
chai.assert.throws(() => decode.decode(toBytes('[n]')), 'CBOR decode error: unexpected end of input at position 1');
chai.assert.throws(() => decode.decode(toBytes('{"v":truu}')), 'CBOR decode error: unexpected token at position 9, expected to find \'true\'');
chai.assert.throws(() => decode.decode(toBytes('[tr]')), 'CBOR decode error: unexpected end of input at position 1');
chai.assert.throws(() => decode.decode(toBytes('{"v":flase}')), 'CBOR decode error: unexpected token at position 7, expected to find \'false\'');
chai.assert.throws(() => decode.decode(toBytes('[fa]')), 'CBOR decode error: unexpected end of input at position 1');
chai.assert.throws(() => decode.decode(toBytes('-0..1')), 'CBOR decode error: unexpected token at position 3');
});
it('should throw when rejectDuplicateMapKeys enabled on duplicate keys', () => {
chai.assert.deepStrictEqual(decode.decode(toBytes('{"foo":1,"foo":2}')), { foo: 2 });
chai.assert.throws(() => decode.decode(toBytes('{"foo":1,"foo":2}'), { rejectDuplicateMapKeys: true }), /CBOR decode error: found repeat map key "foo"/);
});
});
+63
View File
@@ -0,0 +1,63 @@
'use strict';
var chai = require('chai');
var ipldGarbage = require('ipld-garbage');
var _0uint = require('../lib/0uint.js');
require('../cborg.js');
var length = require('../lib/length.js');
var common = require('./common.js');
var encode = require('../lib/encode.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var chai__default = /*#__PURE__*/_interopDefaultLegacy(chai);
const {assert} = chai__default["default"];
function verifyLength(object, options) {
const len = length.encodedLength(object, options);
const encoded = encode.encode(object, options);
const actual = encoded.length;
assert.strictEqual(actual, len, JSON.stringify(object));
}
describe('encodedLength', () => {
it('int boundaries', () => {
for (let ii = 0; ii < 4; ii++) {
verifyLength(_0uint.uintBoundaries[ii]);
verifyLength(_0uint.uintBoundaries[ii] - 1);
verifyLength(_0uint.uintBoundaries[ii] + 1);
verifyLength(-1 * _0uint.uintBoundaries[ii]);
verifyLength(-1 * _0uint.uintBoundaries[ii] - 1);
verifyLength(-1 * _0uint.uintBoundaries[ii] + 1);
}
});
it('tags', () => {
verifyLength({ date: new Date('2013-03-21T20:04:00Z') }, { typeEncoders: { Date: common.dateEncoder } });
});
it('floats', () => {
verifyLength(0.5);
verifyLength(0.5, { float64: true });
verifyLength(8.940696716308594e-8);
verifyLength(8.940696716308594e-8, { float64: true });
});
it('small garbage', function () {
this.timeout(10000);
for (let ii = 0; ii < 1000; ii++) {
const gbg = ipldGarbage.garbage(1 << 6, { weights: { CID: 0 } });
verifyLength(gbg);
}
});
it('medium garbage', function () {
this.timeout(10000);
for (let ii = 0; ii < 100; ii++) {
const gbg = ipldGarbage.garbage(1 << 16, { weights: { CID: 0 } });
verifyLength(gbg);
}
});
it('large garbage', function () {
this.timeout(10000);
for (let ii = 0; ii < 10; ii++) {
const gbg = ipldGarbage.garbage(1 << 20, { weights: { CID: 0 } });
verifyLength(gbg);
}
});
});
+44
View File
@@ -0,0 +1,44 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
require('./cborg.js');
var token = require('./lib/token.js');
const neg1b = BigInt(-1);
const pos1b = BigInt(1);
const zerob = BigInt(0);
const eightb = BigInt(8);
function bigIntDecoder(bytes) {
let bi = zerob;
for (let ii = 0; ii < bytes.length; ii++) {
bi = (bi << eightb) + BigInt(bytes[ii]);
}
return bi;
}
function fromBigInt(bi) {
const buf = [];
while (bi > 0) {
buf.unshift(Number(bi) & 255);
bi >>= eightb;
}
return Uint8Array.from(buf);
}
const maxSafeBigInt = BigInt('18446744073709551615');
const minSafeBigInt = BigInt('-18446744073709551616');
function bigIntEncoder(obj) {
if (obj >= minSafeBigInt && obj <= maxSafeBigInt) {
return null;
}
return [
new token.Token(token.Type.tag, obj >= zerob ? 2 : 3),
new token.Token(token.Type.bytes, fromBigInt(obj >= zerob ? obj : obj * neg1b - pos1b))
];
}
function bigNegIntDecoder(bytes) {
return neg1b - bigIntDecoder(bytes);
}
exports.bigIntDecoder = bigIntDecoder;
exports.bigIntEncoder = bigIntEncoder;
exports.bigNegIntDecoder = bigNegIntDecoder;