UNPKG

2.42 kBJavaScriptView Raw
1/*
2 prefix | delta | note | code
3 ----------|-------|---------------|--------------------------------------------------------------
4 0x00~0x7f | 127 | single buffer | <buffer[0]>
5 0x80~0xb7 | 55 | short buffer | <0x80+length(buffer)>, ...<buffer>
6 0xb8~0xbf | 7 | long buffer | <0xb8+length(length(buffer))>, ...<length(buffer)>, ...<buffer>
7 0xc0~0xf7 | 55 | short array | <0xc0+length(array.bytes)>, ...<array.bytes>
8 0xf8~0xff | 7 | long array | <0xf8+length(length(array.bytes))>, ...<length(array.bytes)>, ...<array.bytes>
9 */
10
11const SHORT_RANGE = 55;
12const BUFFER_OFFSET = 0x80;
13const ARRAY_OFFSET = 0xc0;
14
15function concat(...args) {
16 return Buffer.concat(args.map(value => {
17 if (Buffer.isBuffer(value)) {
18 return value;
19 }
20
21 if (Number.isSafeInteger(value) && value >= 0) {
22 const hex = value.toString(16);
23 return Buffer.from(hex.length % 2 ? `0${hex}` : hex, 'hex');
24 }
25
26 throw new Error(`invalid value, expect unsigned integer or buffer, got ${value}`);
27 }));
28}
29
30// ----------------------------------------------------------------------------
31/**
32 * @param value {Array|Buffer}
33 * @return {Buffer}
34 */
35function encode(value) {
36 if (Buffer.isBuffer(value)) {
37 return encodeBuffer(value);
38 }
39
40 if (Array.isArray(value)) {
41 return encodeArray(value);
42 }
43
44 throw new Error(`invalid value, expect buffer or array, got ${value}`);
45}
46
47/**
48 * @param length {number}
49 * @param offset {number} - Enum of [BUFFER_OFFSET=0x80, ARRAY_OFFSET=0xc0]
50 * @return {Buffer}
51 */
52function encodeLength(length, offset) {
53 if (length <= SHORT_RANGE) {
54 return concat(length + offset);
55 } else {
56 const lengthBuffer = concat(length);
57 return concat(offset + SHORT_RANGE + lengthBuffer.length, lengthBuffer);
58 }
59}
60
61/**
62 * @param buffer {Buffer}
63 * @return {Buffer}
64 */
65function encodeBuffer(buffer) {
66 if (buffer.length === 1 && buffer[0] === 0) {
67 buffer = Buffer.from('');
68 }
69
70 return buffer.length === 1 && buffer[0] < BUFFER_OFFSET
71 ? buffer
72 : concat(encodeLength(buffer.length, BUFFER_OFFSET), buffer);
73}
74
75/**
76 * @param array {Array}
77 * @return {Buffer}
78 */
79function encodeArray(array) {
80 const buffer = concat(...array.map(encode));
81 return concat(encodeLength(buffer.length, ARRAY_OFFSET), buffer);
82}
83
84module.exports = { encode };