1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef AAPT_RESOURCE_TABLE_H 18 #define AAPT_RESOURCE_TABLE_H 19 20 #include "ConfigDescription.h" 21 #include "Diagnostics.h" 22 #include "Resource.h" 23 #include "ResourceValues.h" 24 #include "Source.h" 25 #include "StringPool.h" 26 #include "io/File.h" 27 28 #include "android-base/macros.h" 29 #include "androidfw/StringPiece.h" 30 31 #include <functional> 32 #include <map> 33 #include <memory> 34 #include <string> 35 #include <tuple> 36 #include <unordered_map> 37 #include <vector> 38 39 namespace aapt { 40 41 enum class SymbolState { 42 kUndefined, 43 kPrivate, 44 kPublic, 45 }; 46 47 /** 48 * The Public status of a resource. 49 */ 50 struct Symbol { 51 SymbolState state = SymbolState::kUndefined; 52 Source source; 53 54 // Whether this entry (originating from an overlay) can be added as a new resource. 55 bool allow_new = false; 56 57 std::string comment; 58 }; 59 60 class ResourceConfigValue { 61 public: 62 /** 63 * The configuration for which this value is defined. 64 */ 65 const ConfigDescription config; 66 67 /** 68 * The product for which this value is defined. 69 */ 70 const std::string product; 71 72 /** 73 * The actual Value. 74 */ 75 std::unique_ptr<Value> value; 76 ResourceConfigValue(const ConfigDescription & config,const android::StringPiece & product)77 ResourceConfigValue(const ConfigDescription& config, const android::StringPiece& product) 78 : config(config), product(product.to_string()) {} 79 80 private: 81 DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue); 82 }; 83 84 /** 85 * Represents a resource entry, which may have 86 * varying values for each defined configuration. 87 */ 88 class ResourceEntry { 89 public: 90 /** 91 * The name of the resource. Immutable, as 92 * this determines the order of this resource 93 * when doing lookups. 94 */ 95 const std::string name; 96 97 /** 98 * The entry ID for this resource. 99 */ 100 Maybe<uint16_t> id; 101 102 /** 103 * Whether this resource is public (and must maintain the same entry ID across 104 * builds). 105 */ 106 Symbol symbol_status; 107 108 /** 109 * The resource's values for each configuration. 110 */ 111 std::vector<std::unique_ptr<ResourceConfigValue>> values; 112 ResourceEntry(const android::StringPiece & name)113 explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {} 114 115 ResourceConfigValue* FindValue(const ConfigDescription& config); 116 ResourceConfigValue* FindValue(const ConfigDescription& config, 117 const android::StringPiece& product); 118 ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config, 119 const android::StringPiece& product); 120 std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config); 121 std::vector<ResourceConfigValue*> FindValuesIf( 122 const std::function<bool(ResourceConfigValue*)>& f); 123 124 private: 125 DISALLOW_COPY_AND_ASSIGN(ResourceEntry); 126 }; 127 128 /** 129 * Represents a resource type, which holds entries defined 130 * for this type. 131 */ 132 class ResourceTableType { 133 public: 134 /** 135 * The logical type of resource (string, drawable, layout, etc.). 136 */ 137 const ResourceType type; 138 139 /** 140 * The type ID for this resource. 141 */ 142 Maybe<uint8_t> id; 143 144 /** 145 * Whether this type is public (and must maintain the same 146 * type ID across builds). 147 */ 148 Symbol symbol_status; 149 150 /** 151 * List of resources for this type. 152 */ 153 std::vector<std::unique_ptr<ResourceEntry>> entries; 154 ResourceTableType(const ResourceType type)155 explicit ResourceTableType(const ResourceType type) : type(type) {} 156 157 ResourceEntry* FindEntry(const android::StringPiece& name); 158 ResourceEntry* FindOrCreateEntry(const android::StringPiece& name); 159 160 private: 161 DISALLOW_COPY_AND_ASSIGN(ResourceTableType); 162 }; 163 164 class ResourceTablePackage { 165 public: 166 Maybe<uint8_t> id; 167 std::string name; 168 169 std::vector<std::unique_ptr<ResourceTableType>> types; 170 171 ResourceTablePackage() = default; 172 ResourceTableType* FindType(ResourceType type); 173 ResourceTableType* FindOrCreateType(const ResourceType type); 174 175 private: 176 DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage); 177 }; 178 179 /** 180 * The container and index for all resources defined for an app. This gets 181 * flattened into a binary resource table (resources.arsc). 182 */ 183 class ResourceTable { 184 public: 185 ResourceTable() = default; 186 187 enum class CollisionResult { kKeepOriginal, kConflict, kTakeNew }; 188 189 using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>; 190 191 /** 192 * When a collision of resources occurs, this method decides which value to 193 * keep. 194 */ 195 static CollisionResult ResolveValueCollision(Value* existing, Value* incoming); 196 197 bool AddResource(const ResourceNameRef& name, const ConfigDescription& config, 198 const android::StringPiece& product, std::unique_ptr<Value> value, 199 IDiagnostics* diag); 200 201 bool AddResource(const ResourceNameRef& name, const ResourceId& res_id, 202 const ConfigDescription& config, const android::StringPiece& product, 203 std::unique_ptr<Value> value, IDiagnostics* diag); 204 205 bool AddFileReference(const ResourceNameRef& name, const ConfigDescription& config, 206 const Source& source, const android::StringPiece& path, IDiagnostics* diag); 207 208 bool AddFileReferenceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config, 209 const Source& source, const android::StringPiece& path, 210 io::IFile* file, IDiagnostics* diag); 211 212 /** 213 * Same as AddResource, but doesn't verify the validity of the name. This is 214 * used 215 * when loading resources from an existing binary resource table that may have 216 * mangled 217 * names. 218 */ 219 bool AddResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config, 220 const android::StringPiece& product, std::unique_ptr<Value> value, 221 IDiagnostics* diag); 222 223 bool AddResourceAllowMangled(const ResourceNameRef& name, const ResourceId& id, 224 const ConfigDescription& config, const android::StringPiece& product, 225 std::unique_ptr<Value> value, IDiagnostics* diag); 226 227 bool SetSymbolState(const ResourceNameRef& name, const ResourceId& res_id, 228 const Symbol& symbol, IDiagnostics* diag); 229 230 bool SetSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId& res_id, 231 const Symbol& symbol, IDiagnostics* diag); 232 233 struct SearchResult { 234 ResourceTablePackage* package; 235 ResourceTableType* type; 236 ResourceEntry* entry; 237 }; 238 239 Maybe<SearchResult> FindResource(const ResourceNameRef& name); 240 241 /** 242 * Returns the package struct with the given name, or nullptr if such a 243 * package does not 244 * exist. The empty string is a valid package and typically is used to 245 * represent the 246 * 'current' package before it is known to the ResourceTable. 247 */ 248 ResourceTablePackage* FindPackage(const android::StringPiece& name); 249 250 ResourceTablePackage* FindPackageById(uint8_t id); 251 252 ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {}); 253 254 /** 255 * The string pool used by this resource table. Values that reference strings 256 * must use 257 * this pool to create their strings. 258 * 259 * NOTE: `string_pool` must come before `packages` so that it is destroyed 260 * after. 261 * When `string_pool` references are destroyed (as they will be when 262 * `packages` 263 * is destroyed), they decrement a refCount, which would cause invalid 264 * memory access if the pool was already destroyed. 265 */ 266 StringPool string_pool; 267 268 /** 269 * The list of packages in this table, sorted alphabetically by package name. 270 */ 271 std::vector<std::unique_ptr<ResourceTablePackage>> packages; 272 273 // Set of dynamic packages that this table may reference. Their package names get encoded 274 // into the resources.arsc along with their compile-time assigned IDs. 275 std::map<size_t, std::string> included_packages_; 276 277 private: 278 // The function type that validates a symbol name. Returns a non-empty StringPiece representing 279 // the offending character (which may be more than one byte in UTF-8). Returns an empty string 280 // if the name was valid. 281 using NameValidator = android::StringPiece(const android::StringPiece&); 282 283 ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name); 284 285 bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id, 286 const ConfigDescription& config, const android::StringPiece& product, 287 std::unique_ptr<Value> value, NameValidator name_validator, 288 const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag); 289 290 bool AddFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config, 291 const Source& source, const android::StringPiece& path, io::IFile* file, 292 NameValidator name_validator, IDiagnostics* diag); 293 294 bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id, 295 const Symbol& symbol, NameValidator name_validator, IDiagnostics* diag); 296 297 DISALLOW_COPY_AND_ASSIGN(ResourceTable); 298 }; 299 300 } // namespace aapt 301 302 #endif // AAPT_RESOURCE_TABLE_H 303