UNPKG

node-apk

Version:

A library to parse Android application manifest and signature

154 lines (152 loc) 6.3 kB
"use strict"; /*Copyright (c) 2019 XdevL. All rights reserved. This work is licensed under the terms of the MIT license. For a copy, see <https://opensource.org/licenses/MIT>.*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.Resources = exports.Resource = exports.Locale = void 0; /*Reference implementation found at: frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.cpp*/ var common_1 = require("./common"); var Table = /** @class */ (function () { function Table(chunk) { this.packageCount = chunk.headerSource.readUInt(); this.stringPool = new common_1.StringPool(new common_1.Chunk(chunk.chunkSource, common_1.ChunkType.STRING_POOL)); this.packages = new Map(); for (var i = 0; i < this.packageCount; ++i) { var innerChunk = new common_1.Chunk(chunk.chunkSource); if (innerChunk.type === common_1.ChunkType.TABLE_PACKAGE) { var tablePackageChunk = new TablePackageChunk(innerChunk, this.stringPool); this.packages.set(tablePackageChunk.id, tablePackageChunk); } } } return Table; }()); var TablePackageChunk = /** @class */ (function () { function TablePackageChunk(chunk, stringPool) { this.id = chunk.headerSource.readUInt(); this.name = chunk.headerSource.readUtf16String(128 * 2); this.typeStrings = chunk.headerSource.readUInt(); this.lastPublicType = chunk.headerSource.readUInt(); this.keyStrings = chunk.headerSource.readUInt(); this.lastPublicKey = chunk.headerSource.readUInt(); this.types = new Map(); while (chunk.chunkSource.getCursorAndMove(0) < chunk.chunkSize - chunk.headerSize) { var innerChunk = new common_1.Chunk(chunk.chunkSource); if (innerChunk.type === common_1.ChunkType.TABLE_TYPE) { var tableTypeChunk = new TableTypeChunk(innerChunk, stringPool); TablePackageChunk.getOrCreate(this.types, tableTypeChunk.id).push(tableTypeChunk); } } } TablePackageChunk.getOrCreate = function (map, key) { return (map.has(key) ? map : map.set(key, [])).get(key); }; return TablePackageChunk; }()); var TableTypeChunk = /** @class */ (function () { function TableTypeChunk(chunk, stringPool) { this.id = chunk.headerSource.readUByte(); this.flags = chunk.headerSource.readUByte(); this.reserved = chunk.headerSource.readUShort(); this.entryCount = chunk.headerSource.readUInt(); this.entriesStart = chunk.headerSource.readUInt(); this.resTableConfig = new ResTableConfig(chunk); var indexes = []; for (var i = 0; i < this.entryCount; ++i) { indexes.push(chunk.chunkSource.readUInt()); } this.entries = new Map(); for (var i = 0; i < indexes.length; ++i) { if (indexes[i] !== TableTypeChunk.NO_ENTRY) { chunk.chunkSource.moveAt(this.entriesStart - chunk.headerSize + indexes[i]); this.entries.set(i, new TableEntry(chunk.chunkSource, stringPool)); } } } TableTypeChunk.prototype.resolve = function (index) { return (this.entries.get(index) || {}).value; }; TableTypeChunk.NO_ENTRY = 0xffffffff; return TableTypeChunk; }()); var ResTableConfig = /** @class */ (function () { function ResTableConfig(chunk) { this.size = chunk.headerSource.readUInt(); this.imsi = chunk.headerSource.readUInt(); this.locale = new Locale(chunk.headerSource); this.screenType = chunk.headerSource.readUInt(); this.input = chunk.headerSource.readUInt(); this.screenSize = chunk.headerSource.readUInt(); this.version = chunk.headerSource.readUInt(); } return ResTableConfig; }()); var Locale = /** @class */ (function () { function Locale(source) { this.languageCode = source.readUtf8String(2); this.countryCode = source.readUtf8String(2); } Locale.prototype.convertCode = function (code) { return code !== Locale.EMPTY_CODE ? code : undefined; }; Object.defineProperty(Locale.prototype, "language", { get: function () { return this.convertCode(this.languageCode); }, enumerable: false, configurable: true }); Object.defineProperty(Locale.prototype, "country", { get: function () { return this.convertCode(this.countryCode); }, enumerable: false, configurable: true }); Locale.EMPTY_CODE = "\u0000\u0000"; return Locale; }()); exports.Locale = Locale; var TableEntry = /** @class */ (function () { function TableEntry(source, stringPool) { this.size = source.readUShort(); this.flags = source.readUShort(); this.index = source.readUInt(); this.value = this.flags % 2 === 0 ? (0, common_1.parseResourceValue)(source, stringPool) : null; } return TableEntry; }()); var Resource = /** @class */ (function () { function Resource(value, locale) { this.value = value; if (locale.language || locale.country) { this.locale = locale; } } return Resource; }()); exports.Resource = Resource; var Resources = /** @class */ (function () { function Resources(source) { var chunk = new common_1.Chunk(source, common_1.ChunkType.TABLE); this.table = new Table(chunk); } Resources.prototype.resolve = function (id) { var packageId = Math.floor(id / Math.pow(2, 24)) % Math.pow(2, 8); var typeId = Math.floor(id / Math.pow(2, 16)) % Math.pow(2, 8); var index = id % Math.pow(2, 16); var packageResources = this.table.packages.get(packageId); if (packageResources) { var types = packageResources.types.get(typeId); if (types) { return types.map(function (type) { return new Resource(type.resolve(index), type.resTableConfig.locale); }) .filter(function (resource) { return !!resource.value; }); } } return []; }; return Resources; }()); exports.Resources = Resources;