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