1//
2// Copyright 2006 The Android Open Source Project
3//
4// Build resource files from raw assets.
5//
6
7#ifndef RESOURCE_TABLE_H
8#define RESOURCE_TABLE_H
9
10#include <map>
11#include <queue>
12#include <set>
13
14#include "ConfigDescription.h"
15#include "ResourceFilter.h"
16#include "SourcePos.h"
17#include "StringPool.h"
18#include "Symbol.h"
19
20class XMLNode;
21class ResourceTable;
22
23enum {
24    XML_COMPILE_STRIP_COMMENTS = 1<<0,
25    XML_COMPILE_ASSIGN_ATTRIBUTE_IDS = 1<<1,
26    XML_COMPILE_PARSE_VALUES = 1 << 2,
27    XML_COMPILE_COMPACT_WHITESPACE = 1<<3,
28    XML_COMPILE_STRIP_WHITESPACE = 1<<4,
29    XML_COMPILE_STRIP_RAW_VALUES = 1<<5,
30    XML_COMPILE_UTF8 = 1<<6,
31
32    XML_COMPILE_STANDARD_RESOURCE =
33            XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS | XML_COMPILE_PARSE_VALUES
34            | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
35};
36
37status_t compileXmlFile(const Bundle* bundle,
38                        const sp<AaptAssets>& assets,
39                        const String16& resourceName,
40                        const sp<AaptFile>& target,
41                        ResourceTable* table,
42                        int options = XML_COMPILE_STANDARD_RESOURCE);
43
44status_t compileXmlFile(const Bundle* bundle,
45                        const sp<AaptAssets>& assets,
46                        const String16& resourceName,
47                        const sp<AaptFile>& target,
48                        const sp<AaptFile>& outTarget,
49                        ResourceTable* table,
50                        int options = XML_COMPILE_STANDARD_RESOURCE);
51
52status_t compileXmlFile(const Bundle* bundle,
53                        const sp<AaptAssets>& assets,
54                        const String16& resourceName,
55                        const sp<XMLNode>& xmlTree,
56                        const sp<AaptFile>& target,
57                        ResourceTable* table,
58                        int options = XML_COMPILE_STANDARD_RESOURCE);
59
60status_t compileResourceFile(Bundle* bundle,
61                             const sp<AaptAssets>& assets,
62                             const sp<AaptFile>& in,
63                             const ResTable_config& defParams,
64                             const bool overwrite,
65                             ResourceTable* outTable);
66
67struct AccessorCookie
68{
69    SourcePos sourcePos;
70    String8 attr;
71    String8 value;
72
73    AccessorCookie(const SourcePos&p, const String8& a, const String8& v)
74        :sourcePos(p),
75         attr(a),
76         value(v)
77    {
78    }
79};
80
81// Holds the necessary information to compile the
82// resource.
83struct CompileResourceWorkItem {
84    String16 resourceName;
85    String8 resPath;
86    sp<AaptFile> file;
87    sp<XMLNode> xmlRoot;
88    bool needsCompiling = true;
89};
90
91class ResourceTable : public ResTable::Accessor
92{
93public:
94    // The type of package to build.
95    enum PackageType {
96        App,
97        System,
98        SharedLibrary,
99        AppFeature
100    };
101
102    class Package;
103    class Type;
104    class Entry;
105    class ConfigList;
106
107    /**
108     * Exposed for testing. Determines whether a versioned resource should be generated
109     * based on the other available configurations for that resource.
110     */
111    static bool shouldGenerateVersionedResource(const sp<ConfigList>& configList,
112                                                const ConfigDescription& sourceConfig,
113                                                const int sdkVersionToGenerate);
114
115    ResourceTable(Bundle* bundle, const String16& assetsPackage, PackageType type);
116
117    const String16& getAssetsPackage() const {
118        return mAssetsPackage;
119    }
120
121    /**
122     * Returns the queue of resources that need to be compiled.
123     * This is only used for resources that have been generated
124     * during the compilation phase. If they were just added
125     * to the AaptAssets, then they may be skipped over
126     * and would mess up iteration order for the existing
127     * resources.
128     */
129    std::queue<CompileResourceWorkItem>& getWorkQueue() {
130        return mWorkQueue;
131    }
132
133    status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
134
135    status_t addPublic(const SourcePos& pos,
136                       const String16& package,
137                       const String16& type,
138                       const String16& name,
139                       const uint32_t ident);
140
141    status_t addEntry(const SourcePos& pos,
142                      const String16& package,
143                      const String16& type,
144                      const String16& name,
145                      const String16& value,
146                      const Vector<StringPool::entry_style_span>* style = NULL,
147                      const ResTable_config* params = NULL,
148                      const bool doSetIndex = false,
149                      const int32_t format = ResTable_map::TYPE_ANY,
150                      const bool overwrite = false);
151
152    status_t startBag(const SourcePos& pos,
153                    const String16& package,
154                    const String16& type,
155                    const String16& name,
156                    const String16& bagParent,
157                    const ResTable_config* params = NULL,
158                    bool overlay = false,
159                    bool replace = false,
160                    bool isId = false);
161
162    status_t addBag(const SourcePos& pos,
163                    const String16& package,
164                    const String16& type,
165                    const String16& name,
166                    const String16& bagParent,
167                    const String16& bagKey,
168                    const String16& value,
169                    const Vector<StringPool::entry_style_span>* style = NULL,
170                    const ResTable_config* params = NULL,
171                    bool replace = false,
172                    bool isId = false,
173                    const int32_t format = ResTable_map::TYPE_ANY);
174
175    bool hasBagOrEntry(const String16& package,
176                       const String16& type,
177                       const String16& name) const;
178
179    bool hasBagOrEntry(const String16& package,
180                       const String16& type,
181                       const String16& name,
182                       const ResTable_config& config) const;
183
184    bool hasBagOrEntry(const String16& ref,
185                       const String16* defType = NULL,
186                       const String16* defPackage = NULL);
187
188    bool appendComment(const String16& package,
189                       const String16& type,
190                       const String16& name,
191                       const String16& comment,
192                       bool onlyIfEmpty = false);
193
194    bool appendTypeComment(const String16& package,
195                           const String16& type,
196                           const String16& name,
197                           const String16& comment);
198
199    void canAddEntry(const SourcePos& pos,
200        const String16& package, const String16& type, const String16& name);
201
202    size_t size() const;
203    size_t numLocalResources() const;
204    bool hasResources() const;
205
206    status_t modifyForCompat(const Bundle* bundle);
207    status_t modifyForCompat(const Bundle* bundle,
208                             const String16& resourceName,
209                             const sp<AaptFile>& file,
210                             const sp<XMLNode>& root);
211
212    status_t processBundleFormat(const Bundle* bundle,
213                                 const String16& resourceName,
214                                 const sp<AaptFile>& file,
215                                 const sp<XMLNode>& parent);
216
217
218    sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
219            const bool isBase);
220
221    static inline uint32_t makeResId(uint32_t packageId,
222                                     uint32_t typeId,
223                                     uint32_t nameId)
224    {
225        return nameId | (typeId<<16) | (packageId<<24);
226    }
227
228    static inline uint32_t getResId(const sp<Package>& p,
229                                    const sp<Type>& t,
230                                    uint32_t nameId);
231
232    uint32_t getResId(const String16& package,
233                      const String16& type,
234                      const String16& name,
235                      bool onlyPublic = true) const;
236
237    uint32_t getResId(const String16& ref,
238                      const String16* defType = NULL,
239                      const String16* defPackage = NULL,
240                      const char** outErrorMsg = NULL,
241                      bool onlyPublic = true) const;
242
243    static bool isValidResourceName(const String16& s);
244
245    bool stringToValue(Res_value* outValue, StringPool* pool,
246                       const String16& str,
247                       bool preserveSpaces, bool coerceType,
248                       uint32_t attrID,
249                       const Vector<StringPool::entry_style_span>* style = NULL,
250                       String16* outStr = NULL, void* accessorCookie = NULL,
251                       uint32_t attrType = ResTable_map::TYPE_ANY,
252                       const String8* configTypeName = NULL,
253                       const ConfigDescription* config = NULL);
254
255    status_t assignResourceIds();
256    status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL,
257                        bool skipSymbolsWithoutDefaultLocalization = false);
258    void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
259    void addDefaultLocalization(const String16& name);
260    status_t validateLocalizations(void);
261
262    status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
263            const sp<AaptFile>& dest, const bool isBase);
264    status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
265
266    void writePublicDefinitions(const String16& package, FILE* fp);
267
268    virtual uint32_t getCustomResource(const String16& package,
269                                       const String16& type,
270                                       const String16& name) const;
271    virtual uint32_t getCustomResourceWithCreation(const String16& package,
272                                                   const String16& type,
273                                                   const String16& name,
274                                                   const bool createIfNeeded);
275    virtual uint32_t getRemappedPackage(uint32_t origPackage) const;
276    virtual bool getAttributeType(uint32_t attrID, uint32_t* outType);
277    virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin);
278    virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax);
279    virtual bool getAttributeKeys(uint32_t attrID, Vector<String16>* outKeys);
280    virtual bool getAttributeEnum(uint32_t attrID,
281                                  const char16_t* name, size_t nameLen,
282                                  Res_value* outValue);
283    virtual bool getAttributeFlags(uint32_t attrID,
284                                   const char16_t* name, size_t nameLen,
285                                   Res_value* outValue);
286    virtual uint32_t getAttributeL10N(uint32_t attrID);
287
288    virtual bool getLocalizationSetting();
289    virtual void reportError(void* accessorCookie, const char* fmt, ...);
290
291    void setCurrentXmlPos(const SourcePos& pos) { mCurrentXmlPos = pos; }
292
293    class Item {
294    public:
295        Item() : isId(false), format(ResTable_map::TYPE_ANY), bagKeyId(0), evaluating(false)
296            { memset(&parsedValue, 0, sizeof(parsedValue)); }
297        Item(const SourcePos& pos,
298             bool _isId,
299             const String16& _value,
300             const Vector<StringPool::entry_style_span>* _style = NULL,
301             int32_t format = ResTable_map::TYPE_ANY);
302        Item(const Item& o) : sourcePos(o.sourcePos),
303            isId(o.isId), value(o.value), style(o.style),
304            format(o.format), bagKeyId(o.bagKeyId), evaluating(false) {
305            memset(&parsedValue, 0, sizeof(parsedValue));
306        }
307        ~Item() { }
308
309        Item& operator=(const Item& o) {
310            sourcePos = o.sourcePos;
311            isId = o.isId;
312            value = o.value;
313            style = o.style;
314            format = o.format;
315            bagKeyId = o.bagKeyId;
316            parsedValue = o.parsedValue;
317            return *this;
318        }
319
320        SourcePos                               sourcePos;
321        mutable bool                            isId;
322        String16                                value;
323        Vector<StringPool::entry_style_span>    style;
324        int32_t                                 format;
325        uint32_t                                bagKeyId;
326        mutable bool                            evaluating;
327        Res_value                               parsedValue;
328    };
329
330    class Entry : public RefBase {
331    public:
332        Entry(const String16& name, const SourcePos& pos)
333            : mName(name), mType(TYPE_UNKNOWN),
334              mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos)
335        { }
336
337        Entry(const Entry& entry);
338        Entry& operator=(const Entry& entry);
339
340        virtual ~Entry() { }
341
342        enum type {
343            TYPE_UNKNOWN = 0,
344            TYPE_ITEM,
345            TYPE_BAG
346        };
347
348        String16 getName() const { return mName; }
349        type getType() const { return mType; }
350
351        void setParent(const String16& parent) { mParent = parent; }
352        String16 getParent() const { return mParent; }
353
354        status_t makeItABag(const SourcePos& sourcePos);
355
356        status_t emptyBag(const SourcePos& sourcePos);
357
358        status_t setItem(const SourcePos& pos,
359                         const String16& value,
360                         const Vector<StringPool::entry_style_span>* style = NULL,
361                         int32_t format = ResTable_map::TYPE_ANY,
362                         const bool overwrite = false);
363
364        status_t addToBag(const SourcePos& pos,
365                          const String16& key, const String16& value,
366                          const Vector<StringPool::entry_style_span>* style = NULL,
367                          bool replace=false, bool isId = false,
368                          int32_t format = ResTable_map::TYPE_ANY);
369
370        status_t removeFromBag(const String16& key);
371
372        // Index of the entry's name string in the key pool.
373        int32_t getNameIndex() const { return mNameIndex; }
374        void setNameIndex(int32_t index) { mNameIndex = index; }
375
376        const Item* getItem() const { return mType == TYPE_ITEM ? &mItem : NULL; }
377        const KeyedVector<String16, Item>& getBag() const { return mBag; }
378
379        status_t generateAttributes(ResourceTable* table,
380                                    const String16& package);
381
382        status_t assignResourceIds(ResourceTable* table,
383                                   const String16& package);
384
385        status_t prepareFlatten(StringPool* strings, ResourceTable* table,
386               const String8* configTypeName, const ConfigDescription* config);
387
388        status_t remapStringValue(StringPool* strings);
389
390        ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);
391
392        const SourcePos& getPos() const { return mPos; }
393
394    private:
395        String16 mName;
396        String16 mParent;
397        type mType;
398        Item mItem;
399        int32_t mItemFormat;
400        KeyedVector<String16, Item> mBag;
401        int32_t mNameIndex;
402        uint32_t mParentId;
403        SourcePos mPos;
404    };
405
406    class ConfigList : public RefBase {
407    public:
408        ConfigList(const String16& name, const SourcePos& pos)
409            : mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { }
410        virtual ~ConfigList() { }
411
412        String16 getName() const { return mName; }
413        const SourcePos& getPos() const { return mPos; }
414
415        void appendComment(const String16& comment, bool onlyIfEmpty = false);
416        const String16& getComment() const { return mComment; }
417
418        void appendTypeComment(const String16& comment);
419        const String16& getTypeComment() const { return mTypeComment; }
420
421        // Index of this entry in its Type.
422        int32_t getEntryIndex() const { return mEntryIndex; }
423        void setEntryIndex(int32_t index) { mEntryIndex = index; }
424
425        void setPublic(bool pub) { mPublic = pub; }
426        bool getPublic() const { return mPublic; }
427        void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; }
428        const SourcePos& getPublicSourcePos() { return mPublicSourcePos; }
429
430        void addEntry(const ResTable_config& config, const sp<Entry>& entry) {
431            mEntries.add(config, entry);
432        }
433
434        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
435    private:
436        const String16 mName;
437        const SourcePos mPos;
438        String16 mComment;
439        String16 mTypeComment;
440        bool mPublic;
441        SourcePos mPublicSourcePos;
442        int32_t mEntryIndex;
443        DefaultKeyedVector<ConfigDescription, sp<Entry> > mEntries;
444    };
445
446    class Public {
447    public:
448        Public() : sourcePos(), ident(0) { }
449        Public(const SourcePos& pos,
450               const String16& _comment,
451               uint32_t _ident)
452            : sourcePos(pos),
453            comment(_comment), ident(_ident) { }
454        Public(const Public& o) : sourcePos(o.sourcePos),
455            comment(o.comment), ident(o.ident) { }
456        ~Public() { }
457
458        Public& operator=(const Public& o) {
459            sourcePos = o.sourcePos;
460            comment = o.comment;
461            ident = o.ident;
462            return *this;
463        }
464
465        SourcePos   sourcePos;
466        String16    comment;
467        uint32_t    ident;
468    };
469
470    class Type : public RefBase {
471    public:
472        Type(const String16& name, const SourcePos& pos)
473                : mName(name), mFirstPublicSourcePos(NULL), mPublicIndex(-1), mIndex(-1), mPos(pos)
474        { }
475        virtual ~Type() { delete mFirstPublicSourcePos; }
476
477        status_t addPublic(const SourcePos& pos,
478                           const String16& name,
479                           const uint32_t ident);
480
481        void canAddEntry(const String16& name);
482
483        String16 getName() const { return mName; }
484        sp<Entry> getEntry(const String16& entry,
485                           const SourcePos& pos,
486                           const ResTable_config* config = NULL,
487                           bool doSetIndex = false,
488                           bool overlay = false,
489                           bool autoAddOverlay = false);
490
491        bool isPublic(const String16& entry) const {
492            return mPublic.indexOfKey(entry) >= 0;
493        }
494
495        sp<ConfigList> removeEntry(const String16& entry);
496
497        SortedVector<ConfigDescription> getUniqueConfigs() const;
498
499        const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
500
501        int32_t getPublicIndex() const { return mPublicIndex; }
502
503        int32_t getIndex() const { return mIndex; }
504        void setIndex(int32_t index) { mIndex = index; }
505
506        status_t applyPublicEntryOrder();
507
508        const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
509        const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
510        const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
511
512        const SourcePos& getPos() const { return mPos; }
513
514    private:
515        String16 mName;
516        SourcePos* mFirstPublicSourcePos;
517        DefaultKeyedVector<String16, Public> mPublic;
518        DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
519        Vector<sp<ConfigList> > mOrderedConfigs;
520        SortedVector<String16> mCanAddEntries;
521        int32_t mPublicIndex;
522        int32_t mIndex;
523        SourcePos mPos;
524    };
525
526    class Package : public RefBase {
527    public:
528        Package(const String16& name, size_t packageId);
529        virtual ~Package() { }
530
531        String16 getName() const { return mName; }
532        sp<Type> getType(const String16& type,
533                         const SourcePos& pos,
534                         bool doSetIndex = false);
535
536        size_t getAssignedId() const { return mPackageId; }
537
538        const ResStringPool& getTypeStrings() const { return mTypeStrings; }
539        uint32_t indexOfTypeString(const String16& s) const { return mTypeStringsMapping.valueFor(s); }
540        const sp<AaptFile> getTypeStringsData() const { return mTypeStringsData; }
541        status_t setTypeStrings(const sp<AaptFile>& data);
542
543        const ResStringPool& getKeyStrings() const { return mKeyStrings; }
544        uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); }
545        const sp<AaptFile> getKeyStringsData() const { return mKeyStringsData; }
546        status_t setKeyStrings(const sp<AaptFile>& data);
547
548        status_t applyPublicTypeOrder();
549
550        const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; }
551        const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; }
552
553        void movePrivateAttrs();
554
555    private:
556        status_t setStrings(const sp<AaptFile>& data,
557                            ResStringPool* strings,
558                            DefaultKeyedVector<String16, uint32_t>* mappings);
559
560        const String16 mName;
561        const size_t mPackageId;
562        DefaultKeyedVector<String16, sp<Type> > mTypes;
563        Vector<sp<Type> > mOrderedTypes;
564        sp<AaptFile> mTypeStringsData;
565        sp<AaptFile> mKeyStringsData;
566        ResStringPool mTypeStrings;
567        ResStringPool mKeyStrings;
568        DefaultKeyedVector<String16, uint32_t> mTypeStringsMapping;
569        DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping;
570    };
571
572    void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
573
574    /**
575     * Make an attribute with the specified format. If another attribute with the same name but
576     * different format exists, this method returns false. If the name is not taken, or if the
577     * format is identical, this returns true.
578     */
579    bool makeAttribute(const String16& package,
580                       const String16& name,
581                       const SourcePos& source,
582                       int32_t format,
583                       const String16& comment,
584                       bool appendComment);
585
586private:
587    void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
588    sp<Package> getPackage(const String16& package);
589    sp<Type> getType(const String16& package,
590                     const String16& type,
591                     const SourcePos& pos,
592                     bool doSetIndex = false);
593    sp<Entry> getEntry(const String16& package,
594                       const String16& type,
595                       const String16& name,
596                       const SourcePos& pos,
597                       bool overlay,
598                       const ResTable_config* config = NULL,
599                       bool doSetIndex = false);
600    sp<const Entry> getEntry(uint32_t resID,
601                             const ResTable_config* config = NULL) const;
602    sp<ConfigList> getConfigList(const String16& package,
603                                 const String16& type,
604                                 const String16& name) const;
605    const Item* getItem(uint32_t resID, uint32_t attrID) const;
606    bool getItemValue(uint32_t resID, uint32_t attrID,
607                      Res_value* outValue);
608    int getPublicAttributeSdkLevel(uint32_t attrId) const;
609
610    status_t processBundleFormatImpl(const Bundle* bundle,
611                                     const String16& resourceName,
612                                     const sp<AaptFile>& file,
613                                     const sp<XMLNode>& parent,
614                                     Vector<sp<XMLNode> >* namespaces);
615
616    String16 mAssetsPackage;
617    PackageType mPackageType;
618    sp<AaptAssets> mAssets;
619    uint32_t mTypeIdOffset;
620    DefaultKeyedVector<String16, sp<Package> > mPackages;
621    Vector<sp<Package> > mOrderedPackages;
622    size_t mNumLocal;
623    SourcePos mCurrentXmlPos;
624    Bundle* mBundle;
625
626    // key = string resource name, value = set of locales in which that name is defined
627    std::map<String16, std::map<String8, SourcePos>> mLocalizations;
628    // set of string resources names that have a default localization
629    std::set<String16> mHasDefaultLocalization;
630    std::queue<CompileResourceWorkItem> mWorkQueue;
631};
632
633#endif
634