package com.wj.dexknife.shell.apkparser.parser; import com.wj.dexknife.shell.apkparser.bean.ApkMeta; import com.wj.dexknife.shell.apkparser.bean.GlEsVersion; import com.wj.dexknife.shell.apkparser.bean.Permission; import com.wj.dexknife.shell.apkparser.bean.UseFeature; import com.wj.dexknife.shell.apkparser.struct.xml.Attributes; import com.wj.dexknife.shell.apkparser.struct.xml.XmlCData; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNamespaceEndTag; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNamespaceStartTag; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNodeEndTag; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNodeStartTag; /** * trans binary xml to text * * @author Liu Dong im@dongliu.net */ public class ApkMetaTranslator implements XmlStreamer { private String[] tagStack = new String[100]; private int depth = 0; private ApkMeta apkMeta = new ApkMeta(); @Override public void onStartTag(XmlNodeStartTag xmlNodeStartTag) { Attributes attributes = xmlNodeStartTag.getAttributes(); switch (xmlNodeStartTag.getName()) { case "application": apkMeta.setLabel(attributes.get("label")); apkMeta.setIcon(attributes.get("icon")); break; case "manifest": apkMeta.setPackageName(attributes.get("package")); apkMeta.setVersionName(attributes.get("versionName")); apkMeta.setVersionCode(attributes.getLong("versionCode")); String installLocation = attributes.get("installLocation"); if (installLocation != null) { apkMeta.setInstallLocation(installLocation); } break; case "uses-sdk": apkMeta.setMinSdkVersion(attributes.get("minSdkVersion")); apkMeta.setTargetSdkVersion(attributes.get("targetSdkVersion")); apkMeta.setMaxSdkVersion(attributes.get("maxSdkVersion")); break; case "supports-screens": apkMeta.setAnyDensity(attributes.getBoolean("anyDensity", false)); apkMeta.setSmallScreens(attributes.getBoolean("smallScreens", false)); apkMeta.setNormalScreens(attributes.getBoolean("normalScreens", false)); apkMeta.setLargeScreens(attributes.getBoolean("largeScreens", false)); break; case "uses-feature": String name = attributes.get("name"); boolean required = attributes.getBoolean("required", false); if (name != null) { UseFeature useFeature = new UseFeature(); useFeature.setName(name); useFeature.setRequired(required); apkMeta.addUseFeatures(useFeature); } else { Integer gl = attributes.getInt("glEsVersion"); if (gl != null) { int v = gl; GlEsVersion glEsVersion = new GlEsVersion(); glEsVersion.setMajor(v >> 16); glEsVersion.setMinor(v & 0xffff); glEsVersion.setRequired(required); apkMeta.setGlEsVersion(glEsVersion); } } break; case "uses-permission": apkMeta.addUsesPermission(attributes.get("name")); break; case "permission": Permission permission = new Permission(); permission.setName(attributes.get("name")); permission.setLabel(attributes.get("label")); permission.setIcon(attributes.get("icon")); permission.setGroup(attributes.get("group")); permission.setDescription(attributes.get("description")); String protectionLevel = attributes.get("android:protectionLevel"); if (protectionLevel != null) { permission.setProtectionLevel(protectionLevel); } apkMeta.addPermission(permission); break; } tagStack[depth++] = xmlNodeStartTag.getName(); } @Override public void onEndTag(XmlNodeEndTag xmlNodeEndTag) { depth--; } @Override public void onCData(XmlCData xmlCData) { } @Override public void onNamespaceStart(XmlNamespaceStartTag tag) { } @Override public void onNamespaceEnd(XmlNamespaceEndTag tag) { } public ApkMeta getApkMeta() { return apkMeta; } private boolean matchTagPath(String... tags) { // the root should always be "manifest" if (depth != tags.length + 1) { return false; } for (int i = 1; i < depth; i++) { if (!tagStack[i].equals(tags[i - 1])) { return false; } } return true; } private boolean matchLastTag(String tag) { // the root should always be "manifest" return tagStack[depth - 1].endsWith(tag); } }