AaptAssets.h revision 09384303dea4f3f01d5682918d7bab9bf83a02b1
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, const bool overwriteDuplicate=false);
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                         const bool overwrite=false);
306    virtual ssize_t slurpFullTree(Bundle* bundle,
307                                  const String8& srcDir,
308                                  const AaptGroupEntry& kind,
309                                  const String8& resType,
310                                  sp<FilePathStore>& fullResPaths,
311                                  const bool overwrite=false);
312
313    String8 mLeaf;
314    String8 mPath;
315
316    DefaultKeyedVector<String8, sp<AaptGroup> > mFiles;
317    DefaultKeyedVector<String8, sp<AaptDir> > mDirs;
318};
319
320/**
321 * All information we know about a particular symbol.
322 */
323class AaptSymbolEntry
324{
325public:
326    AaptSymbolEntry()
327        : isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
328    {
329    }
330    AaptSymbolEntry(const String8& _name)
331        : name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
332    {
333    }
334    AaptSymbolEntry(const AaptSymbolEntry& o)
335        : name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic)
336        , isJavaSymbol(o.isJavaSymbol), comment(o.comment), typeComment(o.typeComment)
337        , typeCode(o.typeCode), int32Val(o.int32Val), stringVal(o.stringVal)
338    {
339    }
340    AaptSymbolEntry operator=(const AaptSymbolEntry& o)
341    {
342        sourcePos = o.sourcePos;
343        isPublic = o.isPublic;
344        isJavaSymbol = o.isJavaSymbol;
345        comment = o.comment;
346        typeComment = o.typeComment;
347        typeCode = o.typeCode;
348        int32Val = o.int32Val;
349        stringVal = o.stringVal;
350        return *this;
351    }
352
353    const String8 name;
354
355    SourcePos sourcePos;
356    bool isPublic;
357    bool isJavaSymbol;
358
359    String16 comment;
360    String16 typeComment;
361
362    enum {
363        TYPE_UNKNOWN = 0,
364        TYPE_INT32,
365        TYPE_STRING
366    };
367
368    int typeCode;
369
370    // Value.  May be one of these.
371    int32_t int32Val;
372    String8 stringVal;
373};
374
375/**
376 * A group of related symbols (such as indices into a string block)
377 * that have been generated from the assets.
378 */
379class AaptSymbols : public RefBase
380{
381public:
382    AaptSymbols() { }
383    virtual ~AaptSymbols() { }
384
385    status_t addSymbol(const String8& name, int32_t value, const SourcePos& pos) {
386        if (!check_valid_symbol_name(name, pos, "symbol")) {
387            return BAD_VALUE;
388        }
389        AaptSymbolEntry& sym = edit_symbol(name, &pos);
390        sym.typeCode = AaptSymbolEntry::TYPE_INT32;
391        sym.int32Val = value;
392        return NO_ERROR;
393    }
394
395    status_t addStringSymbol(const String8& name, const String8& value,
396            const SourcePos& pos) {
397        if (!check_valid_symbol_name(name, pos, "symbol")) {
398            return BAD_VALUE;
399        }
400        AaptSymbolEntry& sym = edit_symbol(name, &pos);
401        sym.typeCode = AaptSymbolEntry::TYPE_STRING;
402        sym.stringVal = value;
403        return NO_ERROR;
404    }
405
406    status_t makeSymbolPublic(const String8& name, const SourcePos& pos) {
407        if (!check_valid_symbol_name(name, pos, "symbol")) {
408            return BAD_VALUE;
409        }
410        AaptSymbolEntry& sym = edit_symbol(name, &pos);
411        sym.isPublic = true;
412        return NO_ERROR;
413    }
414
415    status_t makeSymbolJavaSymbol(const String8& name, const SourcePos& pos) {
416        if (!check_valid_symbol_name(name, pos, "symbol")) {
417            return BAD_VALUE;
418        }
419        AaptSymbolEntry& sym = edit_symbol(name, &pos);
420        sym.isJavaSymbol = true;
421        return NO_ERROR;
422    }
423
424    void appendComment(const String8& name, const String16& comment, const SourcePos& pos) {
425        if (comment.size() <= 0) {
426            return;
427        }
428        AaptSymbolEntry& sym = edit_symbol(name, &pos);
429        if (sym.comment.size() == 0) {
430            sym.comment = comment;
431        } else {
432            sym.comment.append(String16("\n"));
433            sym.comment.append(comment);
434        }
435    }
436
437    void appendTypeComment(const String8& name, const String16& comment) {
438        if (comment.size() <= 0) {
439            return;
440        }
441        AaptSymbolEntry& sym = edit_symbol(name, NULL);
442        if (sym.typeComment.size() == 0) {
443            sym.typeComment = comment;
444        } else {
445            sym.typeComment.append(String16("\n"));
446            sym.typeComment.append(comment);
447        }
448    }
449
450    sp<AaptSymbols> addNestedSymbol(const String8& name, const SourcePos& pos) {
451        if (!check_valid_symbol_name(name, pos, "nested symbol")) {
452            return NULL;
453        }
454
455        sp<AaptSymbols> sym = mNestedSymbols.valueFor(name);
456        if (sym == NULL) {
457            sym = new AaptSymbols();
458            mNestedSymbols.add(name, sym);
459        }
460
461        return sym;
462    }
463
464    status_t applyJavaSymbols(const sp<AaptSymbols>& javaSymbols);
465
466    const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const
467        { return mSymbols; }
468    const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const
469        { return mNestedSymbols; }
470
471    const String16& getComment(const String8& name) const
472        { return get_symbol(name).comment; }
473    const String16& getTypeComment(const String8& name) const
474        { return get_symbol(name).typeComment; }
475
476private:
477    bool check_valid_symbol_name(const String8& symbol, const SourcePos& pos, const char* label) {
478        if (valid_symbol_name(symbol)) {
479            return true;
480        }
481        pos.error("invalid %s: '%s'\n", label, symbol.string());
482        return false;
483    }
484    AaptSymbolEntry& edit_symbol(const String8& symbol, const SourcePos* pos) {
485        ssize_t i = mSymbols.indexOfKey(symbol);
486        if (i < 0) {
487            i = mSymbols.add(symbol, AaptSymbolEntry(symbol));
488        }
489        AaptSymbolEntry& sym = mSymbols.editValueAt(i);
490        if (pos != NULL && sym.sourcePos.line < 0) {
491            sym.sourcePos = *pos;
492        }
493        return sym;
494    }
495    const AaptSymbolEntry& get_symbol(const String8& symbol) const {
496        ssize_t i = mSymbols.indexOfKey(symbol);
497        if (i >= 0) {
498            return mSymbols.valueAt(i);
499        }
500        return mDefSymbol;
501    }
502
503    KeyedVector<String8, AaptSymbolEntry>           mSymbols;
504    DefaultKeyedVector<String8, sp<AaptSymbols> >   mNestedSymbols;
505    AaptSymbolEntry                                 mDefSymbol;
506};
507
508class ResourceTypeSet : public RefBase,
509                        public KeyedVector<String8,sp<AaptGroup> >
510{
511public:
512    ResourceTypeSet();
513};
514
515// Storage for lists of fully qualified paths for
516// resources encountered during slurping.
517class FilePathStore : public RefBase,
518                      public Vector<String8>
519{
520public:
521    FilePathStore();
522};
523
524/**
525 * Asset hierarchy being operated on.
526 */
527class AaptAssets : public AaptDir
528{
529public:
530    AaptAssets();
531    virtual ~AaptAssets() { delete mRes; }
532
533    const String8& getPackage() const { return mPackage; }
534    void setPackage(const String8& package) {
535        mPackage = package;
536        mSymbolsPrivatePackage = package;
537        mHavePrivateSymbols = false;
538    }
539
540    const SortedVector<AaptGroupEntry>& getGroupEntries() const;
541
542    virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
543
544    sp<AaptFile> addFile(const String8& filePath,
545                         const AaptGroupEntry& entry,
546                         const String8& srcDir,
547                         sp<AaptGroup>* outGroup,
548                         const String8& resType);
549
550    void addResource(const String8& leafName,
551                     const String8& path,
552                     const sp<AaptFile>& file,
553                     const String8& resType);
554
555    void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); }
556
557    ssize_t slurpFromArgs(Bundle* bundle);
558
559    sp<AaptSymbols> getSymbolsFor(const String8& name);
560
561    sp<AaptSymbols> getJavaSymbolsFor(const String8& name);
562
563    status_t applyJavaSymbols();
564
565    const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; }
566
567    String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; }
568    void setSymbolsPrivatePackage(const String8& pkg) {
569        mSymbolsPrivatePackage = pkg;
570        mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage;
571    }
572
573    bool havePrivateSymbols() const { return mHavePrivateSymbols; }
574
575    bool isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const;
576
577    status_t buildIncludedResources(Bundle* bundle);
578    status_t addIncludedResources(const sp<AaptFile>& file);
579    const ResTable& getIncludedResources() const;
580
581    void print(const String8& prefix) const;
582
583    inline const Vector<sp<AaptDir> >& resDirs() const { return mResDirs; }
584    sp<AaptDir> resDir(const String8& name) const;
585
586    inline sp<AaptAssets> getOverlay() { return mOverlay; }
587    inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
588
589    inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
590    inline void
591        setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
592
593    inline sp<FilePathStore>& getFullResPaths() { return mFullResPaths; }
594    inline void
595        setFullResPaths(sp<FilePathStore>& res) { mFullResPaths = res; }
596
597    inline sp<FilePathStore>& getFullAssetPaths() { return mFullAssetPaths; }
598    inline void
599        setFullAssetPaths(sp<FilePathStore>& res) { mFullAssetPaths = res; }
600
601private:
602    virtual ssize_t slurpFullTree(Bundle* bundle,
603                                  const String8& srcDir,
604                                  const AaptGroupEntry& kind,
605                                  const String8& resType,
606                                  sp<FilePathStore>& fullResPaths);
607
608    ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
609    ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
610
611    status_t filter(Bundle* bundle);
612
613    String8 mPackage;
614    SortedVector<AaptGroupEntry> mGroupEntries;
615    DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols;
616    DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols;
617    String8 mSymbolsPrivatePackage;
618    bool mHavePrivateSymbols;
619
620    Vector<sp<AaptDir> > mResDirs;
621
622    bool mChanged;
623
624    bool mHaveIncludedAssets;
625    AssetManager mIncludedAssets;
626
627    sp<AaptAssets> mOverlay;
628    KeyedVector<String8, sp<ResourceTypeSet> >* mRes;
629
630    sp<FilePathStore> mFullResPaths;
631    sp<FilePathStore> mFullAssetPaths;
632};
633
634#endif // __AAPT_ASSETS_H
635
636