@expo/plist 0.0.18 → 0.0.20
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/build/apkBinary.d.ts +41 -0
- package/build/apkBinary.js +557 -0
- package/build/apkBinary.js.map +1 -0
- package/build/binary.d.ts +41 -0
- package/build/binary.js +557 -0
- package/build/binary.js.map +1 -0
- package/build/osxBinary.d.ts +10 -0
- package/build/osxBinary.js +360 -0
- package/build/osxBinary.js.map +1 -0
- package/build/parse.js +6 -6
- package/build/parse.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare class BinaryXmlParser {
|
|
3
|
+
buffer: Buffer;
|
|
4
|
+
cursor: number;
|
|
5
|
+
strings: string[];
|
|
6
|
+
resources: any[];
|
|
7
|
+
document: any;
|
|
8
|
+
parent: any;
|
|
9
|
+
stack: any[];
|
|
10
|
+
debug: boolean;
|
|
11
|
+
constructor(buffer: Buffer, options?: any);
|
|
12
|
+
readU8(): number;
|
|
13
|
+
readU16(): number;
|
|
14
|
+
readS32(): number;
|
|
15
|
+
readU32(): number;
|
|
16
|
+
readLength8(): number;
|
|
17
|
+
readLength16(): number;
|
|
18
|
+
readDimension(): any;
|
|
19
|
+
readFraction(): any;
|
|
20
|
+
readHex24(): string;
|
|
21
|
+
readHex32(): string;
|
|
22
|
+
readTypedValue(): any;
|
|
23
|
+
convertIntToFloat(int: number): number;
|
|
24
|
+
readString(encoding: string): string;
|
|
25
|
+
readChunkHeader(): {
|
|
26
|
+
startOffset: number;
|
|
27
|
+
chunkType: number;
|
|
28
|
+
headerSize: number;
|
|
29
|
+
chunkSize: number;
|
|
30
|
+
};
|
|
31
|
+
readStringPool(header: any): null;
|
|
32
|
+
readResourceMap(header: any): null;
|
|
33
|
+
readXmlNamespaceStart(): null;
|
|
34
|
+
readXmlNamespaceEnd(): null;
|
|
35
|
+
readXmlElementStart(): any;
|
|
36
|
+
readXmlAttribute(): any;
|
|
37
|
+
readXmlElementEnd(): null;
|
|
38
|
+
readXmlCData(): any;
|
|
39
|
+
readNull(header: any): null;
|
|
40
|
+
parse(): any;
|
|
41
|
+
}
|
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.BinaryXmlParser = void 0;
|
|
23
|
+
/**
|
|
24
|
+
* https://github.com/openstf/adbkit-apkreader/blob/368f6b207c57e82fa7373c1608920ca7f4a8904c/lib/apkreader/parser/binaryxml.js
|
|
25
|
+
*/
|
|
26
|
+
const assert = __importStar(require("assert"));
|
|
27
|
+
// import Debug from 'debug';
|
|
28
|
+
// const debug = Debug('native-run:android:util:binary-xml-parser');
|
|
29
|
+
const NodeType = {
|
|
30
|
+
ELEMENT_NODE: 1,
|
|
31
|
+
ATTRIBUTE_NODE: 2,
|
|
32
|
+
CDATA_SECTION_NODE: 4,
|
|
33
|
+
};
|
|
34
|
+
const ChunkType = {
|
|
35
|
+
NULL: 0x0000,
|
|
36
|
+
STRING_POOL: 0x0001,
|
|
37
|
+
TABLE: 0x0002,
|
|
38
|
+
XML: 0x0003,
|
|
39
|
+
XML_FIRST_CHUNK: 0x0100,
|
|
40
|
+
XML_START_NAMESPACE: 0x0100,
|
|
41
|
+
XML_END_NAMESPACE: 0x0101,
|
|
42
|
+
XML_START_ELEMENT: 0x0102,
|
|
43
|
+
XML_END_ELEMENT: 0x0103,
|
|
44
|
+
XML_CDATA: 0x0104,
|
|
45
|
+
XML_LAST_CHUNK: 0x017f,
|
|
46
|
+
XML_RESOURCE_MAP: 0x0180,
|
|
47
|
+
TABLE_PACKAGE: 0x0200,
|
|
48
|
+
TABLE_TYPE: 0x0201,
|
|
49
|
+
TABLE_TYPE_SPEC: 0x0202,
|
|
50
|
+
};
|
|
51
|
+
const StringFlags = {
|
|
52
|
+
SORTED: 1 << 0,
|
|
53
|
+
UTF8: 1 << 8,
|
|
54
|
+
};
|
|
55
|
+
// Taken from android.util.TypedValue
|
|
56
|
+
const TypedValue = {
|
|
57
|
+
COMPLEX_MANTISSA_MASK: 0x00ffffff,
|
|
58
|
+
COMPLEX_MANTISSA_SHIFT: 0x00000008,
|
|
59
|
+
COMPLEX_RADIX_0p23: 0x00000003,
|
|
60
|
+
COMPLEX_RADIX_16p7: 0x00000001,
|
|
61
|
+
COMPLEX_RADIX_23p0: 0x00000000,
|
|
62
|
+
COMPLEX_RADIX_8p15: 0x00000002,
|
|
63
|
+
COMPLEX_RADIX_MASK: 0x00000003,
|
|
64
|
+
COMPLEX_RADIX_SHIFT: 0x00000004,
|
|
65
|
+
COMPLEX_UNIT_DIP: 0x00000001,
|
|
66
|
+
COMPLEX_UNIT_FRACTION: 0x00000000,
|
|
67
|
+
COMPLEX_UNIT_FRACTION_PARENT: 0x00000001,
|
|
68
|
+
COMPLEX_UNIT_IN: 0x00000004,
|
|
69
|
+
COMPLEX_UNIT_MASK: 0x0000000f,
|
|
70
|
+
COMPLEX_UNIT_MM: 0x00000005,
|
|
71
|
+
COMPLEX_UNIT_PT: 0x00000003,
|
|
72
|
+
COMPLEX_UNIT_PX: 0x00000000,
|
|
73
|
+
COMPLEX_UNIT_SHIFT: 0x00000000,
|
|
74
|
+
COMPLEX_UNIT_SP: 0x00000002,
|
|
75
|
+
DENSITY_DEFAULT: 0x00000000,
|
|
76
|
+
DENSITY_NONE: 0x0000ffff,
|
|
77
|
+
TYPE_ATTRIBUTE: 0x00000002,
|
|
78
|
+
TYPE_DIMENSION: 0x00000005,
|
|
79
|
+
TYPE_FIRST_COLOR_INT: 0x0000001c,
|
|
80
|
+
TYPE_FIRST_INT: 0x00000010,
|
|
81
|
+
TYPE_FLOAT: 0x00000004,
|
|
82
|
+
TYPE_FRACTION: 0x00000006,
|
|
83
|
+
TYPE_INT_BOOLEAN: 0x00000012,
|
|
84
|
+
TYPE_INT_COLOR_ARGB4: 0x0000001e,
|
|
85
|
+
TYPE_INT_COLOR_ARGB8: 0x0000001c,
|
|
86
|
+
TYPE_INT_COLOR_RGB4: 0x0000001f,
|
|
87
|
+
TYPE_INT_COLOR_RGB8: 0x0000001d,
|
|
88
|
+
TYPE_INT_DEC: 0x00000010,
|
|
89
|
+
TYPE_INT_HEX: 0x00000011,
|
|
90
|
+
TYPE_LAST_COLOR_INT: 0x0000001f,
|
|
91
|
+
TYPE_LAST_INT: 0x0000001f,
|
|
92
|
+
TYPE_NULL: 0x00000000,
|
|
93
|
+
TYPE_REFERENCE: 0x00000001,
|
|
94
|
+
TYPE_STRING: 0x00000003,
|
|
95
|
+
};
|
|
96
|
+
class BinaryXmlParser {
|
|
97
|
+
constructor(buffer, options = {}) {
|
|
98
|
+
this.buffer = buffer;
|
|
99
|
+
this.cursor = 0;
|
|
100
|
+
this.strings = [];
|
|
101
|
+
this.resources = [];
|
|
102
|
+
this.stack = [];
|
|
103
|
+
this.debug = false;
|
|
104
|
+
this.debug = options.debug || false;
|
|
105
|
+
}
|
|
106
|
+
readU8() {
|
|
107
|
+
const val = this.buffer[this.cursor];
|
|
108
|
+
this.cursor += 1;
|
|
109
|
+
return val;
|
|
110
|
+
}
|
|
111
|
+
readU16() {
|
|
112
|
+
const val = this.buffer.readUInt16LE(this.cursor);
|
|
113
|
+
this.cursor += 2;
|
|
114
|
+
return val;
|
|
115
|
+
}
|
|
116
|
+
readS32() {
|
|
117
|
+
const val = this.buffer.readInt32LE(this.cursor);
|
|
118
|
+
this.cursor += 4;
|
|
119
|
+
return val;
|
|
120
|
+
}
|
|
121
|
+
readU32() {
|
|
122
|
+
// debug('readU32');
|
|
123
|
+
// debug('cursor:', this.cursor);
|
|
124
|
+
const val = this.buffer.readUInt32LE(this.cursor);
|
|
125
|
+
// debug('value:', val);
|
|
126
|
+
this.cursor += 4;
|
|
127
|
+
return val;
|
|
128
|
+
}
|
|
129
|
+
readLength8() {
|
|
130
|
+
// debug('readLength8');
|
|
131
|
+
let len = this.readU8();
|
|
132
|
+
if (len & 0x80) {
|
|
133
|
+
len = (len & 0x7f) << 8;
|
|
134
|
+
len += this.readU8();
|
|
135
|
+
}
|
|
136
|
+
// debug('length:', len);
|
|
137
|
+
return len;
|
|
138
|
+
}
|
|
139
|
+
readLength16() {
|
|
140
|
+
// debug('readLength16');
|
|
141
|
+
let len = this.readU16();
|
|
142
|
+
if (len & 0x8000) {
|
|
143
|
+
len = (len & 0x7fff) << 16;
|
|
144
|
+
len += this.readU16();
|
|
145
|
+
}
|
|
146
|
+
// debug('length:', len);
|
|
147
|
+
return len;
|
|
148
|
+
}
|
|
149
|
+
readDimension() {
|
|
150
|
+
// debug('readDimension');
|
|
151
|
+
const dimension = {
|
|
152
|
+
value: null,
|
|
153
|
+
unit: null,
|
|
154
|
+
rawUnit: null,
|
|
155
|
+
};
|
|
156
|
+
const value = this.readU32();
|
|
157
|
+
const unit = dimension.value & 0xff;
|
|
158
|
+
dimension.value = value >> 8;
|
|
159
|
+
dimension.rawUnit = unit;
|
|
160
|
+
switch (unit) {
|
|
161
|
+
case TypedValue.COMPLEX_UNIT_MM:
|
|
162
|
+
dimension.unit = 'mm';
|
|
163
|
+
break;
|
|
164
|
+
case TypedValue.COMPLEX_UNIT_PX:
|
|
165
|
+
dimension.unit = 'px';
|
|
166
|
+
break;
|
|
167
|
+
case TypedValue.COMPLEX_UNIT_DIP:
|
|
168
|
+
dimension.unit = 'dp';
|
|
169
|
+
break;
|
|
170
|
+
case TypedValue.COMPLEX_UNIT_SP:
|
|
171
|
+
dimension.unit = 'sp';
|
|
172
|
+
break;
|
|
173
|
+
case TypedValue.COMPLEX_UNIT_PT:
|
|
174
|
+
dimension.unit = 'pt';
|
|
175
|
+
break;
|
|
176
|
+
case TypedValue.COMPLEX_UNIT_IN:
|
|
177
|
+
dimension.unit = 'in';
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
return dimension;
|
|
181
|
+
}
|
|
182
|
+
readFraction() {
|
|
183
|
+
const fraction = {
|
|
184
|
+
value: null,
|
|
185
|
+
type: null,
|
|
186
|
+
rawType: null,
|
|
187
|
+
};
|
|
188
|
+
const value = this.readU32();
|
|
189
|
+
const type = value & 0xf;
|
|
190
|
+
fraction.value = this.convertIntToFloat(value >> 4);
|
|
191
|
+
fraction.rawType = type;
|
|
192
|
+
switch (type) {
|
|
193
|
+
case TypedValue.COMPLEX_UNIT_FRACTION:
|
|
194
|
+
fraction.type = '%';
|
|
195
|
+
break;
|
|
196
|
+
case TypedValue.COMPLEX_UNIT_FRACTION_PARENT:
|
|
197
|
+
fraction.type = '%p';
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
return fraction;
|
|
201
|
+
}
|
|
202
|
+
readHex24() {
|
|
203
|
+
const val = (this.readU32() & 0xffffff).toString(16);
|
|
204
|
+
return val;
|
|
205
|
+
}
|
|
206
|
+
readHex32() {
|
|
207
|
+
const val = this.readU32().toString(16);
|
|
208
|
+
return val;
|
|
209
|
+
}
|
|
210
|
+
readTypedValue() {
|
|
211
|
+
const typedValue = {
|
|
212
|
+
value: null,
|
|
213
|
+
type: null,
|
|
214
|
+
rawType: null,
|
|
215
|
+
};
|
|
216
|
+
const start = this.cursor;
|
|
217
|
+
let size = this.readU16();
|
|
218
|
+
/* const zero = */ this.readU8();
|
|
219
|
+
const dataType = this.readU8();
|
|
220
|
+
// Yes, there has been a real world APK where the size is malformed.
|
|
221
|
+
if (size === 0) {
|
|
222
|
+
size = 8;
|
|
223
|
+
}
|
|
224
|
+
typedValue.rawType = dataType;
|
|
225
|
+
switch (dataType) {
|
|
226
|
+
case TypedValue.TYPE_INT_DEC:
|
|
227
|
+
typedValue.value = this.readS32();
|
|
228
|
+
typedValue.type = 'int_dec';
|
|
229
|
+
break;
|
|
230
|
+
case TypedValue.TYPE_INT_HEX:
|
|
231
|
+
typedValue.value = this.readS32();
|
|
232
|
+
typedValue.type = 'int_hex';
|
|
233
|
+
break;
|
|
234
|
+
case TypedValue.TYPE_STRING: {
|
|
235
|
+
const ref = this.readS32();
|
|
236
|
+
typedValue.value = ref > 0 ? this.strings[ref] : '';
|
|
237
|
+
typedValue.type = 'string';
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
case TypedValue.TYPE_REFERENCE: {
|
|
241
|
+
const id = this.readU32();
|
|
242
|
+
typedValue.value = `resourceId:0x${id.toString(16)}`;
|
|
243
|
+
typedValue.type = 'reference';
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case TypedValue.TYPE_INT_BOOLEAN:
|
|
247
|
+
typedValue.value = this.readS32() !== 0;
|
|
248
|
+
typedValue.type = 'boolean';
|
|
249
|
+
break;
|
|
250
|
+
case TypedValue.TYPE_NULL:
|
|
251
|
+
this.readU32();
|
|
252
|
+
typedValue.value = null;
|
|
253
|
+
typedValue.type = 'null';
|
|
254
|
+
break;
|
|
255
|
+
case TypedValue.TYPE_INT_COLOR_RGB8:
|
|
256
|
+
typedValue.value = this.readHex24();
|
|
257
|
+
typedValue.type = 'rgb8';
|
|
258
|
+
break;
|
|
259
|
+
case TypedValue.TYPE_INT_COLOR_RGB4:
|
|
260
|
+
typedValue.value = this.readHex24();
|
|
261
|
+
typedValue.type = 'rgb4';
|
|
262
|
+
break;
|
|
263
|
+
case TypedValue.TYPE_INT_COLOR_ARGB8:
|
|
264
|
+
typedValue.value = this.readHex32();
|
|
265
|
+
typedValue.type = 'argb8';
|
|
266
|
+
break;
|
|
267
|
+
case TypedValue.TYPE_INT_COLOR_ARGB4:
|
|
268
|
+
typedValue.value = this.readHex32();
|
|
269
|
+
typedValue.type = 'argb4';
|
|
270
|
+
break;
|
|
271
|
+
case TypedValue.TYPE_DIMENSION:
|
|
272
|
+
typedValue.value = this.readDimension();
|
|
273
|
+
typedValue.type = 'dimension';
|
|
274
|
+
break;
|
|
275
|
+
case TypedValue.TYPE_FRACTION:
|
|
276
|
+
typedValue.value = this.readFraction();
|
|
277
|
+
typedValue.type = 'fraction';
|
|
278
|
+
break;
|
|
279
|
+
default: {
|
|
280
|
+
// const type = dataType.toString(16);
|
|
281
|
+
typedValue.value = this.readU32();
|
|
282
|
+
typedValue.type = 'unknown';
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Ensure we consume the whole value
|
|
286
|
+
const end = start + size;
|
|
287
|
+
if (this.cursor !== end) {
|
|
288
|
+
// const type = dataType.toString(16);
|
|
289
|
+
// const diff = end - this.cursor;
|
|
290
|
+
// debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed end \
|
|
291
|
+
// of typed value of type 0x${type}. The typed value started at offset ${start} \
|
|
292
|
+
// and is supposed to end at offset ${end}. Ignoring the rest of the value.`);
|
|
293
|
+
this.cursor = end;
|
|
294
|
+
}
|
|
295
|
+
return typedValue;
|
|
296
|
+
}
|
|
297
|
+
// https://twitter.com/kawasima/status/427730289201139712
|
|
298
|
+
convertIntToFloat(int) {
|
|
299
|
+
const buf = new ArrayBuffer(4);
|
|
300
|
+
new Int32Array(buf)[0] = int;
|
|
301
|
+
return new Float32Array(buf)[0];
|
|
302
|
+
}
|
|
303
|
+
readString(encoding) {
|
|
304
|
+
let stringLength;
|
|
305
|
+
let byteLength;
|
|
306
|
+
let value;
|
|
307
|
+
switch (encoding) {
|
|
308
|
+
case 'utf-8':
|
|
309
|
+
stringLength = this.readLength8();
|
|
310
|
+
byteLength = this.readLength8();
|
|
311
|
+
value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength));
|
|
312
|
+
assert.equal(this.readU8(), 0, 'String must end with trailing zero');
|
|
313
|
+
return value;
|
|
314
|
+
case 'ucs2':
|
|
315
|
+
stringLength = this.readLength16();
|
|
316
|
+
byteLength = stringLength * 2;
|
|
317
|
+
value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength));
|
|
318
|
+
assert.equal(this.readU16(), 0, 'String must end with trailing zero');
|
|
319
|
+
return value;
|
|
320
|
+
default:
|
|
321
|
+
throw new assert.AssertionError({ message: `Unsupported encoding '${encoding}'` });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
readChunkHeader() {
|
|
325
|
+
return {
|
|
326
|
+
startOffset: this.cursor,
|
|
327
|
+
chunkType: this.readU16(),
|
|
328
|
+
headerSize: this.readU16(),
|
|
329
|
+
chunkSize: this.readU32(),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
readStringPool(header) {
|
|
333
|
+
header.stringCount = this.readU32();
|
|
334
|
+
header.styleCount = this.readU32();
|
|
335
|
+
header.flags = this.readU32();
|
|
336
|
+
header.stringsStart = this.readU32();
|
|
337
|
+
header.stylesStart = this.readU32();
|
|
338
|
+
if (header.chunkType !== ChunkType.STRING_POOL) {
|
|
339
|
+
throw new assert.AssertionError({ message: 'Invalid string pool header' });
|
|
340
|
+
}
|
|
341
|
+
const offsets = [];
|
|
342
|
+
for (let i = 0, l = header.stringCount; i < l; ++i) {
|
|
343
|
+
offsets.push(this.readU32());
|
|
344
|
+
}
|
|
345
|
+
const encoding = (header.flags & StringFlags.UTF8) === StringFlags.UTF8 ? 'utf-8' : 'ucs2';
|
|
346
|
+
const stringsStart = header.startOffset + header.stringsStart;
|
|
347
|
+
this.cursor = stringsStart;
|
|
348
|
+
for (let i = 0, l = header.stringCount; i < l; ++i) {
|
|
349
|
+
this.cursor = stringsStart + offsets[i];
|
|
350
|
+
this.strings.push(this.readString(encoding));
|
|
351
|
+
}
|
|
352
|
+
// Skip styles
|
|
353
|
+
this.cursor = header.startOffset + header.chunkSize;
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
readResourceMap(header) {
|
|
357
|
+
const count = Math.floor((header.chunkSize - header.headerSize) / 4);
|
|
358
|
+
for (let i = 0; i < count; ++i) {
|
|
359
|
+
this.resources.push(this.readU32());
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
readXmlNamespaceStart( /* header */) {
|
|
364
|
+
this.readU32();
|
|
365
|
+
this.readU32();
|
|
366
|
+
this.readU32();
|
|
367
|
+
this.readU32();
|
|
368
|
+
// const line = this.readU32();
|
|
369
|
+
// const commentRef = this.readU32();
|
|
370
|
+
// const prefixRef = this.readS32();
|
|
371
|
+
// const uriRef = this.readS32();
|
|
372
|
+
// We don't currently care about the values, but they could
|
|
373
|
+
// be accessed like so:
|
|
374
|
+
//
|
|
375
|
+
// namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0
|
|
376
|
+
// namespaceURI.uri = this.strings[uriRef] // if uriRef > 0
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
readXmlNamespaceEnd( /* header */) {
|
|
380
|
+
// debug('readXmlNamespaceEnd');
|
|
381
|
+
this.readU32();
|
|
382
|
+
this.readU32();
|
|
383
|
+
this.readU32();
|
|
384
|
+
this.readU32();
|
|
385
|
+
// const line = this.readU32();
|
|
386
|
+
// const commentRef = this.readU32();
|
|
387
|
+
// const prefixRef = this.readS32();
|
|
388
|
+
// const uriRef = this.readS32();
|
|
389
|
+
// We don't currently care about the values, but they could
|
|
390
|
+
// be accessed like so:
|
|
391
|
+
//
|
|
392
|
+
// namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0
|
|
393
|
+
// namespaceURI.uri = this.strings[uriRef] // if uriRef > 0
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
readXmlElementStart( /* header */) {
|
|
397
|
+
// debug('readXmlElementStart');
|
|
398
|
+
const node = {
|
|
399
|
+
namespaceURI: null,
|
|
400
|
+
nodeType: NodeType.ELEMENT_NODE,
|
|
401
|
+
nodeName: null,
|
|
402
|
+
attributes: [],
|
|
403
|
+
childNodes: [],
|
|
404
|
+
};
|
|
405
|
+
this.readU32();
|
|
406
|
+
this.readU32();
|
|
407
|
+
// const line = this.readU32();
|
|
408
|
+
// const commentRef = this.readU32();
|
|
409
|
+
const nsRef = this.readS32();
|
|
410
|
+
const nameRef = this.readS32();
|
|
411
|
+
if (nsRef > 0) {
|
|
412
|
+
node.namespaceURI = this.strings[nsRef];
|
|
413
|
+
}
|
|
414
|
+
node.nodeName = this.strings[nameRef];
|
|
415
|
+
this.readU16();
|
|
416
|
+
this.readU16();
|
|
417
|
+
// const attrStart = this.readU16();
|
|
418
|
+
// const attrSize = this.readU16();
|
|
419
|
+
const attrCount = this.readU16();
|
|
420
|
+
// const idIndex = this.readU16();
|
|
421
|
+
// const classIndex = this.readU16();
|
|
422
|
+
// const styleIndex = this.readU16();
|
|
423
|
+
this.readU16();
|
|
424
|
+
this.readU16();
|
|
425
|
+
this.readU16();
|
|
426
|
+
for (let i = 0; i < attrCount; ++i) {
|
|
427
|
+
node.attributes.push(this.readXmlAttribute());
|
|
428
|
+
}
|
|
429
|
+
if (this.document) {
|
|
430
|
+
this.parent.childNodes.push(node);
|
|
431
|
+
this.parent = node;
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
this.document = this.parent = node;
|
|
435
|
+
}
|
|
436
|
+
this.stack.push(node);
|
|
437
|
+
return node;
|
|
438
|
+
}
|
|
439
|
+
readXmlAttribute() {
|
|
440
|
+
// debug('readXmlAttribute');
|
|
441
|
+
const attr = {
|
|
442
|
+
namespaceURI: null,
|
|
443
|
+
nodeType: NodeType.ATTRIBUTE_NODE,
|
|
444
|
+
nodeName: null,
|
|
445
|
+
name: null,
|
|
446
|
+
value: null,
|
|
447
|
+
typedValue: null,
|
|
448
|
+
};
|
|
449
|
+
const nsRef = this.readS32();
|
|
450
|
+
const nameRef = this.readS32();
|
|
451
|
+
const valueRef = this.readS32();
|
|
452
|
+
if (nsRef > 0) {
|
|
453
|
+
attr.namespaceURI = this.strings[nsRef];
|
|
454
|
+
}
|
|
455
|
+
attr.nodeName = attr.name = this.strings[nameRef];
|
|
456
|
+
if (valueRef > 0) {
|
|
457
|
+
attr.value = this.strings[valueRef];
|
|
458
|
+
}
|
|
459
|
+
attr.typedValue = this.readTypedValue();
|
|
460
|
+
return attr;
|
|
461
|
+
}
|
|
462
|
+
readXmlElementEnd( /* header */) {
|
|
463
|
+
// debug('readXmlCData');
|
|
464
|
+
this.readU32();
|
|
465
|
+
this.readU32();
|
|
466
|
+
this.readU32();
|
|
467
|
+
this.readU32();
|
|
468
|
+
// const line = this.readU32();
|
|
469
|
+
// const commentRef = this.readU32();
|
|
470
|
+
// const nsRef = this.readS32();
|
|
471
|
+
// const nameRef = this.readS32();
|
|
472
|
+
this.stack.pop();
|
|
473
|
+
this.parent = this.stack[this.stack.length - 1];
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
readXmlCData( /* header */) {
|
|
477
|
+
// debug('readXmlCData');
|
|
478
|
+
const cdata = {
|
|
479
|
+
namespaceURI: null,
|
|
480
|
+
nodeType: NodeType.CDATA_SECTION_NODE,
|
|
481
|
+
nodeName: '#cdata',
|
|
482
|
+
data: null,
|
|
483
|
+
typedValue: null,
|
|
484
|
+
};
|
|
485
|
+
this.readU32();
|
|
486
|
+
this.readU32();
|
|
487
|
+
// const line = this.readU32();
|
|
488
|
+
// const commentRef = this.readU32();
|
|
489
|
+
const dataRef = this.readS32();
|
|
490
|
+
if (dataRef > 0) {
|
|
491
|
+
cdata.data = this.strings[dataRef];
|
|
492
|
+
}
|
|
493
|
+
cdata.typedValue = this.readTypedValue();
|
|
494
|
+
this.parent.childNodes.push(cdata);
|
|
495
|
+
return cdata;
|
|
496
|
+
}
|
|
497
|
+
readNull(header) {
|
|
498
|
+
// debug('readNull');
|
|
499
|
+
this.cursor += header.chunkSize - header.headerSize;
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
parse() {
|
|
503
|
+
// debug('parse');
|
|
504
|
+
const xmlHeader = this.readChunkHeader();
|
|
505
|
+
if (xmlHeader.chunkType !== ChunkType.XML) {
|
|
506
|
+
throw new assert.AssertionError({ message: 'Invalid XML header' });
|
|
507
|
+
}
|
|
508
|
+
while (this.cursor < this.buffer.length) {
|
|
509
|
+
// debug('chunk');
|
|
510
|
+
const start = this.cursor;
|
|
511
|
+
const header = this.readChunkHeader();
|
|
512
|
+
switch (header.chunkType) {
|
|
513
|
+
case ChunkType.STRING_POOL:
|
|
514
|
+
this.readStringPool(header);
|
|
515
|
+
break;
|
|
516
|
+
case ChunkType.XML_RESOURCE_MAP:
|
|
517
|
+
this.readResourceMap(header);
|
|
518
|
+
break;
|
|
519
|
+
case ChunkType.XML_START_NAMESPACE:
|
|
520
|
+
this.readXmlNamespaceStart();
|
|
521
|
+
break;
|
|
522
|
+
case ChunkType.XML_END_NAMESPACE:
|
|
523
|
+
this.readXmlNamespaceEnd();
|
|
524
|
+
break;
|
|
525
|
+
case ChunkType.XML_START_ELEMENT:
|
|
526
|
+
this.readXmlElementStart();
|
|
527
|
+
break;
|
|
528
|
+
case ChunkType.XML_END_ELEMENT:
|
|
529
|
+
this.readXmlElementEnd();
|
|
530
|
+
break;
|
|
531
|
+
case ChunkType.XML_CDATA:
|
|
532
|
+
this.readXmlCData();
|
|
533
|
+
break;
|
|
534
|
+
case ChunkType.NULL:
|
|
535
|
+
this.readNull(header);
|
|
536
|
+
break;
|
|
537
|
+
default:
|
|
538
|
+
throw new assert.AssertionError({
|
|
539
|
+
message: `Unsupported chunk type '${header.chunkType}'`,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
// Ensure we consume the whole chunk
|
|
543
|
+
const end = start + header.chunkSize;
|
|
544
|
+
if (this.cursor !== end) {
|
|
545
|
+
// const diff = end - this.cursor;
|
|
546
|
+
// const type = header.chunkType.toString(16);
|
|
547
|
+
// debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed \
|
|
548
|
+
// end of chunk of type 0x${type}. The chunk started at offset ${start} and is \
|
|
549
|
+
// supposed to end at offset ${end}. Ignoring the rest of the chunk.`);
|
|
550
|
+
// this.cursor = end;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return this.document;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
exports.BinaryXmlParser = BinaryXmlParser;
|
|
557
|
+
//# sourceMappingURL=apkBinary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apkBinary.js","sourceRoot":"","sources":["../src/apkBinary.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * https://github.com/openstf/adbkit-apkreader/blob/368f6b207c57e82fa7373c1608920ca7f4a8904c/lib/apkreader/parser/binaryxml.js\n */\nimport * as assert from 'assert';\n\n// import Debug from 'debug';\n// const debug = Debug('native-run:android:util:binary-xml-parser');\n\nconst NodeType = {\n ELEMENT_NODE: 1,\n ATTRIBUTE_NODE: 2,\n CDATA_SECTION_NODE: 4,\n};\n\nconst ChunkType = {\n NULL: 0x0000,\n STRING_POOL: 0x0001,\n TABLE: 0x0002,\n XML: 0x0003,\n XML_FIRST_CHUNK: 0x0100,\n XML_START_NAMESPACE: 0x0100,\n XML_END_NAMESPACE: 0x0101,\n XML_START_ELEMENT: 0x0102,\n XML_END_ELEMENT: 0x0103,\n XML_CDATA: 0x0104,\n XML_LAST_CHUNK: 0x017f,\n XML_RESOURCE_MAP: 0x0180,\n TABLE_PACKAGE: 0x0200,\n TABLE_TYPE: 0x0201,\n TABLE_TYPE_SPEC: 0x0202,\n};\n\nconst StringFlags = {\n SORTED: 1 << 0,\n UTF8: 1 << 8,\n};\n\n// Taken from android.util.TypedValue\nconst TypedValue = {\n COMPLEX_MANTISSA_MASK: 0x00ffffff,\n COMPLEX_MANTISSA_SHIFT: 0x00000008,\n COMPLEX_RADIX_0p23: 0x00000003,\n COMPLEX_RADIX_16p7: 0x00000001,\n COMPLEX_RADIX_23p0: 0x00000000,\n COMPLEX_RADIX_8p15: 0x00000002,\n COMPLEX_RADIX_MASK: 0x00000003,\n COMPLEX_RADIX_SHIFT: 0x00000004,\n COMPLEX_UNIT_DIP: 0x00000001,\n COMPLEX_UNIT_FRACTION: 0x00000000,\n COMPLEX_UNIT_FRACTION_PARENT: 0x00000001,\n COMPLEX_UNIT_IN: 0x00000004,\n COMPLEX_UNIT_MASK: 0x0000000f,\n COMPLEX_UNIT_MM: 0x00000005,\n COMPLEX_UNIT_PT: 0x00000003,\n COMPLEX_UNIT_PX: 0x00000000,\n COMPLEX_UNIT_SHIFT: 0x00000000,\n COMPLEX_UNIT_SP: 0x00000002,\n DENSITY_DEFAULT: 0x00000000,\n DENSITY_NONE: 0x0000ffff,\n TYPE_ATTRIBUTE: 0x00000002,\n TYPE_DIMENSION: 0x00000005,\n TYPE_FIRST_COLOR_INT: 0x0000001c,\n TYPE_FIRST_INT: 0x00000010,\n TYPE_FLOAT: 0x00000004,\n TYPE_FRACTION: 0x00000006,\n TYPE_INT_BOOLEAN: 0x00000012,\n TYPE_INT_COLOR_ARGB4: 0x0000001e,\n TYPE_INT_COLOR_ARGB8: 0x0000001c,\n TYPE_INT_COLOR_RGB4: 0x0000001f,\n TYPE_INT_COLOR_RGB8: 0x0000001d,\n TYPE_INT_DEC: 0x00000010,\n TYPE_INT_HEX: 0x00000011,\n TYPE_LAST_COLOR_INT: 0x0000001f,\n TYPE_LAST_INT: 0x0000001f,\n TYPE_NULL: 0x00000000,\n TYPE_REFERENCE: 0x00000001,\n TYPE_STRING: 0x00000003,\n};\n\nexport class BinaryXmlParser {\n cursor = 0;\n strings: string[] = [];\n resources: any[] = [];\n document: any;\n parent: any;\n stack: any[] = [];\n debug = false;\n constructor(public buffer: Buffer, options: any = {}) {\n this.debug = options.debug || false;\n }\n\n readU8(): number {\n const val = this.buffer[this.cursor];\n this.cursor += 1;\n return val;\n }\n\n readU16(): number {\n const val = this.buffer.readUInt16LE(this.cursor);\n this.cursor += 2;\n return val;\n }\n\n readS32(): number {\n const val = this.buffer.readInt32LE(this.cursor);\n this.cursor += 4;\n return val;\n }\n\n readU32(): number {\n // debug('readU32');\n // debug('cursor:', this.cursor);\n const val = this.buffer.readUInt32LE(this.cursor);\n // debug('value:', val);\n this.cursor += 4;\n return val;\n }\n\n readLength8(): number {\n // debug('readLength8');\n let len = this.readU8();\n if (len & 0x80) {\n len = (len & 0x7f) << 8;\n len += this.readU8();\n }\n // debug('length:', len);\n return len;\n }\n\n readLength16(): number {\n // debug('readLength16');\n let len = this.readU16();\n if (len & 0x8000) {\n len = (len & 0x7fff) << 16;\n len += this.readU16();\n }\n // debug('length:', len);\n return len;\n }\n\n readDimension(): any {\n // debug('readDimension');\n\n const dimension: any = {\n value: null,\n unit: null,\n rawUnit: null,\n };\n\n const value = this.readU32();\n const unit = dimension.value & 0xff;\n\n dimension.value = value >> 8;\n dimension.rawUnit = unit;\n\n switch (unit) {\n case TypedValue.COMPLEX_UNIT_MM:\n dimension.unit = 'mm';\n break;\n case TypedValue.COMPLEX_UNIT_PX:\n dimension.unit = 'px';\n break;\n case TypedValue.COMPLEX_UNIT_DIP:\n dimension.unit = 'dp';\n break;\n case TypedValue.COMPLEX_UNIT_SP:\n dimension.unit = 'sp';\n break;\n case TypedValue.COMPLEX_UNIT_PT:\n dimension.unit = 'pt';\n break;\n case TypedValue.COMPLEX_UNIT_IN:\n dimension.unit = 'in';\n break;\n }\n\n return dimension;\n }\n\n readFraction(): any {\n const fraction: any = {\n value: null,\n type: null,\n rawType: null,\n };\n\n const value = this.readU32();\n const type = value & 0xf;\n\n fraction.value = this.convertIntToFloat(value >> 4);\n fraction.rawType = type;\n\n switch (type) {\n case TypedValue.COMPLEX_UNIT_FRACTION:\n fraction.type = '%';\n break;\n case TypedValue.COMPLEX_UNIT_FRACTION_PARENT:\n fraction.type = '%p';\n break;\n }\n\n return fraction;\n }\n\n readHex24(): string {\n const val = (this.readU32() & 0xffffff).toString(16);\n return val;\n }\n\n readHex32(): string {\n const val = this.readU32().toString(16);\n return val;\n }\n\n readTypedValue(): any {\n const typedValue: any = {\n value: null,\n type: null,\n rawType: null,\n };\n\n const start = this.cursor;\n\n let size = this.readU16();\n /* const zero = */ this.readU8();\n const dataType = this.readU8();\n\n // Yes, there has been a real world APK where the size is malformed.\n if (size === 0) {\n size = 8;\n }\n\n typedValue.rawType = dataType;\n\n switch (dataType) {\n case TypedValue.TYPE_INT_DEC:\n typedValue.value = this.readS32();\n typedValue.type = 'int_dec';\n break;\n case TypedValue.TYPE_INT_HEX:\n typedValue.value = this.readS32();\n typedValue.type = 'int_hex';\n break;\n case TypedValue.TYPE_STRING: {\n const ref = this.readS32();\n typedValue.value = ref > 0 ? this.strings[ref] : '';\n typedValue.type = 'string';\n break;\n }\n case TypedValue.TYPE_REFERENCE: {\n const id = this.readU32();\n typedValue.value = `resourceId:0x${id.toString(16)}`;\n typedValue.type = 'reference';\n break;\n }\n case TypedValue.TYPE_INT_BOOLEAN:\n typedValue.value = this.readS32() !== 0;\n typedValue.type = 'boolean';\n break;\n case TypedValue.TYPE_NULL:\n this.readU32();\n typedValue.value = null;\n typedValue.type = 'null';\n break;\n case TypedValue.TYPE_INT_COLOR_RGB8:\n typedValue.value = this.readHex24();\n typedValue.type = 'rgb8';\n break;\n case TypedValue.TYPE_INT_COLOR_RGB4:\n typedValue.value = this.readHex24();\n typedValue.type = 'rgb4';\n break;\n case TypedValue.TYPE_INT_COLOR_ARGB8:\n typedValue.value = this.readHex32();\n typedValue.type = 'argb8';\n break;\n case TypedValue.TYPE_INT_COLOR_ARGB4:\n typedValue.value = this.readHex32();\n typedValue.type = 'argb4';\n break;\n case TypedValue.TYPE_DIMENSION:\n typedValue.value = this.readDimension();\n typedValue.type = 'dimension';\n break;\n case TypedValue.TYPE_FRACTION:\n typedValue.value = this.readFraction();\n typedValue.type = 'fraction';\n break;\n default: {\n // const type = dataType.toString(16);\n typedValue.value = this.readU32();\n typedValue.type = 'unknown';\n }\n }\n\n // Ensure we consume the whole value\n const end = start + size;\n if (this.cursor !== end) {\n // const type = dataType.toString(16);\n // const diff = end - this.cursor;\n // debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed end \\\n // of typed value of type 0x${type}. The typed value started at offset ${start} \\\n // and is supposed to end at offset ${end}. Ignoring the rest of the value.`);\n this.cursor = end;\n }\n\n return typedValue;\n }\n\n // https://twitter.com/kawasima/status/427730289201139712\n convertIntToFloat(int: number): number {\n const buf = new ArrayBuffer(4);\n new Int32Array(buf)[0] = int;\n return new Float32Array(buf)[0];\n }\n\n readString(encoding: string): string {\n let stringLength;\n let byteLength;\n let value;\n switch (encoding) {\n case 'utf-8':\n stringLength = this.readLength8();\n byteLength = this.readLength8();\n value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength));\n assert.equal(this.readU8(), 0, 'String must end with trailing zero');\n return value;\n case 'ucs2':\n stringLength = this.readLength16();\n byteLength = stringLength * 2;\n value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength));\n assert.equal(this.readU16(), 0, 'String must end with trailing zero');\n return value;\n default:\n throw new assert.AssertionError({ message: `Unsupported encoding '${encoding}'` });\n }\n }\n\n readChunkHeader(): {\n startOffset: number;\n chunkType: number;\n headerSize: number;\n chunkSize: number;\n } {\n return {\n startOffset: this.cursor,\n chunkType: this.readU16(),\n headerSize: this.readU16(),\n chunkSize: this.readU32(),\n };\n }\n\n readStringPool(header: any): null {\n header.stringCount = this.readU32();\n header.styleCount = this.readU32();\n header.flags = this.readU32();\n header.stringsStart = this.readU32();\n header.stylesStart = this.readU32();\n\n if (header.chunkType !== ChunkType.STRING_POOL) {\n throw new assert.AssertionError({ message: 'Invalid string pool header' });\n }\n\n const offsets = [];\n for (let i = 0, l = header.stringCount; i < l; ++i) {\n offsets.push(this.readU32());\n }\n\n const encoding = (header.flags & StringFlags.UTF8) === StringFlags.UTF8 ? 'utf-8' : 'ucs2';\n\n const stringsStart = header.startOffset + header.stringsStart;\n this.cursor = stringsStart;\n for (let i = 0, l = header.stringCount; i < l; ++i) {\n this.cursor = stringsStart + offsets[i];\n this.strings.push(this.readString(encoding));\n }\n\n // Skip styles\n this.cursor = header.startOffset + header.chunkSize;\n\n return null;\n }\n\n readResourceMap(header: any): null {\n const count = Math.floor((header.chunkSize - header.headerSize) / 4);\n for (let i = 0; i < count; ++i) {\n this.resources.push(this.readU32());\n }\n return null;\n }\n\n readXmlNamespaceStart(/* header */): null {\n this.readU32();\n this.readU32();\n this.readU32();\n this.readU32();\n\n // const line = this.readU32();\n // const commentRef = this.readU32();\n // const prefixRef = this.readS32();\n // const uriRef = this.readS32();\n\n // We don't currently care about the values, but they could\n // be accessed like so:\n //\n // namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0\n // namespaceURI.uri = this.strings[uriRef] // if uriRef > 0\n\n return null;\n }\n\n readXmlNamespaceEnd(/* header */): null {\n // debug('readXmlNamespaceEnd');\n\n this.readU32();\n this.readU32();\n this.readU32();\n this.readU32();\n\n // const line = this.readU32();\n // const commentRef = this.readU32();\n // const prefixRef = this.readS32();\n // const uriRef = this.readS32();\n\n // We don't currently care about the values, but they could\n // be accessed like so:\n //\n // namespaceURI.prefix = this.strings[prefixRef] // if prefixRef > 0\n // namespaceURI.uri = this.strings[uriRef] // if uriRef > 0\n\n return null;\n }\n\n readXmlElementStart(/* header */): any {\n // debug('readXmlElementStart');\n\n const node: any = {\n namespaceURI: null,\n nodeType: NodeType.ELEMENT_NODE,\n nodeName: null,\n attributes: [],\n childNodes: [],\n };\n\n this.readU32();\n this.readU32();\n // const line = this.readU32();\n // const commentRef = this.readU32();\n const nsRef = this.readS32();\n const nameRef = this.readS32();\n\n if (nsRef > 0) {\n node.namespaceURI = this.strings[nsRef];\n }\n\n node.nodeName = this.strings[nameRef];\n\n this.readU16();\n this.readU16();\n // const attrStart = this.readU16();\n // const attrSize = this.readU16();\n const attrCount = this.readU16();\n // const idIndex = this.readU16();\n // const classIndex = this.readU16();\n // const styleIndex = this.readU16();\n this.readU16();\n this.readU16();\n this.readU16();\n\n for (let i = 0; i < attrCount; ++i) {\n node.attributes.push(this.readXmlAttribute());\n }\n\n if (this.document) {\n this.parent.childNodes.push(node);\n this.parent = node;\n } else {\n this.document = this.parent = node;\n }\n\n this.stack.push(node);\n\n return node;\n }\n\n readXmlAttribute(): any {\n // debug('readXmlAttribute');\n\n const attr: any = {\n namespaceURI: null,\n nodeType: NodeType.ATTRIBUTE_NODE,\n nodeName: null,\n name: null,\n value: null,\n typedValue: null,\n };\n\n const nsRef = this.readS32();\n const nameRef = this.readS32();\n const valueRef = this.readS32();\n\n if (nsRef > 0) {\n attr.namespaceURI = this.strings[nsRef];\n }\n\n attr.nodeName = attr.name = this.strings[nameRef];\n\n if (valueRef > 0) {\n attr.value = this.strings[valueRef];\n }\n\n attr.typedValue = this.readTypedValue();\n\n return attr;\n }\n\n readXmlElementEnd(/* header */): null {\n // debug('readXmlCData');\n\n this.readU32();\n this.readU32();\n this.readU32();\n this.readU32();\n // const line = this.readU32();\n // const commentRef = this.readU32();\n // const nsRef = this.readS32();\n // const nameRef = this.readS32();\n\n this.stack.pop();\n this.parent = this.stack[this.stack.length - 1];\n\n return null;\n }\n\n readXmlCData(/* header */): any {\n // debug('readXmlCData');\n\n const cdata: any = {\n namespaceURI: null,\n nodeType: NodeType.CDATA_SECTION_NODE,\n nodeName: '#cdata',\n data: null,\n typedValue: null,\n };\n\n this.readU32();\n this.readU32();\n // const line = this.readU32();\n // const commentRef = this.readU32();\n const dataRef = this.readS32();\n\n if (dataRef > 0) {\n cdata.data = this.strings[dataRef];\n }\n\n cdata.typedValue = this.readTypedValue();\n\n this.parent.childNodes.push(cdata);\n\n return cdata;\n }\n\n readNull(header: any): null {\n // debug('readNull');\n this.cursor += header.chunkSize - header.headerSize;\n return null;\n }\n\n parse(): any {\n // debug('parse');\n\n const xmlHeader = this.readChunkHeader();\n if (xmlHeader.chunkType !== ChunkType.XML) {\n throw new assert.AssertionError({ message: 'Invalid XML header' });\n }\n\n while (this.cursor < this.buffer.length) {\n // debug('chunk');\n const start = this.cursor;\n const header = this.readChunkHeader();\n switch (header.chunkType) {\n case ChunkType.STRING_POOL:\n this.readStringPool(header);\n break;\n case ChunkType.XML_RESOURCE_MAP:\n this.readResourceMap(header);\n break;\n case ChunkType.XML_START_NAMESPACE:\n this.readXmlNamespaceStart();\n break;\n case ChunkType.XML_END_NAMESPACE:\n this.readXmlNamespaceEnd();\n break;\n case ChunkType.XML_START_ELEMENT:\n this.readXmlElementStart();\n break;\n case ChunkType.XML_END_ELEMENT:\n this.readXmlElementEnd();\n break;\n case ChunkType.XML_CDATA:\n this.readXmlCData();\n break;\n case ChunkType.NULL:\n this.readNull(header);\n break;\n default:\n throw new assert.AssertionError({\n message: `Unsupported chunk type '${header.chunkType}'`,\n });\n }\n\n // Ensure we consume the whole chunk\n const end = start + header.chunkSize;\n if (this.cursor !== end) {\n // const diff = end - this.cursor;\n // const type = header.chunkType.toString(16);\n // debug(`Cursor is off by ${diff} bytes at ${this.cursor} at supposed \\\n // end of chunk of type 0x${type}. The chunk started at offset ${start} and is \\\n // supposed to end at offset ${end}. Ignoring the rest of the chunk.`);\n // this.cursor = end;\n }\n }\n\n return this.document;\n }\n}\n"]}
|