1//
2// Copyright 2006 The Android Open Source Project
3//
4// Information about assets being operated on.
5//
6#ifndef __AAPT_ASSETS_H
7#define __AAPT_ASSETS_H
8
9#include <androidfw/AssetManager.h>
10#include <androidfw/ResourceTypes.h>
11#include <stdlib.h>
12#include <set>
13#include <utils/KeyedVector.h>
14#include <utils/RefBase.h>
15#include <utils/SortedVector.h>
16#include <utils/String8.h>
17#include <utils/Vector.h>
18
19#include "AaptConfig.h"
20#include "Bundle.h"
21#include "ConfigDescription.h"
22#include "SourcePos.h"
23#include "ZipFile.h"
24
25using namespace android;
26
27extern const char * const gDefaultIgnoreAssets;
28extern const char * gUserIgnoreAssets;
29
30bool valid_symbol_name(const String8& str);
31
32class AaptAssets;
33
34enum {
35    AXIS_NONE = 0,
36    AXIS_MCC = 1,
37    AXIS_MNC,
38    AXIS_LOCALE,
39    AXIS_SCREENLAYOUTSIZE,
40    AXIS_SCREENLAYOUTLONG,
41    AXIS_ORIENTATION,
42    AXIS_UIMODETYPE,
43    AXIS_UIMODENIGHT,
44    AXIS_DENSITY,
45    AXIS_TOUCHSCREEN,
46    AXIS_KEYSHIDDEN,
47    AXIS_KEYBOARD,
48    AXIS_NAVHIDDEN,
49    AXIS_NAVIGATION,
50    AXIS_SCREENSIZE,
51    AXIS_SMALLESTSCREENWIDTHDP,
52    AXIS_SCREENWIDTHDP,
53    AXIS_SCREENHEIGHTDP,
54    AXIS_LAYOUTDIR,
55    AXIS_VERSION,
56
57    AXIS_START = AXIS_MCC,
58    AXIS_END = AXIS_VERSION,
59};
60
61struct AaptLocaleValue {
62     char language[4];
63     char region[4];
64     char script[4];
65     char variant[8];
66
67     AaptLocaleValue() {
68         memset(this, 0, sizeof(AaptLocaleValue));
69     }
70
71     // Initialize this AaptLocaleValue from a config string.
72     bool initFromFilterString(const String8& config);
73
74     int initFromDirName(const Vector<String8>& parts, const int startIndex);
75
76     // Initialize this AaptLocaleValue from a ResTable_config.
77     void initFromResTable(const ResTable_config& config);
78
79     void writeTo(ResTable_config* out) const;
80
81     int compare(const AaptLocaleValue& other) const {
82         return memcmp(this, &other, sizeof(AaptLocaleValue));
83     }
84
85     inline bool operator<(const AaptLocaleValue& o) const { return compare(o) < 0; }
86     inline bool operator<=(const AaptLocaleValue& o) const { return compare(o) <= 0; }
87     inline bool operator==(const AaptLocaleValue& o) const { return compare(o) == 0; }
88     inline bool operator!=(const AaptLocaleValue& o) const { return compare(o) != 0; }
89     inline bool operator>=(const AaptLocaleValue& o) const { return compare(o) >= 0; }
90     inline bool operator>(const AaptLocaleValue& o) const { return compare(o) > 0; }
91private:
92     void setLanguage(const char* language);
93     void setRegion(const char* language);
94     void setScript(const char* script);
95     void setVariant(const char* variant);
96};
97
98/**
99 * This structure contains a specific variation of a single file out
100 * of all the variations it can have that we can have.
101 */
102struct AaptGroupEntry
103{
104public:
105    AaptGroupEntry() {}
106    AaptGroupEntry(const ConfigDescription& config) : mParams(config) {}
107
108    bool initFromDirName(const char* dir, String8* resType);
109
110    inline const ConfigDescription& toParams() const { return mParams; }
111
112    inline int compare(const AaptGroupEntry& o) const { return mParams.compareLogical(o.mParams); }
113    inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
114    inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
115    inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
116    inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; }
117    inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
118    inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
119
120    String8 toString() const { return mParams.toString(); }
121    String8 toDirName(const String8& resType) const;
122
123    const String8 getVersionString() const { return AaptConfig::getVersion(mParams); }
124
125private:
126    ConfigDescription mParams;
127};
128
129inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
130{
131    return lhs.compare(rhs);
132}
133
134inline int strictly_order_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
135{
136    return compare_type(lhs, rhs) < 0;
137}
138
139class AaptGroup;
140class FilePathStore;
141
142/**
143 * A single asset file we know about.
144 */
145class AaptFile : public RefBase
146{
147public:
148    AaptFile(const String8& sourceFile, const AaptGroupEntry& groupEntry,
149             const String8& resType)
150        : mGroupEntry(groupEntry)
151        , mResourceType(resType)
152        , mSourceFile(sourceFile)
153        , mData(NULL)
154        , mDataSize(0)
155        , mBufferSize(0)
156        , mCompression(ZipEntry::kCompressStored)
157        {
158            //printf("new AaptFile created %s\n", (const char*)sourceFile);
159        }
160    virtual ~AaptFile() {
161        free(mData);
162    }
163
164    const String8& getPath() const { return mPath; }
165    const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; }
166
167    // Data API.  If there is data attached to the file,
168    // getSourceFile() is not used.
169    bool hasData() const { return mData != NULL; }
170    const void* getData() const { return mData; }
171    size_t getSize() const { return mDataSize; }
172    void* editData(size_t size);
173    void* editData(size_t* outSize = NULL);
174    void* editDataInRange(size_t offset, size_t size);
175    void* padData(size_t wordSize);
176    status_t writeData(const void* data, size_t size);
177    void clearData();
178
179    const String8& getResourceType() const { return mResourceType; }
180
181    // File API.  If the file does not hold raw data, this is
182    // a full path to a file on the filesystem that holds its data.
183    const String8& getSourceFile() const { return mSourceFile; }
184
185    String8 getPrintableSource() const;
186
187    // Desired compression method, as per utils/ZipEntry.h.  For example,
188    // no compression is ZipEntry::kCompressStored.
189    int getCompressionMethod() const { return mCompression; }
190    void setCompressionMethod(int c) { mCompression = c; }
191private:
192    friend class AaptGroup;
193
194    String8 mPath;
195    AaptGroupEntry mGroupEntry;
196    String8 mResourceType;
197    String8 mSourceFile;
198    void* mData;
199    size_t mDataSize;
200    size_t mBufferSize;
201    int mCompression;
202};
203
204/**
205 * A group of related files (the same file, with different
206 * vendor/locale variations).
207 */
208class AaptGroup : public RefBase
209{
210public:
211    AaptGroup(const String8& leaf, const String8& path)
212        : mLeaf(leaf), mPath(path) { }
213    virtual ~AaptGroup() { }
214
215    const String8& getLeaf() const { return mLeaf; }
216
217    // Returns the relative path after the AaptGroupEntry dirs.
218    const String8& getPath() const { return mPath; }
219
220    const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const
221        { return mFiles; }
222
223    status_t addFile(const sp<AaptFile>& file, const bool overwriteDuplicate=false);
224    void removeFile(size_t index);
225
226    void print(const String8& prefix) const;
227
228    String8 getPrintableSource() const;
229
230private:
231    String8 mLeaf;
232    String8 mPath;
233
234    DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > mFiles;
235};
236
237/**
238 * A single directory of assets, which can contain files and other
239 * sub-directories.
240 */
241class AaptDir : public RefBase
242{
243public:
244    AaptDir(const String8& leaf, const String8& path)
245        : mLeaf(leaf), mPath(path) { }
246    virtual ~AaptDir() { }
247
248    const String8& getLeaf() const { return mLeaf; }
249
250    const String8& getPath() const { return mPath; }
251
252    const DefaultKeyedVector<String8, sp<AaptGroup> >& getFiles() const { return mFiles; }
253    const DefaultKeyedVector<String8, sp<AaptDir> >& getDirs() const { return mDirs; }
254
255    virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
256
257    void removeFile(const String8& name);
258    void removeDir(const String8& name);
259
260    /*
261     * Perform some sanity checks on the names of files and directories here.
262     * In particular:
263     *  - Check for illegal chars in filenames.
264     *  - Check filename length.
265     *  - Check for presence of ".gz" and non-".gz" copies of same file.
266     *  - Check for multiple files whose names match in a case-insensitive
267     *    fashion (problematic for some systems).
268     *
269     * Comparing names against all other names is O(n^2).  We could speed
270     * it up some by sorting the entries and being smarter about what we
271     * compare against, but I'm not expecting to have enough files in a
272     * single directory to make a noticeable difference in speed.
273     *
274     * Note that sorting here is not enough to guarantee that the package
275     * contents are sorted -- subsequent updates can rearrange things.
276     */
277    status_t validate() const;
278
279    void print(const String8& prefix) const;
280
281    String8 getPrintableSource() const;
282
283private:
284    friend class AaptAssets;
285
286    status_t addDir(const String8& name, const sp<AaptDir>& dir);
287    sp<AaptDir> makeDir(const String8& name);
288    status_t addLeafFile(const String8& leafName,
289                         const sp<AaptFile>& file,
290                         const bool overwrite=false);
291    virtual ssize_t slurpFullTree(Bundle* bundle,
292                                  const String8& srcDir,
293                                  const AaptGroupEntry& kind,
294                                  const String8& resType,
295                                  sp<FilePathStore>& fullResPaths,
296                                  const bool overwrite=false);
297
298    String8 mLeaf;
299    String8 mPath;
300
301    DefaultKeyedVector<String8, sp<AaptGroup> > mFiles;
302    DefaultKeyedVector<String8, sp<AaptDir> > mDirs;
303};
304
305/**
306 * All information we know about a particular symbol.
307 */
308class AaptSymbolEntry
309{
310public:
311    AaptSymbolEntry()
312        : isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
313    {
314    }
315    AaptSymbolEntry(const String8& _name)
316        : name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
317    {
318    }
319    AaptSymbolEntry(const AaptSymbolEntry& o)
320        : name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic)
321        , isJavaSymbol(o.isJavaSymbol), comment(o.comment), typeComment(o.typeComment)
322        , typeCode(o.typeCode), int32Val(o.int32Val), stringVal(o.stringVal)
323    {
324    }
325    AaptSymbolEntry operator=(const AaptSymbolEntry& o)
326    {
327        sourcePos = o.sourcePos;
328        isPublic = o.isPublic;
329        isJavaSymbol = o.isJavaSymbol;
330        comment = o.comment;
331        typeComment = o.typeComment;
332        typeCode = o.typeCode;
333        int32Val = o.int32Val;
334        stringVal = o.stringVal;
335        return *this;
336    }
337
338    const String8 name;
339
340    SourcePos sourcePos;
341    bool isPublic;
342    bool isJavaSymbol;
343
344    String16 comment;
345    String16 typeComment;
346
347    enum {
348        TYPE_UNKNOWN = 0,
349        TYPE_INT32,
350        TYPE_STRING
351    };
352
353    int typeCode;
354
355    // Value.  May be one of these.
356    int32_t int32Val;
357    String8 stringVal;
358};
359
360/**
361 * A group of related symbols (such as indices into a string block)
362 * that have been generated from the assets.
363 */
364class AaptSymbols : public RefBase
365{
366public:
367    AaptSymbols() { }
368    virtual ~AaptSymbols() { }
369
370    status_t addSymbol(const String8& name, int32_t value, const SourcePos& pos) {
371        if (!check_valid_symbol_name(name, pos, "symbol")) {
372            return BAD_VALUE;
373        }
374        AaptSymbolEntry& sym = edit_symbol(name, &pos);
375        sym.typeCode = AaptSymbolEntry::TYPE_INT32;
376        sym.int32Val = value;
377        return NO_ERROR;
378    }
379
380    status_t addStringSymbol(const String8& name, const String8& value,
381            const SourcePos& pos) {
382        if (!check_valid_symbol_name(name, pos, "symbol")) {
383            return BAD_VALUE;
384        }
385        AaptSymbolEntry& sym = edit_symbol(name, &pos);
386        sym.typeCode = AaptSymbolEntry::TYPE_STRING;
387        sym.stringVal = value;
388        return NO_ERROR;
389    }
390
391    status_t makeSymbolPublic(const String8& name, const SourcePos& pos) {
392        if (!check_valid_symbol_name(name, pos, "symbol")) {
393            return BAD_VALUE;
394        }
395        AaptSymbolEntry& sym = edit_symbol(name, &pos);
396        sym.isPublic = true;
397        return NO_ERROR;
398    }
399
400    status_t makeSymbolJavaSymbol(const String8& name, const SourcePos& pos) {
401        if (!check_valid_symbol_name(name, pos, "symbol")) {
402            return BAD_VALUE;
403        }
404        AaptSymbolEntry& sym = edit_symbol(name, &pos);
405        sym.isJavaSymbol = true;
406        return NO_ERROR;
407    }
408
409    void appendComment(const String8& name, const String16& comment, const SourcePos& pos) {
410        if (comment.size() <= 0) {
411            return;
412        }
413        AaptSymbolEntry& sym = edit_symbol(name, &pos);
414        if (sym.comment.size() == 0) {
415            sym.comment = comment;
416        } else {
417            sym.comment.append(String16("\n"));
418            sym.comment.append(comment);
419        }
420    }
421
422    void appendTypeComment(const String8& name, const String16& comment) {
423        if (comment.size() <= 0) {
424            return;
425        }
426        AaptSymbolEntry& sym = edit_symbol(name, NULL);
427        if (sym.typeComment.size() == 0) {
428            sym.typeComment = comment;
429        } else {
430            sym.typeComment.append(String16("\n"));
431            sym.typeComment.append(comment);
432        }
433    }
434
435    sp<AaptSymbols> addNestedSymbol(const String8& name, const SourcePos& pos) {
436        if (!check_valid_symbol_name(name, pos, "nested symbol")) {
437            return NULL;
438        }
439
440        sp<AaptSymbols> sym = mNestedSymbols.valueFor(name);
441        if (sym == NULL) {
442            sym = new AaptSymbols();
443            mNestedSymbols.add(name, sym);
444        }
445
446        return sym;
447    }
448
449    status_t applyJavaSymbols(const sp<AaptSymbols>& javaSymbols);
450
451    const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const
452        { return mSymbols; }
453    const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const
454        { return mNestedSymbols; }
455
456    const String16& getComment(const String8& name) const
457        { return get_symbol(name).comment; }
458    const String16& getTypeComment(const String8& name) const
459        { return get_symbol(name).typeComment; }
460
461private:
462    bool check_valid_symbol_name(const String8& symbol, const SourcePos& pos, const char* label) {
463        if (valid_symbol_name(symbol)) {
464            return true;
465        }
466        pos.error("invalid %s: '%s'\n", label, symbol.string());
467        return false;
468    }
469    AaptSymbolEntry& edit_symbol(const String8& symbol, const SourcePos* pos) {
470        ssize_t i = mSymbols.indexOfKey(symbol);
471        if (i < 0) {
472            i = mSymbols.add(symbol, AaptSymbolEntry(symbol));
473        }
474        AaptSymbolEntry& sym = mSymbols.editValueAt(i);
475        if (pos != NULL && sym.sourcePos.line < 0) {
476            sym.sourcePos = *pos;
477        }
478        return sym;
479    }
480    const AaptSymbolEntry& get_symbol(const String8& symbol) const {
481        ssize_t i = mSymbols.indexOfKey(symbol);
482        if (i >= 0) {
483            return mSymbols.valueAt(i);
484        }
485        return mDefSymbol;
486    }
487
488    KeyedVector<String8, AaptSymbolEntry>           mSymbols;
489    DefaultKeyedVector<String8, sp<AaptSymbols> >   mNestedSymbols;
490    AaptSymbolEntry                                 mDefSymbol;
491};
492
493class ResourceTypeSet : public RefBase,
494                        public KeyedVector<String8,sp<AaptGroup> >
495{
496public:
497    ResourceTypeSet();
498};
499
500// Storage for lists of fully qualified paths for
501// resources encountered during slurping.
502class FilePathStore : public RefBase,
503                      public Vector<String8>
504{
505public:
506    FilePathStore();
507};
508
509/**
510 * Asset hierarchy being operated on.
511 */
512class AaptAssets : public AaptDir
513{
514public:
515    AaptAssets();
516    virtual ~AaptAssets() { delete mRes; }
517
518    const String8& getPackage() const { return mPackage; }
519    void setPackage(const String8& package) {
520        mPackage = package;
521        mSymbolsPrivatePackage = package;
522        mHavePrivateSymbols = false;
523    }
524
525    const SortedVector<AaptGroupEntry>& getGroupEntries() const;
526
527    virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
528
529    sp<AaptFile> addFile(const String8& filePath,
530                         const AaptGroupEntry& entry,
531                         const String8& srcDir,
532                         sp<AaptGroup>* outGroup,
533                         const String8& resType);
534
535    void addResource(const String8& leafName,
536                     const String8& path,
537                     const sp<AaptFile>& file,
538                     const String8& resType);
539
540    void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); }
541
542    ssize_t slurpFromArgs(Bundle* bundle);
543
544    sp<AaptSymbols> getSymbolsFor(const String8& name);
545
546    sp<AaptSymbols> getJavaSymbolsFor(const String8& name);
547
548    status_t applyJavaSymbols();
549
550    const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; }
551
552    String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; }
553    void setSymbolsPrivatePackage(const String8& pkg) {
554        mSymbolsPrivatePackage = pkg;
555        mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage;
556    }
557
558    bool havePrivateSymbols() const { return mHavePrivateSymbols; }
559
560    bool isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const;
561
562    status_t buildIncludedResources(Bundle* bundle);
563    status_t addIncludedResources(const sp<AaptFile>& file);
564    const ResTable& getIncludedResources() const;
565    AssetManager& getAssetManager();
566
567    void print(const String8& prefix) const;
568
569    inline const Vector<sp<AaptDir> >& resDirs() const { return mResDirs; }
570    sp<AaptDir> resDir(const String8& name) const;
571
572    inline sp<AaptAssets> getOverlay() { return mOverlay; }
573    inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
574
575    inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
576    inline void
577        setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
578
579    inline sp<FilePathStore>& getFullResPaths() { return mFullResPaths; }
580    inline void
581        setFullResPaths(sp<FilePathStore>& res) { mFullResPaths = res; }
582
583    inline sp<FilePathStore>& getFullAssetPaths() { return mFullAssetPaths; }
584    inline void
585        setFullAssetPaths(sp<FilePathStore>& res) { mFullAssetPaths = res; }
586
587private:
588    virtual ssize_t slurpFullTree(Bundle* bundle,
589                                  const String8& srcDir,
590                                  const AaptGroupEntry& kind,
591                                  const String8& resType,
592                                  sp<FilePathStore>& fullResPaths,
593                                  const bool overwrite=false);
594
595    ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
596    ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
597
598    status_t filter(Bundle* bundle);
599
600    String8 mPackage;
601    SortedVector<AaptGroupEntry> mGroupEntries;
602    DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols;
603    DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols;
604    String8 mSymbolsPrivatePackage;
605    bool mHavePrivateSymbols;
606
607    Vector<sp<AaptDir> > mResDirs;
608
609    bool mChanged;
610
611    bool mHaveIncludedAssets;
612    AssetManager mIncludedAssets;
613
614    sp<AaptAssets> mOverlay;
615    KeyedVector<String8, sp<ResourceTypeSet> >* mRes;
616
617    sp<FilePathStore> mFullResPaths;
618    sp<FilePathStore> mFullAssetPaths;
619};
620
621#endif // __AAPT_ASSETS_H
622
623