/* * Copyright (C) 2015 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 AAPT_RESOURCE_TABLE_H #define AAPT_RESOURCE_TABLE_H #include "ConfigDescription.h" #include "Diagnostics.h" #include "Resource.h" #include "ResourceValues.h" #include "Source.h" #include "StringPool.h" #include "io/File.h" #include <android-base/macros.h> #include <map> #include <memory> #include <string> #include <tuple> #include <unordered_map> #include <vector> namespace aapt { enum class SymbolState { kUndefined, kPublic, kPrivate }; /** * The Public status of a resource. */ struct Symbol { SymbolState state = SymbolState::kUndefined; Source source; std::u16string comment; }; class ResourceConfigValue { public: /** * The configuration for which this value is defined. */ const ConfigDescription config; /** * The product for which this value is defined. */ const std::string product; /** * The actual Value. */ std::unique_ptr<Value> value; ResourceConfigValue(const ConfigDescription& config, const StringPiece& product) : config(config), product(product.toString()) { } private: DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue); }; /** * Represents a resource entry, which may have * varying values for each defined configuration. */ class ResourceEntry { public: /** * The name of the resource. Immutable, as * this determines the order of this resource * when doing lookups. */ const std::u16string name; /** * The entry ID for this resource. */ Maybe<uint16_t> id; /** * Whether this resource is public (and must maintain the same entry ID across builds). */ Symbol symbolStatus; /** * The resource's values for each configuration. */ std::vector<std::unique_ptr<ResourceConfigValue>> values; ResourceEntry(const StringPiece16& name) : name(name.toString()) { } ResourceConfigValue* findValue(const ConfigDescription& config); ResourceConfigValue* findValue(const ConfigDescription& config, const StringPiece& product); ResourceConfigValue* findOrCreateValue(const ConfigDescription& config, const StringPiece& product); std::vector<ResourceConfigValue*> findAllValues(const ConfigDescription& config); private: DISALLOW_COPY_AND_ASSIGN(ResourceEntry); }; /** * Represents a resource type, which holds entries defined * for this type. */ class ResourceTableType { public: /** * The logical type of resource (string, drawable, layout, etc.). */ const ResourceType type; /** * The type ID for this resource. */ Maybe<uint8_t> id; /** * Whether this type is public (and must maintain the same * type ID across builds). */ Symbol symbolStatus; /** * List of resources for this type. */ std::vector<std::unique_ptr<ResourceEntry>> entries; explicit ResourceTableType(const ResourceType type) : type(type) { } ResourceEntry* findEntry(const StringPiece16& name); ResourceEntry* findOrCreateEntry(const StringPiece16& name); private: DISALLOW_COPY_AND_ASSIGN(ResourceTableType); }; enum class PackageType { System, Vendor, App, Dynamic }; class ResourceTablePackage { public: PackageType type = PackageType::App; Maybe<uint8_t> id; std::u16string name; std::vector<std::unique_ptr<ResourceTableType>> types; ResourceTablePackage() = default; ResourceTableType* findType(ResourceType type); ResourceTableType* findOrCreateType(const ResourceType type); private: DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage); }; /** * The container and index for all resources defined for an app. This gets * flattened into a binary resource table (resources.arsc). */ class ResourceTable { public: ResourceTable() = default; /** * When a collision of resources occurs, this method decides which value to keep. * Returns -1 if the existing value should be chosen. * Returns 0 if the collision can not be resolved (error). * Returns 1 if the incoming value should be chosen. */ static int resolveValueCollision(Value* existing, Value* incoming); bool addResource(const ResourceNameRef& name, const ConfigDescription& config, const StringPiece& product, std::unique_ptr<Value> value, IDiagnostics* diag); bool addResource(const ResourceNameRef& name, const ResourceId resId, const ConfigDescription& config, const StringPiece& product, std::unique_ptr<Value> value, IDiagnostics* diag); bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config, const Source& source, const StringPiece16& path, IDiagnostics* diag); bool addFileReferenceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config, const Source& source, const StringPiece16& path, io::IFile* file, IDiagnostics* diag); /** * Same as addResource, but doesn't verify the validity of the name. This is used * when loading resources from an existing binary resource table that may have mangled * names. */ bool addResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config, const StringPiece& product, std::unique_ptr<Value> value, IDiagnostics* diag); bool addResourceAllowMangled(const ResourceNameRef& name, const ResourceId id, const ConfigDescription& config, const StringPiece& product, std::unique_ptr<Value> value, IDiagnostics* diag); bool setSymbolState(const ResourceNameRef& name, const ResourceId resId, const Symbol& symbol, IDiagnostics* diag); bool setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId, const Symbol& symbol, IDiagnostics* diag); struct SearchResult { ResourceTablePackage* package; ResourceTableType* type; ResourceEntry* entry; }; Maybe<SearchResult> findResource(const ResourceNameRef& name); /** * The string pool used by this resource table. Values that reference strings must use * this pool to create their strings. * * NOTE: `stringPool` must come before `packages` so that it is destroyed after. * When `string pool` references are destroyed (as they will be when `packages` * is destroyed), they decrement a refCount, which would cause invalid * memory access if the pool was already destroyed. */ StringPool stringPool; /** * The list of packages in this table, sorted alphabetically by package name. */ std::vector<std::unique_ptr<ResourceTablePackage>> packages; /** * Returns the package struct with the given name, or nullptr if such a package does not * exist. The empty string is a valid package and typically is used to represent the * 'current' package before it is known to the ResourceTable. */ ResourceTablePackage* findPackage(const StringPiece16& name); ResourceTablePackage* findPackageById(uint8_t id); ResourceTablePackage* createPackage(const StringPiece16& name, Maybe<uint8_t> id = {}); private: ResourceTablePackage* findOrCreatePackage(const StringPiece16& name); bool addFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config, const Source& source, const StringPiece16& path, io::IFile* file, const char16_t* validChars, IDiagnostics* diag); bool addResourceImpl(const ResourceNameRef& name, ResourceId resId, const ConfigDescription& config, const StringPiece& product, std::unique_ptr<Value> value, const char16_t* validChars, std::function<int(Value*,Value*)> conflictResolver, IDiagnostics* diag); bool setSymbolStateImpl(const ResourceNameRef& name, ResourceId resId, const Symbol& symbol, const char16_t* validChars, IDiagnostics* diag); DISALLOW_COPY_AND_ASSIGN(ResourceTable); }; } // namespace aapt #endif // AAPT_RESOURCE_TABLE_H