Home | History | Annotate | Download | only in aapt2
      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 
     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 
    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 
    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