Home | History | Annotate | Download | only in aapt
      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 
     25 using namespace android;
     26 
     27 extern const char * const gDefaultIgnoreAssets;
     28 extern const char * gUserIgnoreAssets;
     29 
     30 bool valid_symbol_name(const String8& str);
     31 
     32 class AaptAssets;
     33 
     34 enum {
     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 
     61 struct 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; }
     93 private:
     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  */
    104 struct AaptGroupEntry
    105 {
    106 public:
    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 
    127 private:
    128     ConfigDescription mParams;
    129 };
    130 
    131 inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
    132 {
    133     return lhs.compare(rhs);
    134 }
    135 
    136 inline int strictly_order_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
    137 {
    138     return compare_type(lhs, rhs) < 0;
    139 }
    140 
    141 class AaptGroup;
    142 class FilePathStore;
    143 
    144 /**
    145  * A single asset file we know about.
    146  */
    147 class AaptFile : public RefBase
    148 {
    149 public:
    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; }
    193 private:
    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  */
    210 class AaptGroup : public RefBase
    211 {
    212 public:
    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 
    232 private:
    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  */
    243 class AaptDir : public RefBase
    244 {
    245 public:
    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 
    285 private:
    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  */
    310 class AaptSymbolEntry
    311 {
    312 public:
    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  */
    366 class AaptSymbols : public RefBase
    367 {
    368 public:
    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 
    463 private:
    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 
    495 class ResourceTypeSet : public RefBase,
    496                         public KeyedVector<String8,sp<AaptGroup> >
    497 {
    498 public:
    499     ResourceTypeSet();
    500 };
    501 
    502 // Storage for lists of fully qualified paths for
    503 // resources encountered during slurping.
    504 class FilePathStore : public RefBase,
    505                       public Vector<String8>
    506 {
    507 public:
    508     FilePathStore();
    509 };
    510 
    511 /**
    512  * Asset hierarchy being operated on.
    513  */
    514 class AaptAssets : public AaptDir
    515 {
    516 public:
    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 
    589 private:
    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