// // Copyright 2006 The Android Open Source Project // // Build resource files from raw assets. // #ifndef RESOURCE_TABLE_H #define RESOURCE_TABLE_H #include "ConfigDescription.h" #include "StringPool.h" #include "SourcePos.h" #include "ResourceFilter.h" #include <map> #include <queue> #include <set> using namespace std; class XMLNode; class ResourceTable; enum { XML_COMPILE_STRIP_COMMENTS = 1<<0, XML_COMPILE_ASSIGN_ATTRIBUTE_IDS = 1<<1, XML_COMPILE_COMPACT_WHITESPACE = 1<<2, XML_COMPILE_STRIP_WHITESPACE = 1<<3, XML_COMPILE_STRIP_RAW_VALUES = 1<<4, XML_COMPILE_UTF8 = 1<<5, XML_COMPILE_STANDARD_RESOURCE = XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES }; status_t compileXmlFile(const Bundle* bundle, const sp<AaptAssets>& assets, const String16& resourceName, const sp<AaptFile>& target, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); status_t compileXmlFile(const Bundle* bundle, const sp<AaptAssets>& assets, const String16& resourceName, const sp<AaptFile>& target, const sp<AaptFile>& outTarget, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); status_t compileXmlFile(const Bundle* bundle, const sp<AaptAssets>& assets, const String16& resourceName, const sp<XMLNode>& xmlTree, const sp<AaptFile>& target, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); status_t compileResourceFile(Bundle* bundle, const sp<AaptAssets>& assets, const sp<AaptFile>& in, const ResTable_config& defParams, const bool overwrite, ResourceTable* outTable); struct AccessorCookie { SourcePos sourcePos; String8 attr; String8 value; AccessorCookie(const SourcePos&p, const String8& a, const String8& v) :sourcePos(p), attr(a), value(v) { } }; // Holds the necessary information to compile the // resource. struct CompileResourceWorkItem { String16 resourceName; String8 resPath; sp<AaptFile> file; }; class ResourceTable : public ResTable::Accessor { public: // The type of package to build. enum PackageType { App, System, SharedLibrary, AppFeature }; class Package; class Type; class Entry; ResourceTable(Bundle* bundle, const String16& assetsPackage, PackageType type); const String16& getAssetsPackage() const { return mAssetsPackage; } /** * Returns the queue of resources that need to be compiled. * This is only used for resources that have been generated * during the compilation phase. If they were just added * to the AaptAssets, then they may be skipped over * and would mess up iteration order for the existing * resources. */ queue<CompileResourceWorkItem>& getWorkQueue() { return mWorkQueue; } status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets); status_t addPublic(const SourcePos& pos, const String16& package, const String16& type, const String16& name, const uint32_t ident); status_t addEntry(const SourcePos& pos, const String16& package, const String16& type, const String16& name, const String16& value, const Vector<StringPool::entry_style_span>* style = NULL, const ResTable_config* params = NULL, const bool doSetIndex = false, const int32_t format = ResTable_map::TYPE_ANY, const bool overwrite = false); status_t startBag(const SourcePos& pos, const String16& package, const String16& type, const String16& name, const String16& bagParent, const ResTable_config* params = NULL, bool overlay = false, bool replace = false, bool isId = false); status_t addBag(const SourcePos& pos, const String16& package, const String16& type, const String16& name, const String16& bagParent, const String16& bagKey, const String16& value, const Vector<StringPool::entry_style_span>* style = NULL, const ResTable_config* params = NULL, bool replace = false, bool isId = false, const int32_t format = ResTable_map::TYPE_ANY); bool hasBagOrEntry(const String16& package, const String16& type, const String16& name) const; bool hasBagOrEntry(const String16& package, const String16& type, const String16& name, const ResTable_config& config) const; bool hasBagOrEntry(const String16& ref, const String16* defType = NULL, const String16* defPackage = NULL); bool appendComment(const String16& package, const String16& type, const String16& name, const String16& comment, bool onlyIfEmpty = false); bool appendTypeComment(const String16& package, const String16& type, const String16& name, const String16& comment); void canAddEntry(const SourcePos& pos, const String16& package, const String16& type, const String16& name); size_t size() const; size_t numLocalResources() const; bool hasResources() const; status_t modifyForCompat(const Bundle* bundle); status_t modifyForCompat(const Bundle* bundle, const String16& resourceName, const sp<AaptFile>& file, const sp<XMLNode>& root); sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const bool isBase); static inline uint32_t makeResId(uint32_t packageId, uint32_t typeId, uint32_t nameId) { return nameId | (typeId<<16) | (packageId<<24); } static inline uint32_t getResId(const sp<Package>& p, const sp<Type>& t, uint32_t nameId); uint32_t getResId(const String16& package, const String16& type, const String16& name, bool onlyPublic = true) const; uint32_t getResId(const String16& ref, const String16* defType = NULL, const String16* defPackage = NULL, const char** outErrorMsg = NULL, bool onlyPublic = true) const; static bool isValidResourceName(const String16& s); bool stringToValue(Res_value* outValue, StringPool* pool, const String16& str, bool preserveSpaces, bool coerceType, uint32_t attrID, const Vector<StringPool::entry_style_span>* style = NULL, String16* outStr = NULL, void* accessorCookie = NULL, uint32_t attrType = ResTable_map::TYPE_ANY, const String8* configTypeName = NULL, const ConfigDescription* config = NULL); status_t assignResourceIds(); status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL); void addLocalization(const String16& name, const String8& locale, const SourcePos& src); status_t validateLocalizations(void); status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest, const bool isBase); status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs); void writePublicDefinitions(const String16& package, FILE* fp); virtual uint32_t getCustomResource(const String16& package, const String16& type, const String16& name) const; virtual uint32_t getCustomResourceWithCreation(const String16& package, const String16& type, const String16& name, const bool createIfNeeded); virtual uint32_t getRemappedPackage(uint32_t origPackage) const; virtual bool getAttributeType(uint32_t attrID, uint32_t* outType); virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin); virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax); virtual bool getAttributeKeys(uint32_t attrID, Vector<String16>* outKeys); virtual bool getAttributeEnum(uint32_t attrID, const char16_t* name, size_t nameLen, Res_value* outValue); virtual bool getAttributeFlags(uint32_t attrID, const char16_t* name, size_t nameLen, Res_value* outValue); virtual uint32_t getAttributeL10N(uint32_t attrID); virtual bool getLocalizationSetting(); virtual void reportError(void* accessorCookie, const char* fmt, ...); void setCurrentXmlPos(const SourcePos& pos) { mCurrentXmlPos = pos; } class Item { public: Item() : isId(false), format(ResTable_map::TYPE_ANY), bagKeyId(0), evaluating(false) { memset(&parsedValue, 0, sizeof(parsedValue)); } Item(const SourcePos& pos, bool _isId, const String16& _value, const Vector<StringPool::entry_style_span>* _style = NULL, int32_t format = ResTable_map::TYPE_ANY); Item(const Item& o) : sourcePos(o.sourcePos), isId(o.isId), value(o.value), style(o.style), format(o.format), bagKeyId(o.bagKeyId), evaluating(false) { memset(&parsedValue, 0, sizeof(parsedValue)); } ~Item() { } Item& operator=(const Item& o) { sourcePos = o.sourcePos; isId = o.isId; value = o.value; style = o.style; format = o.format; bagKeyId = o.bagKeyId; parsedValue = o.parsedValue; return *this; } SourcePos sourcePos; mutable bool isId; String16 value; Vector<StringPool::entry_style_span> style; int32_t format; uint32_t bagKeyId; mutable bool evaluating; Res_value parsedValue; }; class Entry : public RefBase { public: Entry(const String16& name, const SourcePos& pos) : mName(name), mType(TYPE_UNKNOWN), mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos) { } Entry(const Entry& entry); Entry& operator=(const Entry& entry); virtual ~Entry() { } enum type { TYPE_UNKNOWN = 0, TYPE_ITEM, TYPE_BAG }; String16 getName() const { return mName; } type getType() const { return mType; } void setParent(const String16& parent) { mParent = parent; } String16 getParent() const { return mParent; } status_t makeItABag(const SourcePos& sourcePos); status_t emptyBag(const SourcePos& sourcePos); status_t setItem(const SourcePos& pos, const String16& value, const Vector<StringPool::entry_style_span>* style = NULL, int32_t format = ResTable_map::TYPE_ANY, const bool overwrite = false); status_t addToBag(const SourcePos& pos, const String16& key, const String16& value, const Vector<StringPool::entry_style_span>* style = NULL, bool replace=false, bool isId = false, int32_t format = ResTable_map::TYPE_ANY); status_t removeFromBag(const String16& key); // Index of the entry's name string in the key pool. int32_t getNameIndex() const { return mNameIndex; } void setNameIndex(int32_t index) { mNameIndex = index; } const Item* getItem() const { return mType == TYPE_ITEM ? &mItem : NULL; } const KeyedVector<String16, Item>& getBag() const { return mBag; } status_t generateAttributes(ResourceTable* table, const String16& package); status_t assignResourceIds(ResourceTable* table, const String16& package); status_t prepareFlatten(StringPool* strings, ResourceTable* table, const String8* configTypeName, const ConfigDescription* config); status_t remapStringValue(StringPool* strings); ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic); const SourcePos& getPos() const { return mPos; } private: String16 mName; String16 mParent; type mType; Item mItem; int32_t mItemFormat; KeyedVector<String16, Item> mBag; int32_t mNameIndex; uint32_t mParentId; SourcePos mPos; }; class ConfigList : public RefBase { public: ConfigList(const String16& name, const SourcePos& pos) : mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { } virtual ~ConfigList() { } String16 getName() const { return mName; } const SourcePos& getPos() const { return mPos; } void appendComment(const String16& comment, bool onlyIfEmpty = false); const String16& getComment() const { return mComment; } void appendTypeComment(const String16& comment); const String16& getTypeComment() const { return mTypeComment; } // Index of this entry in its Type. int32_t getEntryIndex() const { return mEntryIndex; } void setEntryIndex(int32_t index) { mEntryIndex = index; } void setPublic(bool pub) { mPublic = pub; } bool getPublic() const { return mPublic; } void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; } const SourcePos& getPublicSourcePos() { return mPublicSourcePos; } void addEntry(const ResTable_config& config, const sp<Entry>& entry) { mEntries.add(config, entry); } const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; } private: const String16 mName; const SourcePos mPos; String16 mComment; String16 mTypeComment; bool mPublic; SourcePos mPublicSourcePos; int32_t mEntryIndex; DefaultKeyedVector<ConfigDescription, sp<Entry> > mEntries; }; class Public { public: Public() : sourcePos(), ident(0) { } Public(const SourcePos& pos, const String16& _comment, uint32_t _ident) : sourcePos(pos), comment(_comment), ident(_ident) { } Public(const Public& o) : sourcePos(o.sourcePos), comment(o.comment), ident(o.ident) { } ~Public() { } Public& operator=(const Public& o) { sourcePos = o.sourcePos; comment = o.comment; ident = o.ident; return *this; } SourcePos sourcePos; String16 comment; uint32_t ident; }; class Type : public RefBase { public: Type(const String16& name, const SourcePos& pos) : mName(name), mFirstPublicSourcePos(NULL), mPublicIndex(-1), mIndex(-1), mPos(pos) { } virtual ~Type() { delete mFirstPublicSourcePos; } status_t addPublic(const SourcePos& pos, const String16& name, const uint32_t ident); void canAddEntry(const String16& name); String16 getName() const { return mName; } sp<Entry> getEntry(const String16& entry, const SourcePos& pos, const ResTable_config* config = NULL, bool doSetIndex = false, bool overlay = false, bool autoAddOverlay = false); const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; } int32_t getPublicIndex() const { return mPublicIndex; } int32_t getIndex() const { return mIndex; } void setIndex(int32_t index) { mIndex = index; } status_t applyPublicEntryOrder(); const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; } const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; } const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; } const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; } const SourcePos& getPos() const { return mPos; } private: String16 mName; SourcePos* mFirstPublicSourcePos; DefaultKeyedVector<String16, Public> mPublic; SortedVector<ConfigDescription> mUniqueConfigs; DefaultKeyedVector<String16, sp<ConfigList> > mConfigs; Vector<sp<ConfigList> > mOrderedConfigs; SortedVector<String16> mCanAddEntries; int32_t mPublicIndex; int32_t mIndex; SourcePos mPos; }; class Package : public RefBase { public: Package(const String16& name, size_t packageId); virtual ~Package() { } String16 getName() const { return mName; } sp<Type> getType(const String16& type, const SourcePos& pos, bool doSetIndex = false); size_t getAssignedId() const { return mPackageId; } const ResStringPool& getTypeStrings() const { return mTypeStrings; } uint32_t indexOfTypeString(const String16& s) const { return mTypeStringsMapping.valueFor(s); } const sp<AaptFile> getTypeStringsData() const { return mTypeStringsData; } status_t setTypeStrings(const sp<AaptFile>& data); const ResStringPool& getKeyStrings() const { return mKeyStrings; } uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); } const sp<AaptFile> getKeyStringsData() const { return mKeyStringsData; } status_t setKeyStrings(const sp<AaptFile>& data); status_t applyPublicTypeOrder(); const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; } const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; } private: status_t setStrings(const sp<AaptFile>& data, ResStringPool* strings, DefaultKeyedVector<String16, uint32_t>* mappings); const String16 mName; const size_t mPackageId; DefaultKeyedVector<String16, sp<Type> > mTypes; Vector<sp<Type> > mOrderedTypes; sp<AaptFile> mTypeStringsData; sp<AaptFile> mKeyStringsData; ResStringPool mTypeStrings; ResStringPool mKeyStrings; DefaultKeyedVector<String16, uint32_t> mTypeStringsMapping; DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping; }; private: void writePublicDefinitions(const String16& package, FILE* fp, bool pub); sp<Package> getPackage(const String16& package); sp<Type> getType(const String16& package, const String16& type, const SourcePos& pos, bool doSetIndex = false); sp<Entry> getEntry(const String16& package, const String16& type, const String16& name, const SourcePos& pos, bool overlay, const ResTable_config* config = NULL, bool doSetIndex = false); sp<const Entry> getEntry(uint32_t resID, const ResTable_config* config = NULL) const; sp<ConfigList> getConfigList(const String16& package, const String16& type, const String16& name) const; const Item* getItem(uint32_t resID, uint32_t attrID) const; bool getItemValue(uint32_t resID, uint32_t attrID, Res_value* outValue); bool isAttributeFromL(uint32_t attrId); String16 mAssetsPackage; PackageType mPackageType; sp<AaptAssets> mAssets; uint32_t mTypeIdOffset; DefaultKeyedVector<String16, sp<Package> > mPackages; Vector<sp<Package> > mOrderedPackages; size_t mNumLocal; SourcePos mCurrentXmlPos; Bundle* mBundle; // key = string resource name, value = set of locales in which that name is defined map<String16, map<String8, SourcePos> > mLocalizations; queue<CompileResourceWorkItem> mWorkQueue; }; #endif