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,86 @@
1
+ 'use strict';
2
+
3
+ const Zip = require('./zip');
4
+ const { mapInfoResource, findApkIconPath, getBase64FromBuffer } = require('./utils');
5
+ const ManifestName = /^androidmanifest\.xml$/;
6
+ const ResourceName = /^resources\.arsc$/;
7
+
8
+ const ManifestXmlParser = require('./xml-parser/manifest');
9
+ const ResourceFinder = require('./resource-finder');
10
+
11
+ class ApkParser extends Zip {
12
+ /**
13
+ * parser for parsing .apk file
14
+ * @param {String | File | Blob} file // file's path in Node, instance of File or Blob in Browser
15
+ */
16
+ constructor(file) {
17
+ super(file);
18
+ if (!(this instanceof ApkParser)) {
19
+ return new ApkParser(file);
20
+ }
21
+ }
22
+ parse() {
23
+ return new Promise((resolve, reject) => {
24
+ this.getEntries([ManifestName, ResourceName]).then(buffers => {
25
+ if (!buffers[ManifestName]) {
26
+ throw new Error('AndroidManifest.xml can\'t be found.');
27
+ }
28
+ let apkInfo = this._parseManifest(buffers[ManifestName]);
29
+ let resourceMap;
30
+ if (!buffers[ResourceName]) {
31
+ resolve(apkInfo);
32
+ } else {
33
+ // parse resourceMap
34
+ resourceMap = this._parseResourceMap(buffers[ResourceName]);
35
+ // update apkInfo with resourceMap
36
+ apkInfo = mapInfoResource(apkInfo, resourceMap);
37
+
38
+ // find icon path and parse icon
39
+ const iconPath = findApkIconPath(apkInfo);
40
+ if (iconPath) {
41
+ this.getEntry(iconPath).then(iconBuffer => {
42
+ apkInfo.icon = iconBuffer ? getBase64FromBuffer(iconBuffer) : null;
43
+ resolve(apkInfo);
44
+ }).catch(e => {
45
+ apkInfo.icon = null;
46
+ resolve(apkInfo);
47
+ console.warn('[Warning] failed to parse icon: ', e);
48
+ });
49
+ } else {
50
+ apkInfo.icon = null;
51
+ resolve(apkInfo);
52
+ }
53
+ }
54
+ }).catch(e => {
55
+ reject(e);
56
+ });
57
+ });
58
+ }
59
+ /**
60
+ * Parse manifest
61
+ * @param {Buffer} buffer // manifest file's buffer
62
+ */
63
+ _parseManifest(buffer) {
64
+ try {
65
+ const parser = new ManifestXmlParser(buffer, {
66
+ ignore: ['application.activity', 'application.service', 'application.receiver', 'application.provider', 'permission-group']
67
+ });
68
+ return parser.parse();
69
+ } catch (e) {
70
+ throw new Error('Parse AndroidManifest.xml error: ', e);
71
+ }
72
+ }
73
+ /**
74
+ * Parse resourceMap
75
+ * @param {Buffer} buffer // resourceMap file's buffer
76
+ */
77
+ _parseResourceMap(buffer) {
78
+ try {
79
+ return new ResourceFinder().processResourceTable(buffer);
80
+ } catch (e) {
81
+ throw new Error('Parser resources.arsc error: ' + e);
82
+ }
83
+ }
84
+ }
85
+
86
+ module.exports = ApkParser;
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const ApkParser = require('./apk');
4
+ const IpaParser = require('./ipa');
5
+ const supportFileTypes = ['ipa', 'apk'];
6
+
7
+ class AppInfoParser {
8
+ /**
9
+ * parser for parsing .ipa or .apk file
10
+ * @param {String | File | Blob} file // file's path in Node, instance of File or Blob in Browser
11
+ */
12
+ constructor(file) {
13
+ if (!file) {
14
+ throw new Error('Param miss: file(file\'s path in Node, instance of File or Blob in browser).');
15
+ }
16
+ const splits = (file.name || file).split('.');
17
+ const fileType = splits[splits.length - 1].toLowerCase();
18
+ if (!supportFileTypes.includes(fileType)) {
19
+ throw new Error('Unsupported file type, only support .ipa or .apk file.');
20
+ }
21
+ this.file = file;
22
+
23
+ switch (fileType) {
24
+ case 'ipa':
25
+ this.parser = new IpaParser(this.file);
26
+ break;
27
+ case 'apk':
28
+ this.parser = new ApkParser(this.file);
29
+ break;
30
+ }
31
+ }
32
+ parse() {
33
+ return this.parser.parse();
34
+ }
35
+ }
36
+
37
+ module.exports = AppInfoParser;
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
4
+
5
+ const parsePlist = require('plist').parse;
6
+ const parseBplist = require('bplist-parser').parseBuffer;
7
+ const cgbiToPng = require('cgbi-to-png');
8
+
9
+ const Zip = require('./zip');
10
+ const { findIpaIconPath, getBase64FromBuffer, isBrowser } = require('./utils');
11
+
12
+ const PlistName = new RegExp('payload/[^/]+?.app/info.plist$', 'i');
13
+ const ProvisionName = /payload\/.+?\.app\/embedded.mobileprovision/;
14
+
15
+ class IpaParser extends Zip {
16
+ /**
17
+ * parser for parsing .ipa file
18
+ * @param {String | File | Blob} file // file's path in Node, instance of File or Blob in Browser
19
+ */
20
+ constructor(file) {
21
+ super(file);
22
+ if (!(this instanceof IpaParser)) {
23
+ return new IpaParser(file);
24
+ }
25
+ }
26
+ parse() {
27
+ return new Promise((resolve, reject) => {
28
+ this.getEntries([PlistName, ProvisionName]).then(buffers => {
29
+ if (!buffers[PlistName]) {
30
+ throw new Error('Info.plist can\'t be found.');
31
+ }
32
+ const plistInfo = this._parsePlist(buffers[PlistName]);
33
+ // parse mobile provision
34
+ const provisionInfo = this._parseProvision(buffers[ProvisionName]);
35
+ plistInfo.mobileProvision = provisionInfo;
36
+
37
+ // find icon path and parse icon
38
+ const iconRegex = new RegExp(findIpaIconPath(plistInfo).toLowerCase());
39
+ this.getEntry(iconRegex).then(iconBuffer => {
40
+ try {
41
+ // In general, the ipa file's icon has been specially processed, should be converted
42
+ plistInfo.icon = iconBuffer ? getBase64FromBuffer(cgbiToPng.revert(iconBuffer)) : null;
43
+ } catch (err) {
44
+ if (isBrowser()) {
45
+ // Normal conversion in other cases
46
+ plistInfo.icon = iconBuffer ? getBase64FromBuffer(window.btoa(String.fromCharCode.apply(String, _toConsumableArray(iconBuffer)))) : null;
47
+ } else {
48
+ plistInfo.icon = null;
49
+ console.warn('[Warning] failed to parse icon: ', err);
50
+ }
51
+ }
52
+ resolve(plistInfo);
53
+ }).catch(e => {
54
+ reject(e);
55
+ });
56
+ }).catch(e => {
57
+ reject(e);
58
+ });
59
+ });
60
+ }
61
+ /**
62
+ * Parse plist
63
+ * @param {Buffer} buffer // plist file's buffer
64
+ */
65
+ _parsePlist(buffer) {
66
+ let result;
67
+ const bufferType = buffer[0];
68
+ if (bufferType === 60 || bufferType === '<' || bufferType === 239) {
69
+ result = parsePlist(buffer.toString());
70
+ } else if (bufferType === 98) {
71
+ result = parseBplist(buffer)[0];
72
+ } else {
73
+ throw new Error('Unknown plist buffer type.');
74
+ }
75
+ return result;
76
+ }
77
+ /**
78
+ * parse provision
79
+ * @param {Buffer} buffer // provision file's buffer
80
+ */
81
+ _parseProvision(buffer) {
82
+ let info = {};
83
+ if (buffer) {
84
+ let content = buffer.toString('utf-8');
85
+ const firstIndex = content.indexOf('<?xml');
86
+ const endIndex = content.indexOf('</plist>');
87
+ content = content.slice(firstIndex, endIndex + 8);
88
+ if (content) {
89
+ info = parsePlist(content);
90
+ }
91
+ }
92
+ return info;
93
+ }
94
+ }
95
+
96
+ module.exports = IpaParser;
@@ -0,0 +1,486 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Code translated from a C# project https://github.com/hylander0/Iteedee.ApkReader/blob/master/Iteedee.ApkReader/ApkResourceFinder.cs
5
+ *
6
+ * Decode binary file `resources.arsc` from a .apk file to a JavaScript Object.
7
+ */
8
+
9
+ var ByteBuffer = require("bytebuffer");
10
+
11
+ var DEBUG = false;
12
+
13
+ var RES_STRING_POOL_TYPE = 0x0001;
14
+ var RES_TABLE_TYPE = 0x0002;
15
+ var RES_TABLE_PACKAGE_TYPE = 0x0200;
16
+ var RES_TABLE_TYPE_TYPE = 0x0201;
17
+ var RES_TABLE_TYPE_SPEC_TYPE = 0x0202;
18
+
19
+ // The 'data' holds a ResTable_ref, a reference to another resource
20
+ // table entry.
21
+ var TYPE_REFERENCE = 0x01;
22
+ // The 'data' holds an index into the containing resource table's
23
+ // global value string pool.
24
+ var TYPE_STRING = 0x03;
25
+
26
+ function ResourceFinder() {
27
+ this.valueStringPool = null;
28
+ this.typeStringPool = null;
29
+ this.keyStringPool = null;
30
+
31
+ this.package_id = 0;
32
+
33
+ this.responseMap = {};
34
+ this.entryMap = {};
35
+ }
36
+
37
+ /**
38
+ * Same to C# BinaryReader.readBytes
39
+ *
40
+ * @param bb ByteBuffer
41
+ * @param len length
42
+ * @returns {Buffer}
43
+ */
44
+ ResourceFinder.readBytes = function (bb, len) {
45
+ var uint8Array = new Uint8Array(len);
46
+ for (var i = 0; i < len; i++) {
47
+ uint8Array[i] = bb.readUint8();
48
+ }
49
+
50
+ return ByteBuffer.wrap(uint8Array, "binary", true);
51
+ };
52
+
53
+ //
54
+ /**
55
+ *
56
+ * @param {ByteBuffer} bb
57
+ * @return {Map<String, Set<String>>}
58
+ */
59
+ ResourceFinder.prototype.processResourceTable = function (resourceBuffer) {
60
+ const bb = ByteBuffer.wrap(resourceBuffer, "binary", true);
61
+
62
+ // Resource table structure
63
+ var type = bb.readShort(),
64
+ headerSize = bb.readShort(),
65
+ size = bb.readInt(),
66
+ packageCount = bb.readInt(),
67
+ buffer,
68
+ bb2;
69
+ if (type != RES_TABLE_TYPE) {
70
+ throw new Error("No RES_TABLE_TYPE found!");
71
+ }
72
+ if (size != bb.limit) {
73
+ throw new Error("The buffer size not matches to the resource table size.");
74
+ }
75
+ bb.offset = headerSize;
76
+
77
+ var realStringPoolCount = 0,
78
+ realPackageCount = 0;
79
+
80
+ while (true) {
81
+ var pos, t, hs, s;
82
+ try {
83
+ pos = bb.offset;
84
+ t = bb.readShort();
85
+ hs = bb.readShort();
86
+ s = bb.readInt();
87
+ } catch (e) {
88
+ break;
89
+ }
90
+ if (t == RES_STRING_POOL_TYPE) {
91
+ // Process the string pool
92
+ if (realStringPoolCount == 0) {
93
+ // Only the first string pool is processed.
94
+ if (DEBUG) {
95
+ console.log("Processing the string pool ...");
96
+ }
97
+
98
+ buffer = new ByteBuffer(s);
99
+ bb.offset = pos;
100
+ bb.prependTo(buffer);
101
+
102
+ bb2 = ByteBuffer.wrap(buffer, "binary", true);
103
+
104
+ bb2.LE();
105
+ this.valueStringPool = this.processStringPool(bb2);
106
+ }
107
+ realStringPoolCount++;
108
+ } else if (t == RES_TABLE_PACKAGE_TYPE) {
109
+ // Process the package
110
+ if (DEBUG) {
111
+ console.log("Processing the package " + realPackageCount + " ...");
112
+ }
113
+
114
+ buffer = new ByteBuffer(s);
115
+ bb.offset = pos;
116
+ bb.prependTo(buffer);
117
+
118
+ bb2 = ByteBuffer.wrap(buffer, "binary", true);
119
+ bb2.LE();
120
+ this.processPackage(bb2);
121
+
122
+ realPackageCount++;
123
+ } else {
124
+ throw new Error("Unsupported type");
125
+ }
126
+ bb.offset = pos + s;
127
+ if (!bb.remaining()) break;
128
+ }
129
+
130
+ if (realStringPoolCount != 1) {
131
+ throw new Error("More than 1 string pool found!");
132
+ }
133
+ if (realPackageCount != packageCount) {
134
+ throw new Error("Real package count not equals the declared count.");
135
+ }
136
+
137
+ return this.responseMap;
138
+ };
139
+
140
+ /**
141
+ *
142
+ * @param {ByteBuffer} bb
143
+ */
144
+ ResourceFinder.prototype.processPackage = function (bb) {
145
+ // Package structure
146
+ var type = bb.readShort(),
147
+ headerSize = bb.readShort(),
148
+ size = bb.readInt(),
149
+ id = bb.readInt();
150
+
151
+ this.package_id = id;
152
+
153
+ for (var i = 0; i < 256; ++i) {
154
+ bb.readUint8();
155
+ }
156
+
157
+ var typeStrings = bb.readInt(),
158
+ lastPublicType = bb.readInt(),
159
+ keyStrings = bb.readInt(),
160
+ lastPublicKey = bb.readInt();
161
+
162
+ if (typeStrings != headerSize) {
163
+ throw new Error("TypeStrings must immediately following the package structure header.");
164
+ }
165
+
166
+ if (DEBUG) {
167
+ console.log("Type strings:");
168
+ }
169
+
170
+ var lastPosition = bb.offset;
171
+ bb.offset = typeStrings;
172
+ var bbTypeStrings = ResourceFinder.readBytes(bb, bb.limit - bb.offset);
173
+ bb.offset = lastPosition;
174
+ this.typeStringPool = this.processStringPool(bbTypeStrings);
175
+
176
+ // Key strings
177
+ if (DEBUG) {
178
+ console.log("Key strings:");
179
+ }
180
+
181
+ bb.offset = keyStrings;
182
+ var key_type = bb.readShort(),
183
+ key_headerSize = bb.readShort(),
184
+ key_size = bb.readInt();
185
+
186
+ lastPosition = bb.offset;
187
+ bb.offset = keyStrings;
188
+ var bbKeyStrings = ResourceFinder.readBytes(bb, bb.limit - bb.offset);
189
+ bb.offset = lastPosition;
190
+ this.keyStringPool = this.processStringPool(bbKeyStrings);
191
+
192
+ // Iterate through all chunks
193
+ var typeSpecCount = 0;
194
+ var typeCount = 0;
195
+
196
+ bb.offset = keyStrings + key_size;
197
+
198
+ var bb2;
199
+
200
+ while (true) {
201
+ var pos = bb.offset;
202
+ try {
203
+ var t = bb.readShort();
204
+ var hs = bb.readShort();
205
+ var s = bb.readInt();
206
+ } catch (e) {
207
+ break;
208
+ }
209
+
210
+ if (t == RES_TABLE_TYPE_SPEC_TYPE) {
211
+ bb.offset = pos;
212
+ bb2 = ResourceFinder.readBytes(bb, s);
213
+ this.processTypeSpec(bb2);
214
+
215
+ typeSpecCount++;
216
+ } else if (t == RES_TABLE_TYPE_TYPE) {
217
+ bb.offset = pos;
218
+ bb2 = ResourceFinder.readBytes(bb, s);
219
+ this.processType(bb2);
220
+
221
+ typeCount++;
222
+ }
223
+
224
+ if (s == 0) {
225
+ break;
226
+ }
227
+
228
+ bb.offset = pos + s;
229
+
230
+ if (!bb.remaining()) {
231
+ break;
232
+ }
233
+ }
234
+ };
235
+
236
+ /**
237
+ *
238
+ * @param {ByteBuffer} bb
239
+ */
240
+ ResourceFinder.prototype.processType = function (bb) {
241
+ var type = bb.readShort(),
242
+ headerSize = bb.readShort(),
243
+ size = bb.readInt(),
244
+ id = bb.readByte(),
245
+ res0 = bb.readByte(),
246
+ res1 = bb.readShort(),
247
+ entryCount = bb.readInt(),
248
+ entriesStart = bb.readInt();
249
+
250
+ var refKeys = {};
251
+
252
+ var config_size = bb.readInt();
253
+
254
+ // Skip the config data
255
+ bb.offset = headerSize;
256
+
257
+ if (headerSize + entryCount * 4 != entriesStart) {
258
+ throw new Error("HeaderSize, entryCount and entriesStart are not valid.");
259
+ }
260
+
261
+ // Start to get entry indices
262
+ var entryIndices = new Array(entryCount);
263
+ for (var i = 0; i < entryCount; ++i) {
264
+ entryIndices[i] = bb.readInt();
265
+ }
266
+
267
+ // Get entries
268
+ for (var i = 0; i < entryCount; ++i) {
269
+ if (entryIndices[i] == -1) continue;
270
+
271
+ var resource_id = this.package_id << 24 | id << 16 | i;
272
+
273
+ var pos = bb.offset,
274
+ entry_size,
275
+ entry_flag,
276
+ entry_key,
277
+ value_size,
278
+ value_res0,
279
+ value_dataType,
280
+ value_data;
281
+ try {
282
+ entry_size = bb.readShort();
283
+ entry_flag = bb.readShort();
284
+ entry_key = bb.readInt();
285
+ } catch (e) {
286
+ break;
287
+ }
288
+
289
+ // Get the value (simple) or map (complex)
290
+
291
+ var FLAG_COMPLEX = 0x0001;
292
+ if ((entry_flag & FLAG_COMPLEX) == 0) {
293
+ // Simple case
294
+ value_size = bb.readShort();
295
+ value_res0 = bb.readByte();
296
+ value_dataType = bb.readByte();
297
+ value_data = bb.readInt();
298
+
299
+ var idStr = Number(resource_id).toString(16);
300
+ var keyStr = this.keyStringPool[entry_key];
301
+
302
+ var data = null;
303
+
304
+ if (DEBUG) {
305
+ console.log("Entry 0x" + idStr + ", key: " + keyStr + ", simple value type: ");
306
+ }
307
+
308
+ var key = parseInt(idStr, 16);
309
+
310
+ var entryArr = this.entryMap[key];
311
+ if (entryArr == null) {
312
+ entryArr = [];
313
+ }
314
+ entryArr.push(keyStr);
315
+
316
+ this.entryMap[key] = entryArr;
317
+
318
+ if (value_dataType == TYPE_STRING) {
319
+ data = this.valueStringPool[value_data];
320
+
321
+ if (DEBUG) {
322
+ console.log(", data: " + this.valueStringPool[value_data] + "");
323
+ }
324
+ } else if (value_dataType == TYPE_REFERENCE) {
325
+ var hexIndex = Number(value_data).toString(16);
326
+
327
+ refKeys[idStr] = value_data;
328
+ } else {
329
+ data = "" + value_data;
330
+ if (DEBUG) {
331
+ console.log(", data: " + value_data + "");
332
+ }
333
+ }
334
+
335
+ this.putIntoMap("@" + idStr, data);
336
+ } else {
337
+ // Complex case
338
+ var entry_parent = bb.readInt();
339
+ var entry_count = bb.readInt();
340
+
341
+ for (var j = 0; j < entry_count; ++j) {
342
+ var ref_name = bb.readInt();
343
+ value_size = bb.readShort();
344
+ value_res0 = bb.readByte();
345
+ value_dataType = bb.readByte();
346
+ value_data = bb.readInt();
347
+ }
348
+
349
+ if (DEBUG) {
350
+ console.log("Entry 0x" + Number(resource_id).toString(16) + ", key: " + this.keyStringPool[entry_key] + ", complex value, not printed.");
351
+ }
352
+ }
353
+ }
354
+
355
+ for (var refK in refKeys) {
356
+ var values = this.responseMap["@" + Number(refKeys[refK]).toString(16).toUpperCase()];
357
+ if (values != null && Object.keys(values).length < 1000) {
358
+ for (var value in values) {
359
+ this.putIntoMap("@" + refK, values[value]);
360
+ }
361
+ }
362
+ }
363
+ };
364
+
365
+ /**
366
+ *
367
+ * @param {ByteBuffer} bb
368
+ * @return {Array}
369
+ */
370
+ ResourceFinder.prototype.processStringPool = function (bb) {
371
+ // String pool structure
372
+ //
373
+ var type = bb.readShort(),
374
+ headerSize = bb.readShort(),
375
+ size = bb.readInt(),
376
+ stringCount = bb.readInt(),
377
+ styleCount = bb.readInt(),
378
+ flags = bb.readInt(),
379
+ stringsStart = bb.readInt(),
380
+ stylesStart = bb.readInt(),
381
+ u16len,
382
+ buffer;
383
+
384
+ var isUTF_8 = (flags & 256) != 0;
385
+
386
+ var offsets = new Array(stringCount);
387
+ for (var i = 0; i < stringCount; ++i) {
388
+ offsets[i] = bb.readInt();
389
+ }
390
+
391
+ var strings = new Array(stringCount);
392
+
393
+ for (var i = 0; i < stringCount; ++i) {
394
+ var pos = stringsStart + offsets[i];
395
+ bb.offset = pos;
396
+
397
+ strings[i] = "";
398
+
399
+ if (isUTF_8) {
400
+ u16len = bb.readUint8();
401
+
402
+ if ((u16len & 0x80) != 0) {
403
+ u16len = ((u16len & 0x7f) << 8) + bb.readUint8();
404
+ }
405
+
406
+ var u8len = bb.readUint8();
407
+ if ((u8len & 0x80) != 0) {
408
+ u8len = ((u8len & 0x7f) << 8) + bb.readUint8();
409
+ }
410
+
411
+ if (u8len > 0) {
412
+ buffer = ResourceFinder.readBytes(bb, u8len);
413
+ try {
414
+ strings[i] = ByteBuffer.wrap(buffer, "utf8", true).toString("utf8");
415
+ } catch (e) {
416
+ if (DEBUG) {
417
+ console.error(e);
418
+ console.log("Error when turning buffer to utf-8 string.");
419
+ }
420
+ }
421
+ } else {
422
+ strings[i] = "";
423
+ }
424
+ } else {
425
+ u16len = bb.readUint16();
426
+ if ((u16len & 0x8000) != 0) {
427
+ // larger than 32768
428
+ u16len = ((u16len & 0x7fff) << 16) + bb.readUint16();
429
+ }
430
+
431
+ if (u16len > 0) {
432
+ var len = u16len * 2;
433
+ buffer = ResourceFinder.readBytes(bb, len);
434
+ try {
435
+ strings[i] = ByteBuffer.wrap(buffer, "utf8", true).toString("utf8");
436
+ } catch (e) {
437
+ if (DEBUG) {
438
+ console.error(e);
439
+ console.log("Error when turning buffer to utf-8 string.");
440
+ }
441
+ }
442
+ }
443
+ }
444
+
445
+ if (DEBUG) {
446
+ console.log("Parsed value: {0}", strings[i]);
447
+ }
448
+ }
449
+
450
+ return strings;
451
+ };
452
+
453
+ /**
454
+ *
455
+ * @param {ByteBuffer} bb
456
+ */
457
+ ResourceFinder.prototype.processTypeSpec = function (bb) {
458
+ var type = bb.readShort(),
459
+ headerSize = bb.readShort(),
460
+ size = bb.readInt(),
461
+ id = bb.readByte(),
462
+ res0 = bb.readByte(),
463
+ res1 = bb.readShort(),
464
+ entryCount = bb.readInt();
465
+
466
+ if (DEBUG) {
467
+ console.log("Processing type spec " + this.typeStringPool[id - 1] + "...");
468
+ }
469
+
470
+ var flags = new Array(entryCount);
471
+
472
+ for (var i = 0; i < entryCount; ++i) {
473
+ flags[i] = bb.readInt();
474
+ }
475
+ };
476
+
477
+ ResourceFinder.prototype.putIntoMap = function (resId, value) {
478
+ if (this.responseMap[resId.toUpperCase()] == null) {
479
+ this.responseMap[resId.toUpperCase()] = [];
480
+ }
481
+ if (value) {
482
+ this.responseMap[resId.toUpperCase()].push(value);
483
+ }
484
+ };
485
+
486
+ module.exports = ResourceFinder;