adbkit-apkreader
Advanced tools
Comparing version 3.0.2 to 3.1.0
# Changelog | ||
## 3.1.0 (2018-09-27) | ||
### Fixes | ||
* Fixed parsing of certain APKs that deduplicate items in the string pool. | ||
### Enhancements | ||
* Optional structured debug output can be enabled by passing `debug: true` to `.readManifest()` or `.readXml()`. | ||
## 3.0.2 (2018-07-11) | ||
@@ -4,0 +14,0 @@ |
@@ -101,11 +101,11 @@ 'use strict' | ||
readManifest() { | ||
readManifest(options = {}) { | ||
return this.usingFile(ApkReader.MANIFEST, content => { | ||
return new ManifestParser(content).parse() | ||
return new ManifestParser(content, options).parse() | ||
}) | ||
} | ||
readXml(path) { | ||
readXml(path, options = {}) { | ||
return this.usingFile(path, content => { | ||
return new BinaryXmlParser(content).parse() | ||
return new BinaryXmlParser(content, options).parse() | ||
}) | ||
@@ -112,0 +112,0 @@ } |
@@ -5,2 +5,5 @@ 'use strict' | ||
/*eslint no-console: "off"*/ | ||
const assert = require('assert') | ||
const debug = require('debug')('adb:apkreader:parser:binaryxml') | ||
@@ -80,3 +83,3 @@ | ||
class BinaryXmlParser { | ||
constructor(buffer) { | ||
constructor(buffer, options = {}) { | ||
this.buffer = buffer | ||
@@ -89,7 +92,12 @@ this.cursor = 0 | ||
this.stack = [] | ||
this.debug = options.debug || false | ||
} | ||
readU8() { | ||
this.debug && console.group('readU8') | ||
this.debug && console.debug('cursor:', this.cursor) | ||
const val = this.buffer[this.cursor] | ||
this.debug && console.debug('value:', val) | ||
this.cursor += 1 | ||
this.debug && console.groupEnd() | ||
return val | ||
@@ -99,4 +107,8 @@ } | ||
readU16() { | ||
this.debug && console.group('readU16') | ||
this.debug && console.debug('cursor:', this.cursor) | ||
const val = this.buffer.readUInt16LE(this.cursor) | ||
this.debug && console.debug('value:', val) | ||
this.cursor += 2 | ||
this.debug && console.groupEnd() | ||
return val | ||
@@ -106,4 +118,8 @@ } | ||
readS32() { | ||
this.debug && console.group('readS32') | ||
this.debug && console.debug('cursor:', this.cursor) | ||
const val = this.buffer.readInt32LE(this.cursor) | ||
this.debug && console.debug('value:', val) | ||
this.cursor += 4 | ||
this.debug && console.groupEnd() | ||
return val | ||
@@ -113,4 +129,8 @@ } | ||
readU32() { | ||
this.debug && console.group('readU32') | ||
this.debug && console.debug('cursor:', this.cursor) | ||
const val = this.buffer.readUInt32LE(this.cursor) | ||
this.debug && console.debug('value:', val) | ||
this.cursor += 4 | ||
this.debug && console.groupEnd() | ||
return val | ||
@@ -120,2 +140,3 @@ } | ||
readLength8() { | ||
this.debug && console.group('readLength8') | ||
let len = this.readU8() | ||
@@ -126,2 +147,4 @@ if (len & 0x80) { | ||
} | ||
this.debug && console.debug('length:', len) | ||
this.debug && console.groupEnd() | ||
return len | ||
@@ -131,2 +154,3 @@ } | ||
readLength16() { | ||
this.debug && console.group('readLength16') | ||
let len = this.readU16() | ||
@@ -137,2 +161,4 @@ if (len & 0x8000) { | ||
} | ||
this.debug && console.debug('length:', len) | ||
this.debug && console.groupEnd() | ||
return len | ||
@@ -142,2 +168,4 @@ } | ||
readDimension() { | ||
this.debug && console.group('readDimension') | ||
const dimension = { | ||
@@ -176,2 +204,4 @@ value: null, | ||
this.debug && console.groupEnd() | ||
return dimension | ||
@@ -181,2 +211,4 @@ } | ||
readFraction() { | ||
this.debug && console.group('readFraction') | ||
const fraction = { | ||
@@ -203,2 +235,4 @@ value: null, | ||
this.debug && console.groupEnd() | ||
return fraction | ||
@@ -208,10 +242,18 @@ } | ||
readHex24() { | ||
return (this.readU32() & 0xffffff).toString(16) | ||
this.debug && console.group('readHex24') | ||
var val = (this.readU32() & 0xffffff).toString(16) | ||
this.debug && console.groupEnd() | ||
return val | ||
} | ||
readHex32() { | ||
return this.readU32().toString(16) | ||
this.debug && console.group('readHex32') | ||
var val = this.readU32().toString(16) | ||
this.debug && console.groupEnd() | ||
return val | ||
} | ||
readTypedValue() { | ||
this.debug && console.group('readTypedValue') | ||
const typedValue = { | ||
@@ -308,2 +350,4 @@ value: null, | ||
this.debug && console.groupEnd() | ||
return typedValue | ||
@@ -320,14 +364,23 @@ } | ||
readString(encoding) { | ||
this.debug && console.group('readString', encoding) | ||
switch (encoding) { | ||
case 'utf-8': | ||
var stringLength = this.readLength8(encoding) | ||
this.debug && console.debug('stringLength:', stringLength) | ||
var byteLength = this.readLength8(encoding) | ||
this.debug && console.debug('byteLength:', byteLength) | ||
var value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength)) | ||
this.readU8() // Trailing zero | ||
this.debug && console.debug('value:', value) | ||
assert.equal(this.readU8(), 0, 'String must end with trailing zero') | ||
this.debug && console.groupEnd() | ||
return value | ||
case 'ucs2': | ||
stringLength = this.readLength16(encoding) | ||
this.debug && console.debug('stringLength:', stringLength) | ||
byteLength = stringLength * 2 | ||
this.debug && console.debug('byteLength:', byteLength) | ||
value = this.buffer.toString(encoding, this.cursor, (this.cursor += byteLength)) | ||
this.readU16() // Trailing zero | ||
this.debug && console.debug('value:', value) | ||
assert.equal(this.readU16(), 0, 'String must end with trailing zero') | ||
this.debug && console.groupEnd() | ||
return value | ||
@@ -340,3 +393,5 @@ default: | ||
readChunkHeader() { | ||
return { | ||
this.debug && console.group('readChunkHeader') | ||
var header = { | ||
startOffset: this.cursor, | ||
chunkType: this.readU16(), | ||
@@ -346,10 +401,23 @@ headerSize: this.readU16(), | ||
} | ||
this.debug && console.debug('startOffset:', header.startOffset) | ||
this.debug && console.debug('chunkType:', header.chunkType) | ||
this.debug && console.debug('headerSize:', header.headerSize) | ||
this.debug && console.debug('chunkSize:', header.chunkSize) | ||
this.debug && console.groupEnd() | ||
return header | ||
} | ||
readStringPool(header) { | ||
this.debug && console.group('readStringPool') | ||
header.stringCount = this.readU32() | ||
this.debug && console.debug('stringCount:', header.stringCount) | ||
header.styleCount = this.readU32() | ||
this.debug && console.debug('styleCount:', header.styleCount) | ||
header.flags = this.readU32() | ||
this.debug && console.debug('flags:', header.flags) | ||
header.stringsStart = this.readU32() | ||
this.debug && console.debug('stringsStart:', header.stringsStart) | ||
header.stylesStart = this.readU32() | ||
this.debug && console.debug('stylesStart:', header.stylesStart) | ||
@@ -360,16 +428,21 @@ if (header.chunkType !== ChunkType.STRING_POOL) { | ||
const anchor = this.cursor | ||
const offsets = [] | ||
for (let i = 0, l = header.stringCount; i < l; ++i) { | ||
this.debug && console.debug('offset:', i) | ||
offsets.push(this.readU32()) | ||
} | ||
// sorted = (header.flags & StringFlags.SORTED) === StringFlags.SORTED | ||
const sorted = (header.flags & StringFlags.SORTED) === StringFlags.SORTED | ||
this.debug && console.debug('sorted:', sorted) | ||
const encoding = (header.flags & StringFlags.UTF8) === StringFlags.UTF8 | ||
? 'utf-8' | ||
: 'ucs2' | ||
this.debug && console.debug('encoding:', encoding) | ||
this.cursor = (anchor + header.stringsStart) - header.headerSize | ||
const stringsStart = header.startOffset + header.stringsStart | ||
this.cursor = stringsStart | ||
for (let i = 0, l = header.stringCount; i < l; ++i) { | ||
this.debug && console.debug('string:', i) | ||
this.debug && console.debug('offset:', offsets[i]) | ||
this.cursor = stringsStart + offsets[i] | ||
this.strings.push(this.readString(encoding)) | ||
@@ -379,4 +452,6 @@ } | ||
// Skip styles | ||
this.cursor = (anchor + header.chunkSize) - header.headerSize | ||
this.cursor = header.startOffset + header.chunkSize | ||
this.debug && console.groupEnd() | ||
return null | ||
@@ -386,2 +461,3 @@ } | ||
readResourceMap(header) { | ||
this.debug && console.group('readResourceMap') | ||
const count = Math.floor((header.chunkSize - header.headerSize) / 4) | ||
@@ -391,2 +467,3 @@ for (let i = 0; i < count; ++i) { | ||
} | ||
this.debug && console.groupEnd() | ||
return null | ||
@@ -396,2 +473,4 @@ } | ||
readXmlNamespaceStart(/* header */) { | ||
this.debug && console.group('readXmlNamespaceStart') | ||
/* const line = */ this.readU32() | ||
@@ -408,2 +487,4 @@ /* const commentRef = */ this.readU32() | ||
this.debug && console.groupEnd() | ||
return null | ||
@@ -413,2 +494,4 @@ } | ||
readXmlNamespaceEnd(/* header */) { | ||
this.debug && console.group('readXmlNamespaceEnd') | ||
/* const line = */ this.readU32() | ||
@@ -425,2 +508,4 @@ /* const commentRef = */ this.readU32() | ||
this.debug && console.groupEnd() | ||
return null | ||
@@ -430,2 +515,4 @@ } | ||
readXmlElementStart(/* header */) { | ||
this.debug && console.group('readXmlElementStart') | ||
const node = { | ||
@@ -470,2 +557,4 @@ namespaceURI: null, | ||
this.debug && console.groupEnd() | ||
return node | ||
@@ -475,2 +564,4 @@ } | ||
readXmlAttribute() { | ||
this.debug && console.group('readXmlAttribute') | ||
const attr = { | ||
@@ -501,2 +592,4 @@ namespaceURI: null, | ||
this.debug && console.groupEnd() | ||
return attr | ||
@@ -506,2 +599,4 @@ } | ||
readXmlElementEnd(/* header */) { | ||
this.debug && console.group('readXmlCData') | ||
/* const line = */ this.readU32() | ||
@@ -515,2 +610,4 @@ /* const commentRef = */ this.readU32() | ||
this.debug && console.groupEnd() | ||
return null | ||
@@ -520,2 +617,4 @@ } | ||
readXmlCData(/* header */) { | ||
this.debug && console.group('readXmlCData') | ||
const cdata = { | ||
@@ -541,2 +640,4 @@ namespaceURI: null, | ||
this.debug && console.groupEnd() | ||
return cdata | ||
@@ -546,3 +647,5 @@ } | ||
readNull(header) { | ||
this.debug && console.group('readNull') | ||
this.cursor += header.chunkSize - header.headerSize | ||
this.debug && console.groupEnd() | ||
return null | ||
@@ -552,2 +655,4 @@ } | ||
parse() { | ||
this.debug && console.group('BinaryXmlParser.parse') | ||
const xmlHeader = this.readChunkHeader() | ||
@@ -559,2 +664,3 @@ if (xmlHeader.chunkType !== ChunkType.XML) { | ||
while (this.cursor < this.buffer.length) { | ||
this.debug && console.group('chunk') | ||
const start = this.cursor | ||
@@ -601,4 +707,8 @@ const header = this.readChunkHeader() | ||
} | ||
this.debug && console.groupEnd() | ||
} | ||
this.debug && console.groupEnd() | ||
return this.document | ||
@@ -605,0 +715,0 @@ } |
@@ -10,5 +10,5 @@ 'use strict' | ||
class ManifestParser { | ||
constructor(buffer) { | ||
constructor(buffer, options = {}) { | ||
this.buffer = buffer | ||
this.xmlParser = new BinaryXmlParser(this.buffer) | ||
this.xmlParser = new BinaryXmlParser(this.buffer, options) | ||
} | ||
@@ -15,0 +15,0 @@ |
{ | ||
"name": "adbkit-apkreader", | ||
"version": "3.0.2", | ||
"version": "3.1.0", | ||
"description": "Extracts information from APK files.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38327
853