msgpackr 1.11.11 → 2.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/README.md +16 -0
- package/dist/index-no-eval.cjs +209 -245
- package/dist/index-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.min.js +1 -1
- package/dist/index-no-eval.min.js.map +1 -1
- package/dist/index.js +209 -245
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/node.cjs +245 -1072
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +246 -1137
- package/dist/test.js.map +1 -1
- package/dist/unpack-no-eval.cjs +167 -186
- package/dist/unpack-no-eval.cjs.map +1 -1
- package/index.js +5 -5
- package/iterators.js +28 -28
- package/node-index.js +12 -13
- package/pack.js +580 -611
- package/package.json +1 -1
- package/stream.js +37 -32
- package/unpack.js +612 -630
- package/struct.js +0 -815
package/struct.js
DELETED
|
@@ -1,815 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/*
|
|
3
|
-
|
|
4
|
-
For "any-data":
|
|
5
|
-
32-55 - record with record ids (-32)
|
|
6
|
-
56 - 8-bit record ids
|
|
7
|
-
57 - 16-bit record ids
|
|
8
|
-
58 - 24-bit record ids
|
|
9
|
-
59 - 32-bit record ids
|
|
10
|
-
250-255 - followed by typed fixed width values
|
|
11
|
-
64-250 msgpackr/cbor/paired data
|
|
12
|
-
arrays and strings within arrays are handled by paired encoding
|
|
13
|
-
|
|
14
|
-
Structure encoding:
|
|
15
|
-
(type - string (using paired encoding))+
|
|
16
|
-
|
|
17
|
-
Type encoding
|
|
18
|
-
encoding byte - fixed width byte - next reference+
|
|
19
|
-
|
|
20
|
-
Encoding byte:
|
|
21
|
-
first bit:
|
|
22
|
-
0 - inline
|
|
23
|
-
1 - reference
|
|
24
|
-
second bit:
|
|
25
|
-
0 - data or number
|
|
26
|
-
1 - string
|
|
27
|
-
|
|
28
|
-
remaining bits:
|
|
29
|
-
character encoding - ISO-8859-x
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
null (0xff)+ 0xf6
|
|
33
|
-
null (0xff)+ 0xf7
|
|
34
|
-
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import {setWriteStructSlots, RECORD_SYMBOL, addExtension} from './pack.js'
|
|
39
|
-
import {setReadStruct, mult10, readString} from './unpack.js';
|
|
40
|
-
const ASCII = 3; // the MIBenum from https://www.iana.org/assignments/character-sets/character-sets.xhtml (and other character encodings could be referenced by MIBenum)
|
|
41
|
-
const NUMBER = 0;
|
|
42
|
-
const UTF8 = 2;
|
|
43
|
-
const OBJECT_DATA = 1;
|
|
44
|
-
const DATE = 16;
|
|
45
|
-
const TYPE_NAMES = ['num', 'object', 'string', 'ascii'];
|
|
46
|
-
TYPE_NAMES[DATE] = 'date';
|
|
47
|
-
const float32Headers = [false, true, true, false, false, true, true, false];
|
|
48
|
-
let evalSupported;
|
|
49
|
-
try {
|
|
50
|
-
new Function('');
|
|
51
|
-
evalSupported = true;
|
|
52
|
-
} catch(error) {
|
|
53
|
-
// if eval variants are not supported, do not create inline object readers ever
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let updatedPosition;
|
|
57
|
-
const hasNodeBuffer = typeof Buffer !== 'undefined'
|
|
58
|
-
let textEncoder, currentSource;
|
|
59
|
-
try {
|
|
60
|
-
textEncoder = new TextEncoder()
|
|
61
|
-
} catch (error) {}
|
|
62
|
-
const encodeUtf8 = hasNodeBuffer ? function(target, string, position) {
|
|
63
|
-
return target.utf8Write(string, position, target.byteLength - position)
|
|
64
|
-
} : (textEncoder && textEncoder.encodeInto) ?
|
|
65
|
-
function(target, string, position) {
|
|
66
|
-
return textEncoder.encodeInto(string, target.subarray(position)).written
|
|
67
|
-
} : false
|
|
68
|
-
|
|
69
|
-
const TYPE = Symbol('type');
|
|
70
|
-
const PARENT = Symbol('parent');
|
|
71
|
-
setWriteStructSlots(writeStruct, prepareStructures);
|
|
72
|
-
function writeStruct(object, target, encodingStart, position, structures, makeRoom, pack, packr) {
|
|
73
|
-
let typedStructs = packr.typedStructs || (packr.typedStructs = []);
|
|
74
|
-
// note that we rely on pack.js to load stored structures before we get to this point
|
|
75
|
-
let targetView = target.dataView;
|
|
76
|
-
let refsStartPosition = (typedStructs.lastStringStart || 100) + position;
|
|
77
|
-
let safeEnd = target.length - 10;
|
|
78
|
-
let start = position;
|
|
79
|
-
if (position > safeEnd) {
|
|
80
|
-
target = makeRoom(position);
|
|
81
|
-
targetView = target.dataView;
|
|
82
|
-
position -= encodingStart;
|
|
83
|
-
start -= encodingStart;
|
|
84
|
-
refsStartPosition -= encodingStart;
|
|
85
|
-
encodingStart = 0;
|
|
86
|
-
safeEnd = target.length - 10;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let refOffset, refPosition = refsStartPosition;
|
|
90
|
-
|
|
91
|
-
let transition = typedStructs.transitions || (typedStructs.transitions = Object.create(null));
|
|
92
|
-
let nextId = typedStructs.nextId || typedStructs.length;
|
|
93
|
-
let headerSize =
|
|
94
|
-
nextId < 0xf ? 1 :
|
|
95
|
-
nextId < 0xf0 ? 2 :
|
|
96
|
-
nextId < 0xf000 ? 3 :
|
|
97
|
-
nextId < 0xf00000 ? 4 : 0;
|
|
98
|
-
if (headerSize === 0)
|
|
99
|
-
return 0;
|
|
100
|
-
position += headerSize;
|
|
101
|
-
let queuedReferences = [];
|
|
102
|
-
let usedAscii0;
|
|
103
|
-
let keyIndex = 0;
|
|
104
|
-
for (let key in object) {
|
|
105
|
-
let value = object[key];
|
|
106
|
-
let nextTransition = transition[key];
|
|
107
|
-
if (!nextTransition) {
|
|
108
|
-
transition[key] = nextTransition = {
|
|
109
|
-
key,
|
|
110
|
-
parent: transition,
|
|
111
|
-
enumerationOffset: 0,
|
|
112
|
-
ascii0: null,
|
|
113
|
-
ascii8: null,
|
|
114
|
-
num8: null,
|
|
115
|
-
string16: null,
|
|
116
|
-
object16: null,
|
|
117
|
-
num32: null,
|
|
118
|
-
float64: null,
|
|
119
|
-
date64: null
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
if (position > safeEnd) {
|
|
123
|
-
target = makeRoom(position);
|
|
124
|
-
targetView = target.dataView;
|
|
125
|
-
position -= encodingStart;
|
|
126
|
-
start -= encodingStart;
|
|
127
|
-
refsStartPosition -= encodingStart;
|
|
128
|
-
refPosition -= encodingStart;
|
|
129
|
-
encodingStart = 0;
|
|
130
|
-
safeEnd = target.length - 10
|
|
131
|
-
}
|
|
132
|
-
switch (typeof value) {
|
|
133
|
-
case 'number':
|
|
134
|
-
let number = value;
|
|
135
|
-
// first check to see if we are using a lot of ids and should default to wide/common format
|
|
136
|
-
if (nextId < 200 || !nextTransition.num64) {
|
|
137
|
-
if (number >> 0 === number && number < 0x20000000 && number > -0x1f000000) {
|
|
138
|
-
if (number < 0xf6 && number >= 0 && (nextTransition.num8 && !(nextId > 200 && nextTransition.num32) || number < 0x20 && !nextTransition.num32)) {
|
|
139
|
-
transition = nextTransition.num8 || createTypeTransition(nextTransition, NUMBER, 1);
|
|
140
|
-
target[position++] = number;
|
|
141
|
-
} else {
|
|
142
|
-
transition = nextTransition.num32 || createTypeTransition(nextTransition, NUMBER, 4);
|
|
143
|
-
targetView.setUint32(position, number, true);
|
|
144
|
-
position += 4;
|
|
145
|
-
}
|
|
146
|
-
break;
|
|
147
|
-
} else if (number < 0x100000000 && number >= -0x80000000) {
|
|
148
|
-
targetView.setFloat32(position, number, true);
|
|
149
|
-
if (float32Headers[target[position + 3] >>> 5]) {
|
|
150
|
-
let xShifted
|
|
151
|
-
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
152
|
-
if (((xShifted = number * mult10[((target[position + 3] & 0x7f) << 1) | (target[position + 2] >> 7)]) >> 0) === xShifted) {
|
|
153
|
-
transition = nextTransition.num32 || createTypeTransition(nextTransition, NUMBER, 4);
|
|
154
|
-
position += 4;
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
transition = nextTransition.num64 || createTypeTransition(nextTransition, NUMBER, 8);
|
|
161
|
-
targetView.setFloat64(position, number, true);
|
|
162
|
-
position += 8;
|
|
163
|
-
break;
|
|
164
|
-
case 'string':
|
|
165
|
-
let strLength = value.length;
|
|
166
|
-
refOffset = refPosition - refsStartPosition;
|
|
167
|
-
if ((strLength << 2) + refPosition > safeEnd) {
|
|
168
|
-
target = makeRoom((strLength << 2) + refPosition);
|
|
169
|
-
targetView = target.dataView;
|
|
170
|
-
position -= encodingStart;
|
|
171
|
-
start -= encodingStart;
|
|
172
|
-
refsStartPosition -= encodingStart;
|
|
173
|
-
refPosition -= encodingStart;
|
|
174
|
-
encodingStart = 0;
|
|
175
|
-
safeEnd = target.length - 10
|
|
176
|
-
}
|
|
177
|
-
if (strLength > ((0xff00 + refOffset) >> 2)) {
|
|
178
|
-
queuedReferences.push(key, value, position - start);
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
let isNotAscii
|
|
182
|
-
let strStart = refPosition;
|
|
183
|
-
if (strLength < 0x40) {
|
|
184
|
-
let i, c1, c2;
|
|
185
|
-
for (i = 0; i < strLength; i++) {
|
|
186
|
-
c1 = value.charCodeAt(i)
|
|
187
|
-
if (c1 < 0x80) {
|
|
188
|
-
target[refPosition++] = c1
|
|
189
|
-
} else if (c1 < 0x800) {
|
|
190
|
-
isNotAscii = true;
|
|
191
|
-
target[refPosition++] = c1 >> 6 | 0xc0
|
|
192
|
-
target[refPosition++] = c1 & 0x3f | 0x80
|
|
193
|
-
} else if (
|
|
194
|
-
(c1 & 0xfc00) === 0xd800 &&
|
|
195
|
-
((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
|
|
196
|
-
) {
|
|
197
|
-
isNotAscii = true;
|
|
198
|
-
c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff)
|
|
199
|
-
i++
|
|
200
|
-
target[refPosition++] = c1 >> 18 | 0xf0
|
|
201
|
-
target[refPosition++] = c1 >> 12 & 0x3f | 0x80
|
|
202
|
-
target[refPosition++] = c1 >> 6 & 0x3f | 0x80
|
|
203
|
-
target[refPosition++] = c1 & 0x3f | 0x80
|
|
204
|
-
} else {
|
|
205
|
-
isNotAscii = true;
|
|
206
|
-
target[refPosition++] = c1 >> 12 | 0xe0
|
|
207
|
-
target[refPosition++] = c1 >> 6 & 0x3f | 0x80
|
|
208
|
-
target[refPosition++] = c1 & 0x3f | 0x80
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
refPosition += encodeUtf8(target, value, refPosition);
|
|
213
|
-
isNotAscii = refPosition - strStart > strLength;
|
|
214
|
-
}
|
|
215
|
-
if (refOffset < 0xa0 || (refOffset < 0xf6 && (nextTransition.ascii8 || nextTransition.string8))) {
|
|
216
|
-
// short strings
|
|
217
|
-
if (isNotAscii) {
|
|
218
|
-
if (!(transition = nextTransition.string8)) {
|
|
219
|
-
if (typedStructs.length > 10 && (transition = nextTransition.ascii8)) {
|
|
220
|
-
// we can safely change ascii to utf8 in place since they are compatible
|
|
221
|
-
transition.__type = UTF8;
|
|
222
|
-
nextTransition.ascii8 = null;
|
|
223
|
-
nextTransition.string8 = transition;
|
|
224
|
-
pack(null, 0, true); // special call to notify that structures have been updated
|
|
225
|
-
} else {
|
|
226
|
-
transition = createTypeTransition(nextTransition, UTF8, 1);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
} else if (refOffset === 0 && !usedAscii0) {
|
|
230
|
-
usedAscii0 = true;
|
|
231
|
-
transition = nextTransition.ascii0 || createTypeTransition(nextTransition, ASCII, 0);
|
|
232
|
-
break; // don't increment position
|
|
233
|
-
}// else ascii:
|
|
234
|
-
else if (!(transition = nextTransition.ascii8) && !(typedStructs.length > 10 && (transition = nextTransition.string8)))
|
|
235
|
-
transition = createTypeTransition(nextTransition, ASCII, 1);
|
|
236
|
-
target[position++] = refOffset;
|
|
237
|
-
} else {
|
|
238
|
-
// TODO: Enable ascii16 at some point, but get the logic right
|
|
239
|
-
//if (isNotAscii)
|
|
240
|
-
transition = nextTransition.string16 || createTypeTransition(nextTransition, UTF8, 2);
|
|
241
|
-
//else
|
|
242
|
-
//transition = nextTransition.ascii16 || createTypeTransition(nextTransition, ASCII, 2);
|
|
243
|
-
targetView.setUint16(position, refOffset, true);
|
|
244
|
-
position += 2;
|
|
245
|
-
}
|
|
246
|
-
break;
|
|
247
|
-
case 'object':
|
|
248
|
-
if (value) {
|
|
249
|
-
if (value.constructor === Date) {
|
|
250
|
-
transition = nextTransition.date64 || createTypeTransition(nextTransition, DATE, 8);
|
|
251
|
-
targetView.setFloat64(position, value.getTime(), true);
|
|
252
|
-
position += 8;
|
|
253
|
-
} else {
|
|
254
|
-
queuedReferences.push(key, value, keyIndex);
|
|
255
|
-
}
|
|
256
|
-
break;
|
|
257
|
-
} else { // null
|
|
258
|
-
nextTransition = anyType(nextTransition, position, targetView, -10); // match CBOR with this
|
|
259
|
-
if (nextTransition) {
|
|
260
|
-
transition = nextTransition;
|
|
261
|
-
position = updatedPosition;
|
|
262
|
-
} else queuedReferences.push(key, value, keyIndex);
|
|
263
|
-
}
|
|
264
|
-
break;
|
|
265
|
-
case 'boolean':
|
|
266
|
-
transition = nextTransition.num8 || nextTransition.ascii8 || createTypeTransition(nextTransition, NUMBER, 1);
|
|
267
|
-
target[position++] = value ? 0xf9 : 0xf8; // match CBOR with these
|
|
268
|
-
break;
|
|
269
|
-
case 'undefined':
|
|
270
|
-
nextTransition = anyType(nextTransition, position, targetView, -9); // match CBOR with this
|
|
271
|
-
if (nextTransition) {
|
|
272
|
-
transition = nextTransition;
|
|
273
|
-
position = updatedPosition;
|
|
274
|
-
} else queuedReferences.push(key, value, keyIndex);
|
|
275
|
-
break;
|
|
276
|
-
default:
|
|
277
|
-
queuedReferences.push(key, value, keyIndex);
|
|
278
|
-
}
|
|
279
|
-
keyIndex++;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
for (let i = 0, l = queuedReferences.length; i < l;) {
|
|
283
|
-
let key = queuedReferences[i++];
|
|
284
|
-
let value = queuedReferences[i++];
|
|
285
|
-
let propertyIndex = queuedReferences[i++];
|
|
286
|
-
let nextTransition = transition[key];
|
|
287
|
-
if (!nextTransition) {
|
|
288
|
-
transition[key] = nextTransition = {
|
|
289
|
-
key,
|
|
290
|
-
parent: transition,
|
|
291
|
-
enumerationOffset: propertyIndex - keyIndex,
|
|
292
|
-
ascii0: null,
|
|
293
|
-
ascii8: null,
|
|
294
|
-
num8: null,
|
|
295
|
-
string16: null,
|
|
296
|
-
object16: null,
|
|
297
|
-
num32: null,
|
|
298
|
-
float64: null
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
let newPosition;
|
|
302
|
-
if (value) {
|
|
303
|
-
/*if (typeof value === 'string') { // TODO: we could re-enable long strings
|
|
304
|
-
if (position + value.length * 3 > safeEnd) {
|
|
305
|
-
target = makeRoom(position + value.length * 3);
|
|
306
|
-
position -= start;
|
|
307
|
-
targetView = target.dataView;
|
|
308
|
-
start = 0;
|
|
309
|
-
}
|
|
310
|
-
newPosition = position + target.utf8Write(value, position, 0xffffffff);
|
|
311
|
-
} else { */
|
|
312
|
-
let size;
|
|
313
|
-
refOffset = refPosition - refsStartPosition;
|
|
314
|
-
if (refOffset < 0xff00) {
|
|
315
|
-
transition = nextTransition.object16;
|
|
316
|
-
if (transition)
|
|
317
|
-
size = 2;
|
|
318
|
-
else if ((transition = nextTransition.object32))
|
|
319
|
-
size = 4;
|
|
320
|
-
else {
|
|
321
|
-
transition = createTypeTransition(nextTransition, OBJECT_DATA, 2);
|
|
322
|
-
size = 2;
|
|
323
|
-
}
|
|
324
|
-
} else {
|
|
325
|
-
transition = nextTransition.object32 || createTypeTransition(nextTransition, OBJECT_DATA, 4);
|
|
326
|
-
size = 4;
|
|
327
|
-
}
|
|
328
|
-
newPosition = pack(value, refPosition);
|
|
329
|
-
//}
|
|
330
|
-
if (typeof newPosition === 'object') {
|
|
331
|
-
// re-allocated
|
|
332
|
-
refPosition = newPosition.position;
|
|
333
|
-
targetView = newPosition.targetView;
|
|
334
|
-
target = newPosition.target;
|
|
335
|
-
refsStartPosition -= encodingStart;
|
|
336
|
-
position -= encodingStart;
|
|
337
|
-
start -= encodingStart;
|
|
338
|
-
encodingStart = 0;
|
|
339
|
-
} else
|
|
340
|
-
refPosition = newPosition;
|
|
341
|
-
if (size === 2) {
|
|
342
|
-
targetView.setUint16(position, refOffset, true);
|
|
343
|
-
position += 2;
|
|
344
|
-
} else {
|
|
345
|
-
targetView.setUint32(position, refOffset, true);
|
|
346
|
-
position += 4;
|
|
347
|
-
}
|
|
348
|
-
} else { // null or undefined
|
|
349
|
-
transition = nextTransition.object16 || createTypeTransition(nextTransition, OBJECT_DATA, 2);
|
|
350
|
-
targetView.setInt16(position, value === null ? -10 : -9, true);
|
|
351
|
-
position += 2;
|
|
352
|
-
}
|
|
353
|
-
keyIndex++;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
let recordId = transition[RECORD_SYMBOL];
|
|
358
|
-
if (recordId == null) {
|
|
359
|
-
recordId = packr.typedStructs.length;
|
|
360
|
-
let structure = [];
|
|
361
|
-
let nextTransition = transition;
|
|
362
|
-
let key, type;
|
|
363
|
-
while ((type = nextTransition.__type) !== undefined) {
|
|
364
|
-
let size = nextTransition.__size;
|
|
365
|
-
nextTransition = nextTransition.__parent;
|
|
366
|
-
key = nextTransition.key;
|
|
367
|
-
let property = [type, size, key];
|
|
368
|
-
if (nextTransition.enumerationOffset)
|
|
369
|
-
property.push(nextTransition.enumerationOffset);
|
|
370
|
-
structure.push(property);
|
|
371
|
-
nextTransition = nextTransition.parent;
|
|
372
|
-
}
|
|
373
|
-
structure.reverse();
|
|
374
|
-
transition[RECORD_SYMBOL] = recordId;
|
|
375
|
-
packr.typedStructs[recordId] = structure;
|
|
376
|
-
pack(null, 0, true); // special call to notify that structures have been updated
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
switch (headerSize) {
|
|
381
|
-
case 1:
|
|
382
|
-
if (recordId >= 0x10) return 0;
|
|
383
|
-
target[start] = recordId + 0x20;
|
|
384
|
-
break;
|
|
385
|
-
case 2:
|
|
386
|
-
if (recordId >= 0x100) return 0;
|
|
387
|
-
target[start] = 0x38;
|
|
388
|
-
target[start + 1] = recordId;
|
|
389
|
-
break;
|
|
390
|
-
case 3:
|
|
391
|
-
if (recordId >= 0x10000) return 0;
|
|
392
|
-
target[start] = 0x39;
|
|
393
|
-
targetView.setUint16(start + 1, recordId, true);
|
|
394
|
-
break;
|
|
395
|
-
case 4:
|
|
396
|
-
if (recordId >= 0x1000000) return 0;
|
|
397
|
-
targetView.setUint32(start, (recordId << 8) + 0x3a, true);
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (position < refsStartPosition) {
|
|
402
|
-
if (refsStartPosition === refPosition)
|
|
403
|
-
return position; // no refs
|
|
404
|
-
// adjust positioning
|
|
405
|
-
target.copyWithin(position, refsStartPosition, refPosition);
|
|
406
|
-
refPosition += position - refsStartPosition;
|
|
407
|
-
typedStructs.lastStringStart = position - start;
|
|
408
|
-
} else if (position > refsStartPosition) {
|
|
409
|
-
if (refsStartPosition === refPosition)
|
|
410
|
-
return position; // no refs
|
|
411
|
-
typedStructs.lastStringStart = position - start;
|
|
412
|
-
return writeStruct(object, target, encodingStart, start, structures, makeRoom, pack, packr);
|
|
413
|
-
}
|
|
414
|
-
return refPosition;
|
|
415
|
-
}
|
|
416
|
-
function anyType(transition, position, targetView, value) {
|
|
417
|
-
let nextTransition;
|
|
418
|
-
if ((nextTransition = transition.ascii8 || transition.num8)) {
|
|
419
|
-
targetView.setInt8(position, value, true);
|
|
420
|
-
updatedPosition = position + 1;
|
|
421
|
-
return nextTransition;
|
|
422
|
-
}
|
|
423
|
-
if ((nextTransition = transition.string16 || transition.object16)) {
|
|
424
|
-
targetView.setInt16(position, value, true);
|
|
425
|
-
updatedPosition = position + 2;
|
|
426
|
-
return nextTransition;
|
|
427
|
-
}
|
|
428
|
-
if (nextTransition = transition.num32) {
|
|
429
|
-
targetView.setUint32(position, 0xe0000100 + value, true);
|
|
430
|
-
updatedPosition = position + 4;
|
|
431
|
-
return nextTransition;
|
|
432
|
-
}
|
|
433
|
-
// transition.float64
|
|
434
|
-
if (nextTransition = transition.num64) {
|
|
435
|
-
targetView.setFloat64(position, NaN, true);
|
|
436
|
-
targetView.setInt8(position, value);
|
|
437
|
-
updatedPosition = position + 8;
|
|
438
|
-
return nextTransition;
|
|
439
|
-
}
|
|
440
|
-
updatedPosition = position;
|
|
441
|
-
// TODO: can we do an "any" type where we defer the decision?
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
function createTypeTransition(transition, type, size) {
|
|
445
|
-
let typeName = TYPE_NAMES[type] + (size << 3);
|
|
446
|
-
let newTransition = transition[typeName] || (transition[typeName] = Object.create(null));
|
|
447
|
-
newTransition.__type = type;
|
|
448
|
-
newTransition.__size = size;
|
|
449
|
-
newTransition.__parent = transition;
|
|
450
|
-
return newTransition;
|
|
451
|
-
}
|
|
452
|
-
function onLoadedStructures(sharedData) {
|
|
453
|
-
if (!(sharedData instanceof Map))
|
|
454
|
-
return sharedData;
|
|
455
|
-
let typed = sharedData.get('typed') || [];
|
|
456
|
-
if (Object.isFrozen(typed))
|
|
457
|
-
typed = typed.map(structure => structure.slice(0));
|
|
458
|
-
let named = sharedData.get('named');
|
|
459
|
-
let transitions = Object.create(null);
|
|
460
|
-
for (let i = 0, l = typed.length; i < l; i++) {
|
|
461
|
-
let structure = typed[i];
|
|
462
|
-
let transition = transitions;
|
|
463
|
-
for (let [type, size, key] of structure) {
|
|
464
|
-
let nextTransition = transition[key];
|
|
465
|
-
if (!nextTransition) {
|
|
466
|
-
transition[key] = nextTransition = {
|
|
467
|
-
key,
|
|
468
|
-
parent: transition,
|
|
469
|
-
enumerationOffset: 0,
|
|
470
|
-
ascii0: null,
|
|
471
|
-
ascii8: null,
|
|
472
|
-
num8: null,
|
|
473
|
-
string16: null,
|
|
474
|
-
object16: null,
|
|
475
|
-
num32: null,
|
|
476
|
-
float64: null,
|
|
477
|
-
date64: null,
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
transition = createTypeTransition(nextTransition, type, size);
|
|
481
|
-
}
|
|
482
|
-
transition[RECORD_SYMBOL] = i;
|
|
483
|
-
}
|
|
484
|
-
typed.transitions = transitions;
|
|
485
|
-
this.typedStructs = typed;
|
|
486
|
-
this.lastTypedStructuresLength = typed.length;
|
|
487
|
-
return named;
|
|
488
|
-
}
|
|
489
|
-
var sourceSymbol = Symbol.for('source')
|
|
490
|
-
function readStruct(src, position, srcEnd, unpackr) {
|
|
491
|
-
let recordId = src[position++] - 0x20;
|
|
492
|
-
if (recordId >= 24) {
|
|
493
|
-
switch(recordId) {
|
|
494
|
-
case 24: recordId = src[position++]; break;
|
|
495
|
-
// little endian:
|
|
496
|
-
case 25: recordId = src[position++] + (src[position++] << 8); break;
|
|
497
|
-
case 26: recordId = src[position++] + (src[position++] << 8) + (src[position++] << 16); break;
|
|
498
|
-
case 27: recordId = src[position++] + (src[position++] << 8) + (src[position++] << 16) + (src[position++] << 24); break;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
let structure = unpackr.typedStructs && unpackr.typedStructs[recordId];
|
|
502
|
-
if (!structure) {
|
|
503
|
-
// copy src buffer because getStructures will override it
|
|
504
|
-
src = Uint8Array.prototype.slice.call(src, position, srcEnd);
|
|
505
|
-
srcEnd -= position;
|
|
506
|
-
position = 0;
|
|
507
|
-
if (!unpackr.getStructures)
|
|
508
|
-
throw new Error(`Reference to shared structure ${recordId} without getStructures method`);
|
|
509
|
-
unpackr._mergeStructures(unpackr.getStructures());
|
|
510
|
-
if (!unpackr.typedStructs)
|
|
511
|
-
throw new Error('Could not find any shared typed structures');
|
|
512
|
-
unpackr.lastTypedStructuresLength = unpackr.typedStructs.length;
|
|
513
|
-
structure = unpackr.typedStructs[recordId];
|
|
514
|
-
if (!structure)
|
|
515
|
-
throw new Error('Could not find typed structure ' + recordId);
|
|
516
|
-
}
|
|
517
|
-
var construct = structure.construct;
|
|
518
|
-
var fullConstruct = structure.fullConstruct;
|
|
519
|
-
if (!construct) {
|
|
520
|
-
construct = structure.construct = function LazyObject() {
|
|
521
|
-
}
|
|
522
|
-
fullConstruct = structure.fullConstruct = function LoadedObject() {
|
|
523
|
-
}
|
|
524
|
-
fullConstruct.prototype = unpackr.structPrototype || {};
|
|
525
|
-
var prototype = construct.prototype = unpackr.structPrototype ? Object.create(unpackr.structPrototype) : {};
|
|
526
|
-
let properties = [];
|
|
527
|
-
let currentOffset = 0;
|
|
528
|
-
let lastRefProperty;
|
|
529
|
-
for (let i = 0, l = structure.length; i < l; i++) {
|
|
530
|
-
let definition = structure[i];
|
|
531
|
-
let [ type, size, key, enumerationOffset ] = definition;
|
|
532
|
-
if (key === '__proto__')
|
|
533
|
-
key = '__proto_';
|
|
534
|
-
let property = {
|
|
535
|
-
key,
|
|
536
|
-
offset: currentOffset,
|
|
537
|
-
}
|
|
538
|
-
if (enumerationOffset)
|
|
539
|
-
properties.splice(i + enumerationOffset, 0, property);
|
|
540
|
-
else
|
|
541
|
-
properties.push(property);
|
|
542
|
-
let getRef;
|
|
543
|
-
switch(size) { // TODO: Move into a separate function
|
|
544
|
-
case 0: getRef = () => 0; break;
|
|
545
|
-
case 1:
|
|
546
|
-
getRef = (source, position) => {
|
|
547
|
-
let ref = source.bytes[position + property.offset];
|
|
548
|
-
return ref >= 0xf6 ? toConstant(ref) : ref;
|
|
549
|
-
};
|
|
550
|
-
break;
|
|
551
|
-
case 2:
|
|
552
|
-
getRef = (source, position) => {
|
|
553
|
-
let src = source.bytes;
|
|
554
|
-
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
555
|
-
let ref = dataView.getUint16(position + property.offset, true);
|
|
556
|
-
return ref >= 0xff00 ? toConstant(ref & 0xff) : ref;
|
|
557
|
-
};
|
|
558
|
-
break;
|
|
559
|
-
case 4:
|
|
560
|
-
getRef = (source, position) => {
|
|
561
|
-
let src = source.bytes;
|
|
562
|
-
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
563
|
-
let ref = dataView.getUint32(position + property.offset, true);
|
|
564
|
-
return ref >= 0xffffff00 ? toConstant(ref & 0xff) : ref;
|
|
565
|
-
};
|
|
566
|
-
break;
|
|
567
|
-
}
|
|
568
|
-
property.getRef = getRef;
|
|
569
|
-
currentOffset += size;
|
|
570
|
-
let get;
|
|
571
|
-
switch(type) {
|
|
572
|
-
case ASCII:
|
|
573
|
-
if (lastRefProperty && !lastRefProperty.next)
|
|
574
|
-
lastRefProperty.next = property;
|
|
575
|
-
lastRefProperty = property;
|
|
576
|
-
property.multiGetCount = 0;
|
|
577
|
-
get = function(source) {
|
|
578
|
-
let src = source.bytes;
|
|
579
|
-
let position = source.position;
|
|
580
|
-
let refStart = currentOffset + position;
|
|
581
|
-
let ref = getRef(source, position);
|
|
582
|
-
if (typeof ref !== 'number') return ref;
|
|
583
|
-
|
|
584
|
-
let end, next = property.next;
|
|
585
|
-
while(next) {
|
|
586
|
-
end = next.getRef(source, position);
|
|
587
|
-
if (typeof end === 'number')
|
|
588
|
-
break;
|
|
589
|
-
else
|
|
590
|
-
end = null;
|
|
591
|
-
next = next.next;
|
|
592
|
-
}
|
|
593
|
-
if (end == null)
|
|
594
|
-
end = source.bytesEnd - refStart;
|
|
595
|
-
if (source.srcString) {
|
|
596
|
-
return source.srcString.slice(ref, end);
|
|
597
|
-
}
|
|
598
|
-
/*if (property.multiGetCount > 0) {
|
|
599
|
-
let asciiEnd;
|
|
600
|
-
next = firstRefProperty;
|
|
601
|
-
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
602
|
-
do {
|
|
603
|
-
asciiEnd = dataView.getUint16(source.position + next.offset, true);
|
|
604
|
-
if (asciiEnd < 0xff00)
|
|
605
|
-
break;
|
|
606
|
-
else
|
|
607
|
-
asciiEnd = null;
|
|
608
|
-
} while((next = next.next));
|
|
609
|
-
if (asciiEnd == null)
|
|
610
|
-
asciiEnd = source.bytesEnd - refStart
|
|
611
|
-
source.srcString = src.toString('latin1', refStart, refStart + asciiEnd);
|
|
612
|
-
return source.srcString.slice(ref, end);
|
|
613
|
-
}
|
|
614
|
-
if (source.prevStringGet) {
|
|
615
|
-
source.prevStringGet.multiGetCount += 2;
|
|
616
|
-
} else {
|
|
617
|
-
source.prevStringGet = property;
|
|
618
|
-
property.multiGetCount--;
|
|
619
|
-
}*/
|
|
620
|
-
return readString(src, ref + refStart, end - ref);
|
|
621
|
-
//return src.toString('latin1', ref + refStart, end + refStart);
|
|
622
|
-
};
|
|
623
|
-
break;
|
|
624
|
-
case UTF8: case OBJECT_DATA:
|
|
625
|
-
if (lastRefProperty && !lastRefProperty.next)
|
|
626
|
-
lastRefProperty.next = property;
|
|
627
|
-
lastRefProperty = property;
|
|
628
|
-
get = function(source) {
|
|
629
|
-
let position = source.position;
|
|
630
|
-
let refStart = currentOffset + position;
|
|
631
|
-
let ref = getRef(source, position);
|
|
632
|
-
if (typeof ref !== 'number') return ref;
|
|
633
|
-
let src = source.bytes;
|
|
634
|
-
let end, next = property.next;
|
|
635
|
-
while(next) {
|
|
636
|
-
end = next.getRef(source, position);
|
|
637
|
-
if (typeof end === 'number')
|
|
638
|
-
break;
|
|
639
|
-
else
|
|
640
|
-
end = null;
|
|
641
|
-
next = next.next;
|
|
642
|
-
}
|
|
643
|
-
if (end == null)
|
|
644
|
-
end = source.bytesEnd - refStart;
|
|
645
|
-
if (type === UTF8) {
|
|
646
|
-
return src.toString('utf8', ref + refStart, end + refStart);
|
|
647
|
-
} else {
|
|
648
|
-
currentSource = source;
|
|
649
|
-
try {
|
|
650
|
-
return unpackr.unpack(src, { start: ref + refStart, end: end + refStart });
|
|
651
|
-
} finally {
|
|
652
|
-
currentSource = null;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
};
|
|
656
|
-
break;
|
|
657
|
-
case NUMBER:
|
|
658
|
-
switch(size) {
|
|
659
|
-
case 4:
|
|
660
|
-
get = function (source) {
|
|
661
|
-
let src = source.bytes;
|
|
662
|
-
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
663
|
-
let position = source.position + property.offset;
|
|
664
|
-
let value = dataView.getInt32(position, true)
|
|
665
|
-
if (value < 0x20000000) {
|
|
666
|
-
if (value > -0x1f000000)
|
|
667
|
-
return value;
|
|
668
|
-
if (value > -0x20000000)
|
|
669
|
-
return toConstant(value & 0xff);
|
|
670
|
-
}
|
|
671
|
-
let fValue = dataView.getFloat32(position, true);
|
|
672
|
-
// this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
673
|
-
let multiplier = mult10[((src[position + 3] & 0x7f) << 1) | (src[position + 2] >> 7)]
|
|
674
|
-
return ((multiplier * fValue + (fValue > 0 ? 0.5 : -0.5)) >> 0) / multiplier;
|
|
675
|
-
};
|
|
676
|
-
break;
|
|
677
|
-
case 8:
|
|
678
|
-
get = function (source) {
|
|
679
|
-
let src = source.bytes;
|
|
680
|
-
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
681
|
-
let value = dataView.getFloat64(source.position + property.offset, true);
|
|
682
|
-
if (isNaN(value)) {
|
|
683
|
-
let byte = src[source.position + property.offset];
|
|
684
|
-
if (byte >= 0xf6)
|
|
685
|
-
return toConstant(byte);
|
|
686
|
-
}
|
|
687
|
-
return value;
|
|
688
|
-
};
|
|
689
|
-
break;
|
|
690
|
-
case 1:
|
|
691
|
-
get = function (source) {
|
|
692
|
-
let src = source.bytes;
|
|
693
|
-
let value = src[source.position + property.offset];
|
|
694
|
-
return value < 0xf6 ? value : toConstant(value);
|
|
695
|
-
};
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
break;
|
|
699
|
-
case DATE:
|
|
700
|
-
get = function (source) {
|
|
701
|
-
let src = source.bytes;
|
|
702
|
-
let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
|
|
703
|
-
return new Date(dataView.getFloat64(source.position + property.offset, true));
|
|
704
|
-
};
|
|
705
|
-
break;
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
property.get = get;
|
|
709
|
-
}
|
|
710
|
-
// TODO: load the srcString for faster string decoding on toJSON
|
|
711
|
-
if (evalSupported) {
|
|
712
|
-
let objectLiteralProperties = [];
|
|
713
|
-
let args = [];
|
|
714
|
-
let i = 0;
|
|
715
|
-
let hasInheritedProperties;
|
|
716
|
-
for (let property of properties) { // assign in enumeration order
|
|
717
|
-
if (unpackr.alwaysLazyProperty && unpackr.alwaysLazyProperty(property.key)) {
|
|
718
|
-
// these properties are not eagerly evaluated and this can be used for creating properties
|
|
719
|
-
// that are not serialized as JSON
|
|
720
|
-
hasInheritedProperties = true;
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
Object.defineProperty(prototype, property.key, { get: withSource(property.get), enumerable: true });
|
|
724
|
-
let valueFunction = 'v' + i++;
|
|
725
|
-
args.push(valueFunction);
|
|
726
|
-
objectLiteralProperties.push('o[' + JSON.stringify(property.key) + ']=' + valueFunction + '(s)');
|
|
727
|
-
}
|
|
728
|
-
if (hasInheritedProperties) {
|
|
729
|
-
objectLiteralProperties.push('__proto__:this');
|
|
730
|
-
}
|
|
731
|
-
let toObject = (new Function(...args, 'var c=this;return function(s){var o=new c();' + objectLiteralProperties.join(';') + ';return o;}')).apply(fullConstruct, properties.map(prop => prop.get));
|
|
732
|
-
Object.defineProperty(prototype, 'toJSON', {
|
|
733
|
-
value(omitUnderscoredProperties) {
|
|
734
|
-
return toObject.call(this, this[sourceSymbol]);
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
} else {
|
|
738
|
-
Object.defineProperty(prototype, 'toJSON', {
|
|
739
|
-
value(omitUnderscoredProperties) {
|
|
740
|
-
// return an enumerable object with own properties to JSON stringify
|
|
741
|
-
let resolved = {};
|
|
742
|
-
for (let i = 0, l = properties.length; i < l; i++) {
|
|
743
|
-
// TODO: check alwaysLazyProperty
|
|
744
|
-
let key = properties[i].key;
|
|
745
|
-
|
|
746
|
-
resolved[key] = this[key];
|
|
747
|
-
}
|
|
748
|
-
return resolved;
|
|
749
|
-
},
|
|
750
|
-
// not enumerable or anything
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
var instance = new construct();
|
|
755
|
-
instance[sourceSymbol] = {
|
|
756
|
-
bytes: src,
|
|
757
|
-
position,
|
|
758
|
-
srcString: '',
|
|
759
|
-
bytesEnd: srcEnd
|
|
760
|
-
}
|
|
761
|
-
return instance;
|
|
762
|
-
}
|
|
763
|
-
function toConstant(code) {
|
|
764
|
-
switch(code) {
|
|
765
|
-
case 0xf6: return null;
|
|
766
|
-
case 0xf7: return undefined;
|
|
767
|
-
case 0xf8: return false;
|
|
768
|
-
case 0xf9: return true;
|
|
769
|
-
}
|
|
770
|
-
throw new Error('Unknown constant');
|
|
771
|
-
}
|
|
772
|
-
function withSource(get) {
|
|
773
|
-
return function() {
|
|
774
|
-
return get(this[sourceSymbol]);
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
function saveState() {
|
|
779
|
-
if (currentSource) {
|
|
780
|
-
currentSource.bytes = Uint8Array.prototype.slice.call(currentSource.bytes, currentSource.position, currentSource.bytesEnd);
|
|
781
|
-
currentSource.position = 0;
|
|
782
|
-
currentSource.bytesEnd = currentSource.bytes.length;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
function prepareStructures(structures, packr) {
|
|
786
|
-
if (packr.typedStructs) {
|
|
787
|
-
let structMap = new Map();
|
|
788
|
-
structMap.set('named', structures);
|
|
789
|
-
structMap.set('typed', packr.typedStructs);
|
|
790
|
-
structures = structMap;
|
|
791
|
-
}
|
|
792
|
-
let lastTypedStructuresLength = packr.lastTypedStructuresLength || 0;
|
|
793
|
-
structures.isCompatible = existing => {
|
|
794
|
-
let compatible = true;
|
|
795
|
-
if (existing instanceof Map) {
|
|
796
|
-
let named = existing.get('named') || [];
|
|
797
|
-
if (named.length !== (packr.lastNamedStructuresLength || 0))
|
|
798
|
-
compatible = false;
|
|
799
|
-
let typed = existing.get('typed') || [];
|
|
800
|
-
if (typed.length !== lastTypedStructuresLength)
|
|
801
|
-
compatible = false;
|
|
802
|
-
} else if (existing instanceof Array || Array.isArray(existing)) {
|
|
803
|
-
if (existing.length !== (packr.lastNamedStructuresLength || 0))
|
|
804
|
-
compatible = false;
|
|
805
|
-
}
|
|
806
|
-
if (!compatible)
|
|
807
|
-
packr._mergeStructures(existing);
|
|
808
|
-
return compatible;
|
|
809
|
-
};
|
|
810
|
-
packr.lastTypedStructuresLength = packr.typedStructs && packr.typedStructs.length;
|
|
811
|
-
return structures;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
setReadStruct(readStruct, onLoadedStructures, saveState);
|
|
815
|
-
|