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