AssetManager2: Add GetResourceId
Add ability to lookup a resource by name. Test: make libandroidfw_tests Change-Id: I262ba5ce4c9892458226fbdb44cf21f9877fb92d
This commit is contained in:
@@ -36,6 +36,7 @@ cc_library {
|
||||
"misc.cpp",
|
||||
"ObbFile.cpp",
|
||||
"ResourceTypes.cpp",
|
||||
"ResourceUtils.cpp",
|
||||
"StreamingZipInflater.cpp",
|
||||
"TypeWrappers.cpp",
|
||||
"Util.cpp",
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
|
||||
@@ -235,9 +237,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
|
||||
desired_config = &density_override_config;
|
||||
}
|
||||
|
||||
const uint32_t package_id = util::get_package_id(resid);
|
||||
const uint8_t type_id = util::get_type_id(resid);
|
||||
const uint16_t entry_id = util::get_entry_id(resid);
|
||||
const uint32_t package_id = get_package_id(resid);
|
||||
const uint8_t type_id = get_type_id(resid);
|
||||
const uint16_t entry_id = get_entry_id(resid);
|
||||
|
||||
if (type_id == 0) {
|
||||
LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
|
||||
@@ -452,7 +454,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
|
||||
ResolvedBag::Entry* new_entry = new_bag->entries;
|
||||
for (; map_entry != map_entry_end; ++map_entry) {
|
||||
uint32_t new_key = dtohl(map_entry->name.ident);
|
||||
if (!util::is_internal_resid(new_key)) {
|
||||
if (!is_internal_resid(new_key)) {
|
||||
// Attributes, arrays, etc don't have a resource id as the name. They specify
|
||||
// other data, which would be wrong to change via a lookup.
|
||||
if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
|
||||
@@ -501,7 +503,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
|
||||
// The keys are expected to be in sorted order. Merge the two bags.
|
||||
while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
|
||||
uint32_t child_key = dtohl(map_entry->name.ident);
|
||||
if (!util::is_internal_resid(child_key)) {
|
||||
if (!is_internal_resid(child_key)) {
|
||||
if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
|
||||
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
|
||||
return nullptr;
|
||||
@@ -533,7 +535,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
|
||||
// Finish the child entries if they exist.
|
||||
while (map_entry != map_entry_end) {
|
||||
uint32_t new_key = dtohl(map_entry->name.ident);
|
||||
if (!util::is_internal_resid(new_key)) {
|
||||
if (!is_internal_resid(new_key)) {
|
||||
if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
|
||||
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
|
||||
return nullptr;
|
||||
@@ -571,12 +573,71 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
|
||||
ssize_t len =
|
||||
utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false);
|
||||
if (len < 0) {
|
||||
return false;
|
||||
}
|
||||
out->resize(static_cast<size_t>(len));
|
||||
utf8_to_utf16(reinterpret_cast<const uint8_t*>(str.data()), str.size(), &*out->begin(),
|
||||
static_cast<size_t>(len + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
|
||||
const std::string& fallback_type,
|
||||
const std::string& fallback_package) {
|
||||
(void)resource_name;
|
||||
(void)fallback_type;
|
||||
(void)fallback_package;
|
||||
StringPiece package_name, type, entry;
|
||||
if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
if (entry.empty()) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
if (package_name.empty()) {
|
||||
package_name = fallback_package;
|
||||
}
|
||||
|
||||
if (type.empty()) {
|
||||
type = fallback_type;
|
||||
}
|
||||
|
||||
std::u16string type16;
|
||||
if (!Utf8ToUtf16(type, &type16)) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
std::u16string entry16;
|
||||
if (!Utf8ToUtf16(entry, &entry16)) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
const StringPiece16 kAttr16 = u"attr";
|
||||
const static std::u16string kAttrPrivate16 = u"^attr-private";
|
||||
|
||||
for (const PackageGroup& package_group : package_groups_) {
|
||||
for (const LoadedPackage* package : package_group.packages_) {
|
||||
if (package_name != package->GetPackageName()) {
|
||||
// All packages in the same group are expected to have the same package name.
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t resid = package->FindEntryByName(type16, entry16);
|
||||
if (resid == 0u && kAttr16 == type16) {
|
||||
// Private attributes in libraries (such as the framework) are sometimes encoded
|
||||
// under the type '^attr-private' in order to leave the ID space of public 'attr'
|
||||
// free for future additions. Check '^attr-private' for the same name.
|
||||
resid = package->FindEntryByName(kAttrPrivate16, entry16);
|
||||
}
|
||||
|
||||
if (resid != 0u) {
|
||||
return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -619,15 +680,15 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) {
|
||||
|
||||
// If the resource ID passed in is not a style, the key can be
|
||||
// some other identifier that is not a resource ID.
|
||||
if (!util::is_valid_resid(attr_resid)) {
|
||||
if (!is_valid_resid(attr_resid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t package_idx = util::get_package_id(attr_resid);
|
||||
const uint32_t package_idx = get_package_id(attr_resid);
|
||||
|
||||
// The type ID is 1-based, so subtract 1 to get an index.
|
||||
const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
|
||||
const uint32_t entry_idx = util::get_entry_id(attr_resid);
|
||||
const uint32_t type_idx = get_type_id(attr_resid) - 1;
|
||||
const uint32_t entry_idx = get_entry_id(attr_resid);
|
||||
|
||||
std::unique_ptr<Package>& package = packages_[package_idx];
|
||||
if (package == nullptr) {
|
||||
@@ -656,9 +717,9 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) {
|
||||
// and populate the structures.
|
||||
for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
|
||||
const uint32_t attr_resid = bag_iter->key;
|
||||
const uint32_t package_idx = util::get_package_id(attr_resid);
|
||||
const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
|
||||
const uint32_t entry_idx = util::get_entry_id(attr_resid);
|
||||
const uint32_t package_idx = get_package_id(attr_resid);
|
||||
const uint32_t type_idx = get_type_id(attr_resid) - 1;
|
||||
const uint32_t entry_idx = get_entry_id(attr_resid);
|
||||
Package* package = packages_[package_idx].get();
|
||||
util::unique_cptr<Type>& type = package->types[type_idx];
|
||||
if (type->entry_count != type->entry_capacity) {
|
||||
@@ -691,15 +752,15 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
|
||||
uint32_t type_spec_flags = 0u;
|
||||
|
||||
for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) {
|
||||
if (!util::is_valid_resid(resid)) {
|
||||
if (!is_valid_resid(resid)) {
|
||||
return kInvalidCookie;
|
||||
}
|
||||
|
||||
const uint32_t package_idx = util::get_package_id(resid);
|
||||
const uint32_t package_idx = get_package_id(resid);
|
||||
|
||||
// Type ID is 1-based, subtract 1 to get the index.
|
||||
const uint32_t type_idx = util::get_type_id(resid) - 1;
|
||||
const uint32_t entry_idx = util::get_entry_id(resid);
|
||||
const uint32_t type_idx = get_type_id(resid) - 1;
|
||||
const uint32_t entry_idx = get_entry_id(resid);
|
||||
|
||||
const Package* package = packages_[package_idx].get();
|
||||
if (package == nullptr) {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "androidfw/ByteBucketArray.h"
|
||||
#include "androidfw/Chunk.h"
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
#include "androidfw/Util.h"
|
||||
|
||||
using android::base::StringPrintf;
|
||||
@@ -181,9 +182,9 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
|
||||
LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
|
||||
uint32_t* out_flags) const {
|
||||
ATRACE_CALL();
|
||||
const uint8_t package_id = util::get_package_id(resid);
|
||||
const uint8_t type_id = util::get_type_id(resid);
|
||||
const uint16_t entry_id = util::get_entry_id(resid);
|
||||
const uint8_t package_id = get_package_id(resid);
|
||||
const uint8_t type_id = get_type_id(resid);
|
||||
const uint16_t entry_id = get_entry_id(resid);
|
||||
|
||||
if (type_id == 0) {
|
||||
LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << ".";
|
||||
@@ -200,7 +201,7 @@ bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
|
||||
}
|
||||
|
||||
const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
|
||||
const uint8_t package_id = util::get_package_id(resid);
|
||||
const uint8_t package_id = get_package_id(resid);
|
||||
for (const auto& loaded_package : packages_) {
|
||||
if (loaded_package->package_id_ == package_id) {
|
||||
return loaded_package.get();
|
||||
@@ -372,6 +373,45 @@ void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
|
||||
const std::u16string& entry_name) const {
|
||||
ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size());
|
||||
if (type_idx < 0) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size());
|
||||
if (key_idx < 0) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
const TypeSpec* type_spec = type_specs_[type_idx].get();
|
||||
if (type_spec == nullptr) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
for (size_t ti = 0; ti < type_spec->type_count; ti++) {
|
||||
const Type* type = &type_spec->types[ti];
|
||||
size_t entry_count = dtohl(type->type->entryCount);
|
||||
for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
|
||||
const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
|
||||
reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
|
||||
const uint32_t offset = dtohl(entry_offsets[entry_idx]);
|
||||
if (offset != ResTable_type::NO_ENTRY) {
|
||||
const ResTable_entry* entry =
|
||||
reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) +
|
||||
dtohl(type->type->entriesStart) + offset);
|
||||
if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
|
||||
// The package ID will be overridden by the caller (due to runtime assignment of package
|
||||
// IDs for shared libraries).
|
||||
return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
|
||||
ATRACE_CALL();
|
||||
std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()};
|
||||
|
||||
48
libs/androidfw/ResourceUtils.cpp
Normal file
48
libs/androidfw/ResourceUtils.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
|
||||
StringPiece* out_entry) {
|
||||
*out_package = "";
|
||||
*out_type = "";
|
||||
bool has_package_separator = false;
|
||||
bool has_type_separator = false;
|
||||
const char* start = str.data();
|
||||
const char* end = start + str.size();
|
||||
const char* current = start;
|
||||
while (current != end) {
|
||||
if (out_type->size() == 0 && *current == '/') {
|
||||
has_type_separator = true;
|
||||
out_type->assign(start, current - start);
|
||||
start = current + 1;
|
||||
} else if (out_package->size() == 0 && *current == ':') {
|
||||
has_package_separator = true;
|
||||
out_package->assign(start, current - start);
|
||||
start = current + 1;
|
||||
}
|
||||
current++;
|
||||
}
|
||||
out_entry->assign(start, end - start);
|
||||
|
||||
return !(has_package_separator && out_package->empty()) &&
|
||||
!(has_type_separator && out_type->empty());
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
@@ -101,6 +101,13 @@ class LoadedPackage {
|
||||
// before being inserted into the set. This may cause some equivalent locales to de-dupe.
|
||||
void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
|
||||
|
||||
// Finds the entry with the specified type name and entry name. The names are in UTF-16 because
|
||||
// the underlying ResStringPool API expects this. For now this is acceptable, but since
|
||||
// the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
|
||||
// Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
|
||||
// for patching the correct package ID to the resource ID.
|
||||
uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
|
||||
|
||||
|
||||
60
libs/androidfw/include/androidfw/ResourceUtils.h
Normal file
60
libs/androidfw/include/androidfw/ResourceUtils.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROIDFW_RESOURCEUTILS_H
|
||||
#define ANDROIDFW_RESOURCEUTILS_H
|
||||
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// Extracts the package, type, and name from a string of the format: [[package:]type/]name
|
||||
// Validation must be performed on each extracted piece.
|
||||
// Returns false if there was a syntax error.
|
||||
bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
|
||||
StringPiece* out_entry);
|
||||
|
||||
inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
|
||||
return resid | (static_cast<uint32_t>(package_id) << 24);
|
||||
}
|
||||
|
||||
inline uint8_t get_package_id(uint32_t resid) {
|
||||
return static_cast<uint8_t>((resid >> 24) & 0x000000ffu);
|
||||
}
|
||||
|
||||
// The type ID is 1-based, so if the returned value is 0 it is invalid.
|
||||
inline uint8_t get_type_id(uint32_t resid) {
|
||||
return static_cast<uint8_t>((resid >> 16) & 0x000000ffu);
|
||||
}
|
||||
|
||||
inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
|
||||
|
||||
inline bool is_internal_resid(uint32_t resid) {
|
||||
return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
|
||||
}
|
||||
|
||||
inline bool is_valid_resid(uint32_t resid) {
|
||||
return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0;
|
||||
}
|
||||
|
||||
inline uint32_t make_resid(uint8_t package_id, uint8_t type_id, uint16_t entry_id) {
|
||||
return (static_cast<uint32_t>(package_id) << 24) | (static_cast<uint32_t>(type_id) << 16) |
|
||||
entry_id;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif /* ANDROIDFW_RESOURCEUTILS_H */
|
||||
@@ -257,6 +257,16 @@ inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>:
|
||||
return data_ + length_;
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
inline bool operator==(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
|
||||
return BasicStringPiece<TChar>(lhs) == rhs;
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
inline bool operator!=(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
|
||||
return BasicStringPiece<TChar>(lhs) != rhs;
|
||||
}
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
|
||||
return out.write(str.data(), str.size());
|
||||
}
|
||||
|
||||
@@ -106,29 +106,6 @@ class unique_cptr {
|
||||
pointer ptr_;
|
||||
};
|
||||
|
||||
inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
|
||||
return resid | (static_cast<uint32_t>(package_id) << 24);
|
||||
}
|
||||
|
||||
inline uint8_t get_package_id(uint32_t resid) {
|
||||
return static_cast<uint8_t>((resid >> 24) & 0x000000ffu);
|
||||
}
|
||||
|
||||
// The type ID is 1-based, so if the returned value is 0 it is invalid.
|
||||
inline uint8_t get_type_id(uint32_t resid) {
|
||||
return static_cast<uint8_t>((resid >> 16) & 0x000000ffu);
|
||||
}
|
||||
|
||||
inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
|
||||
|
||||
inline bool is_internal_resid(uint32_t resid) {
|
||||
return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
|
||||
}
|
||||
|
||||
inline bool is_valid_resid(uint32_t resid) {
|
||||
return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0;
|
||||
}
|
||||
|
||||
void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out);
|
||||
|
||||
} // namespace util
|
||||
|
||||
@@ -32,6 +32,7 @@ testFiles := \
|
||||
ConfigLocale_test.cpp \
|
||||
Idmap_test.cpp \
|
||||
LoadedArsc_test.cpp \
|
||||
ResourceUtils_test.cpp \
|
||||
ResTable_test.cpp \
|
||||
Split_test.cpp \
|
||||
StringPiece_test.cpp \
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "android-base/logging.h"
|
||||
|
||||
#include "TestHelpers.h"
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
#include "data/appaslib/R.h"
|
||||
#include "data/basic/R.h"
|
||||
#include "data/lib_one/R.h"
|
||||
@@ -194,11 +195,11 @@ TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
|
||||
ResTable_config selected_config;
|
||||
uint32_t flags;
|
||||
ApkAssetsCookie cookie = assetmanager.GetResource(
|
||||
util::fix_package_id(appaslib::R::integer::number1, 0x02), false /*may_be_bag*/,
|
||||
fix_package_id(appaslib::R::integer::number1, 0x02), false /*may_be_bag*/,
|
||||
0u /*density_override*/, &value, &selected_config, &flags);
|
||||
ASSERT_NE(kInvalidCookie, cookie);
|
||||
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
|
||||
EXPECT_EQ(util::fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
|
||||
EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
|
||||
@@ -238,9 +239,9 @@ TEST_F(AssetManager2Test, FindsBagResourceFromSharedLibrary) {
|
||||
|
||||
// First two attributes come from lib_one.
|
||||
EXPECT_EQ(1, bag->entries[0].cookie);
|
||||
EXPECT_EQ(0x03, util::get_package_id(bag->entries[0].key));
|
||||
EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
|
||||
EXPECT_EQ(1, bag->entries[1].cookie);
|
||||
EXPECT_EQ(0x03, util::get_package_id(bag->entries[1].key));
|
||||
EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
|
||||
|
||||
49
libs/androidfw/tests/ResourceUtils_test.cpp
Normal file
49
libs/androidfw/tests/ResourceUtils_test.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
|
||||
#include "TestHelpers.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST(ResourceUtilsTest, ExtractResourceName) {
|
||||
StringPiece package, type, entry;
|
||||
ASSERT_TRUE(ExtractResourceName("android:string/foo", &package, &type, &entry));
|
||||
EXPECT_EQ("android", package);
|
||||
EXPECT_EQ("string", type);
|
||||
EXPECT_EQ("foo", entry);
|
||||
|
||||
ASSERT_TRUE(ExtractResourceName("string/foo", &package, &type, &entry));
|
||||
EXPECT_EQ("", package);
|
||||
EXPECT_EQ("string", type);
|
||||
EXPECT_EQ("foo", entry);
|
||||
|
||||
ASSERT_TRUE(ExtractResourceName("foo", &package, &type, &entry));
|
||||
EXPECT_EQ("", package);
|
||||
EXPECT_EQ("", type);
|
||||
EXPECT_EQ("foo", entry);
|
||||
|
||||
ASSERT_TRUE(ExtractResourceName("android:foo", &package, &type, &entry));
|
||||
EXPECT_EQ("android", package);
|
||||
EXPECT_EQ("", type);
|
||||
EXPECT_EQ("foo", entry);
|
||||
|
||||
EXPECT_FALSE(ExtractResourceName(":string/foo", &package, &type, &entry));
|
||||
EXPECT_FALSE(ExtractResourceName("/foo", &package, &type, &entry));
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "android-base/logging.h"
|
||||
|
||||
#include "TestHelpers.h"
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
#include "data/lib_one/R.h"
|
||||
#include "data/libclient/R.h"
|
||||
#include "data/styles/R.h"
|
||||
@@ -215,9 +216,9 @@ TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
|
||||
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
|
||||
|
||||
// lib_one is assigned package ID 0x03.
|
||||
EXPECT_EQ(3u, util::get_package_id(value.data));
|
||||
EXPECT_EQ(util::get_type_id(lib_one::R::string::foo), util::get_type_id(value.data));
|
||||
EXPECT_EQ(util::get_entry_id(lib_one::R::string::foo), util::get_entry_id(value.data));
|
||||
EXPECT_EQ(3u, get_package_id(value.data));
|
||||
EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value.data));
|
||||
EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value.data));
|
||||
}
|
||||
|
||||
TEST_F(ThemeTest, CopyThemeSameAssetManager) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "androidfw/ResourceTypes.h"
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
|
||||
#include "NameMangler.h"
|
||||
#include "SdkConstants.h"
|
||||
@@ -69,31 +70,6 @@ Maybe<ResourceName> ToResourceName(
|
||||
return name_out;
|
||||
}
|
||||
|
||||
bool ExtractResourceName(const StringPiece& str, StringPiece* out_package,
|
||||
StringPiece* out_type, StringPiece* out_entry) {
|
||||
bool has_package_separator = false;
|
||||
bool has_type_separator = false;
|
||||
const char* start = str.data();
|
||||
const char* end = start + str.size();
|
||||
const char* current = start;
|
||||
while (current != end) {
|
||||
if (out_type->size() == 0 && *current == '/') {
|
||||
has_type_separator = true;
|
||||
out_type->assign(start, current - start);
|
||||
start = current + 1;
|
||||
} else if (out_package->size() == 0 && *current == ':') {
|
||||
has_package_separator = true;
|
||||
out_package->assign(start, current - start);
|
||||
start = current + 1;
|
||||
}
|
||||
current++;
|
||||
}
|
||||
out_entry->assign(start, end - start);
|
||||
|
||||
return !(has_package_separator && out_package->empty()) &&
|
||||
!(has_type_separator && out_type->empty());
|
||||
}
|
||||
|
||||
bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
|
||||
bool* out_private) {
|
||||
if (str.empty()) {
|
||||
@@ -110,8 +86,8 @@ bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
|
||||
StringPiece package;
|
||||
StringPiece type;
|
||||
StringPiece entry;
|
||||
if (!ExtractResourceName(str.substr(offset, str.size() - offset), &package,
|
||||
&type, &entry)) {
|
||||
if (!android::ExtractResourceName(str.substr(offset, str.size() - offset), &package, &type,
|
||||
&entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -197,8 +173,8 @@ bool ParseAttributeReference(const StringPiece& str, ResourceNameRef* out_ref) {
|
||||
StringPiece package;
|
||||
StringPiece type;
|
||||
StringPiece entry;
|
||||
if (!ExtractResourceName(trimmed_str.substr(1, trimmed_str.size() - 1),
|
||||
&package, &type, &entry)) {
|
||||
if (!android::ExtractResourceName(trimmed_str.substr(1, trimmed_str.size() - 1), &package,
|
||||
&type, &entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -258,7 +234,7 @@ Maybe<Reference> ParseStyleParentReference(const StringPiece& str,
|
||||
ref.type = ResourceType::kStyle;
|
||||
|
||||
StringPiece type_str;
|
||||
ExtractResourceName(name, &ref.package, &type_str, &ref.entry);
|
||||
android::ExtractResourceName(name, &ref.package, &type_str, &ref.entry);
|
||||
if (!type_str.empty()) {
|
||||
// If we have a type, make sure it is a Style.
|
||||
const ResourceType* parsed_type = ParseResourceType(type_str);
|
||||
|
||||
@@ -29,18 +29,6 @@
|
||||
namespace aapt {
|
||||
namespace ResourceUtils {
|
||||
|
||||
/*
|
||||
* Extracts the package, type, and name from a string of the format:
|
||||
*
|
||||
* [package:]type/name
|
||||
*
|
||||
* where the package can be empty. Validation must be performed on each
|
||||
* individual extracted piece to verify that the pieces are valid.
|
||||
* Returns false if there was no package but a ':' was present.
|
||||
*/
|
||||
bool ExtractResourceName(const android::StringPiece& str, android::StringPiece* out_package,
|
||||
android::StringPiece* out_type, android::StringPiece* out_entry);
|
||||
|
||||
/**
|
||||
* Returns true if the string was parsed as a resource name
|
||||
* ([*][package:]type/name), with
|
||||
|
||||
Reference in New Issue
Block a user