/** * read String pool, for apk binary xml file and resource table. * * @param in * @param stringPoolHeader * @return * @throws IOException */ public static StringPool readStringPool(TellableInputStream in, StringPoolHeader stringPoolHeader) throws IOException { long beginPos = in.tell(); long[] offsets = new long[(int) stringPoolHeader.stringCount]; // read strings offset if (stringPoolHeader.stringCount > 0) { for (int idx = 0; idx < stringPoolHeader.stringCount; idx++) { offsets[idx] = in.readUInt(); } } // read flag boolean sorted = (stringPoolHeader.flags & StringPoolHeader.SORTED_FLAG) != 0; StringEncoding stringEncoding = (stringPoolHeader.flags & StringPoolHeader.UTF8_FLAG) != 0 ? StringEncoding.UTF8 : StringEncoding.UTF16; // read strings. the head and metas have 28 bytes long stringPos = beginPos + stringPoolHeader.stringsStart - stringPoolHeader.headerSize; in.advanceIfNotRearch(stringPos); StringPoolEntry[] entries = new StringPoolEntry[offsets.length]; for (int i = 0; i < offsets.length; i++) { entries[i] = new StringPoolEntry(i, stringPos + offsets[i]); } Arrays.sort(entries); String lastStr = null; long lastOffset = -1; StringPool stringPool = new StringPool((int) stringPoolHeader.stringCount); for (StringPoolEntry entry : entries) { if (entry.getOffset() == lastOffset) { stringPool.set(entry.getIdx(), lastStr); continue; } in.advanceIfNotRearch(entry.getOffset()); lastOffset = entry.getOffset(); String str = ParseUtils.readString(in, stringEncoding); lastStr = str; stringPool.set(entry.getIdx(), str); } // read styles if (stringPoolHeader.styleCount > 0) { // now we just skip it } in.advanceIfNotRearch(beginPos + stringPoolHeader.chunkSize - stringPoolHeader.headerSize); return stringPool; }
/** * read res value, convert from different types to string. * * @param in * @param stringPool * @return * @throws IOException */ public static ResValue readResValue( TellableInputStream in, StringPool stringPool, ResourceTable resourceTable, boolean isStyle, Locale locale) throws IOException { ResValue resValue = new ResValue(); resValue.size = in.readUShort(); resValue.res0 = in.readUByte(); resValue.dataType = in.readUByte(); switch (resValue.dataType) { case ResValue.ResType.INT_DEC: case ResValue.ResType.INT_HEX: resValue.data = String.valueOf(in.readInt()); break; case ResValue.ResType.STRING: int strRef = in.readInt(); if (strRef > 0) { resValue.data = stringPool.get(strRef); } break; case ResValue.ResType.REFERENCE: long resourceId = in.readUInt(); resValue.data = getResourceByid(resourceId, isStyle, resourceTable, locale); break; case ResValue.ResType.INT_BOOLEAN: resValue.data = String.valueOf(in.readInt() != 0); break; case ResValue.ResType.NULL: resValue.data = ""; break; case ResValue.ResType.INT_COLOR_RGB8: case ResValue.ResType.INT_COLOR_RGB4: resValue.data = readRGBs(in, 6); break; case ResValue.ResType.INT_COLOR_ARGB8: case ResValue.ResType.INT_COLOR_ARGB4: resValue.data = readRGBs(in, 8); break; case ResValue.ResType.DIMENSION: resValue.data = getDemension(in); break; case ResValue.ResType.FRACTION: resValue.data = getFraction(in); break; default: resValue.data = "{" + resValue.dataType + ":" + in.readUInt() + "}"; } return resValue; }