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