react-native-update-cli 1.20.0 → 1.20.6

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.
@@ -0,0 +1,674 @@
1
+ // From https://github.com/openstf/adbkit-apkreader
2
+ const NodeType = {
3
+ ELEMENT_NODE: 1,
4
+ ATTRIBUTE_NODE: 2,
5
+ CDATA_SECTION_NODE: 4
6
+ }
7
+
8
+ const ChunkType = {
9
+ NULL: 0x0000,
10
+ STRING_POOL: 0x0001,
11
+ TABLE: 0x0002,
12
+ XML: 0x0003,
13
+ XML_FIRST_CHUNK: 0x0100,
14
+ XML_START_NAMESPACE: 0x0100,
15
+ XML_END_NAMESPACE: 0x0101,
16
+ XML_START_ELEMENT: 0x0102,
17
+ XML_END_ELEMENT: 0x0103,
18
+ XML_CDATA: 0x0104,
19
+ XML_LAST_CHUNK: 0x017f,
20
+ XML_RESOURCE_MAP: 0x0180,
21
+ TABLE_PACKAGE: 0x0200,
22
+ TABLE_TYPE: 0x0201,
23
+ TABLE_TYPE_SPEC: 0x0202
24
+ }
25
+
26
+ const StringFlags = {
27
+ SORTED: 1 << 0,
28
+ UTF8: 1 << 8
29
+ }
30
+
31
+ // Taken from android.util.TypedValue
32
+ const TypedValue = {
33
+ COMPLEX_MANTISSA_MASK: 0x00ffffff,
34
+ COMPLEX_MANTISSA_SHIFT: 0x00000008,
35
+ COMPLEX_RADIX_0p23: 0x00000003,
36
+ COMPLEX_RADIX_16p7: 0x00000001,
37
+ COMPLEX_RADIX_23p0: 0x00000000,
38
+ COMPLEX_RADIX_8p15: 0x00000002,
39
+ COMPLEX_RADIX_MASK: 0x00000003,
40
+ COMPLEX_RADIX_SHIFT: 0x00000004,
41
+ COMPLEX_UNIT_DIP: 0x00000001,
42
+ COMPLEX_UNIT_FRACTION: 0x00000000,
43
+ COMPLEX_UNIT_FRACTION_PARENT: 0x00000001,
44
+ COMPLEX_UNIT_IN: 0x00000004,
45
+ COMPLEX_UNIT_MASK: 0x0000000f,
46
+ COMPLEX_UNIT_MM: 0x00000005,
47
+ COMPLEX_UNIT_PT: 0x00000003,
48
+ COMPLEX_UNIT_PX: 0x00000000,
49
+ COMPLEX_UNIT_SHIFT: 0x00000000,
50
+ COMPLEX_UNIT_SP: 0x00000002,
51
+ DENSITY_DEFAULT: 0x00000000,
52
+ DENSITY_NONE: 0x0000ffff,
53
+ TYPE_ATTRIBUTE: 0x00000002,
54
+ TYPE_DIMENSION: 0x00000005,
55
+ TYPE_FIRST_COLOR_INT: 0x0000001c,
56
+ TYPE_FIRST_INT: 0x00000010,
57
+ TYPE_FLOAT: 0x00000004,
58
+ TYPE_FRACTION: 0x00000006,
59
+ TYPE_INT_BOOLEAN: 0x00000012,
60
+ TYPE_INT_COLOR_ARGB4: 0x0000001e,
61
+ TYPE_INT_COLOR_ARGB8: 0x0000001c,
62
+ TYPE_INT_COLOR_RGB4: 0x0000001f,
63
+ TYPE_INT_COLOR_RGB8: 0x0000001d,
64
+ TYPE_INT_DEC: 0x00000010,
65
+ TYPE_INT_HEX: 0x00000011,
66
+ TYPE_LAST_COLOR_INT: 0x0000001f,
67
+ TYPE_LAST_INT: 0x0000001f,
68
+ TYPE_NULL: 0x00000000,
69
+ TYPE_REFERENCE: 0x00000001,
70
+ TYPE_STRING: 0x00000003
71
+ }
72
+
73
+ class BinaryXmlParser {
74
+ constructor (buffer, options = {}) {
75
+ this.buffer = buffer
76
+ this.cursor = 0
77
+ this.strings = []
78
+ this.resources = []
79
+ this.document = null
80
+ this.parent = null
81
+ this.stack = []
82
+ this.debug = options.debug || false
83
+ }
84
+
85
+ readU8 () {
86
+ this.debug && console.group('readU8')
87
+ this.debug && console.debug('cursor:', this.cursor)
88
+ const val = this.buffer[this.cursor]
89
+ this.debug && console.debug('value:', val)
90
+ this.cursor += 1
91
+ this.debug && console.groupEnd()
92
+ return val
93
+ }
94
+
95
+ readU16 () {
96
+ this.debug && console.group('readU16')
97
+ this.debug && console.debug('cursor:', this.cursor)
98
+ const val = this.buffer.readUInt16LE(this.cursor)
99
+ this.debug && console.debug('value:', val)
100
+ this.cursor += 2
101
+ this.debug && console.groupEnd()
102
+ return val
103
+ }
104
+
105
+ readS32 () {
106
+ this.debug && console.group('readS32')
107
+ this.debug && console.debug('cursor:', this.cursor)
108
+ const val = this.buffer.readInt32LE(this.cursor)
109
+ this.debug && console.debug('value:', val)
110
+ this.cursor += 4
111
+ this.debug && console.groupEnd()
112
+ return val
113
+ }
114
+
115
+ readU32 () {
116
+ this.debug && console.group('readU32')
117
+ this.debug && console.debug('cursor:', this.cursor)
118
+ const val = this.buffer.readUInt32LE(this.cursor)
119
+ this.debug && console.debug('value:', val)
120
+ this.cursor += 4
121
+ this.debug && console.groupEnd()
122
+ return val
123
+ }
124
+
125
+ readLength8 () {
126
+ this.debug && console.group('readLength8')
127
+ let len = this.readU8()
128
+ if (len & 0x80) {
129
+ len = (len & 0x7f) << 8
130
+ len += this.readU8()
131
+ }
132
+ this.debug && console.debug('length:', len)
133
+ this.debug && console.groupEnd()
134
+ return len
135
+ }
136
+
137
+ readLength16 () {
138
+ this.debug && console.group('readLength16')
139
+ let len = this.readU16()
140
+ if (len & 0x8000) {
141
+ len = (len & 0x7fff) << 16
142
+ len += this.readU16()
143
+ }
144
+ this.debug && console.debug('length:', len)
145
+ this.debug && console.groupEnd()
146
+ return len
147
+ }
148
+
149
+ readDimension () {
150
+ this.debug && console.group('readDimension')
151
+
152
+ const dimension = {
153
+ value: null,
154
+ unit: null,
155
+ rawUnit: null
156
+ }
157
+
158
+ const value = this.readU32()
159
+ const unit = dimension.value & 0xff
160
+
161
+ dimension.value = value >> 8
162
+ dimension.rawUnit = unit
163
+
164
+ switch (unit) {
165
+ case TypedValue.COMPLEX_UNIT_MM:
166
+ dimension.unit = 'mm'
167
+ break
168
+ case TypedValue.COMPLEX_UNIT_PX:
169
+ dimension.unit = 'px'
170
+ break
171
+ case TypedValue.COMPLEX_UNIT_DIP:
172
+ dimension.unit = 'dp'
173
+ break
174
+ case TypedValue.COMPLEX_UNIT_SP:
175
+ dimension.unit = 'sp'
176
+ break
177
+ case TypedValue.COMPLEX_UNIT_PT:
178
+ dimension.unit = 'pt'
179
+ break
180
+ case TypedValue.COMPLEX_UNIT_IN:
181
+ dimension.unit = 'in'
182
+ break
183
+ }
184
+
185
+ this.debug && console.groupEnd()
186
+
187
+ return dimension
188
+ }
189
+
190
+ readFraction () {
191
+ this.debug && console.group('readFraction')
192
+
193
+ const fraction = {
194
+ value: null,
195
+ type: null,
196
+ rawType: null
197
+ }
198
+
199
+ const value = this.readU32()
200
+ const type = value & 0xf
201
+
202
+ fraction.value = this.convertIntToFloat(value >> 4)
203
+ fraction.rawType = type
204
+
205
+ switch (type) {
206
+ case TypedValue.COMPLEX_UNIT_FRACTION:
207
+ fraction.type = '%'
208
+ break
209
+ case TypedValue.COMPLEX_UNIT_FRACTION_PARENT:
210
+ fraction.type = '%p'
211
+ break
212
+ }
213
+
214
+ this.debug && console.groupEnd()
215
+
216
+ return fraction
217
+ }
218
+
219
+ readHex24 () {
220
+ this.debug && console.group('readHex24')
221
+ var val = (this.readU32() & 0xffffff).toString(16)
222
+ this.debug && console.groupEnd()
223
+ return val
224
+ }
225
+
226
+ readHex32 () {
227
+ this.debug && console.group('readHex32')
228
+ var val = this.readU32().toString(16)
229
+ this.debug && console.groupEnd()
230
+ return val
231
+ }
232
+
233
+ readTypedValue () {
234
+ this.debug && console.group('readTypedValue')
235
+
236
+ const typedValue = {
237
+ value: null,
238
+ type: null,
239
+ rawType: null
240
+ }
241
+
242
+ const start = this.cursor
243
+
244
+ let size = this.readU16()
245
+ /* const zero = */ this.readU8()
246
+ const dataType = this.readU8()
247
+
248
+ // Yes, there has been a real world APK where the size is malformed.
249
+ if (size === 0) {
250
+ size = 8
251
+ }
252
+
253
+ typedValue.rawType = dataType
254
+
255
+ switch (dataType) {
256
+ case TypedValue.TYPE_INT_DEC:
257
+ typedValue.value = this.readS32()
258
+ typedValue.type = 'int_dec'
259
+ break
260
+ case TypedValue.TYPE_INT_HEX:
261
+ typedValue.value = this.readS32()
262
+ typedValue.type = 'int_hex'
263
+ break
264
+ case TypedValue.TYPE_STRING:
265
+ var ref = this.readS32()
266
+ typedValue.value = ref > 0 ? this.strings[ref] : ''
267
+ typedValue.type = 'string'
268
+ break
269
+ case TypedValue.TYPE_REFERENCE:
270
+ var id = this.readU32()
271
+ typedValue.value = `resourceId:0x${id.toString(16)}`
272
+ typedValue.type = 'reference'
273
+ break
274
+ case TypedValue.TYPE_INT_BOOLEAN:
275
+ typedValue.value = this.readS32() !== 0
276
+ typedValue.type = 'boolean'
277
+ break
278
+ case TypedValue.TYPE_NULL:
279
+ this.readU32()
280
+ typedValue.value = null
281
+ typedValue.type = 'null'
282
+ break
283
+ case TypedValue.TYPE_INT_COLOR_RGB8:
284
+ typedValue.value = this.readHex24()
285
+ typedValue.type = 'rgb8'
286
+ break
287
+ case TypedValue.TYPE_INT_COLOR_RGB4:
288
+ typedValue.value = this.readHex24()
289
+ typedValue.type = 'rgb4'
290
+ break
291
+ case TypedValue.TYPE_INT_COLOR_ARGB8:
292
+ typedValue.value = this.readHex32()
293
+ typedValue.type = 'argb8'
294
+ break
295
+ case TypedValue.TYPE_INT_COLOR_ARGB4:
296
+ typedValue.value = this.readHex32()
297
+ typedValue.type = 'argb4'
298
+ break
299
+ case TypedValue.TYPE_DIMENSION:
300
+ typedValue.value = this.readDimension()
301
+ typedValue.type = 'dimension'
302
+ break
303
+ case TypedValue.TYPE_FRACTION:
304
+ typedValue.value = this.readFraction()
305
+ typedValue.type = 'fraction'
306
+ break
307
+ default: {
308
+ const type = dataType.toString(16)
309
+ console.debug(`Not sure what to do with typed value of type 0x${type}, falling back to reading an uint32.`)
310
+ typedValue.value = this.readU32()
311
+ typedValue.type = 'unknown'
312
+ }
313
+ }
314
+
315
+ // Ensure we consume the whole value
316
+ const end = start + size
317
+ if (this.cursor !== end) {
318
+ const type = dataType.toString(16)
319
+ const diff = end - this.cursor
320
+ console.debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed end \
321
+ of typed value of type 0x${type}. The typed value started at offset ${start} \
322
+ and is supposed to end at offset ${end}. Ignoring the rest of the value.`)
323
+ this.cursor = end
324
+ }
325
+
326
+ this.debug && console.groupEnd()
327
+
328
+ return typedValue
329
+ }
330
+
331
+ // https://twitter.com/kawasima/status/427730289201139712
332
+ convertIntToFloat (int) {
333
+ const buf = new ArrayBuffer(4)
334
+ ;(new Int32Array(buf))[0] = int
335
+ return (new Float32Array(buf))[0]
336
+ }
337
+
338
+ readString (encoding) {
339
+ this.debug && console.group('readString', encoding)
340
+ switch (encoding) {
341
+ case 'utf-8':
342
+ var stringLength = this.readLength8(encoding)
343
+ this.debug && console.debug('stringLength:', stringLength)
344
+ var byteLength = this.readLength8(encoding)
345
+ this.debug && console.debug('byteLength:', byteLength)
346
+ var value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength))
347
+ this.debug && console.debug('value:', value)
348
+ this.debug && console.groupEnd()
349
+ return value
350
+ case 'ucs2':
351
+ stringLength = this.readLength16(encoding)
352
+ this.debug && console.debug('stringLength:', stringLength)
353
+ byteLength = stringLength * 2
354
+ this.debug && console.debug('byteLength:', byteLength)
355
+ value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength))
356
+ this.debug && console.debug('value:', value)
357
+ this.debug && console.groupEnd()
358
+ return value
359
+ default:
360
+ throw new Error(`Unsupported encoding '${encoding}'`)
361
+ }
362
+ }
363
+
364
+ readChunkHeader () {
365
+ this.debug && console.group('readChunkHeader')
366
+ var header = {
367
+ startOffset: this.cursor,
368
+ chunkType: this.readU16(),
369
+ headerSize: this.readU16(),
370
+ chunkSize: this.readU32()
371
+ }
372
+ this.debug && console.debug('startOffset:', header.startOffset)
373
+ this.debug && console.debug('chunkType:', header.chunkType)
374
+ this.debug && console.debug('headerSize:', header.headerSize)
375
+ this.debug && console.debug('chunkSize:', header.chunkSize)
376
+ this.debug && console.groupEnd()
377
+ return header
378
+ }
379
+
380
+ readStringPool (header) {
381
+ this.debug && console.group('readStringPool')
382
+
383
+ header.stringCount = this.readU32()
384
+ this.debug && console.debug('stringCount:', header.stringCount)
385
+ header.styleCount = this.readU32()
386
+ this.debug && console.debug('styleCount:', header.styleCount)
387
+ header.flags = this.readU32()
388
+ this.debug && console.debug('flags:', header.flags)
389
+ header.stringsStart = this.readU32()
390
+ this.debug && console.debug('stringsStart:', header.stringsStart)
391
+ header.stylesStart = this.readU32()
392
+ this.debug && console.debug('stylesStart:', header.stylesStart)
393
+
394
+ if (header.chunkType !== ChunkType.STRING_POOL) {
395
+ throw new Error('Invalid string pool header')
396
+ }
397
+
398
+ const offsets = []
399
+ for (let i = 0, l = header.stringCount; i < l; ++i) {
400
+ this.debug && console.debug('offset:', i)
401
+ offsets.push(this.readU32())
402
+ }
403
+
404
+ const sorted = (header.flags & StringFlags.SORTED) === StringFlags.SORTED
405
+ this.debug && console.debug('sorted:', sorted)
406
+ const encoding = (header.flags & StringFlags.UTF8) === StringFlags.UTF8
407
+ ? 'utf-8'
408
+ : 'ucs2'
409
+ this.debug && console.debug('encoding:', encoding)
410
+
411
+ const stringsStart = header.startOffset + header.stringsStart
412
+ this.cursor = stringsStart
413
+ for (let i = 0, l = header.stringCount; i < l; ++i) {
414
+ this.debug && console.debug('string:', i)
415
+ this.debug && console.debug('offset:', offsets[i])
416
+ this.cursor = stringsStart + offsets[i]
417
+ this.strings.push(this.readString(encoding))
418
+ }
419
+
420
+ // Skip styles
421
+ this.cursor = header.startOffset + header.chunkSize
422
+
423
+ this.debug && console.groupEnd()
424
+
425
+ return null
426
+ }
427
+
428
+ readResourceMap (header) {
429
+ this.debug && console.group('readResourceMap')
430
+ const count = Math.floor((header.chunkSize - header.headerSize) / 4)
431
+ for (let i = 0; i < count; ++i) {
432
+ this.resources.push(this.readU32())
433
+ }
434
+ this.debug && console.groupEnd()
435
+ return null
436
+ }
437
+
438
+ readXmlNamespaceStart (/* header */) {
439
+ this.debug && console.group('readXmlNamespaceStart')
440
+
441
+ /* const line = */ this.readU32()
442
+ /* const commentRef = */ this.readU32()
443
+ /* const prefixRef = */ this.readS32()
444
+ /* const uriRef = */ this.readS32()
445
+
446
+ // We don't currently care about the values, but they could
447
+ // be accessed like so:
448
+ //
449
+ // namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0
450
+ // namespaceURI.uri = this.strings[uriRef] // if uriRef > 0
451
+
452
+ this.debug && console.groupEnd()
453
+
454
+ return null
455
+ }
456
+
457
+ readXmlNamespaceEnd (/* header */) {
458
+ this.debug && console.group('readXmlNamespaceEnd')
459
+
460
+ /* const line = */ this.readU32()
461
+ /* const commentRef = */ this.readU32()
462
+ /* const prefixRef = */ this.readS32()
463
+ /* const uriRef = */ this.readS32()
464
+
465
+ // We don't currently care about the values, but they could
466
+ // be accessed like so:
467
+ //
468
+ // namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0
469
+ // namespaceURI.uri = this.strings[uriRef] // if uriRef > 0
470
+
471
+ this.debug && console.groupEnd()
472
+
473
+ return null
474
+ }
475
+
476
+ readXmlElementStart (/* header */) {
477
+ this.debug && console.group('readXmlElementStart')
478
+
479
+ const node = {
480
+ namespaceURI: null,
481
+ nodeType: NodeType.ELEMENT_NODE,
482
+ nodeName: null,
483
+ attributes: [],
484
+ childNodes: []
485
+ }
486
+
487
+ /* const line = */ this.readU32()
488
+ /* const commentRef = */ this.readU32()
489
+ const nsRef = this.readS32()
490
+ const nameRef = this.readS32()
491
+
492
+ if (nsRef > 0) {
493
+ node.namespaceURI = this.strings[nsRef]
494
+ }
495
+
496
+ node.nodeName = this.strings[nameRef]
497
+
498
+ /* const attrStart = */ this.readU16()
499
+ /* const attrSize = */ this.readU16()
500
+ const attrCount = this.readU16()
501
+ /* const idIndex = */ this.readU16()
502
+ /* const classIndex = */ this.readU16()
503
+ /* const styleIndex = */ this.readU16()
504
+
505
+ for (let i = 0; i < attrCount; ++i) {
506
+ node.attributes.push(this.readXmlAttribute())
507
+ }
508
+
509
+ if (this.document) {
510
+ this.parent.childNodes.push(node)
511
+ this.parent = node
512
+ } else {
513
+ this.document = (this.parent = node)
514
+ }
515
+
516
+ this.stack.push(node)
517
+
518
+ this.debug && console.groupEnd()
519
+
520
+ return node
521
+ }
522
+
523
+ readXmlAttribute () {
524
+ this.debug && console.group('readXmlAttribute')
525
+
526
+ const attr = {
527
+ namespaceURI: null,
528
+ nodeType: NodeType.ATTRIBUTE_NODE,
529
+ nodeName: null,
530
+ name: null,
531
+ value: null,
532
+ typedValue: null
533
+ }
534
+
535
+ const nsRef = this.readS32()
536
+ const nameRef = this.readS32()
537
+ const valueRef = this.readS32()
538
+
539
+ if (nsRef > 0) {
540
+ attr.namespaceURI = this.strings[nsRef]
541
+ }
542
+
543
+ attr.nodeName = attr.name = this.strings[nameRef]
544
+
545
+ if (valueRef > 0) {
546
+ // some apk have versionName with special characters
547
+ if (attr.name === 'versionName') {
548
+ // only keep printable characters
549
+ // https://www.ascii-code.com/characters/printable-characters
550
+ this.strings[valueRef] = this.strings[valueRef].replace(/[^\x21-\x7E]/g, '')
551
+ }
552
+ attr.value = this.strings[valueRef]
553
+ }
554
+
555
+ attr.typedValue = this.readTypedValue()
556
+
557
+ this.debug && console.groupEnd()
558
+
559
+ return attr
560
+ }
561
+
562
+ readXmlElementEnd (/* header */) {
563
+ this.debug && console.group('readXmlCData')
564
+
565
+ /* const line = */ this.readU32()
566
+ /* const commentRef = */ this.readU32()
567
+ /* const nsRef = */ this.readS32()
568
+ /* const nameRef = */ this.readS32()
569
+
570
+ this.stack.pop()
571
+ this.parent = this.stack[this.stack.length - 1]
572
+
573
+ this.debug && console.groupEnd()
574
+
575
+ return null
576
+ }
577
+
578
+ readXmlCData (/* header */) {
579
+ this.debug && console.group('readXmlCData')
580
+
581
+ const cdata = {
582
+ namespaceURI: null,
583
+ nodeType: NodeType.CDATA_SECTION_NODE,
584
+ nodeName: '#cdata',
585
+ data: null,
586
+ typedValue: null
587
+ }
588
+
589
+ /* const line = */ this.readU32()
590
+ /* const commentRef = */ this.readU32()
591
+ const dataRef = this.readS32()
592
+
593
+ if (dataRef > 0) {
594
+ cdata.data = this.strings[dataRef]
595
+ }
596
+
597
+ cdata.typedValue = this.readTypedValue()
598
+
599
+ this.parent.childNodes.push(cdata)
600
+
601
+ this.debug && console.groupEnd()
602
+
603
+ return cdata
604
+ }
605
+
606
+ readNull (header) {
607
+ this.debug && console.group('readNull')
608
+ this.cursor += header.chunkSize - header.headerSize
609
+ this.debug && console.groupEnd()
610
+ return null
611
+ }
612
+
613
+ parse () {
614
+ this.debug && console.group('BinaryXmlParser.parse')
615
+
616
+ const xmlHeader = this.readChunkHeader()
617
+ if (xmlHeader.chunkType !== ChunkType.XML) {
618
+ throw new Error('Invalid XML header')
619
+ }
620
+
621
+ while (this.cursor < this.buffer.length) {
622
+ this.debug && console.group('chunk')
623
+ const start = this.cursor
624
+ const header = this.readChunkHeader()
625
+ switch (header.chunkType) {
626
+ case ChunkType.STRING_POOL:
627
+ this.readStringPool(header)
628
+ break
629
+ case ChunkType.XML_RESOURCE_MAP:
630
+ this.readResourceMap(header)
631
+ break
632
+ case ChunkType.XML_START_NAMESPACE:
633
+ this.readXmlNamespaceStart(header)
634
+ break
635
+ case ChunkType.XML_END_NAMESPACE:
636
+ this.readXmlNamespaceEnd(header)
637
+ break
638
+ case ChunkType.XML_START_ELEMENT:
639
+ this.readXmlElementStart(header)
640
+ break
641
+ case ChunkType.XML_END_ELEMENT:
642
+ this.readXmlElementEnd(header)
643
+ break
644
+ case ChunkType.XML_CDATA:
645
+ this.readXmlCData(header)
646
+ break
647
+ case ChunkType.NULL:
648
+ this.readNull(header)
649
+ break
650
+ default:
651
+ throw new Error(`Unsupported chunk type '${header.chunkType}'`)
652
+ }
653
+
654
+ // Ensure we consume the whole chunk
655
+ const end = start + header.chunkSize
656
+ if (this.cursor !== end) {
657
+ const diff = end - this.cursor
658
+ const type = header.chunkType.toString(16)
659
+ console.debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed \
660
+ end of chunk of type 0x${type}. The chunk started at offset ${start} and is \
661
+ supposed to end at offset ${end}. Ignoring the rest of the chunk.`)
662
+ this.cursor = end
663
+ }
664
+
665
+ this.debug && console.groupEnd()
666
+ }
667
+
668
+ this.debug && console.groupEnd()
669
+
670
+ return this.document
671
+ }
672
+ }
673
+
674
+ module.exports = BinaryXmlParser