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
AaptLocaleValueAaptLocaleValue67 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
compareAaptLocaleValue83 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:
AaptGroupEntryAaptGroupEntry107 AaptGroupEntry() {}
AaptGroupEntryAaptGroupEntry108 AaptGroupEntry(const ConfigDescription& config) : mParams(config) {}
109
110 bool initFromDirName(const char* dir, String8* resType);
111
toParamsAaptGroupEntry112 inline const ConfigDescription& toParams() const { return mParams; }
113
compareAaptGroupEntry114 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
toStringAaptGroupEntry122 String8 toString() const { return mParams.toString(); }
123 String8 toDirName(const String8& resType) const;
124
getVersionStringAaptGroupEntry125 const String8 getVersionString() const { return AaptConfig::getVersion(mParams); }
126
127 private:
128 ConfigDescription mParams;
129 };
130
compare_type(const AaptGroupEntry & lhs,const AaptGroupEntry & rhs)131 inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
132 {
133 return lhs.compare(rhs);
134 }
135
strictly_order_type(const AaptGroupEntry & lhs,const AaptGroupEntry & rhs)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:
AaptFile(const String8 & sourceFile,const AaptGroupEntry & groupEntry,const String8 & resType)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 }
~AaptFile()162 virtual ~AaptFile() {
163 free(mData);
164 }
165
getPath()166 const String8& getPath() const { return mPath; }
getGroupEntry()167 const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; }
168
169 // Data API. If there is data attached to the file,
170 // getSourceFile() is not used.
hasData()171 bool hasData() const { return mData != NULL; }
getData()172 const void* getData() const { return mData; }
getSize()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
getResourceType()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.
getSourceFile()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.
getCompressionMethod()191 int getCompressionMethod() const { return mCompression; }
setCompressionMethod(int c)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:
AaptGroup(const String8 & leaf,const String8 & path)213 AaptGroup(const String8& leaf, const String8& path)
214 : mLeaf(leaf), mPath(path) { }
~AaptGroup()215 virtual ~AaptGroup() { }
216
getLeaf()217 const String8& getLeaf() const { return mLeaf; }
218
219 // Returns the relative path after the AaptGroupEntry dirs.
getPath()220 const String8& getPath() const { return mPath; }
221
getFiles()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:
AaptDir(const String8 & leaf,const String8 & path)246 AaptDir(const String8& leaf, const String8& path)
247 : mLeaf(leaf), mPath(path) { }
~AaptDir()248 virtual ~AaptDir() { }
249
getLeaf()250 const String8& getLeaf() const { return mLeaf; }
251
getPath()252 const String8& getPath() const { return mPath; }
253
getFiles()254 const DefaultKeyedVector<String8, sp<AaptGroup> >& getFiles() const { return mFiles; }
getDirs()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:
AaptSymbolEntry()313 AaptSymbolEntry()
314 : isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
315 {
316 }
AaptSymbolEntry(const String8 & _name)317 AaptSymbolEntry(const String8& _name)
318 : name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
319 {
320 }
AaptSymbolEntry(const AaptSymbolEntry & o)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:
AaptSymbols()369 AaptSymbols() { }
~AaptSymbols()370 virtual ~AaptSymbols() { }
371
addSymbol(const String8 & name,int32_t value,const SourcePos & pos)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
addStringSymbol(const String8 & name,const String8 & value,const SourcePos & pos)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
makeSymbolPublic(const String8 & name,const SourcePos & pos)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
makeSymbolJavaSymbol(const String8 & name,const SourcePos & pos)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
appendComment(const String8 & name,const String16 & comment,const SourcePos & pos)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
appendTypeComment(const String8 & name,const String16 & comment)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
addNestedSymbol(const String8 & name,const SourcePos & pos)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
getSymbols()453 const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const
454 { return mSymbols; }
getNestedSymbols()455 const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const
456 { return mNestedSymbols; }
457
getComment(const String8 & name)458 const String16& getComment(const String8& name) const
459 { return get_symbol(name).comment; }
getTypeComment(const String8 & name)460 const String16& getTypeComment(const String8& name) const
461 { return get_symbol(name).typeComment; }
462
463 private:
check_valid_symbol_name(const String8 & symbol,const SourcePos & pos,const char * label)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 }
edit_symbol(const String8 & symbol,const SourcePos * pos)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 }
get_symbol(const String8 & symbol)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();
~AaptAssets()518 virtual ~AaptAssets() { delete mRes; }
519
getPackage()520 const String8& getPackage() const { return mPackage; }
setPackage(const String8 & package)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
addGroupEntry(const AaptGroupEntry & entry)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
getSymbols()552 const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; }
553
getSymbolsPrivatePackage()554 String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; }
setSymbolsPrivatePackage(const String8 & pkg)555 void setSymbolsPrivatePackage(const String8& pkg) {
556 mSymbolsPrivatePackage = pkg;
557 mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage;
558 }
559
havePrivateSymbols()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
resDirs()571 inline const Vector<sp<AaptDir> >& resDirs() const { return mResDirs; }
572 sp<AaptDir> resDir(const String8& name) const;
573
getOverlay()574 inline sp<AaptAssets> getOverlay() { return mOverlay; }
setOverlay(sp<AaptAssets> & overlay)575 inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
576
getResources()577 inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
578 inline void
setResources(KeyedVector<String8,sp<ResourceTypeSet>> * res)579 setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
580
getFullResPaths()581 inline sp<FilePathStore>& getFullResPaths() { return mFullResPaths; }
582 inline void
setFullResPaths(sp<FilePathStore> & res)583 setFullResPaths(sp<FilePathStore>& res) { mFullResPaths = res; }
584
getFullAssetPaths()585 inline sp<FilePathStore>& getFullAssetPaths() { return mFullAssetPaths; }
586 inline void
setFullAssetPaths(sp<FilePathStore> & res)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
596 ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
597 ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
598
599 status_t filter(Bundle* bundle);
600
601 String8 mPackage;
602 SortedVector<AaptGroupEntry> mGroupEntries;
603 DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols;
604 DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols;
605 String8 mSymbolsPrivatePackage;
606 bool mHavePrivateSymbols;
607
608 Vector<sp<AaptDir> > mResDirs;
609
610 bool mChanged;
611
612 bool mHaveIncludedAssets;
613 AssetManager mIncludedAssets;
614
615 sp<AaptAssets> mOverlay;
616 KeyedVector<String8, sp<ResourceTypeSet> >* mRes;
617
618 sp<FilePathStore> mFullResPaths;
619 sp<FilePathStore> mFullAssetPaths;
620 };
621
622 #endif // __AAPT_ASSETS_H
623
624