static jint android_content_XmlBlock_nativeCreate(JNIEnv* env, jobject clazz, jbyteArray bArray, jint off, jint len) { if (bArray == NULL) { doThrow(env, "java/lang/NullPointerException"); return 0; } jsize bLen = env->GetArrayLength(bArray); if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) { doThrow(env, "java/lang/IndexOutOfBoundsException"); return 0; } jbyte* b = env->GetByteArrayElements(bArray, NULL); ResXMLTree* osb = new ResXMLTree(b+off, len, true); env->ReleaseByteArrayElements(bArray, b, 0); if (osb == NULL || osb->getError() != NO_ERROR) { doThrow(env, "java/lang/IllegalArgumentException"); return 0; } return (jint)osb; }
static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) { size_t N = tree.getAttributeCount(); for (size_t i=0; i<N; i++) { if (tree.getAttributeNameResID(i) == attrRes) { return (ssize_t)i; } } return -1; }
static jint android_content_XmlBlock_nativeGetStringBlock(JNIEnv* env, jobject clazz, jint token) { ResXMLTree* osb = (ResXMLTree*)token; if (osb == NULL) { doThrow(env, "java/lang/NullPointerException"); return 0; } return (jint)&osb->getStrings(); }
static jlong android_content_XmlBlock_nativeGetStringBlock(JNIEnv* env, jobject clazz, jlong token) { ResXMLTree* osb = reinterpret_cast<ResXMLTree*>(token); if (osb == NULL) { jniThrowNullPointerException(env, NULL); return 0; } return reinterpret_cast<jlong>(&osb->getStrings()); }
static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) { ssize_t idx = indexOfAttribute(tree, attrRes); if (idx < 0) { return String8(); } Res_value value; if (tree.getAttributeValue(idx, &value) != NO_ERROR) { if (value.dataType != Res_value::TYPE_STRING) { if (outError != NULL) *outError = "attribute is not a string value"; return String8(); } } size_t len; const uint16_t* str = tree.getAttributeStringValue(idx, &len); return str ? String8(str, len) : String8(); }
static void printCompatibleScreens(ResXMLTree& tree, String8* outError) { size_t len; ResXMLTree::event_code_t code; int depth = 0; bool first = true; printf("compatible-screens:"); while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; if (depth < 0) { break; } continue; } if (code != ResXMLTree::START_TAG) { continue; } depth++; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { *outError = "failed to get XML element name (bad string pool)"; return; } String8 tag(ctag16); if (tag == "screen") { int32_t screenSize = AaptXml::getIntegerAttribute(tree, SCREEN_SIZE_ATTR); int32_t screenDensity = AaptXml::getIntegerAttribute(tree, SCREEN_DENSITY_ATTR); if (screenSize > 0 && screenDensity > 0) { if (!first) { printf(","); } first = false; printf("'%d/%d'", screenSize, screenDensity); } } } printf("\n"); }
static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError, int32_t defValue = -1) { ssize_t idx = indexOfAttribute(tree, attrRes); if (idx < 0) { return defValue; } Res_value value; if (tree.getAttributeValue(idx, &value) != NO_ERROR) { if (value.dataType < Res_value::TYPE_FIRST_INT || value.dataType > Res_value::TYPE_LAST_INT) { if (outError != NULL) *outError = "attribute is not an integer value"; return defValue; } }
/* * Handle the "list" command, which can be a simple file dump or * a verbose listing. * * The verbose listing closely matches the output of the Info-ZIP "unzip" * command. */ int doList(Bundle* bundle) { int result = 1; ZipFile* zip = NULL; const ZipEntry* entry; long totalUncLen, totalCompLen; const char* zipFileName; if (bundle->getFileSpecCount() != 1) { fprintf(stderr, "ERROR: specify zip file name (only)\n"); goto bail; } zipFileName = bundle->getFileSpecEntry(0); zip = openReadOnly(zipFileName); if (zip == NULL) goto bail; int count, i; if (bundle->getVerbose()) { printf("Archive: %s\n", zipFileName); printf( " Length Method Size Ratio Offset Date Time CRC-32 Name\n"); printf( "-------- ------ ------- ----- ------- ---- ---- ------ ----\n"); } totalUncLen = totalCompLen = 0; count = zip->getNumEntries(); for (i = 0; i < count; i++) { entry = zip->getEntryByIndex(i); if (bundle->getVerbose()) { char dateBuf[32]; time_t when; when = entry->getModWhen(); strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M", localtime(&when)); printf("%8ld %-7.7s %7ld %3d%% %8zd %s %08lx %s\n", (long) entry->getUncompressedLen(), compressionName(entry->getCompressionMethod()), (long) entry->getCompressedLen(), calcPercent(entry->getUncompressedLen(), entry->getCompressedLen()), (size_t) entry->getLFHOffset(), dateBuf, entry->getCRC32(), entry->getFileName()); } else { printf("%s\n", entry->getFileName()); } totalUncLen += entry->getUncompressedLen(); totalCompLen += entry->getCompressedLen(); } if (bundle->getVerbose()) { printf( "-------- ------- --- -------\n"); printf("%8ld %7ld %2d%% %d files\n", totalUncLen, totalCompLen, calcPercent(totalUncLen, totalCompLen), zip->getNumEntries()); } if (bundle->getAndroidList()) { AssetManager assets; if (!assets.addAssetPath(String8(zipFileName), NULL)) { fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n"); goto bail; } const ResTable& res = assets.getResources(false); if (&res == NULL) { printf("\nNo resource table found.\n"); } else { #ifndef HAVE_ANDROID_OS printf("\nResource table:\n"); res.print(false); #endif } Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml", Asset::ACCESS_BUFFER); if (manifestAsset == NULL) { printf("\nNo AndroidManifest.xml found.\n"); } else { printf("\nAndroid manifest:\n"); ResXMLTree tree; tree.setTo(manifestAsset->getBuffer(true), manifestAsset->getLength()); printXMLBlock(&tree); } delete manifestAsset; } result = 0; bail: delete zip; return result; }
Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost, String8 *outError = NULL) { Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER); if (aidAsset == NULL) { if (outError != NULL) *outError = "xml resource does not exist"; return Vector<String8>(); } const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service"); bool withinApduService = false; Vector<String8> categories; String8 error; ResXMLTree tree; tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength()); size_t len; int depth = 0; ResXMLTree::event_code_t code; while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { *outError = "failed to get XML element name (bad string pool)"; return Vector<String8>(); } String8 tag(ctag16); if (depth == 0 && tag == serviceTagName) { withinApduService = false; } } else if (code == ResXMLTree::START_TAG) { depth++; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { *outError = "failed to get XML element name (bad string pool)"; return Vector<String8>(); } String8 tag(ctag16); if (depth == 1) { if (tag == serviceTagName) { withinApduService = true; } } else if (depth == 2 && withinApduService) { if (tag == "aid-group") { String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error); if (error != "") { if (outError != NULL) *outError = error; return Vector<String8>(); } categories.add(category); } } } } aidAsset->close(); return categories; }
static bool getAppInfo(const String8& path, AppInfo& outInfo) { memset(&outInfo, 0, sizeof(outInfo)); AssetManager assetManager; int32_t cookie = 0; if (!assetManager.addAssetPath(path, &cookie)) { return false; } Asset* asset = assetManager.openNonAsset(cookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER); if (asset == NULL) { return false; } ResXMLTree xml; if (xml.setTo(asset->getBuffer(true), asset->getLength(), false) != NO_ERROR) { delete asset; return false; } const String16 kAndroidNamespace("http://schemas.android.com/apk/res/android"); const String16 kManifestTag("manifest"); const String16 kApplicationTag("application"); const String16 kUsesSdkTag("uses-sdk"); const String16 kVersionCodeAttr("versionCode"); const String16 kMultiArchAttr("multiArch"); const String16 kMinSdkVersionAttr("minSdkVersion"); ResXMLParser::event_code_t event; while ((event = xml.next()) != ResXMLParser::BAD_DOCUMENT && event != ResXMLParser::END_DOCUMENT) { if (event != ResXMLParser::START_TAG) { continue; } size_t len; const char16_t* name = xml.getElementName(&len); String16 name16(name, len); if (name16 == kManifestTag) { ssize_t idx = xml.indexOfAttribute( kAndroidNamespace.string(), kAndroidNamespace.size(), kVersionCodeAttr.string(), kVersionCodeAttr.size()); if (idx >= 0) { outInfo.versionCode = xml.getAttributeData(idx); } } else if (name16 == kApplicationTag) { ssize_t idx = xml.indexOfAttribute( kAndroidNamespace.string(), kAndroidNamespace.size(), kMultiArchAttr.string(), kMultiArchAttr.size()); if (idx >= 0) { outInfo.multiArch = xml.getAttributeData(idx) != 0; } } else if (name16 == kUsesSdkTag) { ssize_t idx = xml.indexOfAttribute( kAndroidNamespace.string(), kAndroidNamespace.size(), kMinSdkVersionAttr.string(), kMinSdkVersionAttr.size()); if (idx >= 0) { uint16_t type = xml.getAttributeDataType(idx); if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) { outInfo.minSdkVersion = xml.getAttributeData(idx); } else if (type == Res_value::TYPE_STRING) { String8 minSdk8(xml.getStrings().string8ObjectAt(idx)); char* endPtr; int minSdk = strtol(minSdk8.string(), &endPtr, 10); if (endPtr != minSdk8.string() + minSdk8.size()) { fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n", minSdk8.string()); } else { outInfo.minSdkVersion = minSdk; } } else { fprintf(stderr, "warning: unrecognized value for android:minSdkVersion.\n"); } } } } delete asset; return true; }