msgpack5 5.3.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/decoder.js CHANGED
@@ -38,233 +38,231 @@ function isValidDataSize (dataLength, bufLength, headerLength) {
38
38
  }
39
39
 
40
40
  module.exports = function buildDecode (decodingTypes, options) {
41
+ const context = { decodingTypes, options, decode }
41
42
  return decode
42
43
 
43
44
  function decode (buf) {
44
- // TODO: Make it into ensureBl handler ?
45
- if (!(buf instanceof bl)) {
46
- buf = bl().append(buf)
45
+ if (!bl.isBufferList(buf)) {
46
+ buf = bl(buf)
47
47
  }
48
48
 
49
- const result = tryDecode(buf, 0)
49
+ const result = tryDecode(buf, 0, context)
50
50
  // Handle worst case ASAP and keep code flat
51
51
  if (!result) throw new IncompleteBufferError()
52
52
 
53
53
  buf.consume(result[1])
54
54
  return result[0]
55
55
  }
56
+ }
56
57
 
57
- function tryDecode (buf, initialOffset) {
58
- if (buf.length <= initialOffset) return null
59
-
60
- const bufLength = buf.length - initialOffset
61
- let offset = initialOffset
58
+ function decodeArray (buf, initialOffset, length, headerLength, context) {
59
+ let offset = initialOffset
60
+ const result = []
61
+ let i = 0
62
62
 
63
- const first = buf.readUInt8(offset)
64
- offset += 1
63
+ while (i++ < length) {
64
+ const decodeResult = tryDecode(buf, offset, context)
65
+ if (!decodeResult) return null
65
66
 
66
- const size = SIZES[first] || -1
67
- if (bufLength < size) return null
67
+ result.push(decodeResult[0])
68
+ offset += decodeResult[1]
69
+ }
70
+ return [result, headerLength + offset - initialOffset]
71
+ }
68
72
 
69
- const inRange = (start, end) => first >= start && first <= end
73
+ function decodeMap (buf, offset, length, headerLength, context) {
74
+ const _temp = decodeArray(buf, offset, 2 * length, headerLength, context)
75
+ if (!_temp) return null
76
+ const [result, consumedBytes] = _temp
70
77
 
71
- if (first < 0x80) return [first, 1] // 7-bits positive ints
72
- if ((first & 0xf0) === 0x80) {
73
- const length = first & 0x0f
74
- const headerSize = offset - initialOffset
75
- // we have a map with less than 15 elements
76
- return decodeMap(buf, offset, length, headerSize, options)
77
- }
78
- if ((first & 0xf0) === 0x90) {
79
- const length = first & 0x0f
80
- const headerSize = offset - initialOffset
81
- // we have an array with less than 15 elements
82
- return decodeArray(buf, offset, length, headerSize)
83
- }
78
+ let isPlainObject = !context.options.preferMap
84
79
 
85
- if ((first & 0xe0) === 0xa0) {
86
- // fixstr up to 31 bytes
87
- const length = first & 0x1f
88
- if (!isValidDataSize(length, bufLength, 1)) return null
89
- const result = buf.toString('utf8', offset, offset + length)
90
- return [result, length + 1]
91
- }
92
- if (inRange(0xc0, 0xc3)) return decodeConstants(first)
93
- if (inRange(0xc4, 0xc6)) {
94
- const length = buf.readUIntBE(offset, size - 1)
95
- offset += size - 1
96
-
97
- if (!isValidDataSize(length, bufLength, size)) return null
98
- const result = buf.slice(offset, offset + length)
99
- return [result, size + length]
80
+ if (isPlainObject) {
81
+ for (let i = 0; i < 2 * length; i += 2) {
82
+ if (typeof result[i] !== 'string') {
83
+ isPlainObject = false
84
+ break
85
+ }
100
86
  }
101
- if (inRange(0xc7, 0xc9)) {
102
- const length = buf.readUIntBE(offset, size - 2)
103
- offset += size - 2
87
+ }
104
88
 
105
- const type = buf.readInt8(offset)
106
- offset += 1
89
+ if (isPlainObject) {
90
+ const object = {}
91
+ for (let i = 0; i < 2 * length; i += 2) {
92
+ const key = result[i]
93
+ const val = result[i + 1]
107
94
 
108
- if (!isValidDataSize(length, bufLength, size)) return null
109
- return decodeExt(buf, offset, type, length, size)
110
- }
111
- if (inRange(0xca, 0xcb)) return decodeFloat(buf, offset, size - 1)
112
- if (inRange(0xcc, 0xcf)) return decodeUnsignedInt(buf, offset, size - 1)
113
- if (inRange(0xd0, 0xd3)) return decodeSigned(buf, offset, size - 1)
114
- if (inRange(0xd4, 0xd8)) {
115
- const type = buf.readInt8(offset) // Signed
116
- offset += 1
117
- return decodeExt(buf, offset, type, size - 2, 2)
118
- }
95
+ if (key === '__proto__') {
96
+ if (context.options.protoAction === 'error') {
97
+ throw new SyntaxError('Object contains forbidden prototype property')
98
+ }
119
99
 
120
- if (inRange(0xd9, 0xdb)) {
121
- const length = buf.readUIntBE(offset, size - 1)
122
- offset += size - 1
100
+ if (context.options.protoAction === 'remove') {
101
+ continue
102
+ }
103
+ }
123
104
 
124
- if (!isValidDataSize(length, bufLength, size)) return null
125
- const result = buf.toString('utf8', offset, offset + length)
126
- return [result, size + length]
105
+ object[key] = val
127
106
  }
128
- if (inRange(0xdc, 0xdd)) {
129
- const length = buf.readUIntBE(offset, size - 1)
130
- offset += size - 1
131
- return decodeArray(buf, offset, length, size)
132
- }
133
- if (inRange(0xde, 0xdf)) {
134
- let length
135
- switch (first) {
136
- case 0xde:
137
- // maps up to 2^16 elements - 2 bytes
138
- length = buf.readUInt16BE(offset)
139
- offset += 2
140
- // console.log(offset - initialOffset)
141
- return decodeMap(buf, offset, length, 3, options)
142
-
143
- case 0xdf:
144
- length = buf.readUInt32BE(offset)
145
- offset += 4
146
- return decodeMap(buf, offset, length, 5, options)
147
- }
107
+ return [object, consumedBytes]
108
+ } else {
109
+ const mapping = new Map()
110
+ for (let i = 0; i < 2 * length; i += 2) {
111
+ const key = result[i]
112
+ const val = result[i + 1]
113
+ mapping.set(key, val)
148
114
  }
149
- if (first >= 0xe0) return [first - 0x100, 1] // 5 bits negative ints
150
-
151
- throw new Error('not implemented yet')
115
+ return [mapping, consumedBytes]
152
116
  }
117
+ }
153
118
 
154
- function decodeArray (buf, initialOffset, length, headerLength) {
155
- let offset = initialOffset
156
- const result = []
157
- let i = 0
119
+ function tryDecode (buf, initialOffset, context) {
120
+ if (buf.length <= initialOffset) return null
158
121
 
159
- while (i++ < length) {
160
- const decodeResult = tryDecode(buf, offset)
161
- if (!decodeResult) return null
122
+ const bufLength = buf.length - initialOffset
123
+ let offset = initialOffset
162
124
 
163
- result.push(decodeResult[0])
164
- offset += decodeResult[1]
165
- }
166
- return [result, headerLength + offset - initialOffset]
167
- }
125
+ const first = buf.readUInt8(offset)
126
+ offset += 1
168
127
 
169
- function decodeMap (buf, offset, length, headerLength, options) {
170
- const _temp = decodeArray(buf, offset, 2 * length, headerLength)
171
- if (!_temp) return null
172
- const [result, consumedBytes] = _temp
128
+ const size = SIZES[first] || -1
129
+ if (bufLength < size) return null
173
130
 
174
- let isPlainObject = !options.preferMap
131
+ if (first < 0x80) return [first, 1] // 7-bits positive ints
132
+ if ((first & 0xf0) === 0x80) {
133
+ const length = first & 0x0f
134
+ const headerSize = offset - initialOffset
135
+ // we have a map with less than 15 elements
136
+ return decodeMap(buf, offset, length, headerSize, context)
137
+ }
138
+ if ((first & 0xf0) === 0x90) {
139
+ const length = first & 0x0f
140
+ const headerSize = offset - initialOffset
141
+ // we have an array with less than 15 elements
142
+ return decodeArray(buf, offset, length, headerSize, context)
143
+ }
175
144
 
176
- if (isPlainObject) {
177
- for (let i = 0; i < 2 * length; i += 2) {
178
- if (typeof result[i] !== 'string') {
179
- isPlainObject = false
180
- break
181
- }
182
- }
183
- }
145
+ if ((first & 0xe0) === 0xa0) {
146
+ // fixstr up to 31 bytes
147
+ const length = first & 0x1f
148
+ if (!isValidDataSize(length, bufLength, 1)) return null
149
+ const result = buf.toString('utf8', offset, offset + length)
150
+ return [result, length + 1]
151
+ }
152
+ if (first >= 0xc0 && first <= 0xc3) return decodeConstants(first)
153
+ if (first >= 0xc4 && first <= 0xc6) {
154
+ const length = buf.readUIntBE(offset, size - 1)
155
+ offset += size - 1
156
+
157
+ if (!isValidDataSize(length, bufLength, size)) return null
158
+ const result = buf.slice(offset, offset + length)
159
+ return [result, size + length]
160
+ }
161
+ if (first >= 0xc7 && first <= 0xc9) {
162
+ const length = buf.readUIntBE(offset, size - 2)
163
+ offset += size - 2
184
164
 
185
- if (isPlainObject) {
186
- const object = {}
187
- for (let i = 0; i < 2 * length; i += 2) {
188
- const key = result[i]
189
- const val = result[i + 1]
165
+ const type = buf.readInt8(offset)
166
+ offset += 1
190
167
 
191
- if (key === '__proto__') {
192
- if (options.protoAction === 'error') {
193
- throw new SyntaxError('Object contains forbidden prototype property')
194
- }
168
+ if (!isValidDataSize(length, bufLength, size)) return null
169
+ return decodeExt(buf, offset, type, length, size, context)
170
+ }
171
+ if (first >= 0xca && first <= 0xcb) return decodeFloat(buf, offset, size - 1)
172
+ if (first >= 0xcc && first <= 0xcf) return decodeUnsignedInt(buf, offset, size - 1)
173
+ if (first >= 0xd0 && first <= 0xd3) return decodeSigned(buf, offset, size - 1)
174
+ if (first >= 0xd4 && first <= 0xd8) {
175
+ const type = buf.readInt8(offset) // Signed
176
+ offset += 1
177
+ return decodeExt(buf, offset, type, size - 2, 2, context)
178
+ }
195
179
 
196
- if (options.protoAction === 'remove') {
197
- continue
198
- }
199
- }
180
+ if (first >= 0xd9 && first <= 0xdb) {
181
+ const length = buf.readUIntBE(offset, size - 1)
182
+ offset += size - 1
200
183
 
201
- object[key] = val
202
- }
203
- return [object, consumedBytes]
204
- } else {
205
- const mapping = new Map()
206
- for (let i = 0; i < 2 * length; i += 2) {
207
- const key = result[i]
208
- const val = result[i + 1]
209
- mapping.set(key, val)
210
- }
211
- return [mapping, consumedBytes]
184
+ if (!isValidDataSize(length, bufLength, size)) return null
185
+ const result = buf.toString('utf8', offset, offset + length)
186
+ return [result, size + length]
187
+ }
188
+ if (first >= 0xdc && first <= 0xdd) {
189
+ const length = buf.readUIntBE(offset, size - 1)
190
+ offset += size - 1
191
+ return decodeArray(buf, offset, length, size, context)
192
+ }
193
+ if (first >= 0xde && first <= 0xdf) {
194
+ let length
195
+ switch (first) {
196
+ case 0xde:
197
+ // maps up to 2^16 elements - 2 bytes
198
+ length = buf.readUInt16BE(offset)
199
+ offset += 2
200
+ // console.log(offset - initialOffset)
201
+ return decodeMap(buf, offset, length, 3, context)
202
+
203
+ case 0xdf:
204
+ length = buf.readUInt32BE(offset)
205
+ offset += 4
206
+ return decodeMap(buf, offset, length, 5, context)
212
207
  }
213
208
  }
209
+ if (first >= 0xe0) return [first - 0x100, 1] // 5 bits negative ints
214
210
 
215
- function readInt64BE (buf, offset) {
216
- var negate = (buf[offset] & 0x80) == 0x80; // eslint-disable-line
211
+ throw new Error('not implemented yet')
212
+ }
217
213
 
218
- if (negate) {
219
- let carry = 1
220
- for (let i = offset + 7; i >= offset; i--) {
221
- const v = (buf[i] ^ 0xff) + carry
222
- buf[i] = v & 0xff
223
- carry = v >> 8
224
- }
225
- }
214
+ function decodeSigned (buf, offset, size) {
215
+ let result
216
+ if (size === 1) result = buf.readInt8(offset)
217
+ if (size === 2) result = buf.readInt16BE(offset)
218
+ if (size === 4) result = buf.readInt32BE(offset)
219
+ if (size === 8) result = readInt64BE(buf.slice(offset, offset + 8), 0)
220
+ return [result, size + 1]
221
+ }
226
222
 
227
- const hi = buf.readUInt32BE(offset + 0)
228
- const lo = buf.readUInt32BE(offset + 4)
229
- return (hi * 4294967296 + lo) * (negate ? -1 : +1)
230
- }
223
+ function decodeExt (buf, offset, type, size, headerSize, context) {
224
+ const toDecode = buf.slice(offset, offset + size)
231
225
 
232
- function decodeUnsignedInt (buf, offset, size) {
233
- const maxOffset = offset + size
234
- let result = 0
235
- while (offset < maxOffset) { result += buf.readUInt8(offset++) * Math.pow(256, maxOffset - offset) }
236
- return [result, size + 1]
237
- }
226
+ const decode = context.decodingTypes.get(type)
227
+ if (!decode) throw new Error('unable to find ext type ' + type)
238
228
 
239
- function decodeConstants (first) {
240
- if (first === 0xc0) return [null, 1]
241
- if (first === 0xc2) return [false, 1]
242
- if (first === 0xc3) return [true, 1]
243
- }
229
+ const value = decode(toDecode)
230
+ return [value, headerSize + size]
231
+ }
244
232
 
245
- function decodeSigned (buf, offset, size) {
246
- let result
247
- if (size === 1) result = buf.readInt8(offset)
248
- if (size === 2) result = buf.readInt16BE(offset)
249
- if (size === 4) result = buf.readInt32BE(offset)
250
- if (size === 8) result = readInt64BE(buf.slice(offset, offset + 8), 0)
251
- return [result, size + 1]
252
- }
233
+ function decodeUnsignedInt (buf, offset, size) {
234
+ const maxOffset = offset + size
235
+ let result = 0
236
+ while (offset < maxOffset) { result += buf.readUInt8(offset++) * Math.pow(256, maxOffset - offset) }
237
+ return [result, size + 1]
238
+ }
253
239
 
254
- function decodeFloat (buf, offset, size) {
255
- let result
256
- if (size === 4) result = buf.readFloatBE(offset)
257
- if (size === 8) result = buf.readDoubleBE(offset)
258
- return [result, size + 1]
259
- }
240
+ function decodeConstants (first) {
241
+ if (first === 0xc0) return [null, 1]
242
+ if (first === 0xc2) return [false, 1]
243
+ if (first === 0xc3) return [true, 1]
244
+ }
260
245
 
261
- function decodeExt (buf, offset, type, size, headerSize) {
262
- const toDecode = buf.slice(offset, offset + size)
246
+ function decodeFloat (buf, offset, size) {
247
+ let result
248
+ if (size === 4) result = buf.readFloatBE(offset)
249
+ if (size === 8) result = buf.readDoubleBE(offset)
250
+ return [result, size + 1]
251
+ }
263
252
 
264
- const decode = decodingTypes.get(type)
265
- if (!decode) throw new Error('unable to find ext type ' + type)
253
+ function readInt64BE (buf, offset) {
254
+ var negate = (buf[offset] & 0x80) == 0x80; // eslint-disable-line
266
255
 
267
- const value = decode(toDecode)
268
- return [value, headerSize + size]
256
+ if (negate) {
257
+ let carry = 1
258
+ for (let i = offset + 7; i >= offset; i--) {
259
+ const v = (buf[i] ^ 0xff) + carry
260
+ buf[i] = v & 0xff
261
+ carry = v >> 8
262
+ }
269
263
  }
264
+
265
+ const hi = buf.readUInt32BE(offset + 0)
266
+ const lo = buf.readUInt32BE(offset + 4)
267
+ return (hi * 4294967296 + lo) * (negate ? -1 : +1)
270
268
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msgpack5",
3
- "version": "5.3.0",
3
+ "version": "6.0.0",
4
4
  "description": "A msgpack v5 implementation for node.js and the browser, with extension points",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -44,7 +44,7 @@
44
44
  ]
45
45
  },
46
46
  "dependencies": {
47
- "bl": "^4.0.0",
47
+ "bl": "^5.0.0",
48
48
  "inherits": "^2.0.3",
49
49
  "readable-stream": "^3.0.0",
50
50
  "safe-buffer": "^5.1.2"
@@ -0,0 +1,44 @@
1
+ 'use strict'
2
+
3
+ const test = require('tape').test
4
+ const msgpack = require('../')
5
+
6
+ test('encode/decode nested containers (map/array)', function (t) {
7
+ const encoder = msgpack()
8
+
9
+ function doEncodeDecode (value) {
10
+ return encoder.decode(encoder.encode(value))
11
+ }
12
+
13
+ function preserveTest (A, message = 'works') {
14
+ const B = doEncodeDecode(A)
15
+ t.deepEqual(A, B, message)
16
+ }
17
+
18
+ preserveTest({
19
+ hello: 'world',
20
+ digit: 111,
21
+ array: [1, 2, 3, 4, 'string', { hello: 'world' }]
22
+ })
23
+
24
+ preserveTest([
25
+ [
26
+ {
27
+ hello: 'world',
28
+ array: [1, 2, 3, 4, 'string', { hello: 'world' }]
29
+ },
30
+ {
31
+ digit: 111
32
+ }
33
+ ],
34
+ [
35
+ {
36
+ hello: 'world',
37
+ digit: 111,
38
+ array: [1, 2, 3, 4, 'string', { hello: 'world' }]
39
+ }
40
+ ]
41
+ ])
42
+
43
+ t.end()
44
+ })