Loading core/jni/android_util_AssetManager.cpp +25 −9 Original line number Diff line number Diff line Loading @@ -586,7 +586,7 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } Loading @@ -594,20 +594,28 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject if (name.package != NULL) { str.setTo(name.package, name.packageLen); } if (name.type != NULL) { if (name.type8 != NULL || name.type != NULL) { if (str.size() > 0) { char16_t div = ':'; str.append(&div, 1); } if (name.type8 != NULL) { str.append(String16(name.type8, name.typeLen)); } else { str.append(name.type, name.typeLen); } if (name.name != NULL) { } if (name.name8 != NULL || name.name != NULL) { if (str.size() > 0) { char16_t div = '/'; str.append(&div, 1); } if (name.name8 != NULL) { str.append(String16(name.name8, name.nameLen)); } else { str.append(name.name, name.nameLen); } } return env->NewString((const jchar*)str.string(), str.size()); } Loading @@ -621,7 +629,7 @@ static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } Loading @@ -641,10 +649,14 @@ static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, job } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } if (name.type8 != NULL) { return env->NewStringUTF(name.type8); } if (name.type != NULL) { return env->NewString((const jchar*)name.type, name.typeLen); } Loading @@ -661,10 +673,14 @@ static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jo } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } if (name.name8 != NULL) { return env->NewStringUTF(name.name8); } if (name.name != NULL) { return env->NewString((const jchar*)name.name, name.nameLen); } Loading @@ -680,7 +696,7 @@ static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject { if (outValue == NULL) { jniThrowNullPointerException(env, "outValue"); return NULL; return 0; } AssetManager* am = assetManagerForJavaObject(env, clazz); if (am == NULL) { Loading include/androidfw/ResourceTypes.h +10 −4 Original line number Diff line number Diff line Loading @@ -479,7 +479,7 @@ private: const uint32_t* mEntries; const uint32_t* mEntryStyles; const void* mStrings; char16_t** mCache; char16_t mutable** mCache; uint32_t mStringPoolSize; // number of uint16_t const uint32_t* mStyles; uint32_t mStylePoolSize; // number of uint32_t Loading Loading @@ -683,6 +683,10 @@ public: const uint16_t* getAttributeName(size_t idx, size_t* outLen) const; uint32_t getAttributeNameResID(size_t idx) const; // These will work only if the underlying string pool is UTF-8. const char* getAttributeNamespace8(size_t idx, size_t* outLen) const; const char* getAttributeName8(size_t idx, size_t* outLen) const; int32_t getAttributeValueStringID(size_t idx) const; const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const; Loading Loading @@ -1294,12 +1298,14 @@ public: const char16_t* package; size_t packageLen; const char16_t* type; const char* type8; size_t typeLen; const char16_t* name; const char* name8; size_t nameLen; }; bool getResourceName(uint32_t resID, resource_name* outName) const; bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const; /** * Retrieve the value of a resource. If the resource is found, returns a Loading libs/androidfw/ResourceTypes.cpp +257 −83 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ #define INT32_MAX ((int32_t)(2147483647)) #endif #define POOL_NOISY(x) //x #define STRING_POOL_NOISY(x) //x #define XML_NOISY(x) //x #define TABLE_NOISY(x) //x #define TABLE_GETENTRY(x) //x Loading Loading @@ -378,7 +378,6 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) size_t charSize; if (mHeader->flags&ResStringPool_header::UTF8_FLAG) { charSize = sizeof(uint8_t); mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); } else { charSize = sizeof(char16_t); } Loading Loading @@ -593,6 +592,23 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) { AutoMutex lock(mDecodeLock); if (mCache == NULL) { #ifndef HAVE_ANDROID_OS STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes", mHeader->stringCount*sizeof(char16_t**))); #else // We do not want to be in this case when actually running Android. ALOGW("CREATING STRING CACHE OF %d bytes", mHeader->stringCount*sizeof(char16_t**)); #endif mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); if (mCache == NULL) { ALOGW("No memory trying to allocate decode cache table of %d bytes\n", (int)(mHeader->stringCount*sizeof(char16_t**))); return NULL; } } if (mCache[idx] != NULL) { return mCache[idx]; } Loading @@ -612,6 +628,7 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const return NULL; } STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str)); utf8_to_utf16(u8str, u8len, u16str); mCache[idx] = u16str; return u16str; Loading @@ -633,10 +650,11 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const const char* ResStringPool::string8At(size_t idx, size_t* outLen) const { if (mError == NO_ERROR && idx < mHeader->stringCount) { const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) { return NULL; } const uint32_t off = mEntries[idx]/sizeof(char); if (off < (mStringPoolSize-1)) { if (isUTF8) { const uint8_t* strings = (uint8_t*)mStrings; const uint8_t* str = strings+off; *outLen = decodeLength(&str); Loading @@ -647,7 +665,6 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const ALOGW("Bad string block: string #%d extends to %d, past end at %d\n", (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); } } } else { ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n", (int)idx, (int)(off*sizeof(uint16_t)), Loading Loading @@ -695,9 +712,67 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const size_t len; // TODO optimize searching for UTF-8 strings taking into account // the cache fill to determine when to convert the searched-for // string key to UTF-8. if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string())); // The string pool contains UTF 8 strings; we don't want to cause // temporary UTF-16 strings to be created as we search. if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... this is a little tricky, // because the strings are sorted with strzcmp16(). So to match // the ordering, we need to convert strings in the pool to UTF-16. // But we don't want to hit the cache, so instead we will have a // local temporary allocation for the conversions. char16_t* convBuffer = (char16_t*)malloc(strLen+4); ssize_t l = 0; ssize_t h = mHeader->stringCount-1; ssize_t mid; while (l <= h) { mid = l + (h - l)/2; const uint8_t* s = (const uint8_t*)string8At(mid, &len); int c; if (s != NULL) { char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3); *end = 0; c = strzcmp16(convBuffer, end-convBuffer, str, strLen); } else { c = -1; } STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", (const char*)s, c, (int)l, (int)mid, (int)h)); if (c == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); free(convBuffer); return mid; } else if (c < 0) { l = mid + 1; } else { h = mid - 1; } } free(convBuffer); } else { // It is unusual to get the ID from an unsorted string block... // most often this happens because we want to get IDs for style // span tags; since those always appear at the end of the string // block, start searching at the back. String8 str8(str, strLen); const size_t str8Len = str8.size(); for (int i=mHeader->stringCount-1; i>=0; i--) { const char* s = string8At(i, &len); STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", String8(s).string(), i)); if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); return i; } } } } else { STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string())); if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... Loading @@ -709,11 +784,11 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const mid = l + (h - l)/2; const char16_t* s = stringAt(mid, &len); int c = s ? strzcmp16(s, len, str, strLen) : -1; POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n", String8(str).string(), STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", String8(s).string(), c, (int)l, (int)mid, (int)h)); if (c == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); return mid; } else if (c < 0) { l = mid + 1; Loading @@ -728,15 +803,16 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const // block, start searching at the back. for (int i=mHeader->stringCount-1; i>=0; i--) { const char16_t* s = stringAt(i, &len); POOL_NOISY(printf("Looking for %s, at %s, i=%d\n", String8(str, strLen).string(), STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", String8(s).string(), i)); if (s && strzcmp16(s, len, str, strLen) == 0) { if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); return i; } } } } return NAME_NOT_FOUND; } Loading Loading @@ -936,6 +1012,14 @@ const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; } const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const { int32_t id = getAttributeNamespaceID(idx); //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; } int32_t ResXMLParser::getAttributeNameID(size_t idx) const { if (mEventCode == START_TAG) { Loading @@ -959,6 +1043,14 @@ const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; } const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const { int32_t id = getAttributeNameID(idx); //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; } uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const { int32_t id = getAttributeNameID(idx); Loading Loading @@ -1048,22 +1140,67 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen, const char16_t* attr, size_t attrLen) const { if (mEventCode == START_TAG) { if (attr == NULL) { return NAME_NOT_FOUND; } const size_t N = getAttributeCount(); if (mTree.mStrings.isUTF8()) { String8 ns8, attr8; if (ns != NULL) { ns8 = String8(ns, nsLen); } attr8 = String8(attr, attrLen); STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen, attr8.string(), attrLen)); for (size_t i=0; i<N; i++) { size_t curNsLen = 0, curAttrLen = 0; const char* curNs = getAttributeNamespace8(i, &curNsLen); const char* curAttr = getAttributeName8(i, &curAttrLen); STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen, curAttr, curAttrLen)); if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen && memcmp(attr8.string(), curAttr, attrLen) == 0) { if (ns == NULL) { if (curNs == NULL) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } else if (curNs != NULL) { //printf(" --> ns=%s, curNs=%s\n", // String8(ns).string(), String8(curNs).string()); if (memcmp(ns8.string(), curNs, nsLen) == 0) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } } } } else { STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)", String8(ns, nsLen).string(), nsLen, String8(attr, attrLen).string(), attrLen)); for (size_t i=0; i<N; i++) { size_t curNsLen, curAttrLen; size_t curNsLen = 0, curAttrLen = 0; const char16_t* curNs = getAttributeNamespace(i, &curNsLen); const char16_t* curAttr = getAttributeName(i, &curAttrLen); //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n", // i, ns, attr, curNs, curAttr); //printf(" --> attr=%s, curAttr=%s\n", // String8(attr).string(), String8(curAttr).string()); if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) { STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", String8(curNs, curNsLen).string(), curNsLen, String8(curAttr, curAttrLen).string(), curAttrLen)); if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) { if (ns == NULL) { if (curNs == NULL) return i; if (curNs == NULL) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } else if (curNs != NULL) { //printf(" --> ns=%s, curNs=%s\n", // String8(ns).string(), String8(curNs).string()); if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i; if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } } } } Loading Loading @@ -2940,7 +3077,7 @@ void ResTable::uninit() mHeaders.clear(); } bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const { if (mError != NO_ERROR) { return false; Loading Loading @@ -2980,14 +3117,29 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const outName->package = grp->name.string(); outName->packageLen = grp->name.size(); if (allowUtf8) { outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen); outName->name8 = grp->basePackage->keyStrings.string8At( dtohl(entry->key.index), &outName->nameLen); } else { outName->type8 = NULL; outName->name8 = NULL; } if (outName->type8 == NULL) { outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen); // If we have a bad index for some reason, we should abort. if (outName->type == NULL) { return false; } } if (outName->name8 == NULL) { outName->name = grp->basePackage->keyStrings.stringAt( dtohl(entry->key.index), &outName->nameLen); // If we have a bad index for some reason, we should abort. if (outName->type == NULL || outName->name == NULL) { if (outName->name == NULL) { return false; } } return true; } Loading Loading @@ -4485,7 +4637,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, while (cnt > 0) { if (!Res_INTERNALID(bag->map.name.ident)) { //printf("Trying attr #%08x\n", bag->map.name.ident); if (getResourceName(bag->map.name.ident, &rname)) { if (getResourceName(bag->map.name.ident, false, &rname)) { #if 0 printf("Matching %s against %s (0x%08x)\n", String8(s, len).string(), Loading Loading @@ -4538,7 +4690,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, for (i=0; i<cnt; i++, bagi++) { if (!Res_INTERNALID(bagi->map.name.ident)) { //printf("Trying attr #%08x\n", bagi->map.name.ident); if (getResourceName(bagi->map.name.ident, &rname)) { if (getResourceName(bagi->map.name.ident, false, &rname)) { #if 0 printf("Matching %s against %s (0x%08x)\n", String8(start,pos-start).string(), Loading Loading @@ -5216,7 +5368,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; if (!this->getResourceName(resID, &resName)) { if (!this->getResourceName(resID, true, &resName)) { ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID); // add dummy value, or trimming leading/trailing zeroes later will fail vector.push(0); Loading Loading @@ -5483,12 +5635,23 @@ void ResTable::print(bool inclValues) const | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; if (this->getResourceName(resID, &resName)) { if (this->getResourceName(resID, true, &resName)) { String8 type8; String8 name8; if (resName.type8 != NULL) { type8 = String8(resName.type8, resName.typeLen); } else { type8 = String8(resName.type, resName.typeLen); } if (resName.name8 != NULL) { name8 = String8(resName.name8, resName.nameLen); } else { name8 = String8(resName.name, resName.nameLen); } printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", resID, CHAR16_TO_CSTR(resName.package, resName.packageLen), CHAR16_TO_CSTR(resName.type, resName.typeLen), CHAR16_TO_CSTR(resName.name, resName.nameLen), type8.string(), name8.string(), dtohl(typeConfigs->typeSpecFlags[entryIndex])); } else { printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID); Loading Loading @@ -5531,11 +5694,22 @@ void ResTable::print(bool inclValues) const | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; if (this->getResourceName(resID, &resName)) { if (this->getResourceName(resID, true, &resName)) { String8 type8; String8 name8; if (resName.type8 != NULL) { type8 = String8(resName.type8, resName.typeLen); } else { type8 = String8(resName.type, resName.typeLen); } if (resName.name8 != NULL) { name8 = String8(resName.name8, resName.nameLen); } else { name8 = String8(resName.name, resName.nameLen); } printf(" resource 0x%08x %s:%s/%s: ", resID, CHAR16_TO_CSTR(resName.package, resName.packageLen), CHAR16_TO_CSTR(resName.type, resName.typeLen), CHAR16_TO_CSTR(resName.name, resName.nameLen)); type8.string(), name8.string()); } else { printf(" INVALID RESOURCE 0x%08x: ", resID); } Loading Loading
core/jni/android_util_AssetManager.cpp +25 −9 Original line number Diff line number Diff line Loading @@ -586,7 +586,7 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } Loading @@ -594,20 +594,28 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject if (name.package != NULL) { str.setTo(name.package, name.packageLen); } if (name.type != NULL) { if (name.type8 != NULL || name.type != NULL) { if (str.size() > 0) { char16_t div = ':'; str.append(&div, 1); } if (name.type8 != NULL) { str.append(String16(name.type8, name.typeLen)); } else { str.append(name.type, name.typeLen); } if (name.name != NULL) { } if (name.name8 != NULL || name.name != NULL) { if (str.size() > 0) { char16_t div = '/'; str.append(&div, 1); } if (name.name8 != NULL) { str.append(String16(name.name8, name.nameLen)); } else { str.append(name.name, name.nameLen); } } return env->NewString((const jchar*)str.string(), str.size()); } Loading @@ -621,7 +629,7 @@ static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } Loading @@ -641,10 +649,14 @@ static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, job } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } if (name.type8 != NULL) { return env->NewStringUTF(name.type8); } if (name.type != NULL) { return env->NewString((const jchar*)name.type, name.typeLen); } Loading @@ -661,10 +673,14 @@ static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jo } ResTable::resource_name name; if (!am->getResources().getResourceName(resid, &name)) { if (!am->getResources().getResourceName(resid, true, &name)) { return NULL; } if (name.name8 != NULL) { return env->NewStringUTF(name.name8); } if (name.name != NULL) { return env->NewString((const jchar*)name.name, name.nameLen); } Loading @@ -680,7 +696,7 @@ static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject { if (outValue == NULL) { jniThrowNullPointerException(env, "outValue"); return NULL; return 0; } AssetManager* am = assetManagerForJavaObject(env, clazz); if (am == NULL) { Loading
include/androidfw/ResourceTypes.h +10 −4 Original line number Diff line number Diff line Loading @@ -479,7 +479,7 @@ private: const uint32_t* mEntries; const uint32_t* mEntryStyles; const void* mStrings; char16_t** mCache; char16_t mutable** mCache; uint32_t mStringPoolSize; // number of uint16_t const uint32_t* mStyles; uint32_t mStylePoolSize; // number of uint32_t Loading Loading @@ -683,6 +683,10 @@ public: const uint16_t* getAttributeName(size_t idx, size_t* outLen) const; uint32_t getAttributeNameResID(size_t idx) const; // These will work only if the underlying string pool is UTF-8. const char* getAttributeNamespace8(size_t idx, size_t* outLen) const; const char* getAttributeName8(size_t idx, size_t* outLen) const; int32_t getAttributeValueStringID(size_t idx) const; const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const; Loading Loading @@ -1294,12 +1298,14 @@ public: const char16_t* package; size_t packageLen; const char16_t* type; const char* type8; size_t typeLen; const char16_t* name; const char* name8; size_t nameLen; }; bool getResourceName(uint32_t resID, resource_name* outName) const; bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const; /** * Retrieve the value of a resource. If the resource is found, returns a Loading
libs/androidfw/ResourceTypes.cpp +257 −83 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ #define INT32_MAX ((int32_t)(2147483647)) #endif #define POOL_NOISY(x) //x #define STRING_POOL_NOISY(x) //x #define XML_NOISY(x) //x #define TABLE_NOISY(x) //x #define TABLE_GETENTRY(x) //x Loading Loading @@ -378,7 +378,6 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) size_t charSize; if (mHeader->flags&ResStringPool_header::UTF8_FLAG) { charSize = sizeof(uint8_t); mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); } else { charSize = sizeof(char16_t); } Loading Loading @@ -593,6 +592,23 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) { AutoMutex lock(mDecodeLock); if (mCache == NULL) { #ifndef HAVE_ANDROID_OS STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes", mHeader->stringCount*sizeof(char16_t**))); #else // We do not want to be in this case when actually running Android. ALOGW("CREATING STRING CACHE OF %d bytes", mHeader->stringCount*sizeof(char16_t**)); #endif mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); if (mCache == NULL) { ALOGW("No memory trying to allocate decode cache table of %d bytes\n", (int)(mHeader->stringCount*sizeof(char16_t**))); return NULL; } } if (mCache[idx] != NULL) { return mCache[idx]; } Loading @@ -612,6 +628,7 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const return NULL; } STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str)); utf8_to_utf16(u8str, u8len, u16str); mCache[idx] = u16str; return u16str; Loading @@ -633,10 +650,11 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const const char* ResStringPool::string8At(size_t idx, size_t* outLen) const { if (mError == NO_ERROR && idx < mHeader->stringCount) { const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) { return NULL; } const uint32_t off = mEntries[idx]/sizeof(char); if (off < (mStringPoolSize-1)) { if (isUTF8) { const uint8_t* strings = (uint8_t*)mStrings; const uint8_t* str = strings+off; *outLen = decodeLength(&str); Loading @@ -647,7 +665,6 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const ALOGW("Bad string block: string #%d extends to %d, past end at %d\n", (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); } } } else { ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n", (int)idx, (int)(off*sizeof(uint16_t)), Loading Loading @@ -695,9 +712,67 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const size_t len; // TODO optimize searching for UTF-8 strings taking into account // the cache fill to determine when to convert the searched-for // string key to UTF-8. if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string())); // The string pool contains UTF 8 strings; we don't want to cause // temporary UTF-16 strings to be created as we search. if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... this is a little tricky, // because the strings are sorted with strzcmp16(). So to match // the ordering, we need to convert strings in the pool to UTF-16. // But we don't want to hit the cache, so instead we will have a // local temporary allocation for the conversions. char16_t* convBuffer = (char16_t*)malloc(strLen+4); ssize_t l = 0; ssize_t h = mHeader->stringCount-1; ssize_t mid; while (l <= h) { mid = l + (h - l)/2; const uint8_t* s = (const uint8_t*)string8At(mid, &len); int c; if (s != NULL) { char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3); *end = 0; c = strzcmp16(convBuffer, end-convBuffer, str, strLen); } else { c = -1; } STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", (const char*)s, c, (int)l, (int)mid, (int)h)); if (c == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); free(convBuffer); return mid; } else if (c < 0) { l = mid + 1; } else { h = mid - 1; } } free(convBuffer); } else { // It is unusual to get the ID from an unsorted string block... // most often this happens because we want to get IDs for style // span tags; since those always appear at the end of the string // block, start searching at the back. String8 str8(str, strLen); const size_t str8Len = str8.size(); for (int i=mHeader->stringCount-1; i>=0; i--) { const char* s = string8At(i, &len); STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", String8(s).string(), i)); if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); return i; } } } } else { STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string())); if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... Loading @@ -709,11 +784,11 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const mid = l + (h - l)/2; const char16_t* s = stringAt(mid, &len); int c = s ? strzcmp16(s, len, str, strLen) : -1; POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n", String8(str).string(), STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", String8(s).string(), c, (int)l, (int)mid, (int)h)); if (c == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); return mid; } else if (c < 0) { l = mid + 1; Loading @@ -728,15 +803,16 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const // block, start searching at the back. for (int i=mHeader->stringCount-1; i>=0; i--) { const char16_t* s = stringAt(i, &len); POOL_NOISY(printf("Looking for %s, at %s, i=%d\n", String8(str, strLen).string(), STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", String8(s).string(), i)); if (s && strzcmp16(s, len, str, strLen) == 0) { if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) { STRING_POOL_NOISY(ALOGI("MATCH!")); return i; } } } } return NAME_NOT_FOUND; } Loading Loading @@ -936,6 +1012,14 @@ const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; } const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const { int32_t id = getAttributeNamespaceID(idx); //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; } int32_t ResXMLParser::getAttributeNameID(size_t idx) const { if (mEventCode == START_TAG) { Loading @@ -959,6 +1043,14 @@ const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; } const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const { int32_t id = getAttributeNameID(idx); //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; } uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const { int32_t id = getAttributeNameID(idx); Loading Loading @@ -1048,22 +1140,67 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen, const char16_t* attr, size_t attrLen) const { if (mEventCode == START_TAG) { if (attr == NULL) { return NAME_NOT_FOUND; } const size_t N = getAttributeCount(); if (mTree.mStrings.isUTF8()) { String8 ns8, attr8; if (ns != NULL) { ns8 = String8(ns, nsLen); } attr8 = String8(attr, attrLen); STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen, attr8.string(), attrLen)); for (size_t i=0; i<N; i++) { size_t curNsLen = 0, curAttrLen = 0; const char* curNs = getAttributeNamespace8(i, &curNsLen); const char* curAttr = getAttributeName8(i, &curAttrLen); STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen, curAttr, curAttrLen)); if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen && memcmp(attr8.string(), curAttr, attrLen) == 0) { if (ns == NULL) { if (curNs == NULL) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } else if (curNs != NULL) { //printf(" --> ns=%s, curNs=%s\n", // String8(ns).string(), String8(curNs).string()); if (memcmp(ns8.string(), curNs, nsLen) == 0) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } } } } else { STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)", String8(ns, nsLen).string(), nsLen, String8(attr, attrLen).string(), attrLen)); for (size_t i=0; i<N; i++) { size_t curNsLen, curAttrLen; size_t curNsLen = 0, curAttrLen = 0; const char16_t* curNs = getAttributeNamespace(i, &curNsLen); const char16_t* curAttr = getAttributeName(i, &curAttrLen); //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n", // i, ns, attr, curNs, curAttr); //printf(" --> attr=%s, curAttr=%s\n", // String8(attr).string(), String8(curAttr).string()); if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) { STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", String8(curNs, curNsLen).string(), curNsLen, String8(curAttr, curAttrLen).string(), curAttrLen)); if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) { if (ns == NULL) { if (curNs == NULL) return i; if (curNs == NULL) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } else if (curNs != NULL) { //printf(" --> ns=%s, curNs=%s\n", // String8(ns).string(), String8(curNs).string()); if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i; if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) { STRING_POOL_NOISY(ALOGI(" FOUND!")); return i; } } } } } Loading Loading @@ -2940,7 +3077,7 @@ void ResTable::uninit() mHeaders.clear(); } bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const { if (mError != NO_ERROR) { return false; Loading Loading @@ -2980,14 +3117,29 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const outName->package = grp->name.string(); outName->packageLen = grp->name.size(); if (allowUtf8) { outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen); outName->name8 = grp->basePackage->keyStrings.string8At( dtohl(entry->key.index), &outName->nameLen); } else { outName->type8 = NULL; outName->name8 = NULL; } if (outName->type8 == NULL) { outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen); // If we have a bad index for some reason, we should abort. if (outName->type == NULL) { return false; } } if (outName->name8 == NULL) { outName->name = grp->basePackage->keyStrings.stringAt( dtohl(entry->key.index), &outName->nameLen); // If we have a bad index for some reason, we should abort. if (outName->type == NULL || outName->name == NULL) { if (outName->name == NULL) { return false; } } return true; } Loading Loading @@ -4485,7 +4637,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, while (cnt > 0) { if (!Res_INTERNALID(bag->map.name.ident)) { //printf("Trying attr #%08x\n", bag->map.name.ident); if (getResourceName(bag->map.name.ident, &rname)) { if (getResourceName(bag->map.name.ident, false, &rname)) { #if 0 printf("Matching %s against %s (0x%08x)\n", String8(s, len).string(), Loading Loading @@ -4538,7 +4690,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, for (i=0; i<cnt; i++, bagi++) { if (!Res_INTERNALID(bagi->map.name.ident)) { //printf("Trying attr #%08x\n", bagi->map.name.ident); if (getResourceName(bagi->map.name.ident, &rname)) { if (getResourceName(bagi->map.name.ident, false, &rname)) { #if 0 printf("Matching %s against %s (0x%08x)\n", String8(start,pos-start).string(), Loading Loading @@ -5216,7 +5368,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; if (!this->getResourceName(resID, &resName)) { if (!this->getResourceName(resID, true, &resName)) { ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID); // add dummy value, or trimming leading/trailing zeroes later will fail vector.push(0); Loading Loading @@ -5483,12 +5635,23 @@ void ResTable::print(bool inclValues) const | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; if (this->getResourceName(resID, &resName)) { if (this->getResourceName(resID, true, &resName)) { String8 type8; String8 name8; if (resName.type8 != NULL) { type8 = String8(resName.type8, resName.typeLen); } else { type8 = String8(resName.type, resName.typeLen); } if (resName.name8 != NULL) { name8 = String8(resName.name8, resName.nameLen); } else { name8 = String8(resName.name, resName.nameLen); } printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", resID, CHAR16_TO_CSTR(resName.package, resName.packageLen), CHAR16_TO_CSTR(resName.type, resName.typeLen), CHAR16_TO_CSTR(resName.name, resName.nameLen), type8.string(), name8.string(), dtohl(typeConfigs->typeSpecFlags[entryIndex])); } else { printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID); Loading Loading @@ -5531,11 +5694,22 @@ void ResTable::print(bool inclValues) const | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; if (this->getResourceName(resID, &resName)) { if (this->getResourceName(resID, true, &resName)) { String8 type8; String8 name8; if (resName.type8 != NULL) { type8 = String8(resName.type8, resName.typeLen); } else { type8 = String8(resName.type, resName.typeLen); } if (resName.name8 != NULL) { name8 = String8(resName.name8, resName.nameLen); } else { name8 = String8(resName.name, resName.nameLen); } printf(" resource 0x%08x %s:%s/%s: ", resID, CHAR16_TO_CSTR(resName.package, resName.packageLen), CHAR16_TO_CSTR(resName.type, resName.typeLen), CHAR16_TO_CSTR(resName.name, resName.nameLen)); type8.string(), name8.string()); } else { printf(" INVALID RESOURCE 0x%08x: ", resID); } Loading