AssetManager2: Add GetResourceId

Add ability to lookup a resource by name.

Test: make libandroidfw_tests
Change-Id: I262ba5ce4c9892458226fbdb44cf21f9877fb92d
This commit is contained in:
Adam Lesinski
2017-01-16 19:11:19 -08:00
parent c270de85cc
commit 929d6517df
14 changed files with 316 additions and 96 deletions

View File

@@ -36,6 +36,7 @@ cc_library {
"misc.cpp",
"ObbFile.cpp",
"ResourceTypes.cpp",
"ResourceUtils.cpp",
"StreamingZipInflater.cpp",
"TypeWrappers.cpp",
"Util.cpp",

View File

@@ -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) {

View File

@@ -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()};

View 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

View File

@@ -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);

View 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 */

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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 \

View File

@@ -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) {

View 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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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