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