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