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 // The Public status of a resource. 42 struct Visibility { 43 enum class Level { 44 kUndefined, 45 kPrivate, 46 kPublic, 47 }; 48 49 Level level = Level::kUndefined; 50 Source source; 51 std::string comment; 52 }; 53 54 // Represents <add-resource> in an overlay. 55 struct AllowNew { 56 Source source; 57 std::string comment; 58 }; 59 60 // The policy dictating whether an entry is overlayable at runtime by RROs. 61 struct Overlayable { 62 Source source; 63 std::string comment; 64 }; 65 66 class ResourceConfigValue { 67 public: 68 // The configuration for which this value is defined. 69 const ConfigDescription config; 70 71 // The product for which this value is defined. 72 const std::string product; 73 74 // The actual Value. 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 // Represents a resource entry, which may have varying values for each defined configuration. 85 class ResourceEntry { 86 public: 87 // The name of the resource. Immutable, as this determines the order of this resource 88 // when doing lookups. 89 const std::string name; 90 91 // The entry ID for this resource (the EEEE in 0xPPTTEEEE). 92 Maybe<uint16_t> id; 93 94 // Whether this resource is public (and must maintain the same entry ID across builds). 95 Visibility visibility; 96 97 Maybe<AllowNew> allow_new; 98 99 Maybe<Overlayable> overlayable; 100 101 // The resource's values for each configuration. 102 std::vector<std::unique_ptr<ResourceConfigValue>> values; 103 ResourceEntry(const android::StringPiece & name)104 explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {} 105 106 ResourceConfigValue* FindValue(const ConfigDescription& config); 107 108 ResourceConfigValue* FindValue(const ConfigDescription& config, 109 const android::StringPiece& product); 110 111 ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config, 112 const android::StringPiece& product); 113 std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config); 114 115 template <typename Func> FindValuesIf(Func f)116 std::vector<ResourceConfigValue*> FindValuesIf(Func f) { 117 std::vector<ResourceConfigValue*> results; 118 for (auto& config_value : values) { 119 if (f(config_value.get())) { 120 results.push_back(config_value.get()); 121 } 122 } 123 return results; 124 } 125 126 bool HasDefaultValue() const; 127 128 private: 129 DISALLOW_COPY_AND_ASSIGN(ResourceEntry); 130 }; 131 132 // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries. 133 class ResourceTableType { 134 public: 135 // The logical type of resource (string, drawable, layout, etc.). 136 const ResourceType type; 137 138 // The type ID for this resource (the TT in 0xPPTTEEEE). 139 Maybe<uint8_t> id; 140 141 // Whether this type is public (and must maintain the same type ID across builds). 142 Visibility::Level visibility_level = Visibility::Level::kUndefined; 143 144 // List of resources for this type. 145 std::vector<std::unique_ptr<ResourceEntry>> entries; 146 ResourceTableType(const ResourceType type)147 explicit ResourceTableType(const ResourceType type) : type(type) {} 148 149 ResourceEntry* FindEntry(const android::StringPiece& name); 150 ResourceEntry* FindOrCreateEntry(const android::StringPiece& name); 151 152 private: 153 DISALLOW_COPY_AND_ASSIGN(ResourceTableType); 154 }; 155 156 class ResourceTablePackage { 157 public: 158 std::string name; 159 160 // The package ID (the PP in 0xPPTTEEEE). 161 Maybe<uint8_t> id; 162 163 std::vector<std::unique_ptr<ResourceTableType>> types; 164 165 ResourceTablePackage() = default; 166 ResourceTableType* FindType(ResourceType type); 167 ResourceTableType* FindOrCreateType(const ResourceType type); 168 169 private: 170 DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage); 171 }; 172 173 // The container and index for all resources defined for an app. 174 class ResourceTable { 175 public: 176 ResourceTable() = default; 177 178 enum class CollisionResult { kKeepOriginal, kConflict, kTakeNew }; 179 180 using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>; 181 182 // When a collision of resources occurs, this method decides which value to keep. 183 static CollisionResult ResolveValueCollision(Value* existing, Value* incoming); 184 185 bool AddResource(const ResourceNameRef& name, const ConfigDescription& config, 186 const android::StringPiece& product, std::unique_ptr<Value> value, 187 IDiagnostics* diag); 188 189 bool AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id, 190 const ConfigDescription& config, const android::StringPiece& product, 191 std::unique_ptr<Value> value, IDiagnostics* diag); 192 193 bool AddFileReference(const ResourceNameRef& name, const ConfigDescription& config, 194 const Source& source, const android::StringPiece& path, IDiagnostics* diag); 195 196 bool AddFileReferenceMangled(const ResourceNameRef& name, const ConfigDescription& config, 197 const Source& source, const android::StringPiece& path, 198 io::IFile* file, IDiagnostics* diag); 199 200 // Same as AddResource, but doesn't verify the validity of the name. This is used 201 // when loading resources from an existing binary resource table that may have mangled names. 202 bool AddResourceMangled(const ResourceNameRef& name, const ConfigDescription& config, 203 const android::StringPiece& product, std::unique_ptr<Value> value, 204 IDiagnostics* diag); 205 206 bool AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id, 207 const ConfigDescription& config, 208 const android::StringPiece& product, std::unique_ptr<Value> value, 209 IDiagnostics* diag); 210 211 bool SetVisibility(const ResourceNameRef& name, const Visibility& visibility, IDiagnostics* diag); 212 bool SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility, 213 IDiagnostics* diag); 214 bool SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility, 215 const ResourceId& res_id, IDiagnostics* diag); 216 bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility, 217 const ResourceId& res_id, IDiagnostics* diag); 218 219 bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, 220 IDiagnostics* diag); 221 bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable, 222 IDiagnostics* diag); 223 224 bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag); 225 bool SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new, 226 IDiagnostics* diag); 227 228 struct SearchResult { 229 ResourceTablePackage* package; 230 ResourceTableType* type; 231 ResourceEntry* entry; 232 }; 233 234 Maybe<SearchResult> FindResource(const ResourceNameRef& name) const; 235 236 // Returns the package struct with the given name, or nullptr if such a package does not 237 // exist. The empty string is a valid package and typically is used to represent the 238 // 'current' package before it is known to the ResourceTable. 239 ResourceTablePackage* FindPackage(const android::StringPiece& name) const; 240 241 ResourceTablePackage* FindPackageById(uint8_t id) const; 242 243 ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {}); 244 245 // Attempts to find a package having the specified name and ID. If not found, a new package 246 // of the specified parameters is created and returned. 247 ResourceTablePackage* CreatePackageAllowingDuplicateNames(const android::StringPiece& name, 248 const Maybe<uint8_t> id); 249 250 std::unique_ptr<ResourceTable> Clone() const; 251 252 // The string pool used by this resource table. Values that reference strings must use 253 // this pool to create their strings. 254 // NOTE: `string_pool` must come before `packages` so that it is destroyed after. 255 // When `string_pool` references are destroyed (as they will be when `packages` is destroyed), 256 // they decrement a refCount, which would cause invalid memory access if the pool was already 257 // destroyed. 258 StringPool string_pool; 259 260 // The list of packages in this table, sorted alphabetically by package name and increasing 261 // package ID (missing ID being the lowest). 262 std::vector<std::unique_ptr<ResourceTablePackage>> packages; 263 264 // Set of dynamic packages that this table may reference. Their package names get encoded 265 // into the resources.arsc along with their compile-time assigned IDs. 266 std::map<size_t, std::string> included_packages_; 267 268 private: 269 // The function type that validates a symbol name. Returns a non-empty StringPiece representing 270 // the offending character (which may be more than one byte in UTF-8). Returns an empty string 271 // if the name was valid. 272 using NameValidator = android::StringPiece(const android::StringPiece&); 273 274 ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name); 275 276 bool ValidateName(NameValidator validator, const ResourceNameRef& name, const Source& source, 277 IDiagnostics* diag); 278 279 bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id, 280 const ConfigDescription& config, const android::StringPiece& product, 281 std::unique_ptr<Value> value, NameValidator name_validator, 282 const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag); 283 284 bool AddFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config, 285 const Source& source, const android::StringPiece& path, io::IFile* file, 286 NameValidator name_validator, IDiagnostics* diag); 287 288 bool SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility, 289 const ResourceId& res_id, NameValidator name_validator, 290 IDiagnostics* diag); 291 292 bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new, 293 NameValidator name_validator, IDiagnostics* diag); 294 295 bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, 296 NameValidator name_validator, IDiagnostics* diag); 297 298 bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id, 299 const Visibility& symbol, NameValidator name_validator, 300 IDiagnostics* diag); 301 302 DISALLOW_COPY_AND_ASSIGN(ResourceTable); 303 }; 304 305 } // namespace aapt 306 307 #endif // AAPT_RESOURCE_TABLE_H 308