Loading libs/androidfw/ResourceTypes.cpp +51 −123 Original line number Diff line number Diff line Loading @@ -1020,141 +1020,69 @@ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool: return base::unexpected(std::nullopt); } base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str, size_t strLen) const { if (mError != NO_ERROR) { return base::unexpected(std::nullopt); } if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { if (kDebugStringPoolNoisy) { 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. size_t convBufferLen = strLen + 4; std::vector<char16_t> convBuffer(convBufferLen); ssize_t l = 0; ssize_t h = mHeader->stringCount-1; ssize_t mid; while (l <= h) { mid = l + (h - l)/2; int c = -1; const base::expected<StringPiece, NullOrIOError> s = string8At(mid); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); } if (s.has_value()) { char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()), s->size(), convBuffer.data(), convBufferLen); c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen); } if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", s->data(), c, (int)l, (int)mid, (int)h); } if (c == 0) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return mid; } else if (c < 0) { l = mid + 1; template <typename TChar, typename SP> base::expected<size_t, NullOrIOError> ResStringPool::stringIndex( SP sp, std::unordered_map<SP, size_t>& map) const { AutoMutex lock(mStringIndexLock); if (map.empty()) { // build string index on the first call for (size_t i = 0; i < mHeader->stringCount; i++) { base::expected<SP, NullOrIOError> s; if constexpr(std::is_same_v<TChar, char16_t>) { s = stringAt(i); } else { h = mid - 1; s = string8At(i); } if (s.has_value()) { const auto r = map.insert({*s, i}); if (!r.second) { ALOGE("failed to build string index, string id=%zu\n", i); } } 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 base::expected<StringPiece, NullOrIOError> s = string8At(i); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); } if (s.has_value()) { if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, i=%d\n", s->data(), i); } if (str8Len == s->size() && memcmp(s->data(), str8.string(), str8Len) == 0) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return i; } } if (!map.empty()) { const auto result = map.find(sp); if (result != map.end()) return result->second; } return base::unexpected(std::nullopt); } } else { if (kDebugStringPoolNoisy) { ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()); base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str, size_t strLen) const { if (mError != NO_ERROR) { return base::unexpected(std::nullopt); } if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... ssize_t l = 0; ssize_t h = mHeader->stringCount-1; ssize_t mid; while (l <= h) { mid = l + (h - l)/2; const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); } int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1; if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h); } if (c == 0) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return mid; } else if (c < 0) { l = mid + 1; } else { h = mid - 1; } ALOGI("indexOfString (%s): %s", isUTF8() ? "UTF-8" : "UTF-16", String8(str, strLen).string()); } base::expected<size_t, NullOrIOError> idx; if (isUTF8()) { auto str8 = String8(str, strLen); idx = stringIndex<char>(StringPiece(str8.c_str(), str8.size()), mStringIndex8); } 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. for (int i=mHeader->stringCount-1; i>=0; i--) { const base::expected<StringPiece16, NullOrIOError> s = stringAt(i); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); idx = stringIndex<char16_t>(StringPiece16(str, strLen), mStringIndex16); } if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i); if (UNLIKELY(!idx.has_value())) { return base::unexpected(idx.error()); } if (s.has_value() && strLen == s->size() && strzcmp16(s->data(), s->size(), str, strLen) == 0) { if (*idx < mHeader->stringCount) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return i; } } ALOGI("MATCH! (idx=%zu)", *idx); } return *idx; } return base::unexpected(std::nullopt); } Loading libs/androidfw/include/androidfw/ResourceTypes.h +10 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include <array> #include <map> #include <memory> #include <unordered_map> namespace android { Loading Loading @@ -562,8 +563,17 @@ private: incfs::map_ptr<uint32_t> mStyles; uint32_t mStylePoolSize; // number of uint32_t // mStringIndex is used to quickly map a string to its ID mutable Mutex mStringIndexLock; mutable std::unordered_map<StringPiece, size_t> mStringIndex8; mutable std::unordered_map<StringPiece16, size_t> mStringIndex16; base::expected<StringPiece, NullOrIOError> stringDecodeAt( size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const; template <typename TChar, typename SP=BasicStringPiece<TChar>> base::expected<size_t, NullOrIOError> stringIndex( SP str, std::unordered_map<SP, size_t>& map) const; }; /** Loading Loading
libs/androidfw/ResourceTypes.cpp +51 −123 Original line number Diff line number Diff line Loading @@ -1020,141 +1020,69 @@ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool: return base::unexpected(std::nullopt); } base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str, size_t strLen) const { if (mError != NO_ERROR) { return base::unexpected(std::nullopt); } if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { if (kDebugStringPoolNoisy) { 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. size_t convBufferLen = strLen + 4; std::vector<char16_t> convBuffer(convBufferLen); ssize_t l = 0; ssize_t h = mHeader->stringCount-1; ssize_t mid; while (l <= h) { mid = l + (h - l)/2; int c = -1; const base::expected<StringPiece, NullOrIOError> s = string8At(mid); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); } if (s.has_value()) { char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()), s->size(), convBuffer.data(), convBufferLen); c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen); } if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", s->data(), c, (int)l, (int)mid, (int)h); } if (c == 0) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return mid; } else if (c < 0) { l = mid + 1; template <typename TChar, typename SP> base::expected<size_t, NullOrIOError> ResStringPool::stringIndex( SP sp, std::unordered_map<SP, size_t>& map) const { AutoMutex lock(mStringIndexLock); if (map.empty()) { // build string index on the first call for (size_t i = 0; i < mHeader->stringCount; i++) { base::expected<SP, NullOrIOError> s; if constexpr(std::is_same_v<TChar, char16_t>) { s = stringAt(i); } else { h = mid - 1; s = string8At(i); } if (s.has_value()) { const auto r = map.insert({*s, i}); if (!r.second) { ALOGE("failed to build string index, string id=%zu\n", i); } } 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 base::expected<StringPiece, NullOrIOError> s = string8At(i); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); } if (s.has_value()) { if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, i=%d\n", s->data(), i); } if (str8Len == s->size() && memcmp(s->data(), str8.string(), str8Len) == 0) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return i; } } if (!map.empty()) { const auto result = map.find(sp); if (result != map.end()) return result->second; } return base::unexpected(std::nullopt); } } else { if (kDebugStringPoolNoisy) { ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()); base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str, size_t strLen) const { if (mError != NO_ERROR) { return base::unexpected(std::nullopt); } if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... ssize_t l = 0; ssize_t h = mHeader->stringCount-1; ssize_t mid; while (l <= h) { mid = l + (h - l)/2; const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); } int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1; if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h); } if (c == 0) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return mid; } else if (c < 0) { l = mid + 1; } else { h = mid - 1; } ALOGI("indexOfString (%s): %s", isUTF8() ? "UTF-8" : "UTF-16", String8(str, strLen).string()); } base::expected<size_t, NullOrIOError> idx; if (isUTF8()) { auto str8 = String8(str, strLen); idx = stringIndex<char>(StringPiece(str8.c_str(), str8.size()), mStringIndex8); } 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. for (int i=mHeader->stringCount-1; i>=0; i--) { const base::expected<StringPiece16, NullOrIOError> s = stringAt(i); if (UNLIKELY(IsIOError(s))) { return base::unexpected(s.error()); idx = stringIndex<char16_t>(StringPiece16(str, strLen), mStringIndex16); } if (kDebugStringPoolNoisy) { ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i); if (UNLIKELY(!idx.has_value())) { return base::unexpected(idx.error()); } if (s.has_value() && strLen == s->size() && strzcmp16(s->data(), s->size(), str, strLen) == 0) { if (*idx < mHeader->stringCount) { if (kDebugStringPoolNoisy) { ALOGI("MATCH!"); } return i; } } ALOGI("MATCH! (idx=%zu)", *idx); } return *idx; } return base::unexpected(std::nullopt); } Loading
libs/androidfw/include/androidfw/ResourceTypes.h +10 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include <array> #include <map> #include <memory> #include <unordered_map> namespace android { Loading Loading @@ -562,8 +563,17 @@ private: incfs::map_ptr<uint32_t> mStyles; uint32_t mStylePoolSize; // number of uint32_t // mStringIndex is used to quickly map a string to its ID mutable Mutex mStringIndexLock; mutable std::unordered_map<StringPiece, size_t> mStringIndex8; mutable std::unordered_map<StringPiece16, size_t> mStringIndex16; base::expected<StringPiece, NullOrIOError> stringDecodeAt( size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const; template <typename TChar, typename SP=BasicStringPiece<TChar>> base::expected<size_t, NullOrIOError> stringIndex( SP str, std::unordered_map<SP, size_t>& map) const; }; /** Loading