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