]> git.saurik.com Git - android/aapt.git/blame - AaptAssets.cpp
Fix build break on glibc hosts.
[android/aapt.git] / AaptAssets.cpp
CommitLineData
a534180c
TAOSP
1//
2// Copyright 2006 The Android Open Source Project
3//
4
5#include "AaptAssets.h"
e29f4ada 6#include "ResourceFilter.h"
a534180c
TAOSP
7#include "Main.h"
8
9#include <utils/misc.h>
10#include <utils/SortedVector.h>
11
12#include <ctype.h>
13#include <dirent.h>
14#include <errno.h>
15
16static const char* kDefaultLocale = "default";
17static const char* kWildcardName = "any";
18static const char* kAssetDir = "assets";
19static const char* kResourceDir = "res";
e29f4ada
DH
20static const char* kValuesDir = "values";
21static const char* kMipmapDir = "mipmap";
a534180c
TAOSP
22static const char* kInvalidChars = "/\\:";
23static const size_t kMaxAssetFileName = 100;
24
25static const String8 kResString(kResourceDir);
26
27/*
28 * Names of asset files must meet the following criteria:
29 *
30 * - the filename length must be less than kMaxAssetFileName bytes long
31 * (and can't be empty)
32 * - all characters must be 7-bit printable ASCII
33 * - none of { '/' '\\' ':' }
34 *
35 * Pass in just the filename, not the full path.
36 */
37static bool validateFileName(const char* fileName)
38{
39 const char* cp = fileName;
40 size_t len = 0;
41
42 while (*cp != '\0') {
43 if ((*cp & 0x80) != 0)
44 return false; // reject high ASCII
45 if (*cp < 0x20 || *cp >= 0x7f)
46 return false; // reject control chars and 0x7f
47 if (strchr(kInvalidChars, *cp) != NULL)
48 return false; // reject path sep chars
49 cp++;
50 len++;
51 }
52
53 if (len < 1 || len > kMaxAssetFileName)
54 return false; // reject empty or too long
55
56 return true;
57}
58
59static bool isHidden(const char *root, const char *path)
60{
ce704366 61 const char *ext = NULL;
a534180c
TAOSP
62 const char *type = NULL;
63
64 // Skip all hidden files.
65 if (path[0] == '.') {
66 // Skip ., .. and .svn but don't chatter about it.
67 if (strcmp(path, ".") == 0
68 || strcmp(path, "..") == 0
69 || strcmp(path, ".svn") == 0) {
70 return true;
71 }
72 type = "hidden";
73 } else if (path[0] == '_') {
74 // skip directories starting with _ (don't chatter about it)
75 String8 subdirName(root);
76 subdirName.appendPath(path);
77 if (getFileType(subdirName.string()) == kFileTypeDirectory) {
78 return true;
79 }
80 } else if (strcmp(path, "CVS") == 0) {
81 // Skip CVS but don't chatter about it.
82 return true;
83 } else if (strcasecmp(path, "thumbs.db") == 0
84 || strcasecmp(path, "picasa.ini") == 0) {
85 // Skip suspected image indexes files.
86 type = "index";
87 } else if (path[strlen(path)-1] == '~') {
88 // Skip suspected emacs backup files.
89 type = "backup";
ce704366
R
90 } else if ((ext = strrchr(path, '.')) != NULL && strcmp(ext, ".scc") == 0) {
91 // Skip VisualSourceSafe files and don't chatter about it
92 return true;
a534180c
TAOSP
93 } else {
94 // Let everything else through.
95 return false;
96 }
97
98 /* If we get this far, "type" should be set and the file
99 * should be skipped.
100 */
101 String8 subdirName(root);
102 subdirName.appendPath(path);
103 fprintf(stderr, " (skipping %s %s '%s')\n", type,
104 getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file",
105 subdirName.string());
106
107 return true;
108}
109
110// =========================================================================
111// =========================================================================
112// =========================================================================
113
114status_t
115AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
116{
117 ResTable_config config;
118
119 // IMSI - MCC
120 if (getMccName(part.string(), &config)) {
121 *axis = AXIS_MCC;
122 *value = config.mcc;
123 return 0;
124 }
125
126 // IMSI - MNC
127 if (getMncName(part.string(), &config)) {
128 *axis = AXIS_MNC;
129 *value = config.mnc;
130 return 0;
131 }
132
133 // locale - language
134 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
135 *axis = AXIS_LANGUAGE;
136 *value = part[1] << 8 | part[0];
137 return 0;
138 }
139
140 // locale - language_REGION
141 if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
142 && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
143 *axis = AXIS_LANGUAGE;
144 *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
145 return 0;
146 }
147
f1f3915b
DH
148 // smallest screen dp width
149 if (getSmallestScreenWidthDpName(part.string(), &config)) {
150 *axis = AXIS_SMALLESTSCREENWIDTHDP;
151 *value = config.smallestScreenWidthDp;
784c6915
DH
152 return 0;
153 }
154
4ee37df2
DH
155 // screen dp width
156 if (getScreenWidthDpName(part.string(), &config)) {
157 *axis = AXIS_SCREENWIDTHDP;
158 *value = config.screenWidthDp;
159 return 0;
160 }
161
162 // screen dp height
163 if (getScreenHeightDpName(part.string(), &config)) {
164 *axis = AXIS_SCREENHEIGHTDP;
165 *value = config.screenHeightDp;
166 return 0;
167 }
168
f1f3915b
DH
169 // screen layout size
170 if (getScreenLayoutSizeName(part.string(), &config)) {
171 *axis = AXIS_SCREENLAYOUTSIZE;
172 *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
173 return 0;
174 }
175
176 // screen layout long
177 if (getScreenLayoutLongName(part.string(), &config)) {
178 *axis = AXIS_SCREENLAYOUTLONG;
179 *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
180 return 0;
181 }
182
a534180c
TAOSP
183 // orientation
184 if (getOrientationName(part.string(), &config)) {
185 *axis = AXIS_ORIENTATION;
186 *value = config.orientation;
187 return 0;
188 }
189
2ca01a37
TH
190 // ui mode type
191 if (getUiModeTypeName(part.string(), &config)) {
192 *axis = AXIS_UIMODETYPE;
193 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
194 return 0;
195 }
196
197 // ui mode night
198 if (getUiModeNightName(part.string(), &config)) {
199 *axis = AXIS_UIMODENIGHT;
200 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
201 return 0;
202 }
203
a534180c
TAOSP
204 // density
205 if (getDensityName(part.string(), &config)) {
206 *axis = AXIS_DENSITY;
207 *value = config.density;
208 return 0;
209 }
210
211 // touchscreen
212 if (getTouchscreenName(part.string(), &config)) {
213 *axis = AXIS_TOUCHSCREEN;
214 *value = config.touchscreen;
215 return 0;
216 }
217
218 // keyboard hidden
219 if (getKeysHiddenName(part.string(), &config)) {
220 *axis = AXIS_KEYSHIDDEN;
221 *value = config.inputFlags;
222 return 0;
223 }
224
225 // keyboard
226 if (getKeyboardName(part.string(), &config)) {
227 *axis = AXIS_KEYBOARD;
228 *value = config.keyboard;
229 return 0;
230 }
231
0096feb5
DH
232 // navigation hidden
233 if (getNavHiddenName(part.string(), &config)) {
234 *axis = AXIS_NAVHIDDEN;
235 *value = config.inputFlags;
236 return 0;
237 }
238
a534180c
TAOSP
239 // navigation
240 if (getNavigationName(part.string(), &config)) {
241 *axis = AXIS_NAVIGATION;
242 *value = config.navigation;
243 return 0;
244 }
245
246 // screen size
247 if (getScreenSizeName(part.string(), &config)) {
248 *axis = AXIS_SCREENSIZE;
249 *value = config.screenSize;
250 return 0;
251 }
252
253 // version
254 if (getVersionName(part.string(), &config)) {
255 *axis = AXIS_VERSION;
256 *value = config.version;
257 return 0;
258 }
259
260 return 1;
261}
262
e29f4ada
DH
263uint32_t
264AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
265{
266 switch (axis) {
267 case AXIS_MCC:
268 return config.mcc;
269 case AXIS_MNC:
270 return config.mnc;
271 case AXIS_LANGUAGE:
272 return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16)
273 | (((uint32_t)config.language[1]) << 8) | (config.language[0]);
274 case AXIS_SCREENLAYOUTSIZE:
275 return config.screenLayout&ResTable_config::MASK_SCREENSIZE;
276 case AXIS_ORIENTATION:
277 return config.orientation;
278 case AXIS_UIMODETYPE:
279 return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
280 case AXIS_UIMODENIGHT:
281 return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
282 case AXIS_DENSITY:
283 return config.density;
284 case AXIS_TOUCHSCREEN:
285 return config.touchscreen;
286 case AXIS_KEYSHIDDEN:
287 return config.inputFlags;
288 case AXIS_KEYBOARD:
289 return config.keyboard;
290 case AXIS_NAVIGATION:
291 return config.navigation;
292 case AXIS_SCREENSIZE:
293 return config.screenSize;
294 case AXIS_SMALLESTSCREENWIDTHDP:
295 return config.smallestScreenWidthDp;
296 case AXIS_SCREENWIDTHDP:
297 return config.screenWidthDp;
298 case AXIS_SCREENHEIGHTDP:
299 return config.screenHeightDp;
300 case AXIS_VERSION:
301 return config.version;
302 }
303 return 0;
304}
305
306bool
307AaptGroupEntry::configSameExcept(const ResTable_config& config,
308 const ResTable_config& otherConfig, int axis)
309{
310 for (int i=AXIS_START; i<=AXIS_END; i++) {
311 if (i == axis) {
312 continue;
313 }
314 if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
315 return false;
316 }
317 }
318 return true;
319}
320
a534180c
TAOSP
321bool
322AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
323{
e29f4ada
DH
324 mParamsChanged = true;
325
a534180c
TAOSP
326 Vector<String8> parts;
327
784c6915 328 String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
0096feb5 329 String8 touch, key, keysHidden, nav, navHidden, size, vers;
f1f3915b 330 String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
a534180c
TAOSP
331
332 const char *p = dir;
333 const char *q;
334 while (NULL != (q = strchr(p, '-'))) {
335 String8 val(p, q-p);
336 val.toLower();
337 parts.add(val);
338 //printf("part: %s\n", parts[parts.size()-1].string());
339 p = q+1;
340 }
341 String8 val(p);
342 val.toLower();
343 parts.add(val);
344 //printf("part: %s\n", parts[parts.size()-1].string());
345
346 const int N = parts.size();
347 int index = 0;
348 String8 part = parts[index];
349
350 // resource type
351 if (!isValidResourceType(part)) {
352 return false;
353 }
354 *resType = part;
355
356 index++;
357 if (index == N) {
358 goto success;
359 }
360 part = parts[index];
361
362 // imsi - mcc
363 if (getMccName(part.string())) {
364 mcc = part;
365
366 index++;
367 if (index == N) {
368 goto success;
369 }
370 part = parts[index];
371 } else {
372 //printf("not mcc: %s\n", part.string());
373 }
374
375 // imsi - mnc
376 if (getMncName(part.string())) {
377 mnc = part;
378
379 index++;
380 if (index == N) {
381 goto success;
382 }
383 part = parts[index];
384 } else {
385 //printf("not mcc: %s\n", part.string());
386 }
387
388 // locale - language
389 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
390 loc = part;
391
392 index++;
393 if (index == N) {
394 goto success;
395 }
396 part = parts[index];
397 } else {
398 //printf("not language: %s\n", part.string());
399 }
400
401 // locale - region
402 if (loc.length() > 0
403 && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
404 loc += "-";
405 part.toUpper();
406 loc += part.string() + 1;
407
408 index++;
409 if (index == N) {
410 goto success;
411 }
412 part = parts[index];
413 } else {
414 //printf("not region: %s\n", part.string());
415 }
416
f1f3915b
DH
417 if (getSmallestScreenWidthDpName(part.string())) {
418 smallestwidthdp = part;
784c6915
DH
419
420 index++;
421 if (index == N) {
422 goto success;
423 }
424 part = parts[index];
425 } else {
f1f3915b 426 //printf("not smallest screen width dp: %s\n", part.string());
784c6915
DH
427 }
428
f1f3915b
DH
429 if (getScreenWidthDpName(part.string())) {
430 widthdp = part;
784c6915
DH
431
432 index++;
433 if (index == N) {
434 goto success;
435 }
436 part = parts[index];
437 } else {
f1f3915b 438 //printf("not screen width dp: %s\n", part.string());
784c6915
DH
439 }
440
f1f3915b
DH
441 if (getScreenHeightDpName(part.string())) {
442 heightdp = part;
4ee37df2
DH
443
444 index++;
445 if (index == N) {
446 goto success;
447 }
448 part = parts[index];
449 } else {
f1f3915b 450 //printf("not screen height dp: %s\n", part.string());
4ee37df2
DH
451 }
452
f1f3915b
DH
453 if (getScreenLayoutSizeName(part.string())) {
454 layoutsize = part;
4ee37df2
DH
455
456 index++;
457 if (index == N) {
458 goto success;
459 }
460 part = parts[index];
461 } else {
f1f3915b
DH
462 //printf("not screen layout size: %s\n", part.string());
463 }
464
465 if (getScreenLayoutLongName(part.string())) {
466 layoutlong = part;
467
468 index++;
469 if (index == N) {
470 goto success;
471 }
472 part = parts[index];
473 } else {
474 //printf("not screen layout long: %s\n", part.string());
4ee37df2
DH
475 }
476
a534180c
TAOSP
477 // orientation
478 if (getOrientationName(part.string())) {
479 orient = part;
480
481 index++;
482 if (index == N) {
483 goto success;
484 }
485 part = parts[index];
486 } else {
487 //printf("not orientation: %s\n", part.string());
488 }
489
2ca01a37
TH
490 // ui mode type
491 if (getUiModeTypeName(part.string())) {
492 uiModeType = part;
493
494 index++;
495 if (index == N) {
496 goto success;
497 }
498 part = parts[index];
499 } else {
500 //printf("not ui mode type: %s\n", part.string());
501 }
502
503 // ui mode night
504 if (getUiModeNightName(part.string())) {
505 uiModeNight = part;
506
507 index++;
508 if (index == N) {
509 goto success;
510 }
511 part = parts[index];
512 } else {
513 //printf("not ui mode night: %s\n", part.string());
514 }
515
a534180c
TAOSP
516 // density
517 if (getDensityName(part.string())) {
518 den = part;
519
520 index++;
521 if (index == N) {
522 goto success;
523 }
524 part = parts[index];
525 } else {
526 //printf("not density: %s\n", part.string());
527 }
528
529 // touchscreen
530 if (getTouchscreenName(part.string())) {
531 touch = part;
532
533 index++;
534 if (index == N) {
535 goto success;
536 }
537 part = parts[index];
538 } else {
539 //printf("not touchscreen: %s\n", part.string());
540 }
541
542 // keyboard hidden
543 if (getKeysHiddenName(part.string())) {
544 keysHidden = part;
545
546 index++;
547 if (index == N) {
548 goto success;
549 }
550 part = parts[index];
551 } else {
552 //printf("not keysHidden: %s\n", part.string());
553 }
554
555 // keyboard
556 if (getKeyboardName(part.string())) {
557 key = part;
558
559 index++;
560 if (index == N) {
561 goto success;
562 }
563 part = parts[index];
564 } else {
565 //printf("not keyboard: %s\n", part.string());
566 }
567
0096feb5
DH
568 // navigation hidden
569 if (getNavHiddenName(part.string())) {
570 navHidden = part;
571
572 index++;
573 if (index == N) {
574 goto success;
575 }
576 part = parts[index];
577 } else {
578 //printf("not navHidden: %s\n", part.string());
579 }
580
a534180c
TAOSP
581 if (getNavigationName(part.string())) {
582 nav = part;
583
584 index++;
585 if (index == N) {
586 goto success;
587 }
588 part = parts[index];
589 } else {
590 //printf("not navigation: %s\n", part.string());
591 }
592
593 if (getScreenSizeName(part.string())) {
594 size = part;
595
596 index++;
597 if (index == N) {
598 goto success;
599 }
600 part = parts[index];
601 } else {
602 //printf("not screen size: %s\n", part.string());
603 }
604
605 if (getVersionName(part.string())) {
606 vers = part;
607
608 index++;
609 if (index == N) {
610 goto success;
611 }
612 part = parts[index];
613 } else {
614 //printf("not version: %s\n", part.string());
615 }
616
617 // if there are extra parts, it doesn't match
618 return false;
619
620success:
621 this->mcc = mcc;
622 this->mnc = mnc;
623 this->locale = loc;
784c6915
DH
624 this->screenLayoutSize = layoutsize;
625 this->screenLayoutLong = layoutlong;
f1f3915b 626 this->smallestScreenWidthDp = smallestwidthdp;
4ee37df2
DH
627 this->screenWidthDp = widthdp;
628 this->screenHeightDp = heightdp;
a534180c 629 this->orientation = orient;
2ca01a37
TH
630 this->uiModeType = uiModeType;
631 this->uiModeNight = uiModeNight;
a534180c
TAOSP
632 this->density = den;
633 this->touchscreen = touch;
634 this->keysHidden = keysHidden;
635 this->keyboard = key;
0096feb5 636 this->navHidden = navHidden;
a534180c
TAOSP
637 this->navigation = nav;
638 this->screenSize = size;
639 this->version = vers;
640
641 // what is this anyway?
642 this->vendor = "";
643
644 return true;
645}
646
647String8
648AaptGroupEntry::toString() const
649{
650 String8 s = this->mcc;
651 s += ",";
652 s += this->mnc;
653 s += ",";
654 s += this->locale;
655 s += ",";
f1f3915b 656 s += smallestScreenWidthDp;
784c6915 657 s += ",";
4ee37df2
DH
658 s += screenWidthDp;
659 s += ",";
660 s += screenHeightDp;
661 s += ",";
f1f3915b
DH
662 s += screenLayoutSize;
663 s += ",";
664 s += screenLayoutLong;
665 s += ",";
a534180c
TAOSP
666 s += this->orientation;
667 s += ",";
2ca01a37
TH
668 s += uiModeType;
669 s += ",";
670 s += uiModeNight;
671 s += ",";
a534180c
TAOSP
672 s += density;
673 s += ",";
674 s += touchscreen;
675 s += ",";
676 s += keysHidden;
677 s += ",";
678 s += keyboard;
679 s += ",";
0096feb5
DH
680 s += navHidden;
681 s += ",";
a534180c
TAOSP
682 s += navigation;
683 s += ",";
684 s += screenSize;
685 s += ",";
686 s += version;
687 return s;
688}
689
690String8
691AaptGroupEntry::toDirName(const String8& resType) const
692{
693 String8 s = resType;
694 if (this->mcc != "") {
e29f4ada
DH
695 if (s.length() > 0) {
696 s += "-";
697 }
a534180c
TAOSP
698 s += mcc;
699 }
700 if (this->mnc != "") {
e29f4ada
DH
701 if (s.length() > 0) {
702 s += "-";
703 }
a534180c
TAOSP
704 s += mnc;
705 }
706 if (this->locale != "") {
e29f4ada
DH
707 if (s.length() > 0) {
708 s += "-";
709 }
a534180c
TAOSP
710 s += locale;
711 }
f1f3915b 712 if (this->smallestScreenWidthDp != "") {
e29f4ada
DH
713 if (s.length() > 0) {
714 s += "-";
715 }
f1f3915b 716 s += smallestScreenWidthDp;
784c6915 717 }
4ee37df2 718 if (this->screenWidthDp != "") {
e29f4ada
DH
719 if (s.length() > 0) {
720 s += "-";
721 }
4ee37df2
DH
722 s += screenWidthDp;
723 }
724 if (this->screenHeightDp != "") {
e29f4ada
DH
725 if (s.length() > 0) {
726 s += "-";
727 }
4ee37df2
DH
728 s += screenHeightDp;
729 }
f1f3915b 730 if (this->screenLayoutSize != "") {
e29f4ada
DH
731 if (s.length() > 0) {
732 s += "-";
733 }
f1f3915b
DH
734 s += screenLayoutSize;
735 }
736 if (this->screenLayoutLong != "") {
e29f4ada
DH
737 if (s.length() > 0) {
738 s += "-";
739 }
f1f3915b
DH
740 s += screenLayoutLong;
741 }
a534180c 742 if (this->orientation != "") {
e29f4ada
DH
743 if (s.length() > 0) {
744 s += "-";
745 }
a534180c
TAOSP
746 s += orientation;
747 }
2ca01a37 748 if (this->uiModeType != "") {
e29f4ada
DH
749 if (s.length() > 0) {
750 s += "-";
751 }
2ca01a37
TH
752 s += uiModeType;
753 }
754 if (this->uiModeNight != "") {
e29f4ada
DH
755 if (s.length() > 0) {
756 s += "-";
757 }
2ca01a37
TH
758 s += uiModeNight;
759 }
a534180c 760 if (this->density != "") {
e29f4ada
DH
761 if (s.length() > 0) {
762 s += "-";
763 }
a534180c
TAOSP
764 s += density;
765 }
766 if (this->touchscreen != "") {
e29f4ada
DH
767 if (s.length() > 0) {
768 s += "-";
769 }
a534180c
TAOSP
770 s += touchscreen;
771 }
772 if (this->keysHidden != "") {
e29f4ada
DH
773 if (s.length() > 0) {
774 s += "-";
775 }
a534180c
TAOSP
776 s += keysHidden;
777 }
778 if (this->keyboard != "") {
e29f4ada
DH
779 if (s.length() > 0) {
780 s += "-";
781 }
a534180c
TAOSP
782 s += keyboard;
783 }
0096feb5 784 if (this->navHidden != "") {
e29f4ada
DH
785 if (s.length() > 0) {
786 s += "-";
787 }
0096feb5
DH
788 s += navHidden;
789 }
a534180c 790 if (this->navigation != "") {
e29f4ada
DH
791 if (s.length() > 0) {
792 s += "-";
793 }
a534180c
TAOSP
794 s += navigation;
795 }
796 if (this->screenSize != "") {
e29f4ada
DH
797 if (s.length() > 0) {
798 s += "-";
799 }
a534180c
TAOSP
800 s += screenSize;
801 }
802 if (this->version != "") {
e29f4ada
DH
803 if (s.length() > 0) {
804 s += "-";
805 }
a534180c
TAOSP
806 s += version;
807 }
808
809 return s;
810}
811
812bool AaptGroupEntry::getMccName(const char* name,
813 ResTable_config* out)
814{
815 if (strcmp(name, kWildcardName) == 0) {
816 if (out) out->mcc = 0;
817 return true;
818 }
819 const char* c = name;
820 if (tolower(*c) != 'm') return false;
821 c++;
822 if (tolower(*c) != 'c') return false;
823 c++;
824 if (tolower(*c) != 'c') return false;
825 c++;
826
827 const char* val = c;
828
829 while (*c >= '0' && *c <= '9') {
830 c++;
831 }
832 if (*c != 0) return false;
833 if (c-val != 3) return false;
834
835 int d = atoi(val);
836 if (d != 0) {
837 if (out) out->mcc = d;
838 return true;
839 }
840
841 return false;
842}
843
844bool AaptGroupEntry::getMncName(const char* name,
845 ResTable_config* out)
846{
847 if (strcmp(name, kWildcardName) == 0) {
848 if (out) out->mcc = 0;
849 return true;
850 }
851 const char* c = name;
852 if (tolower(*c) != 'm') return false;
853 c++;
854 if (tolower(*c) != 'n') return false;
855 c++;
856 if (tolower(*c) != 'c') return false;
857 c++;
858
859 const char* val = c;
860
861 while (*c >= '0' && *c <= '9') {
862 c++;
863 }
864 if (*c != 0) return false;
865 if (c-val == 0 || c-val > 3) return false;
866
a4424abe
JR
867 if (out) {
868 out->mnc = atoi(val);
a534180c
TAOSP
869 }
870
a4424abe 871 return true;
a534180c
TAOSP
872}
873
874/*
875 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
876 * "default")?
877 *
878 * TODO: Should insist that the first two letters are lower case, and the
879 * second two are upper.
880 */
881bool AaptGroupEntry::getLocaleName(const char* fileName,
882 ResTable_config* out)
883{
884 if (strcmp(fileName, kWildcardName) == 0
885 || strcmp(fileName, kDefaultLocale) == 0) {
886 if (out) {
887 out->language[0] = 0;
888 out->language[1] = 0;
889 out->country[0] = 0;
890 out->country[1] = 0;
891 }
892 return true;
893 }
894
895 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
896 if (out) {
897 out->language[0] = fileName[0];
898 out->language[1] = fileName[1];
899 out->country[0] = 0;
900 out->country[1] = 0;
901 }
902 return true;
903 }
904
905 if (strlen(fileName) == 5 &&
906 isalpha(fileName[0]) &&
907 isalpha(fileName[1]) &&
908 fileName[2] == '-' &&
909 isalpha(fileName[3]) &&
910 isalpha(fileName[4])) {
911 if (out) {
912 out->language[0] = fileName[0];
913 out->language[1] = fileName[1];
914 out->country[0] = fileName[3];
915 out->country[1] = fileName[4];
916 }
917 return true;
918 }
919
920 return false;
921}
922
784c6915
DH
923bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
924 ResTable_config* out)
925{
926 if (strcmp(name, kWildcardName) == 0) {
927 if (out) out->screenLayout =
928 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
929 | ResTable_config::SCREENSIZE_ANY;
930 return true;
931 } else if (strcmp(name, "small") == 0) {
932 if (out) out->screenLayout =
933 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
934 | ResTable_config::SCREENSIZE_SMALL;
935 return true;
936 } else if (strcmp(name, "normal") == 0) {
937 if (out) out->screenLayout =
938 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
939 | ResTable_config::SCREENSIZE_NORMAL;
940 return true;
941 } else if (strcmp(name, "large") == 0) {
942 if (out) out->screenLayout =
943 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
944 | ResTable_config::SCREENSIZE_LARGE;
945 return true;
69e2fb69
DH
946 } else if (strcmp(name, "xlarge") == 0) {
947 if (out) out->screenLayout =
948 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
949 | ResTable_config::SCREENSIZE_XLARGE;
950 return true;
784c6915
DH
951 }
952
953 return false;
954}
955
956bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
957 ResTable_config* out)
958{
959 if (strcmp(name, kWildcardName) == 0) {
960 if (out) out->screenLayout =
961 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
962 | ResTable_config::SCREENLONG_ANY;
963 return true;
964 } else if (strcmp(name, "long") == 0) {
965 if (out) out->screenLayout =
966 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
967 | ResTable_config::SCREENLONG_YES;
968 return true;
969 } else if (strcmp(name, "notlong") == 0) {
970 if (out) out->screenLayout =
971 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
972 | ResTable_config::SCREENLONG_NO;
973 return true;
974 }
975
976 return false;
977}
978
a534180c
TAOSP
979bool AaptGroupEntry::getOrientationName(const char* name,
980 ResTable_config* out)
981{
982 if (strcmp(name, kWildcardName) == 0) {
983 if (out) out->orientation = out->ORIENTATION_ANY;
984 return true;
985 } else if (strcmp(name, "port") == 0) {
986 if (out) out->orientation = out->ORIENTATION_PORT;
987 return true;
988 } else if (strcmp(name, "land") == 0) {
989 if (out) out->orientation = out->ORIENTATION_LAND;
990 return true;
991 } else if (strcmp(name, "square") == 0) {
992 if (out) out->orientation = out->ORIENTATION_SQUARE;
993 return true;
994 }
995
996 return false;
997}
998
2ca01a37
TH
999bool AaptGroupEntry::getUiModeTypeName(const char* name,
1000 ResTable_config* out)
1001{
1002 if (strcmp(name, kWildcardName) == 0) {
1003 if (out) out->uiMode =
1004 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
e3c6837d
DH
1005 | ResTable_config::UI_MODE_TYPE_ANY;
1006 return true;
1007 } else if (strcmp(name, "desk") == 0) {
1008 if (out) out->uiMode =
1009 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1010 | ResTable_config::UI_MODE_TYPE_DESK;
2ca01a37
TH
1011 return true;
1012 } else if (strcmp(name, "car") == 0) {
1013 if (out) out->uiMode =
1014 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1015 | ResTable_config::UI_MODE_TYPE_CAR;
1016 return true;
718f0a85
DH
1017 } else if (strcmp(name, "television") == 0) {
1018 if (out) out->uiMode =
1019 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1020 | ResTable_config::UI_MODE_TYPE_TELEVISION;
1021 return true;
2cf07fe6
JO
1022 } else if (strcmp(name, "appliance") == 0) {
1023 if (out) out->uiMode =
1024 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1025 | ResTable_config::UI_MODE_TYPE_APPLIANCE;
1026 return true;
2ca01a37
TH
1027 }
1028
1029 return false;
1030}
1031
1032bool AaptGroupEntry::getUiModeNightName(const char* name,
1033 ResTable_config* out)
1034{
1035 if (strcmp(name, kWildcardName) == 0) {
1036 if (out) out->uiMode =
1037 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1038 | ResTable_config::UI_MODE_NIGHT_ANY;
1039 return true;
1040 } else if (strcmp(name, "night") == 0) {
1041 if (out) out->uiMode =
1042 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1043 | ResTable_config::UI_MODE_NIGHT_YES;
1044 return true;
1045 } else if (strcmp(name, "notnight") == 0) {
1046 if (out) out->uiMode =
1047 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1048 | ResTable_config::UI_MODE_NIGHT_NO;
1049 return true;
1050 }
1051
1052 return false;
1053}
1054
a534180c
TAOSP
1055bool AaptGroupEntry::getDensityName(const char* name,
1056 ResTable_config* out)
1057{
1058 if (strcmp(name, kWildcardName) == 0) {
41ff305d 1059 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
a534180c
TAOSP
1060 return true;
1061 }
41ff305d
DH
1062
1063 if (strcmp(name, "nodpi") == 0) {
1064 if (out) out->density = ResTable_config::DENSITY_NONE;
1065 return true;
1066 }
1067
784c6915
DH
1068 if (strcmp(name, "ldpi") == 0) {
1069 if (out) out->density = ResTable_config::DENSITY_LOW;
1070 return true;
1071 }
1072
1073 if (strcmp(name, "mdpi") == 0) {
1074 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
1075 return true;
1076 }
1077
465c2ef5
DH
1078 if (strcmp(name, "tvdpi") == 0) {
1079 if (out) out->density = ResTable_config::DENSITY_TV;
1080 return true;
1081 }
1082
784c6915
DH
1083 if (strcmp(name, "hdpi") == 0) {
1084 if (out) out->density = ResTable_config::DENSITY_HIGH;
1085 return true;
1086 }
e2380bf2 1087
bd8c05dd 1088 if (strcmp(name, "xhdpi") == 0) {
e2380bf2 1089 if (out) out->density = ResTable_config::DENSITY_XHIGH;
bd8c05dd
DH
1090 return true;
1091 }
e2380bf2
DH
1092
1093 if (strcmp(name, "xxhdpi") == 0) {
1094 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
1095 return true;
1096 }
1097
a534180c
TAOSP
1098 char* c = (char*)name;
1099 while (*c >= '0' && *c <= '9') {
1100 c++;
1101 }
1102
1103 // check that we have 'dpi' after the last digit.
1104 if (toupper(c[0]) != 'D' ||
1105 toupper(c[1]) != 'P' ||
1106 toupper(c[2]) != 'I' ||
1107 c[3] != 0) {
1108 return false;
1109 }
1110
1111 // temporarily replace the first letter with \0 to
1112 // use atoi.
1113 char tmp = c[0];
1114 c[0] = '\0';
1115
1116 int d = atoi(name);
1117 c[0] = tmp;
1118
1119 if (d != 0) {
1120 if (out) out->density = d;
1121 return true;
1122 }
1123
1124 return false;
1125}
1126
1127bool AaptGroupEntry::getTouchscreenName(const char* name,
1128 ResTable_config* out)
1129{
1130 if (strcmp(name, kWildcardName) == 0) {
1131 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
1132 return true;
1133 } else if (strcmp(name, "notouch") == 0) {
1134 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
1135 return true;
1136 } else if (strcmp(name, "stylus") == 0) {
1137 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
1138 return true;
1139 } else if (strcmp(name, "finger") == 0) {
1140 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
1141 return true;
1142 }
1143
1144 return false;
1145}
1146
1147bool AaptGroupEntry::getKeysHiddenName(const char* name,
1148 ResTable_config* out)
1149{
1150 uint8_t mask = 0;
1151 uint8_t value = 0;
1152 if (strcmp(name, kWildcardName) == 0) {
18a923f6
KR
1153 mask = ResTable_config::MASK_KEYSHIDDEN;
1154 value = ResTable_config::KEYSHIDDEN_ANY;
a534180c 1155 } else if (strcmp(name, "keysexposed") == 0) {
18a923f6
KR
1156 mask = ResTable_config::MASK_KEYSHIDDEN;
1157 value = ResTable_config::KEYSHIDDEN_NO;
a534180c 1158 } else if (strcmp(name, "keyshidden") == 0) {
18a923f6
KR
1159 mask = ResTable_config::MASK_KEYSHIDDEN;
1160 value = ResTable_config::KEYSHIDDEN_YES;
a534180c 1161 } else if (strcmp(name, "keyssoft") == 0) {
18a923f6
KR
1162 mask = ResTable_config::MASK_KEYSHIDDEN;
1163 value = ResTable_config::KEYSHIDDEN_SOFT;
a534180c
TAOSP
1164 }
1165
1166 if (mask != 0) {
1167 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1168 return true;
1169 }
1170
1171 return false;
1172}
1173
1174bool AaptGroupEntry::getKeyboardName(const char* name,
1175 ResTable_config* out)
1176{
1177 if (strcmp(name, kWildcardName) == 0) {
1178 if (out) out->keyboard = out->KEYBOARD_ANY;
1179 return true;
1180 } else if (strcmp(name, "nokeys") == 0) {
1181 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
1182 return true;
1183 } else if (strcmp(name, "qwerty") == 0) {
1184 if (out) out->keyboard = out->KEYBOARD_QWERTY;
1185 return true;
1186 } else if (strcmp(name, "12key") == 0) {
1187 if (out) out->keyboard = out->KEYBOARD_12KEY;
1188 return true;
1189 }
1190
1191 return false;
1192}
1193
0096feb5
DH
1194bool AaptGroupEntry::getNavHiddenName(const char* name,
1195 ResTable_config* out)
1196{
1197 uint8_t mask = 0;
1198 uint8_t value = 0;
1199 if (strcmp(name, kWildcardName) == 0) {
491d9ef0
KR
1200 mask = ResTable_config::MASK_NAVHIDDEN;
1201 value = ResTable_config::NAVHIDDEN_ANY;
0096feb5 1202 } else if (strcmp(name, "navexposed") == 0) {
491d9ef0
KR
1203 mask = ResTable_config::MASK_NAVHIDDEN;
1204 value = ResTable_config::NAVHIDDEN_NO;
0096feb5 1205 } else if (strcmp(name, "navhidden") == 0) {
491d9ef0
KR
1206 mask = ResTable_config::MASK_NAVHIDDEN;
1207 value = ResTable_config::NAVHIDDEN_YES;
0096feb5
DH
1208 }
1209
1210 if (mask != 0) {
1211 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1212 return true;
1213 }
1214
1215 return false;
1216}
1217
a534180c
TAOSP
1218bool AaptGroupEntry::getNavigationName(const char* name,
1219 ResTable_config* out)
1220{
1221 if (strcmp(name, kWildcardName) == 0) {
1222 if (out) out->navigation = out->NAVIGATION_ANY;
1223 return true;
1224 } else if (strcmp(name, "nonav") == 0) {
1225 if (out) out->navigation = out->NAVIGATION_NONAV;
1226 return true;
1227 } else if (strcmp(name, "dpad") == 0) {
1228 if (out) out->navigation = out->NAVIGATION_DPAD;
1229 return true;
1230 } else if (strcmp(name, "trackball") == 0) {
1231 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
1232 return true;
1233 } else if (strcmp(name, "wheel") == 0) {
1234 if (out) out->navigation = out->NAVIGATION_WHEEL;
1235 return true;
1236 }
1237
1238 return false;
1239}
1240
4ee37df2 1241bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
a534180c
TAOSP
1242{
1243 if (strcmp(name, kWildcardName) == 0) {
1244 if (out) {
1245 out->screenWidth = out->SCREENWIDTH_ANY;
1246 out->screenHeight = out->SCREENHEIGHT_ANY;
1247 }
1248 return true;
1249 }
1250
1251 const char* x = name;
1252 while (*x >= '0' && *x <= '9') x++;
1253 if (x == name || *x != 'x') return false;
1254 String8 xName(name, x-name);
1255 x++;
1256
1257 const char* y = x;
1258 while (*y >= '0' && *y <= '9') y++;
1259 if (y == name || *y != 0) return false;
1260 String8 yName(x, y-x);
1261
1262 uint16_t w = (uint16_t)atoi(xName.string());
1263 uint16_t h = (uint16_t)atoi(yName.string());
1264 if (w < h) {
1265 return false;
1266 }
1267
1268 if (out) {
1269 out->screenWidth = w;
1270 out->screenHeight = h;
1271 }
1272
1273 return true;
1274}
1275
f1f3915b
DH
1276bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
1277{
1278 if (strcmp(name, kWildcardName) == 0) {
1279 if (out) {
1280 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
1281 }
1282 return true;
1283 }
1284
1285 if (*name != 's') return false;
1286 name++;
1287 if (*name != 'w') return false;
1288 name++;
1289 const char* x = name;
1290 while (*x >= '0' && *x <= '9') x++;
1291 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1292 String8 xName(name, x-name);
1293
1294 if (out) {
1295 out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
1296 }
1297
1298 return true;
1299}
1300
4ee37df2
DH
1301bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
1302{
1303 if (strcmp(name, kWildcardName) == 0) {
1304 if (out) {
1305 out->screenWidthDp = out->SCREENWIDTH_ANY;
1306 }
1307 return true;
1308 }
1309
1310 if (*name != 'w') return false;
1311 name++;
1312 const char* x = name;
1313 while (*x >= '0' && *x <= '9') x++;
1314 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1315 String8 xName(name, x-name);
1316
1317 if (out) {
1318 out->screenWidthDp = (uint16_t)atoi(xName.string());
1319 }
1320
1321 return true;
1322}
1323
1324bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
1325{
1326 if (strcmp(name, kWildcardName) == 0) {
1327 if (out) {
1328 out->screenHeightDp = out->SCREENWIDTH_ANY;
1329 }
1330 return true;
1331 }
1332
1333 if (*name != 'h') return false;
1334 name++;
1335 const char* x = name;
1336 while (*x >= '0' && *x <= '9') x++;
1337 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1338 String8 xName(name, x-name);
1339
1340 if (out) {
1341 out->screenHeightDp = (uint16_t)atoi(xName.string());
1342 }
1343
1344 return true;
1345}
1346
1347bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
a534180c
TAOSP
1348{
1349 if (strcmp(name, kWildcardName) == 0) {
1350 if (out) {
1351 out->sdkVersion = out->SDKVERSION_ANY;
1352 out->minorVersion = out->MINORVERSION_ANY;
1353 }
1354 return true;
1355 }
1356
1357 if (*name != 'v') {
1358 return false;
1359 }
1360
1361 name++;
1362 const char* s = name;
1363 while (*s >= '0' && *s <= '9') s++;
1364 if (s == name || *s != 0) return false;
1365 String8 sdkName(name, s-name);
1366
1367 if (out) {
1368 out->sdkVersion = (uint16_t)atoi(sdkName.string());
1369 out->minorVersion = 0;
1370 }
1371
1372 return true;
1373}
1374
1375int AaptGroupEntry::compare(const AaptGroupEntry& o) const
1376{
1377 int v = mcc.compare(o.mcc);
1378 if (v == 0) v = mnc.compare(o.mnc);
1379 if (v == 0) v = locale.compare(o.locale);
1380 if (v == 0) v = vendor.compare(o.vendor);
f1f3915b 1381 if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
4ee37df2
DH
1382 if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
1383 if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
f1f3915b
DH
1384 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
1385 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
a534180c 1386 if (v == 0) v = orientation.compare(o.orientation);
2ca01a37
TH
1387 if (v == 0) v = uiModeType.compare(o.uiModeType);
1388 if (v == 0) v = uiModeNight.compare(o.uiModeNight);
a534180c
TAOSP
1389 if (v == 0) v = density.compare(o.density);
1390 if (v == 0) v = touchscreen.compare(o.touchscreen);
1391 if (v == 0) v = keysHidden.compare(o.keysHidden);
1392 if (v == 0) v = keyboard.compare(o.keyboard);
0096feb5 1393 if (v == 0) v = navHidden.compare(o.navHidden);
a534180c
TAOSP
1394 if (v == 0) v = navigation.compare(o.navigation);
1395 if (v == 0) v = screenSize.compare(o.screenSize);
1396 if (v == 0) v = version.compare(o.version);
1397 return v;
1398}
1399
e29f4ada 1400const ResTable_config& AaptGroupEntry::toParams() const
a534180c 1401{
e29f4ada
DH
1402 if (!mParamsChanged) {
1403 return mParams;
1404 }
1405
1406 mParamsChanged = false;
1407 ResTable_config& params(mParams);
a534180c
TAOSP
1408 memset(&params, 0, sizeof(params));
1409 getMccName(mcc.string(), &params);
1410 getMncName(mnc.string(), &params);
1411 getLocaleName(locale.string(), &params);
f1f3915b 1412 getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
4ee37df2
DH
1413 getScreenWidthDpName(screenWidthDp.string(), &params);
1414 getScreenHeightDpName(screenHeightDp.string(), &params);
f1f3915b
DH
1415 getScreenLayoutSizeName(screenLayoutSize.string(), &params);
1416 getScreenLayoutLongName(screenLayoutLong.string(), &params);
a534180c 1417 getOrientationName(orientation.string(), &params);
2ca01a37
TH
1418 getUiModeTypeName(uiModeType.string(), &params);
1419 getUiModeNightName(uiModeNight.string(), &params);
a534180c
TAOSP
1420 getDensityName(density.string(), &params);
1421 getTouchscreenName(touchscreen.string(), &params);
1422 getKeysHiddenName(keysHidden.string(), &params);
1423 getKeyboardName(keyboard.string(), &params);
0096feb5 1424 getNavHiddenName(navHidden.string(), &params);
a534180c
TAOSP
1425 getNavigationName(navigation.string(), &params);
1426 getScreenSizeName(screenSize.string(), &params);
1427 getVersionName(version.string(), &params);
af945cf3
DH
1428
1429 // Fix up version number based on specified parameters.
1430 int minSdk = 0;
f1f3915b
DH
1431 if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
1432 || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
4ee37df2 1433 || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
f1f3915b 1434 minSdk = SDK_HONEYCOMB_MR2;
4ee37df2 1435 } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
af945cf3
DH
1436 != ResTable_config::UI_MODE_TYPE_ANY
1437 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
1438 != ResTable_config::UI_MODE_NIGHT_ANY) {
1439 minSdk = SDK_FROYO;
1440 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
1441 != ResTable_config::SCREENSIZE_ANY
1442 || (params.screenLayout&ResTable_config::MASK_SCREENLONG)
1443 != ResTable_config::SCREENLONG_ANY
1444 || params.density != ResTable_config::DENSITY_DEFAULT) {
1445 minSdk = SDK_DONUT;
1446 }
1447
1448 if (minSdk > params.sdkVersion) {
1449 params.sdkVersion = minSdk;
1450 }
1451
a534180c
TAOSP
1452 return params;
1453}
1454
1455// =========================================================================
1456// =========================================================================
1457// =========================================================================
1458
1459void* AaptFile::editData(size_t size)
1460{
1461 if (size <= mBufferSize) {
1462 mDataSize = size;
1463 return mData;
1464 }
1465 size_t allocSize = (size*3)/2;
1466 void* buf = realloc(mData, allocSize);
1467 if (buf == NULL) {
1468 return NULL;
1469 }
1470 mData = buf;
1471 mDataSize = size;
1472 mBufferSize = allocSize;
1473 return buf;
1474}
1475
1476void* AaptFile::editData(size_t* outSize)
1477{
1478 if (outSize) {
1479 *outSize = mDataSize;
1480 }
1481 return mData;
1482}
1483
1484void* AaptFile::padData(size_t wordSize)
1485{
1486 const size_t extra = mDataSize%wordSize;
1487 if (extra == 0) {
1488 return mData;
1489 }
1490
1491 size_t initial = mDataSize;
1492 void* data = editData(initial+(wordSize-extra));
1493 if (data != NULL) {
1494 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
1495 }
1496 return data;
1497}
1498
1499status_t AaptFile::writeData(const void* data, size_t size)
1500{
1501 size_t end = mDataSize;
1502 size_t total = size + end;
1503 void* buf = editData(total);
1504 if (buf == NULL) {
1505 return UNKNOWN_ERROR;
1506 }
1507 memcpy(((char*)buf)+end, data, size);
1508 return NO_ERROR;
1509}
1510
1511void AaptFile::clearData()
1512{
1513 if (mData != NULL) free(mData);
1514 mData = NULL;
1515 mDataSize = 0;
1516 mBufferSize = 0;
1517}
1518
1519String8 AaptFile::getPrintableSource() const
1520{
1521 if (hasData()) {
e29f4ada 1522 String8 name(mGroupEntry.toDirName(String8()));
a534180c
TAOSP
1523 name.appendPath(mPath);
1524 name.append(" #generated");
1525 return name;
1526 }
1527 return mSourceFile;
1528}
1529
1530// =========================================================================
1531// =========================================================================
1532// =========================================================================
1533
1534status_t AaptGroup::addFile(const sp<AaptFile>& file)
1535{
1536 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
1537 file->mPath = mPath;
1538 mFiles.add(file->getGroupEntry(), file);
1539 return NO_ERROR;
1540 }
1541
e29f4ada
DH
1542#if 0
1543 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1544 file->getSourceFile().string(),
1545 file->getGroupEntry().toDirName(String8()).string(),
1546 mLeaf.string(), mPath.string());
1547#endif
1548
a534180c
TAOSP
1549 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1550 getPrintableSource().string());
1551 return UNKNOWN_ERROR;
1552}
1553
1554void AaptGroup::removeFile(size_t index)
1555{
1556 mFiles.removeItemsAt(index);
1557}
1558
e29f4ada 1559void AaptGroup::print(const String8& prefix) const
a534180c 1560{
e29f4ada 1561 printf("%s%s\n", prefix.string(), getPath().string());
a534180c
TAOSP
1562 const size_t N=mFiles.size();
1563 size_t i;
1564 for (i=0; i<N; i++) {
1565 sp<AaptFile> file = mFiles.valueAt(i);
1566 const AaptGroupEntry& e = file->getGroupEntry();
1567 if (file->hasData()) {
e29f4ada 1568 printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
a534180c
TAOSP
1569 (int)file->getSize());
1570 } else {
e29f4ada
DH
1571 printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
1572 file->getPrintableSource().string());
a534180c 1573 }
e29f4ada
DH
1574 //printf("%s File Group Entry: %s\n", prefix.string(),
1575 // file->getGroupEntry().toDirName(String8()).string());
a534180c
TAOSP
1576 }
1577}
1578
1579String8 AaptGroup::getPrintableSource() const
1580{
1581 if (mFiles.size() > 0) {
1582 // Arbitrarily pull the first source file out of the list.
1583 return mFiles.valueAt(0)->getPrintableSource();
1584 }
1585
1586 // Should never hit this case, but to be safe...
1587 return getPath();
1588
1589}
1590
1591// =========================================================================
1592// =========================================================================
1593// =========================================================================
1594
1595status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1596{
1597 if (mFiles.indexOfKey(name) >= 0) {
1598 return ALREADY_EXISTS;
1599 }
1600 mFiles.add(name, file);
1601 return NO_ERROR;
1602}
1603
1604status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1605{
1606 if (mDirs.indexOfKey(name) >= 0) {
1607 return ALREADY_EXISTS;
1608 }
1609 mDirs.add(name, dir);
1610 return NO_ERROR;
1611}
1612
1613sp<AaptDir> AaptDir::makeDir(const String8& path)
1614{
1615 String8 name;
1616 String8 remain = path;
1617
1618 sp<AaptDir> subdir = this;
1619 while (name = remain.walkPath(&remain), remain != "") {
1620 subdir = subdir->makeDir(name);
1621 }
1622
1623 ssize_t i = subdir->mDirs.indexOfKey(name);
1624 if (i >= 0) {
1625 return subdir->mDirs.valueAt(i);
1626 }
1627 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1628 subdir->mDirs.add(name, dir);
1629 return dir;
1630}
1631
1632void AaptDir::removeFile(const String8& name)
1633{
1634 mFiles.removeItem(name);
1635}
1636
1637void AaptDir::removeDir(const String8& name)
1638{
1639 mDirs.removeItem(name);
1640}
1641
a534180c
TAOSP
1642status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1643{
1644 sp<AaptGroup> group;
1645 if (mFiles.indexOfKey(leafName) >= 0) {
1646 group = mFiles.valueFor(leafName);
1647 } else {
1648 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1649 mFiles.add(leafName, group);
1650 }
1651
1652 return group->addFile(file);
1653}
1654
1655ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
52ffc169
JG
1656 const AaptGroupEntry& kind, const String8& resType,
1657 sp<FilePathStore>& fullResPaths)
a534180c
TAOSP
1658{
1659 Vector<String8> fileNames;
a534180c
TAOSP
1660 {
1661 DIR* dir = NULL;
1662
1663 dir = opendir(srcDir.string());
1664 if (dir == NULL) {
1665 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1666 return UNKNOWN_ERROR;
1667 }
1668
1669 /*
1670 * Slurp the filenames out of the directory.
1671 */
1672 while (1) {
1673 struct dirent* entry;
1674
1675 entry = readdir(dir);
1676 if (entry == NULL)
1677 break;
1678
1679 if (isHidden(srcDir.string(), entry->d_name))
1680 continue;
1681
52ffc169
JG
1682 String8 name(entry->d_name);
1683 fileNames.add(name);
1684 // Add fully qualified path for dependency purposes
1685 // if we're collecting them
1686 if (fullResPaths != NULL) {
1687 fullResPaths->add(srcDir.appendPathCopy(name));
1688 }
a534180c 1689 }
a534180c
TAOSP
1690 closedir(dir);
1691 }
1692
1693 ssize_t count = 0;
1694
1695 /*
1696 * Stash away the files and recursively descend into subdirectories.
1697 */
1698 const size_t N = fileNames.size();
1699 size_t i;
1700 for (i = 0; i < N; i++) {
1701 String8 pathName(srcDir);
1702 FileType type;
1703
1704 pathName.appendPath(fileNames[i].string());
1705 type = getFileType(pathName.string());
1706 if (type == kFileTypeDirectory) {
1707 sp<AaptDir> subdir;
1708 bool notAdded = false;
1709 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1710 subdir = mDirs.valueFor(fileNames[i]);
1711 } else {
1712 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1713 notAdded = true;
1714 }
1715 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
52ffc169 1716 resType, fullResPaths);
a534180c
TAOSP
1717 if (res < NO_ERROR) {
1718 return res;
1719 }
1720 if (res > 0 && notAdded) {
1721 mDirs.add(fileNames[i], subdir);
1722 }
1723 count += res;
1724 } else if (type == kFileTypeRegular) {
1725 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1726 status_t err = addLeafFile(fileNames[i], file);
1727 if (err != NO_ERROR) {
1728 return err;
1729 }
1730
1731 count++;
1732
1733 } else {
1734 if (bundle->getVerbose())
1735 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
1736 }
1737 }
1738
1739 return count;
1740}
1741
1742status_t AaptDir::validate() const
1743{
1744 const size_t NF = mFiles.size();
1745 const size_t ND = mDirs.size();
1746 size_t i;
1747 for (i = 0; i < NF; i++) {
1748 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1749 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1750 "Invalid filename. Unable to add.");
1751 return UNKNOWN_ERROR;
1752 }
1753
1754 size_t j;
1755 for (j = i+1; j < NF; j++) {
1756 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1757 mFiles.valueAt(j)->getLeaf().string()) == 0) {
1758 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1759 "File is case-insensitive equivalent to: %s",
1760 mFiles.valueAt(j)->getPrintableSource().string());
1761 return UNKNOWN_ERROR;
1762 }
1763
1764 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1765 // (this is mostly caught by the "marked" stuff, below)
1766 }
1767
1768 for (j = 0; j < ND; j++) {
1769 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1770 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1771 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1772 "File conflicts with dir from: %s",
1773 mDirs.valueAt(j)->getPrintableSource().string());
1774 return UNKNOWN_ERROR;
1775 }
1776 }
1777 }
1778
1779 for (i = 0; i < ND; i++) {
1780 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1781 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1782 "Invalid directory name, unable to add.");
1783 return UNKNOWN_ERROR;
1784 }
1785
1786 size_t j;
1787 for (j = i+1; j < ND; j++) {
1788 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1789 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1790 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1791 "Directory is case-insensitive equivalent to: %s",
1792 mDirs.valueAt(j)->getPrintableSource().string());
1793 return UNKNOWN_ERROR;
1794 }
1795 }
1796
1797 status_t err = mDirs.valueAt(i)->validate();
1798 if (err != NO_ERROR) {
1799 return err;
1800 }
1801 }
1802
1803 return NO_ERROR;
1804}
1805
e29f4ada 1806void AaptDir::print(const String8& prefix) const
a534180c
TAOSP
1807{
1808 const size_t ND=getDirs().size();
1809 size_t i;
1810 for (i=0; i<ND; i++) {
e29f4ada 1811 getDirs().valueAt(i)->print(prefix);
a534180c
TAOSP
1812 }
1813
1814 const size_t NF=getFiles().size();
1815 for (i=0; i<NF; i++) {
e29f4ada 1816 getFiles().valueAt(i)->print(prefix);
a534180c
TAOSP
1817 }
1818}
1819
1820String8 AaptDir::getPrintableSource() const
1821{
1822 if (mFiles.size() > 0) {
1823 // Arbitrarily pull the first file out of the list as the source dir.
1824 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1825 }
1826 if (mDirs.size() > 0) {
1827 // Or arbitrarily pull the first dir out of the list as the source dir.
1828 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1829 }
1830
1831 // Should never hit this case, but to be safe...
1832 return mPath;
1833
1834}
1835
1836// =========================================================================
1837// =========================================================================
1838// =========================================================================
1839
6415576e
DH
1840status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
1841{
1842 status_t err = NO_ERROR;
1843 size_t N = javaSymbols->mSymbols.size();
1844 for (size_t i=0; i<N; i++) {
1845 const String8& name = javaSymbols->mSymbols.keyAt(i);
1846 const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
1847 ssize_t pos = mSymbols.indexOfKey(name);
1848 if (pos < 0) {
1849 entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
1850 err = UNKNOWN_ERROR;
1851 continue;
1852 }
1853 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1854 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1855 mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
1856 }
1857
1858 N = javaSymbols->mNestedSymbols.size();
1859 for (size_t i=0; i<N; i++) {
1860 const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
1861 const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
1862 ssize_t pos = mNestedSymbols.indexOfKey(name);
1863 if (pos < 0) {
1864 SourcePos pos;
1865 pos.error("Java symbol dir %s not defined\n", name.string());
1866 err = UNKNOWN_ERROR;
1867 continue;
1868 }
1869 //printf("**** applying java symbols in dir %s\n", name.string());
1870 status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
1871 if (myerr != NO_ERROR) {
1872 err = myerr;
1873 }
1874 }
1875
1876 return err;
1877}
1878
1879// =========================================================================
1880// =========================================================================
1881// =========================================================================
1882
e29f4ada
DH
1883AaptAssets::AaptAssets()
1884 : AaptDir(String8(), String8()),
1885 mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
1886{
1887}
1888
1889const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
1890 if (mChanged) {
1891 }
1892 return mGroupEntries;
1893}
1894
1895status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
1896{
1897 mChanged = true;
1898 return AaptDir::addFile(name, file);
1899}
1900
a534180c
TAOSP
1901sp<AaptFile> AaptAssets::addFile(
1902 const String8& filePath, const AaptGroupEntry& entry,
1903 const String8& srcDir, sp<AaptGroup>* outGroup,
1904 const String8& resType)
1905{
1906 sp<AaptDir> dir = this;
1907 sp<AaptGroup> group;
1908 sp<AaptFile> file;
1909 String8 root, remain(filePath), partialPath;
1910 while (remain.length() > 0) {
1911 root = remain.walkPath(&remain);
1912 partialPath.appendPath(root);
1913
1914 const String8 rootStr(root);
1915
1916 if (remain.length() == 0) {
1917 ssize_t i = dir->getFiles().indexOfKey(rootStr);
1918 if (i >= 0) {
1919 group = dir->getFiles().valueAt(i);
1920 } else {
1921 group = new AaptGroup(rootStr, filePath);
1922 status_t res = dir->addFile(rootStr, group);
1923 if (res != NO_ERROR) {
1924 return NULL;
1925 }
1926 }
1927 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
1928 status_t res = group->addFile(file);
1929 if (res != NO_ERROR) {
1930 return NULL;
1931 }
1932 break;
1933
1934 } else {
1935 ssize_t i = dir->getDirs().indexOfKey(rootStr);
1936 if (i >= 0) {
1937 dir = dir->getDirs().valueAt(i);
1938 } else {
1939 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
1940 status_t res = dir->addDir(rootStr, subdir);
1941 if (res != NO_ERROR) {
1942 return NULL;
1943 }
1944 dir = subdir;
1945 }
1946 }
1947 }
1948
1949 mGroupEntries.add(entry);
1950 if (outGroup) *outGroup = group;
1951 return file;
1952}
1953
1954void AaptAssets::addResource(const String8& leafName, const String8& path,
1955 const sp<AaptFile>& file, const String8& resType)
1956{
1957 sp<AaptDir> res = AaptDir::makeDir(kResString);
1958 String8 dirname = file->getGroupEntry().toDirName(resType);
1959 sp<AaptDir> subdir = res->makeDir(dirname);
1960 sp<AaptGroup> grr = new AaptGroup(leafName, path);
1961 grr->addFile(file);
1962
1963 subdir->addFile(leafName, grr);
1964}
1965
1966
1967ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
1968{
1969 int count;
1970 int totalCount = 0;
1971 FileType type;
1972 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
1973 const size_t dirCount =resDirs.size();
1974 sp<AaptAssets> current = this;
1975
1976 const int N = bundle->getFileSpecCount();
1977
1978 /*
1979 * If a package manifest was specified, include that first.
1980 */
1981 if (bundle->getAndroidManifestFile() != NULL) {
1982 // place at root of zip.
1983 String8 srcFile(bundle->getAndroidManifestFile());
1984 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
1985 NULL, String8());
1986 totalCount++;
1987 }
1988
1989 /*
1990 * If a directory of custom assets was supplied, slurp 'em up.
1991 */
1992 if (bundle->getAssetSourceDir()) {
1993 const char* assetDir = bundle->getAssetSourceDir();
1994
1995 FileType type = getFileType(assetDir);
1996 if (type == kFileTypeNonexistent) {
1997 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
1998 return UNKNOWN_ERROR;
1999 }
2000 if (type != kFileTypeDirectory) {
2001 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
2002 return UNKNOWN_ERROR;
2003 }
2004
2005 String8 assetRoot(assetDir);
2006 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
2007 AaptGroupEntry group;
2008 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
b5a473da 2009 String8(), mFullAssetPaths);
a534180c
TAOSP
2010 if (count < 0) {
2011 totalCount = count;
2012 goto bail;
2013 }
2014 if (count > 0) {
2015 mGroupEntries.add(group);
2016 }
2017 totalCount += count;
2018
2019 if (bundle->getVerbose())
2020 printf("Found %d custom asset file%s in %s\n",
2021 count, (count==1) ? "" : "s", assetDir);
2022 }
2023
2024 /*
2025 * If a directory of resource-specific assets was supplied, slurp 'em up.
2026 */
2027 for (size_t i=0; i<dirCount; i++) {
2028 const char *res = resDirs[i];
2029 if (res) {
2030 type = getFileType(res);
2031 if (type == kFileTypeNonexistent) {
2032 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
2033 return UNKNOWN_ERROR;
2034 }
2035 if (type == kFileTypeDirectory) {
2036 if (i>0) {
2037 sp<AaptAssets> nextOverlay = new AaptAssets();
2038 current->setOverlay(nextOverlay);
2039 current = nextOverlay;
52ffc169 2040 current->setFullResPaths(mFullResPaths);
a534180c
TAOSP
2041 }
2042 count = current->slurpResourceTree(bundle, String8(res));
2043
2044 if (count < 0) {
2045 totalCount = count;
2046 goto bail;
2047 }
2048 totalCount += count;
2049 }
2050 else {
2051 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
2052 return UNKNOWN_ERROR;
2053 }
2054 }
2055
2056 }
2057 /*
2058 * Now do any additional raw files.
2059 */
2060 for (int arg=0; arg<N; arg++) {
2061 const char* assetDir = bundle->getFileSpecEntry(arg);
2062
2063 FileType type = getFileType(assetDir);
2064 if (type == kFileTypeNonexistent) {
2065 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
2066 return UNKNOWN_ERROR;
2067 }
2068 if (type != kFileTypeDirectory) {
2069 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
2070 return UNKNOWN_ERROR;
2071 }
2072
2073 String8 assetRoot(assetDir);
2074
2075 if (bundle->getVerbose())
2076 printf("Processing raw dir '%s'\n", (const char*) assetDir);
2077
2078 /*
2079 * Do a recursive traversal of subdir tree. We don't make any
2080 * guarantees about ordering, so we're okay with an inorder search
2081 * using whatever order the OS happens to hand back to us.
2082 */
b5a473da 2083 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);
a534180c
TAOSP
2084 if (count < 0) {
2085 /* failure; report error and remove archive */
2086 totalCount = count;
2087 goto bail;
2088 }
2089 totalCount += count;
2090
2091 if (bundle->getVerbose())
2092 printf("Found %d asset file%s in %s\n",
2093 count, (count==1) ? "" : "s", assetDir);
2094 }
2095
2096 count = validate();
2097 if (count != NO_ERROR) {
2098 totalCount = count;
2099 goto bail;
2100 }
2101
e29f4ada
DH
2102 count = filter(bundle);
2103 if (count != NO_ERROR) {
2104 totalCount = count;
2105 goto bail;
2106 }
a534180c
TAOSP
2107
2108bail:
2109 return totalCount;
2110}
2111
2112ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
2113 const AaptGroupEntry& kind,
52ffc169
JG
2114 const String8& resType,
2115 sp<FilePathStore>& fullResPaths)
a534180c 2116{
52ffc169 2117 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
a534180c
TAOSP
2118 if (res > 0) {
2119 mGroupEntries.add(kind);
2120 }
2121
2122 return res;
2123}
2124
2125ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
2126{
2127 ssize_t err = 0;
2128
2129 DIR* dir = opendir(srcDir.string());
2130 if (dir == NULL) {
2131 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
2132 return UNKNOWN_ERROR;
2133 }
2134
2135 status_t count = 0;
2136
2137 /*
2138 * Run through the directory, looking for dirs that match the
2139 * expected pattern.
2140 */
2141 while (1) {
2142 struct dirent* entry = readdir(dir);
2143 if (entry == NULL) {
2144 break;
2145 }
2146
2147 if (isHidden(srcDir.string(), entry->d_name)) {
2148 continue;
2149 }
2150
2151 String8 subdirName(srcDir);
2152 subdirName.appendPath(entry->d_name);
2153
2154 AaptGroupEntry group;
2155 String8 resType;
2156 bool b = group.initFromDirName(entry->d_name, &resType);
2157 if (!b) {
2158 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
2159 entry->d_name);
2160 err = -1;
2161 continue;
2162 }
2163
e29f4ada 2164 if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
73412e58 2165 int maxResInt = atoi(bundle->getMaxResVersion());
e29f4ada 2166 const char *verString = group.getVersionString().string();
73412e58
FK
2167 int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
2168 if (dirVersionInt > maxResInt) {
2169 fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
2170 continue;
2171 }
2172 }
2173
a534180c
TAOSP
2174 FileType type = getFileType(subdirName.string());
2175
2176 if (type == kFileTypeDirectory) {
e29f4ada 2177 sp<AaptDir> dir = makeDir(resType);
a534180c 2178 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
52ffc169 2179 resType, mFullResPaths);
a534180c
TAOSP
2180 if (res < 0) {
2181 count = res;
2182 goto bail;
2183 }
2184 if (res > 0) {
2185 mGroupEntries.add(group);
2186 count += res;
2187 }
2188
e29f4ada
DH
2189 // Only add this directory if we don't already have a resource dir
2190 // for the current type. This ensures that we only add the dir once
2191 // for all configs.
2192 sp<AaptDir> rdir = resDir(resType);
2193 if (rdir == NULL) {
2194 mResDirs.add(dir);
2195 }
a534180c
TAOSP
2196 } else {
2197 if (bundle->getVerbose()) {
2198 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
2199 }
2200 }
2201 }
2202
2203bail:
2204 closedir(dir);
2205 dir = NULL;
2206
2207 if (err != 0) {
2208 return err;
2209 }
2210 return count;
2211}
2212
2213ssize_t
2214AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
2215{
2216 int count = 0;
2217 SortedVector<AaptGroupEntry> entries;
2218
2219 ZipFile* zip = new ZipFile;
2220 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
2221 if (err != NO_ERROR) {
2222 fprintf(stderr, "error opening zip file %s\n", filename);
2223 count = err;
2224 delete zip;
2225 return -1;
2226 }
2227
2228 const int N = zip->getNumEntries();
2229 for (int i=0; i<N; i++) {
2230 ZipEntry* entry = zip->getEntryByIndex(i);
2231 if (entry->getDeleted()) {
2232 continue;
2233 }
2234
2235 String8 entryName(entry->getFileName());
2236
2237 String8 dirName = entryName.getPathDir();
2238 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
2239
2240 String8 resType;
2241 AaptGroupEntry kind;
2242
2243 String8 remain;
2244 if (entryName.walkPath(&remain) == kResourceDir) {
2245 // these are the resources, pull their type out of the directory name
2246 kind.initFromDirName(remain.walkPath().string(), &resType);
2247 } else {
2248 // these are untyped and don't have an AaptGroupEntry
2249 }
2250 if (entries.indexOf(kind) < 0) {
2251 entries.add(kind);
2252 mGroupEntries.add(kind);
2253 }
2254
2255 // use the one from the zip file if they both exist.
2256 dir->removeFile(entryName.getPathLeaf());
2257
2258 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
2259 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
2260 if (err != NO_ERROR) {
2261 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
2262 count = err;
2263 goto bail;
2264 }
2265 file->setCompressionMethod(entry->getCompressionMethod());
2266
2267#if 0
2268 if (entryName == "AndroidManifest.xml") {
2269 printf("AndroidManifest.xml\n");
2270 }
2271 printf("\n\nfile: %s\n", entryName.string());
2272#endif
2273
2274 size_t len = entry->getUncompressedLen();
2275 void* data = zip->uncompress(entry);
2276 void* buf = file->editData(len);
2277 memcpy(buf, data, len);
2278
2279#if 0
2280 const int OFF = 0;
2281 const unsigned char* p = (unsigned char*)data;
2282 const unsigned char* end = p+len;
2283 p += OFF;
2284 for (int i=0; i<32 && p < end; i++) {
2285 printf("0x%03x ", i*0x10 + OFF);
2286 for (int j=0; j<0x10 && p < end; j++) {
2287 printf(" %02x", *p);
2288 p++;
2289 }
2290 printf("\n");
2291 }
2292#endif
2293
2294 free(data);
2295
2296 count++;
2297 }
2298
2299bail:
2300 delete zip;
2301 return count;
2302}
2303
e29f4ada
DH
2304status_t AaptAssets::filter(Bundle* bundle)
2305{
2306 ResourceFilter reqFilter;
2307 status_t err = reqFilter.parse(bundle->getConfigurations());
2308 if (err != NO_ERROR) {
2309 return err;
2310 }
2311
2312 ResourceFilter prefFilter;
2313 err = prefFilter.parse(bundle->getPreferredConfigurations());
2314 if (err != NO_ERROR) {
2315 return err;
2316 }
2317
2318 if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
2319 return NO_ERROR;
2320 }
2321
9fbf0ad5 2322 if (bundle->getVerbose()) {
e29f4ada
DH
2323 if (!reqFilter.isEmpty()) {
2324 printf("Applying required filter: %s\n",
2325 bundle->getConfigurations());
2326 }
2327 if (!prefFilter.isEmpty()) {
2328 printf("Applying preferred filter: %s\n",
2329 bundle->getPreferredConfigurations());
2330 }
2331 }
2332
2333 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2334 const size_t ND = resdirs.size();
2335 for (size_t i=0; i<ND; i++) {
2336 const sp<AaptDir>& dir = resdirs.itemAt(i);
2337 if (dir->getLeaf() == kValuesDir) {
2338 // The "value" dir is special since a single file defines
2339 // multiple resources, so we can not do filtering on the
2340 // files themselves.
2341 continue;
2342 }
2343 if (dir->getLeaf() == kMipmapDir) {
2344 // We also skip the "mipmap" directory, since the point of this
2345 // is to include all densities without stripping. If you put
2346 // other configurations in here as well they won't be stripped
2347 // either... So don't do that. Seriously. What is wrong with you?
2348 continue;
2349 }
2350
2351 const size_t NG = dir->getFiles().size();
2352 for (size_t j=0; j<NG; j++) {
2353 sp<AaptGroup> grp = dir->getFiles().valueAt(j);
2354
2355 // First remove any configurations we know we don't need.
2356 for (size_t k=0; k<grp->getFiles().size(); k++) {
2357 sp<AaptFile> file = grp->getFiles().valueAt(k);
2358 if (k == 0 && grp->getFiles().size() == 1) {
2359 // If this is the only file left, we need to keep it.
2360 // Otherwise the resource IDs we are using will be inconsistent
2361 // with what we get when not stripping. Sucky, but at least
2362 // for now we can rely on the back-end doing another filtering
2363 // pass to take this out and leave us with this resource name
2364 // containing no entries.
2365 continue;
2366 }
2367 if (file->getPath().getPathExtension() == ".xml") {
2368 // We can't remove .xml files at this point, because when
2369 // we parse them they may add identifier resources, so
2370 // removing them can cause our resource identifiers to
2371 // become inconsistent.
2372 continue;
2373 }
2374 const ResTable_config& config(file->getGroupEntry().toParams());
2375 if (!reqFilter.match(config)) {
2376 if (bundle->getVerbose()) {
2377 printf("Pruning unneeded resource: %s\n",
2378 file->getPrintableSource().string());
2379 }
2380 grp->removeFile(k);
2381 k--;
2382 }
2383 }
2384
2385 // Quick check: no preferred filters, nothing more to do.
2386 if (prefFilter.isEmpty()) {
2387 continue;
2388 }
2389
2390 // Now deal with preferred configurations.
2391 for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
2392 for (size_t k=0; k<grp->getFiles().size(); k++) {
2393 sp<AaptFile> file = grp->getFiles().valueAt(k);
2394 if (k == 0 && grp->getFiles().size() == 1) {
2395 // If this is the only file left, we need to keep it.
2396 // Otherwise the resource IDs we are using will be inconsistent
2397 // with what we get when not stripping. Sucky, but at least
2398 // for now we can rely on the back-end doing another filtering
2399 // pass to take this out and leave us with this resource name
2400 // containing no entries.
2401 continue;
2402 }
2403 if (file->getPath().getPathExtension() == ".xml") {
2404 // We can't remove .xml files at this point, because when
2405 // we parse them they may add identifier resources, so
2406 // removing them can cause our resource identifiers to
2407 // become inconsistent.
2408 continue;
2409 }
2410 const ResTable_config& config(file->getGroupEntry().toParams());
2411 if (!prefFilter.match(axis, config)) {
2412 // This is a resource we would prefer not to have. Check
2413 // to see if have a similar variation that we would like
2414 // to have and, if so, we can drop it.
2415 for (size_t m=0; m<grp->getFiles().size(); m++) {
2416 if (m == k) continue;
2417 sp<AaptFile> mfile = grp->getFiles().valueAt(m);
2418 const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
2419 if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
2420 if (prefFilter.match(axis, mconfig)) {
2421 if (bundle->getVerbose()) {
2422 printf("Pruning unneeded resource: %s\n",
2423 file->getPrintableSource().string());
2424 }
2425 grp->removeFile(k);
2426 k--;
2427 break;
2428 }
2429 }
2430 }
2431 }
2432 }
2433 }
2434 }
2435 }
2436
2437 return NO_ERROR;
2438}
2439
a534180c
TAOSP
2440sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
2441{
2442 sp<AaptSymbols> sym = mSymbols.valueFor(name);
2443 if (sym == NULL) {
2444 sym = new AaptSymbols();
2445 mSymbols.add(name, sym);
2446 }
2447 return sym;
2448}
2449
6415576e
DH
2450sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
2451{
2452 sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
2453 if (sym == NULL) {
2454 sym = new AaptSymbols();
2455 mJavaSymbols.add(name, sym);
2456 }
2457 return sym;
2458}
2459
2460status_t AaptAssets::applyJavaSymbols()
2461{
2462 size_t N = mJavaSymbols.size();
2463 for (size_t i=0; i<N; i++) {
2464 const String8& name = mJavaSymbols.keyAt(i);
2465 const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
2466 ssize_t pos = mSymbols.indexOfKey(name);
2467 if (pos < 0) {
2468 SourcePos pos;
2469 pos.error("Java symbol dir %s not defined\n", name.string());
2470 return UNKNOWN_ERROR;
2471 }
2472 //printf("**** applying java symbols in dir %s\n", name.string());
2473 status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
2474 if (err != NO_ERROR) {
2475 return err;
2476 }
2477 }
2478
2479 return NO_ERROR;
2480}
2481
2482bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
2483 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2484 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2485 // sym.isJavaSymbol ? 1 : 0);
2486 if (!mHavePrivateSymbols) return true;
2487 if (sym.isPublic) return true;
2488 if (includePrivate && sym.isJavaSymbol) return true;
2489 return false;
2490}
2491
a534180c
TAOSP
2492status_t AaptAssets::buildIncludedResources(Bundle* bundle)
2493{
2494 if (!mHaveIncludedAssets) {
2495 // Add in all includes.
2496 const Vector<const char*>& incl = bundle->getPackageIncludes();
2497 const size_t N=incl.size();
2498 for (size_t i=0; i<N; i++) {
2499 if (bundle->getVerbose())
2500 printf("Including resources from package: %s\n", incl[i]);
2501 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
2502 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
2503 incl[i]);
2504 return UNKNOWN_ERROR;
2505 }
2506 }
2507 mHaveIncludedAssets = true;
2508 }
2509
2510 return NO_ERROR;
2511}
2512
2513status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
2514{
2515 const ResTable& res = getIncludedResources();
2516 // XXX dirty!
2517 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
2518}
2519
2520const ResTable& AaptAssets::getIncludedResources() const
2521{
2522 return mIncludedAssets.getResources(false);
2523}
2524
e29f4ada 2525void AaptAssets::print(const String8& prefix) const
a534180c 2526{
e29f4ada
DH
2527 String8 innerPrefix(prefix);
2528 innerPrefix.append(" ");
2529 String8 innerInnerPrefix(innerPrefix);
2530 innerInnerPrefix.append(" ");
2531 printf("%sConfigurations:\n", prefix.string());
a534180c
TAOSP
2532 const size_t N=mGroupEntries.size();
2533 for (size_t i=0; i<N; i++) {
e29f4ada
DH
2534 String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
2535 printf("%s %s\n", prefix.string(),
2536 cname != "" ? cname.string() : "(default)");
a534180c
TAOSP
2537 }
2538
e29f4ada
DH
2539 printf("\n%sFiles:\n", prefix.string());
2540 AaptDir::print(innerPrefix);
2541
2542 printf("\n%sResource Dirs:\n", prefix.string());
2543 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2544 const size_t NR = resdirs.size();
2545 for (size_t i=0; i<NR; i++) {
2546 const sp<AaptDir>& d = resdirs.itemAt(i);
2547 printf("%s Type %s\n", prefix.string(), d->getLeaf().string());
2548 d->print(innerInnerPrefix);
2549 }
a534180c
TAOSP
2550}
2551
e29f4ada 2552sp<AaptDir> AaptAssets::resDir(const String8& name) const
6648ff78 2553{
e29f4ada
DH
2554 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2555 const size_t N = resdirs.size();
6648ff78 2556 for (size_t i=0; i<N; i++) {
e29f4ada 2557 const sp<AaptDir>& d = resdirs.itemAt(i);
6648ff78
JO
2558 if (d->getLeaf() == name) {
2559 return d;
2560 }
2561 }
2562 return NULL;
2563}
2564
a534180c
TAOSP
2565bool
2566valid_symbol_name(const String8& symbol)
2567{
2568 static char const * const KEYWORDS[] = {
2569 "abstract", "assert", "boolean", "break",
2570 "byte", "case", "catch", "char", "class", "const", "continue",
2571 "default", "do", "double", "else", "enum", "extends", "final",
2572 "finally", "float", "for", "goto", "if", "implements", "import",
2573 "instanceof", "int", "interface", "long", "native", "new", "package",
2574 "private", "protected", "public", "return", "short", "static",
2575 "strictfp", "super", "switch", "synchronized", "this", "throw",
2576 "throws", "transient", "try", "void", "volatile", "while",
2577 "true", "false", "null",
2578 NULL
2579 };
2580 const char*const* k = KEYWORDS;
2581 const char*const s = symbol.string();
2582 while (*k) {
2583 if (0 == strcmp(s, *k)) {
2584 return false;
2585 }
2586 k++;
2587 }
2588 return true;
2589}