static jint norwegianime_BinaryDictionary_open (JNIEnv *env, jobject object, jobject assetManager, jstring resourceString, jint typedLetterMultiplier, jint fullWordMultiplier) { // Get the native file descriptor from the FileDescriptor object AssetManager *am = (AssetManager*) env->GetIntField(assetManager, sAssetManagerNativeField); if (!am) { LOGE("DICT: Couldn't get AssetManager native peer\n"); return 0; } const char *resourcePath = env->GetStringUTFChars(resourceString, NULL); Asset *dictAsset = am->openNonAsset(resourcePath, Asset::ACCESS_BUFFER); if (dictAsset == NULL) { LOGE("DICT: Couldn't get asset %s\n", resourcePath); env->ReleaseStringUTFChars(resourceString, resourcePath); return 0; } void *dict = (void*) dictAsset->getBuffer(false); if (dict == NULL) { LOGE("DICT: Dictionary buffer is null\n"); env->ReleaseStringUTFChars(resourceString, resourcePath); return 0; } Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier); dictionary->setAsset(dictAsset); env->ReleaseStringUTFChars(resourceString, resourcePath); return (jint) dictionary; }
void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) { ASSERT(m_frame); // Ignore ErrorInterrupted since it is due to a policy interruption. This // is caused by a decision to download the main resource rather than // display it. if (error.errorCode() == InternalErrorInterrupted || error.errorCode() == InternalErrorCancelled) { // If we decided to download the main resource or if the user cancelled // it, make sure we report that the load is done. didFinishLoad(); return; } AssetManager* am = globalAssetManager(); // Check to see if the error code was not generated internally WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain; if ((error.errorCode() == ErrorFile || error.errorCode() == ErrorFileNotFound) && (!error.localizedDescription().isEmpty())) { id = WebCore::PlatformBridge::LoadError; } String filename = m_webFrame->getRawResourceFilename(id); if (filename.isEmpty()) return; // Grab the error page from the asset manager Asset* a = am->openNonAsset( filename.utf8().data(), Asset::ACCESS_BUFFER); if (!a) return; // Take the failing url and encode html entities so javascript urls are not // executed. CString failingUrl = error.failingURL().utf8(); WTF::Vector<char> url; int len = failingUrl.length(); const char* data = failingUrl.data(); for (int i = 0; i < len; i++) { char c = data[i]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) url.append(c); else { char buf[16]; int res = sprintf(buf, "&#%d;", c); buf[res] = 0; url.append(buf, res); } } // Replace all occurances of %s with the failing url. String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength()); // samsung shkim // \frameworks\base\core\res\res\raw-XX\nodomain.html or loaderror.html // These error pages does not have <viewport> tag, it is loaded as low zoom scale if( s.contains( "viewport" ) == false ) s = s.replace( "<head>", "<head> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\"/>" ); s = s.replace("%s", String(url.data(), url.size())); // Replace all occurances of %e with the error text s = s.replace("%e", error.localizedDescription()); // Create the request and the substitute data and tell the FrameLoader to // load with the replacement data. // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for // invalidate URL string. loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s); // Delete the asset. delete a; }
/* * 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; }
int doDump(Bundle* bundle) { status_t result = UNKNOWN_ERROR; if (bundle->getFileSpecCount() < 1) { fprintf(stderr, "ERROR: no dump option specified\n"); return 1; } if (bundle->getFileSpecCount() < 2) { fprintf(stderr, "ERROR: no dump file specified\n"); return 1; } const char* option = bundle->getFileSpecEntry(0); const char* filename = bundle->getFileSpecEntry(1); AssetManager assets; int32_t assetsCookie; if (!assets.addAssetPath(String8(filename), &assetsCookie)) { fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); return 1; } // Make a dummy config for retrieving resources... we need to supply // non-default values for some configs so that we can retrieve resources // in the app that don't have a default. The most important of these is // the API version because key resources like icons will have an implicit // version if they are using newer config types like density. ResTable_config config; memset(&config, 0, sizeof(ResTable_config)); config.language[0] = 'e'; config.language[1] = 'n'; config.country[0] = 'U'; config.country[1] = 'S'; config.orientation = ResTable_config::ORIENTATION_PORT; config.density = ResTable_config::DENSITY_MEDIUM; config.sdkVersion = 10000; // Very high. config.screenWidthDp = 320; config.screenHeightDp = 480; config.smallestScreenWidthDp = 320; config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL; assets.setConfiguration(config); const ResTable& res = assets.getResources(false); if (res.getError() != NO_ERROR) { fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n"); return 1; } // The dynamicRefTable can be null if there are no resources for this asset cookie. // This fine. const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie); Asset* asset = NULL; if (strcmp("resources", option) == 0) { #ifndef __ANDROID__ res.print(bundle->getValues()); #endif } else if (strcmp("strings", option) == 0) { const ResStringPool* pool = res.getTableStringBlock(0); printStringPool(pool); } else if (strcmp("xmltree", option) == 0) { if (bundle->getFileSpecCount() < 3) { fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); goto bail; } for (int i=2; i<bundle->getFileSpecCount(); i++) { const char* resname = bundle->getFileSpecEntry(i); ResXMLTree tree(dynamicRefTable); asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); goto bail; } if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); goto bail; } tree.restart(); printXMLBlock(&tree); tree.uninit(); delete asset; asset = NULL; } } else if (strcmp("xmlstrings", option) == 0) { if (bundle->getFileSpecCount() < 3) { fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); goto bail; } for (int i=2; i<bundle->getFileSpecCount(); i++) { const char* resname = bundle->getFileSpecEntry(i); asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); goto bail; } ResXMLTree tree(dynamicRefTable); if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); goto bail; } printStringPool(&tree.getStrings()); delete asset; asset = NULL; } } else { asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); goto bail; } ResXMLTree tree(dynamicRefTable); if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); goto bail; } tree.restart(); if (strcmp("permissions", option) == 0) { size_t len; ResXMLTree::event_code_t code; int depth = 0; while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; continue; } if (code != ResXMLTree::START_TAG) { continue; } depth++; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n"); goto bail; } String8 tag(ctag16); //printf("Depth %d tag %s\n", depth, tag.string()); if (depth == 1) { if (tag != "manifest") { fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); goto bail; } String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL); printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string()); } else if (depth == 2 && tag == "permission") { String8 error; String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); goto bail; } printf("permission: %s\n", ResTable::normalizeForOutput(name.string()).string()); } else if (depth == 2 && tag == "uses-permission") { String8 error; String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); goto bail; } printUsesPermission(name, AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR)); } } } else if (strcmp("badging", option) == 0) { Vector<String8> locales; res.getLocales(&locales); Vector<ResTable_config> configs; res.getConfigurations(&configs); SortedVector<int> densities; const size_t NC = configs.size(); for (size_t i=0; i<NC; i++) { int dens = configs[i].density; if (dens == 0) { dens = 160; } densities.add(dens); } size_t len; ResXMLTree::event_code_t code; int depth = 0; String8 error; bool withinActivity = false; bool isMainActivity = false; bool isLauncherActivity = false; bool isLeanbackLauncherActivity = false; bool isSearchable = false; bool withinApplication = false; bool withinSupportsInput = false; bool withinFeatureGroup = false; bool withinReceiver = false; bool withinService = false; bool withinProvider = false; bool withinIntentFilter = false; bool hasMainActivity = false; bool hasOtherActivities = false; bool hasOtherReceivers = false; bool hasOtherServices = false; bool hasIntentFilter = false; bool hasWallpaperService = false; bool hasImeService = false; bool hasAccessibilityService = false; bool hasPrintService = false; bool hasWidgetReceivers = false; bool hasDeviceAdminReceiver = false; bool hasPaymentService = false; bool hasDocumentsProvider = false; bool hasCameraActivity = false; bool hasCameraSecureActivity = false; bool hasLauncher = false; bool hasNotificationListenerService = false; bool hasDreamService = false; bool actMainActivity = false; bool actWidgetReceivers = false; bool actDeviceAdminEnabled = false; bool actImeService = false; bool actWallpaperService = false; bool actAccessibilityService = false; bool actPrintService = false; bool actHostApduService = false; bool actOffHostApduService = false; bool actDocumentsProvider = false; bool actNotificationListenerService = false; bool actDreamService = false; bool actCamera = false; bool actCameraSecure = false; bool catLauncher = false; bool hasMetaHostPaymentCategory = false; bool hasMetaOffHostPaymentCategory = false; // These permissions are required by services implementing services // the system binds to (IME, Accessibility, PrintServices, etc.) bool hasBindDeviceAdminPermission = false; bool hasBindInputMethodPermission = false; bool hasBindAccessibilityServicePermission = false; bool hasBindPrintServicePermission = false; bool hasBindNfcServicePermission = false; bool hasRequiredSafAttributes = false; bool hasBindNotificationListenerServicePermission = false; bool hasBindDreamServicePermission = false; // These two implement the implicit permissions that are granted // to pre-1.6 applications. bool hasWriteExternalStoragePermission = false; bool hasReadPhoneStatePermission = false; // If an app requests write storage, they will also get read storage. bool hasReadExternalStoragePermission = false; // Implement transition to read and write call log. bool hasReadContactsPermission = false; bool hasWriteContactsPermission = false; bool hasReadCallLogPermission = false; bool hasWriteCallLogPermission = false; // If an app declares itself as multiArch, we report the // native libraries differently. bool hasMultiArch = false; // This next group of variables is used to implement a group of // backward-compatibility heuristics necessitated by the addition of // some new uses-feature constants in 2.1 and 2.2. In most cases, the // heuristic is "if an app requests a permission but doesn't explicitly // request the corresponding <uses-feature>, presume it's there anyway". // 2.2 also added some other features that apps can request, but that // have no corresponding permission, so we cannot implement any // back-compatibility heuristic for them. The below are thus unnecessary // (but are retained here for documentary purposes.) //bool specCompassFeature = false; //bool specAccelerometerFeature = false; //bool specProximityFeature = false; //bool specAmbientLightFeature = false; //bool specLiveWallpaperFeature = false; int targetSdk = 0; int smallScreen = 1; int normalScreen = 1; int largeScreen = 1; int xlargeScreen = 1; int anyDensity = 1; int requiresSmallestWidthDp = 0; int compatibleWidthLimitDp = 0; int largestWidthLimitDp = 0; String8 pkg; String8 activityName; String8 activityLabel; String8 activityIcon; String8 activityBanner; String8 receiverName; String8 serviceName; Vector<String8> supportedInput; FeatureGroup commonFeatures; Vector<FeatureGroup> featureGroups; KeyedVector<String8, ImpliedFeature> impliedFeatures; while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; if (depth < 2) { if (withinSupportsInput && !supportedInput.isEmpty()) { printf("supports-input: '"); const size_t N = supportedInput.size(); for (size_t i=0; i<N; i++) { printf("%s", ResTable::normalizeForOutput( supportedInput[i].string()).string()); if (i != N - 1) { printf("' '"); } else { printf("'\n"); } } supportedInput.clear(); } withinApplication = false; withinSupportsInput = false; withinFeatureGroup = false; } else if (depth < 3) { if (withinActivity && isMainActivity) { String8 aName(getComponentName(pkg, activityName)); if (isLauncherActivity) { printf("launchable-activity:"); if (aName.length() > 0) { printf(" name='%s' ", ResTable::normalizeForOutput(aName.string()).string()); } printf(" label='%s' icon='%s'\n", ResTable::normalizeForOutput(activityLabel.string()).string(), ResTable::normalizeForOutput(activityIcon.string()).string()); } if (isLeanbackLauncherActivity) { printf("leanback-launchable-activity:"); if (aName.length() > 0) { printf(" name='%s' ", ResTable::normalizeForOutput(aName.string()).string()); } printf(" label='%s' icon='%s' banner='%s'\n", ResTable::normalizeForOutput(activityLabel.string()).string(), ResTable::normalizeForOutput(activityIcon.string()).string(), ResTable::normalizeForOutput(activityBanner.string()).string()); } } if (!hasIntentFilter) { hasOtherActivities |= withinActivity; hasOtherReceivers |= withinReceiver; hasOtherServices |= withinService; } else { if (withinService) { hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory && hasBindNfcServicePermission); hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory && hasBindNfcServicePermission); } } withinActivity = false; withinService = false; withinReceiver = false; withinProvider = false; hasIntentFilter = false; isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false; } else if (depth < 4) { if (withinIntentFilter) { if (withinActivity) { hasMainActivity |= actMainActivity; hasLauncher |= catLauncher; hasCameraActivity |= actCamera; hasCameraSecureActivity |= actCameraSecure; hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure; } else if (withinReceiver) { hasWidgetReceivers |= actWidgetReceivers; hasDeviceAdminReceiver |= (actDeviceAdminEnabled && hasBindDeviceAdminPermission); hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled); } else if (withinService) { hasImeService |= actImeService; hasWallpaperService |= actWallpaperService; hasAccessibilityService |= (actAccessibilityService && hasBindAccessibilityServicePermission); hasPrintService |= (actPrintService && hasBindPrintServicePermission); hasNotificationListenerService |= actNotificationListenerService && hasBindNotificationListenerServicePermission; hasDreamService |= actDreamService && hasBindDreamServicePermission; hasOtherServices |= (!actImeService && !actWallpaperService && !actAccessibilityService && !actPrintService && !actHostApduService && !actOffHostApduService && !actNotificationListenerService); } else if (withinProvider) { hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes; } } withinIntentFilter = false; } continue; } if (code != ResXMLTree::START_TAG) { continue; } depth++; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n"); goto bail; } String8 tag(ctag16); //printf("Depth %d, %s\n", depth, tag.string()); if (depth == 1) { if (tag != "manifest") { fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); goto bail; } pkg = AaptXml::getAttribute(tree, NULL, "package", NULL); printf("package: name='%s' ", ResTable::normalizeForOutput(pkg.string()).string()); int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); goto bail; } if (versionCode > 0) { printf("versionCode='%d' ", versionCode); } else { printf("versionCode='' "); } String8 versionName = AaptXml::getResolvedAttribute(res, tree, VERSION_NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); goto bail; } printf("versionName='%s'", ResTable::normalizeForOutput(versionName.string()).string()); String8 splitName = AaptXml::getAttribute(tree, NULL, "split"); if (!splitName.isEmpty()) { printf(" split='%s'", ResTable::normalizeForOutput( splitName.string()).string()); } String8 platformVersionName = AaptXml::getAttribute(tree, NULL, "platformBuildVersionName"); printf(" platformBuildVersionName='%s'", platformVersionName.string()); printf("\n"); int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree, INSTALL_LOCATION_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n", error.string()); goto bail; } if (installLocation >= 0) { printf("install-location:'"); switch (installLocation) { case 0: printf("auto"); break; case 1: printf("internalOnly"); break; case 2: printf("preferExternal"); break; default: fprintf(stderr, "Invalid installLocation %d\n", installLocation); goto bail; } printf("'\n"); } } else if (depth == 2) { withinApplication = false; if (tag == "application") {
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; }