/** * read String pool, for apk binary xml file and resource table. */ public static async Task <StringPool> readStringPool(ByteBuffer buffer, StringPoolHeader stringPoolHeader) { long beginPos = buffer.position(); long[] offsets = new long[(int)stringPoolHeader.getStringCount()]; // read strings offset if (stringPoolHeader.getStringCount() > 0) { for (int idx = 0; idx < stringPoolHeader.getStringCount(); idx++) { offsets[idx] = Buffers.readUInt(buffer); } } // read flag // the string index is sorted by the string values if true bool sorted = (stringPoolHeader.getFlags() & StringPoolHeader.SORTED_FLAG) != 0; // string use utf-8 format if true, otherwise utf-16 bool utf8 = (stringPoolHeader.getFlags() & StringPoolHeader.UTF8_FLAG) != 0; // read strings. the head and metas have 28 bytes long stringPos = beginPos + stringPoolHeader.getStringsStart() - stringPoolHeader.getHeaderSize(); buffer.position((int)stringPos); StringPoolEntry[] entries = new StringPoolEntry[offsets.Length]; for (int i = 0; i < offsets.Length; i++) { entries[i] = new StringPoolEntry(i, stringPos + offsets[i]); } string lastStr = null; long lastOffset = -1; StringPool stringPool = new StringPool((int)stringPoolHeader.getStringCount()); foreach (StringPoolEntry entry in entries) { if (entry.getOffset() == lastOffset) { stringPool.set(entry.getIdx(), lastStr); continue; } buffer.position((int)entry.getOffset()); lastOffset = entry.getOffset(); string str = await ParseUtils.readString(buffer, utf8); lastStr = str; stringPool.set(entry.getIdx(), str); } // read styles if (stringPoolHeader.getStyleCount() > 0) { // now we just skip it } buffer.position((int)(beginPos + stringPoolHeader.getBodySize())); return(stringPool); }
private async Task <ChunkHeader> readChunkHeader() { // finished if (!buffer.hasRemaining()) { return(null); } long begin = buffer.position(); int chunkType = await Buffers.readUShort(buffer); int headerSize = await Buffers.readUShort(buffer); long chunkSize = Buffers.readUInt(buffer); switch (chunkType) { case ChunkType.XML: return(new XmlHeader(chunkType, headerSize, chunkSize)); case ChunkType.STRING_POOL: StringPoolHeader stringPoolHeader = new StringPoolHeader(chunkType, headerSize, chunkSize); stringPoolHeader.setStringCount(Buffers.readUInt(buffer)); stringPoolHeader.setStyleCount(Buffers.readUInt(buffer)); stringPoolHeader.setFlags(Buffers.readUInt(buffer)); stringPoolHeader.setStringsStart(Buffers.readUInt(buffer)); stringPoolHeader.setStylesStart(Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(stringPoolHeader); case ChunkType.XML_RESOURCE_MAP: buffer.position((int)(begin + headerSize)); return(new XmlResourceMapHeader(chunkType, headerSize, chunkSize)); case ChunkType.XML_START_NAMESPACE: case ChunkType.XML_END_NAMESPACE: case ChunkType.XML_START_ELEMENT: case ChunkType.XML_END_ELEMENT: case ChunkType.XML_CDATA: XmlNodeHeader header = new XmlNodeHeader(chunkType, headerSize, chunkSize); header.setLineNum((int)Buffers.readUInt(buffer)); header.setCommentRef((int)Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(header); case ChunkType.NULL: return(new NullHeader(chunkType, headerSize, chunkSize)); default: throw new ParserException("Unexpected chunk type:" + chunkType); } }
private async Task <ChunkHeader> readChunkHeader() { long begin = buffer.position(); int chunkType = await Buffers.readUShort(buffer); int headerSize = await Buffers.readUShort(buffer); long chunkSize = Buffers.readUInt(buffer); switch (chunkType) { case ChunkType.TABLE: ResourceTableHeader resourceTableHeader = new ResourceTableHeader(chunkType, headerSize, chunkSize); resourceTableHeader.setPackageCount(Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(resourceTableHeader); case ChunkType.STRING_POOL: StringPoolHeader stringPoolHeader = new StringPoolHeader(chunkType, headerSize, chunkSize); stringPoolHeader.setStringCount(Buffers.readUInt(buffer)); stringPoolHeader.setStyleCount(Buffers.readUInt(buffer)); stringPoolHeader.setFlags(Buffers.readUInt(buffer)); stringPoolHeader.setStringsStart(Buffers.readUInt(buffer)); stringPoolHeader.setStylesStart(Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(stringPoolHeader); case ChunkType.TABLE_PACKAGE: PackageHeader packageHeader = new PackageHeader(chunkType, headerSize, chunkSize); packageHeader.setId(Buffers.readUInt(buffer)); packageHeader.setName(ParseUtils.readStringUTF16(buffer, 128)); packageHeader.setTypeStrings(Buffers.readUInt(buffer)); packageHeader.setLastPublicType(Buffers.readUInt(buffer)); packageHeader.setKeyStrings(Buffers.readUInt(buffer)); packageHeader.setLastPublicKey(Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(packageHeader); case ChunkType.TABLE_TYPE_SPEC: TypeSpecHeader typeSpecHeader = new TypeSpecHeader(chunkType, headerSize, chunkSize); typeSpecHeader.setId(Buffers.readUByte(buffer)); typeSpecHeader.setRes0(Buffers.readUByte(buffer)); typeSpecHeader.setRes1(await Buffers.readUShort(buffer)); typeSpecHeader.setEntryCount(Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(typeSpecHeader); case ChunkType.TABLE_TYPE: TypeHeader typeHeader = new TypeHeader(chunkType, headerSize, chunkSize); typeHeader.setId(Buffers.readUByte(buffer)); typeHeader.setRes0(Buffers.readUByte(buffer)); typeHeader.setRes1(await Buffers.readUShort(buffer)); typeHeader.setEntryCount(Buffers.readUInt(buffer)); typeHeader.setEntriesStart(Buffers.readUInt(buffer)); typeHeader.setConfig(readResTableConfig()); buffer.position((int)(begin + headerSize)); return(typeHeader); case ChunkType.TABLE_LIBRARY: //DynamicRefTable LibraryHeader libraryHeader = new LibraryHeader(chunkType, headerSize, chunkSize); libraryHeader.setCount(Buffers.readUInt(buffer)); buffer.position((int)(begin + headerSize)); return(libraryHeader); case ChunkType.NULL: //buffer.skip((int) (chunkSize - headerSize)); default: throw new ParserException("Unexpected chunk Type: 0x" + chunkType.ToString("X")); } }