]> git.saurik.com Git - android/aapt.git/blob - AaptAssets.cpp
Fix potential aapt crash when processing overlay.
[android/aapt.git] / AaptAssets.cpp
1 //
2 // Copyright 2006 The Android Open Source Project
3 //
4
5 #include "AaptAssets.h"
6 #include "Main.h"
7
8 #include <utils/misc.h>
9 #include <utils/SortedVector.h>
10
11 #include <ctype.h>
12 #include <dirent.h>
13 #include <errno.h>
14
15 static const char* kDefaultLocale = "default";
16 static const char* kWildcardName = "any";
17 static const char* kAssetDir = "assets";
18 static const char* kResourceDir = "res";
19 static const char* kInvalidChars = "/\\:";
20 static const size_t kMaxAssetFileName = 100;
21
22 static const String8 kResString(kResourceDir);
23
24 /*
25 * Names of asset files must meet the following criteria:
26 *
27 * - the filename length must be less than kMaxAssetFileName bytes long
28 * (and can't be empty)
29 * - all characters must be 7-bit printable ASCII
30 * - none of { '/' '\\' ':' }
31 *
32 * Pass in just the filename, not the full path.
33 */
34 static bool validateFileName(const char* fileName)
35 {
36 const char* cp = fileName;
37 size_t len = 0;
38
39 while (*cp != '\0') {
40 if ((*cp & 0x80) != 0)
41 return false; // reject high ASCII
42 if (*cp < 0x20 || *cp >= 0x7f)
43 return false; // reject control chars and 0x7f
44 if (strchr(kInvalidChars, *cp) != NULL)
45 return false; // reject path sep chars
46 cp++;
47 len++;
48 }
49
50 if (len < 1 || len > kMaxAssetFileName)
51 return false; // reject empty or too long
52
53 return true;
54 }
55
56 static bool isHidden(const char *root, const char *path)
57 {
58 const char *ext = NULL;
59 const char *type = NULL;
60
61 // Skip all hidden files.
62 if (path[0] == '.') {
63 // Skip ., .. and .svn but don't chatter about it.
64 if (strcmp(path, ".") == 0
65 || strcmp(path, "..") == 0
66 || strcmp(path, ".svn") == 0) {
67 return true;
68 }
69 type = "hidden";
70 } else if (path[0] == '_') {
71 // skip directories starting with _ (don't chatter about it)
72 String8 subdirName(root);
73 subdirName.appendPath(path);
74 if (getFileType(subdirName.string()) == kFileTypeDirectory) {
75 return true;
76 }
77 } else if (strcmp(path, "CVS") == 0) {
78 // Skip CVS but don't chatter about it.
79 return true;
80 } else if (strcasecmp(path, "thumbs.db") == 0
81 || strcasecmp(path, "picasa.ini") == 0) {
82 // Skip suspected image indexes files.
83 type = "index";
84 } else if (path[strlen(path)-1] == '~') {
85 // Skip suspected emacs backup files.
86 type = "backup";
87 } else if ((ext = strrchr(path, '.')) != NULL && strcmp(ext, ".scc") == 0) {
88 // Skip VisualSourceSafe files and don't chatter about it
89 return true;
90 } else {
91 // Let everything else through.
92 return false;
93 }
94
95 /* If we get this far, "type" should be set and the file
96 * should be skipped.
97 */
98 String8 subdirName(root);
99 subdirName.appendPath(path);
100 fprintf(stderr, " (skipping %s %s '%s')\n", type,
101 getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file",
102 subdirName.string());
103
104 return true;
105 }
106
107 // =========================================================================
108 // =========================================================================
109 // =========================================================================
110
111 status_t
112 AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
113 {
114 ResTable_config config;
115
116 // IMSI - MCC
117 if (getMccName(part.string(), &config)) {
118 *axis = AXIS_MCC;
119 *value = config.mcc;
120 return 0;
121 }
122
123 // IMSI - MNC
124 if (getMncName(part.string(), &config)) {
125 *axis = AXIS_MNC;
126 *value = config.mnc;
127 return 0;
128 }
129
130 // locale - language
131 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
132 *axis = AXIS_LANGUAGE;
133 *value = part[1] << 8 | part[0];
134 return 0;
135 }
136
137 // locale - language_REGION
138 if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
139 && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
140 *axis = AXIS_LANGUAGE;
141 *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
142 return 0;
143 }
144
145 // screen layout size
146 if (getScreenLayoutSizeName(part.string(), &config)) {
147 *axis = AXIS_SCREENLAYOUTSIZE;
148 *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
149 return 0;
150 }
151
152 // screen layout long
153 if (getScreenLayoutLongName(part.string(), &config)) {
154 *axis = AXIS_SCREENLAYOUTLONG;
155 *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
156 return 0;
157 }
158
159 // orientation
160 if (getOrientationName(part.string(), &config)) {
161 *axis = AXIS_ORIENTATION;
162 *value = config.orientation;
163 return 0;
164 }
165
166 // ui mode type
167 if (getUiModeTypeName(part.string(), &config)) {
168 *axis = AXIS_UIMODETYPE;
169 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
170 return 0;
171 }
172
173 // ui mode night
174 if (getUiModeNightName(part.string(), &config)) {
175 *axis = AXIS_UIMODENIGHT;
176 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
177 return 0;
178 }
179
180 // density
181 if (getDensityName(part.string(), &config)) {
182 *axis = AXIS_DENSITY;
183 *value = config.density;
184 return 0;
185 }
186
187 // touchscreen
188 if (getTouchscreenName(part.string(), &config)) {
189 *axis = AXIS_TOUCHSCREEN;
190 *value = config.touchscreen;
191 return 0;
192 }
193
194 // keyboard hidden
195 if (getKeysHiddenName(part.string(), &config)) {
196 *axis = AXIS_KEYSHIDDEN;
197 *value = config.inputFlags;
198 return 0;
199 }
200
201 // keyboard
202 if (getKeyboardName(part.string(), &config)) {
203 *axis = AXIS_KEYBOARD;
204 *value = config.keyboard;
205 return 0;
206 }
207
208 // navigation hidden
209 if (getNavHiddenName(part.string(), &config)) {
210 *axis = AXIS_NAVHIDDEN;
211 *value = config.inputFlags;
212 return 0;
213 }
214
215 // navigation
216 if (getNavigationName(part.string(), &config)) {
217 *axis = AXIS_NAVIGATION;
218 *value = config.navigation;
219 return 0;
220 }
221
222 // screen size
223 if (getScreenSizeName(part.string(), &config)) {
224 *axis = AXIS_SCREENSIZE;
225 *value = config.screenSize;
226 return 0;
227 }
228
229 // version
230 if (getVersionName(part.string(), &config)) {
231 *axis = AXIS_VERSION;
232 *value = config.version;
233 return 0;
234 }
235
236 return 1;
237 }
238
239 bool
240 AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
241 {
242 Vector<String8> parts;
243
244 String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
245 String8 touch, key, keysHidden, nav, navHidden, size, vers;
246 String8 uiModeType, uiModeNight;
247
248 const char *p = dir;
249 const char *q;
250 while (NULL != (q = strchr(p, '-'))) {
251 String8 val(p, q-p);
252 val.toLower();
253 parts.add(val);
254 //printf("part: %s\n", parts[parts.size()-1].string());
255 p = q+1;
256 }
257 String8 val(p);
258 val.toLower();
259 parts.add(val);
260 //printf("part: %s\n", parts[parts.size()-1].string());
261
262 const int N = parts.size();
263 int index = 0;
264 String8 part = parts[index];
265
266 // resource type
267 if (!isValidResourceType(part)) {
268 return false;
269 }
270 *resType = part;
271
272 index++;
273 if (index == N) {
274 goto success;
275 }
276 part = parts[index];
277
278 // imsi - mcc
279 if (getMccName(part.string())) {
280 mcc = part;
281
282 index++;
283 if (index == N) {
284 goto success;
285 }
286 part = parts[index];
287 } else {
288 //printf("not mcc: %s\n", part.string());
289 }
290
291 // imsi - mnc
292 if (getMncName(part.string())) {
293 mnc = part;
294
295 index++;
296 if (index == N) {
297 goto success;
298 }
299 part = parts[index];
300 } else {
301 //printf("not mcc: %s\n", part.string());
302 }
303
304 // locale - language
305 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
306 loc = part;
307
308 index++;
309 if (index == N) {
310 goto success;
311 }
312 part = parts[index];
313 } else {
314 //printf("not language: %s\n", part.string());
315 }
316
317 // locale - region
318 if (loc.length() > 0
319 && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
320 loc += "-";
321 part.toUpper();
322 loc += part.string() + 1;
323
324 index++;
325 if (index == N) {
326 goto success;
327 }
328 part = parts[index];
329 } else {
330 //printf("not region: %s\n", part.string());
331 }
332
333 if (getScreenLayoutSizeName(part.string())) {
334 layoutsize = part;
335
336 index++;
337 if (index == N) {
338 goto success;
339 }
340 part = parts[index];
341 } else {
342 //printf("not screen layout size: %s\n", part.string());
343 }
344
345 if (getScreenLayoutLongName(part.string())) {
346 layoutlong = part;
347
348 index++;
349 if (index == N) {
350 goto success;
351 }
352 part = parts[index];
353 } else {
354 //printf("not screen layout long: %s\n", part.string());
355 }
356
357 // orientation
358 if (getOrientationName(part.string())) {
359 orient = part;
360
361 index++;
362 if (index == N) {
363 goto success;
364 }
365 part = parts[index];
366 } else {
367 //printf("not orientation: %s\n", part.string());
368 }
369
370 // ui mode type
371 if (getUiModeTypeName(part.string())) {
372 uiModeType = part;
373
374 index++;
375 if (index == N) {
376 goto success;
377 }
378 part = parts[index];
379 } else {
380 //printf("not ui mode type: %s\n", part.string());
381 }
382
383 // ui mode night
384 if (getUiModeNightName(part.string())) {
385 uiModeNight = part;
386
387 index++;
388 if (index == N) {
389 goto success;
390 }
391 part = parts[index];
392 } else {
393 //printf("not ui mode night: %s\n", part.string());
394 }
395
396 // density
397 if (getDensityName(part.string())) {
398 den = part;
399
400 index++;
401 if (index == N) {
402 goto success;
403 }
404 part = parts[index];
405 } else {
406 //printf("not density: %s\n", part.string());
407 }
408
409 // touchscreen
410 if (getTouchscreenName(part.string())) {
411 touch = part;
412
413 index++;
414 if (index == N) {
415 goto success;
416 }
417 part = parts[index];
418 } else {
419 //printf("not touchscreen: %s\n", part.string());
420 }
421
422 // keyboard hidden
423 if (getKeysHiddenName(part.string())) {
424 keysHidden = part;
425
426 index++;
427 if (index == N) {
428 goto success;
429 }
430 part = parts[index];
431 } else {
432 //printf("not keysHidden: %s\n", part.string());
433 }
434
435 // keyboard
436 if (getKeyboardName(part.string())) {
437 key = part;
438
439 index++;
440 if (index == N) {
441 goto success;
442 }
443 part = parts[index];
444 } else {
445 //printf("not keyboard: %s\n", part.string());
446 }
447
448 // navigation hidden
449 if (getNavHiddenName(part.string())) {
450 navHidden = part;
451
452 index++;
453 if (index == N) {
454 goto success;
455 }
456 part = parts[index];
457 } else {
458 //printf("not navHidden: %s\n", part.string());
459 }
460
461 if (getNavigationName(part.string())) {
462 nav = part;
463
464 index++;
465 if (index == N) {
466 goto success;
467 }
468 part = parts[index];
469 } else {
470 //printf("not navigation: %s\n", part.string());
471 }
472
473 if (getScreenSizeName(part.string())) {
474 size = part;
475
476 index++;
477 if (index == N) {
478 goto success;
479 }
480 part = parts[index];
481 } else {
482 //printf("not screen size: %s\n", part.string());
483 }
484
485 if (getVersionName(part.string())) {
486 vers = part;
487
488 index++;
489 if (index == N) {
490 goto success;
491 }
492 part = parts[index];
493 } else {
494 //printf("not version: %s\n", part.string());
495 }
496
497 // if there are extra parts, it doesn't match
498 return false;
499
500 success:
501 this->mcc = mcc;
502 this->mnc = mnc;
503 this->locale = loc;
504 this->screenLayoutSize = layoutsize;
505 this->screenLayoutLong = layoutlong;
506 this->orientation = orient;
507 this->uiModeType = uiModeType;
508 this->uiModeNight = uiModeNight;
509 this->density = den;
510 this->touchscreen = touch;
511 this->keysHidden = keysHidden;
512 this->keyboard = key;
513 this->navHidden = navHidden;
514 this->navigation = nav;
515 this->screenSize = size;
516 this->version = vers;
517
518 // what is this anyway?
519 this->vendor = "";
520
521 return true;
522 }
523
524 String8
525 AaptGroupEntry::toString() const
526 {
527 String8 s = this->mcc;
528 s += ",";
529 s += this->mnc;
530 s += ",";
531 s += this->locale;
532 s += ",";
533 s += screenLayoutSize;
534 s += ",";
535 s += screenLayoutLong;
536 s += ",";
537 s += this->orientation;
538 s += ",";
539 s += uiModeType;
540 s += ",";
541 s += uiModeNight;
542 s += ",";
543 s += density;
544 s += ",";
545 s += touchscreen;
546 s += ",";
547 s += keysHidden;
548 s += ",";
549 s += keyboard;
550 s += ",";
551 s += navHidden;
552 s += ",";
553 s += navigation;
554 s += ",";
555 s += screenSize;
556 s += ",";
557 s += version;
558 return s;
559 }
560
561 String8
562 AaptGroupEntry::toDirName(const String8& resType) const
563 {
564 String8 s = resType;
565 if (this->mcc != "") {
566 s += "-";
567 s += mcc;
568 }
569 if (this->mnc != "") {
570 s += "-";
571 s += mnc;
572 }
573 if (this->locale != "") {
574 s += "-";
575 s += locale;
576 }
577 if (this->screenLayoutSize != "") {
578 s += "-";
579 s += screenLayoutSize;
580 }
581 if (this->screenLayoutLong != "") {
582 s += "-";
583 s += screenLayoutLong;
584 }
585 if (this->orientation != "") {
586 s += "-";
587 s += orientation;
588 }
589 if (this->uiModeType != "") {
590 s += "-";
591 s += uiModeType;
592 }
593 if (this->uiModeNight != "") {
594 s += "-";
595 s += uiModeNight;
596 }
597 if (this->density != "") {
598 s += "-";
599 s += density;
600 }
601 if (this->touchscreen != "") {
602 s += "-";
603 s += touchscreen;
604 }
605 if (this->keysHidden != "") {
606 s += "-";
607 s += keysHidden;
608 }
609 if (this->keyboard != "") {
610 s += "-";
611 s += keyboard;
612 }
613 if (this->navHidden != "") {
614 s += "-";
615 s += navHidden;
616 }
617 if (this->navigation != "") {
618 s += "-";
619 s += navigation;
620 }
621 if (this->screenSize != "") {
622 s += "-";
623 s += screenSize;
624 }
625 if (this->version != "") {
626 s += "-";
627 s += version;
628 }
629
630 return s;
631 }
632
633 bool AaptGroupEntry::getMccName(const char* name,
634 ResTable_config* out)
635 {
636 if (strcmp(name, kWildcardName) == 0) {
637 if (out) out->mcc = 0;
638 return true;
639 }
640 const char* c = name;
641 if (tolower(*c) != 'm') return false;
642 c++;
643 if (tolower(*c) != 'c') return false;
644 c++;
645 if (tolower(*c) != 'c') return false;
646 c++;
647
648 const char* val = c;
649
650 while (*c >= '0' && *c <= '9') {
651 c++;
652 }
653 if (*c != 0) return false;
654 if (c-val != 3) return false;
655
656 int d = atoi(val);
657 if (d != 0) {
658 if (out) out->mcc = d;
659 return true;
660 }
661
662 return false;
663 }
664
665 bool AaptGroupEntry::getMncName(const char* name,
666 ResTable_config* out)
667 {
668 if (strcmp(name, kWildcardName) == 0) {
669 if (out) out->mcc = 0;
670 return true;
671 }
672 const char* c = name;
673 if (tolower(*c) != 'm') return false;
674 c++;
675 if (tolower(*c) != 'n') return false;
676 c++;
677 if (tolower(*c) != 'c') return false;
678 c++;
679
680 const char* val = c;
681
682 while (*c >= '0' && *c <= '9') {
683 c++;
684 }
685 if (*c != 0) return false;
686 if (c-val == 0 || c-val > 3) return false;
687
688 int d = atoi(val);
689 if (d != 0) {
690 if (out) out->mnc = d;
691 return true;
692 }
693
694 return false;
695 }
696
697 /*
698 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
699 * "default")?
700 *
701 * TODO: Should insist that the first two letters are lower case, and the
702 * second two are upper.
703 */
704 bool AaptGroupEntry::getLocaleName(const char* fileName,
705 ResTable_config* out)
706 {
707 if (strcmp(fileName, kWildcardName) == 0
708 || strcmp(fileName, kDefaultLocale) == 0) {
709 if (out) {
710 out->language[0] = 0;
711 out->language[1] = 0;
712 out->country[0] = 0;
713 out->country[1] = 0;
714 }
715 return true;
716 }
717
718 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
719 if (out) {
720 out->language[0] = fileName[0];
721 out->language[1] = fileName[1];
722 out->country[0] = 0;
723 out->country[1] = 0;
724 }
725 return true;
726 }
727
728 if (strlen(fileName) == 5 &&
729 isalpha(fileName[0]) &&
730 isalpha(fileName[1]) &&
731 fileName[2] == '-' &&
732 isalpha(fileName[3]) &&
733 isalpha(fileName[4])) {
734 if (out) {
735 out->language[0] = fileName[0];
736 out->language[1] = fileName[1];
737 out->country[0] = fileName[3];
738 out->country[1] = fileName[4];
739 }
740 return true;
741 }
742
743 return false;
744 }
745
746 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
747 ResTable_config* out)
748 {
749 if (strcmp(name, kWildcardName) == 0) {
750 if (out) out->screenLayout =
751 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
752 | ResTable_config::SCREENSIZE_ANY;
753 return true;
754 } else if (strcmp(name, "small") == 0) {
755 if (out) out->screenLayout =
756 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
757 | ResTable_config::SCREENSIZE_SMALL;
758 return true;
759 } else if (strcmp(name, "normal") == 0) {
760 if (out) out->screenLayout =
761 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
762 | ResTable_config::SCREENSIZE_NORMAL;
763 return true;
764 } else if (strcmp(name, "large") == 0) {
765 if (out) out->screenLayout =
766 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
767 | ResTable_config::SCREENSIZE_LARGE;
768 return true;
769 }
770
771 return false;
772 }
773
774 bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
775 ResTable_config* out)
776 {
777 if (strcmp(name, kWildcardName) == 0) {
778 if (out) out->screenLayout =
779 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
780 | ResTable_config::SCREENLONG_ANY;
781 return true;
782 } else if (strcmp(name, "long") == 0) {
783 if (out) out->screenLayout =
784 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
785 | ResTable_config::SCREENLONG_YES;
786 return true;
787 } else if (strcmp(name, "notlong") == 0) {
788 if (out) out->screenLayout =
789 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
790 | ResTable_config::SCREENLONG_NO;
791 return true;
792 }
793
794 return false;
795 }
796
797 bool AaptGroupEntry::getOrientationName(const char* name,
798 ResTable_config* out)
799 {
800 if (strcmp(name, kWildcardName) == 0) {
801 if (out) out->orientation = out->ORIENTATION_ANY;
802 return true;
803 } else if (strcmp(name, "port") == 0) {
804 if (out) out->orientation = out->ORIENTATION_PORT;
805 return true;
806 } else if (strcmp(name, "land") == 0) {
807 if (out) out->orientation = out->ORIENTATION_LAND;
808 return true;
809 } else if (strcmp(name, "square") == 0) {
810 if (out) out->orientation = out->ORIENTATION_SQUARE;
811 return true;
812 }
813
814 return false;
815 }
816
817 bool AaptGroupEntry::getUiModeTypeName(const char* name,
818 ResTable_config* out)
819 {
820 if (strcmp(name, kWildcardName) == 0) {
821 if (out) out->uiMode =
822 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
823 | ResTable_config::UI_MODE_TYPE_NORMAL;
824 return true;
825 } else if (strcmp(name, "car") == 0) {
826 if (out) out->uiMode =
827 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
828 | ResTable_config::UI_MODE_TYPE_CAR;
829 return true;
830 }
831
832 return false;
833 }
834
835 bool AaptGroupEntry::getUiModeNightName(const char* name,
836 ResTable_config* out)
837 {
838 if (strcmp(name, kWildcardName) == 0) {
839 if (out) out->uiMode =
840 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
841 | ResTable_config::UI_MODE_NIGHT_ANY;
842 return true;
843 } else if (strcmp(name, "night") == 0) {
844 if (out) out->uiMode =
845 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
846 | ResTable_config::UI_MODE_NIGHT_YES;
847 return true;
848 } else if (strcmp(name, "notnight") == 0) {
849 if (out) out->uiMode =
850 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
851 | ResTable_config::UI_MODE_NIGHT_NO;
852 return true;
853 }
854
855 return false;
856 }
857
858 bool AaptGroupEntry::getDensityName(const char* name,
859 ResTable_config* out)
860 {
861 if (strcmp(name, kWildcardName) == 0) {
862 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
863 return true;
864 }
865
866 if (strcmp(name, "nodpi") == 0) {
867 if (out) out->density = ResTable_config::DENSITY_NONE;
868 return true;
869 }
870
871 if (strcmp(name, "ldpi") == 0) {
872 if (out) out->density = ResTable_config::DENSITY_LOW;
873 return true;
874 }
875
876 if (strcmp(name, "mdpi") == 0) {
877 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
878 return true;
879 }
880
881 if (strcmp(name, "hdpi") == 0) {
882 if (out) out->density = ResTable_config::DENSITY_HIGH;
883 return true;
884 }
885
886 char* c = (char*)name;
887 while (*c >= '0' && *c <= '9') {
888 c++;
889 }
890
891 // check that we have 'dpi' after the last digit.
892 if (toupper(c[0]) != 'D' ||
893 toupper(c[1]) != 'P' ||
894 toupper(c[2]) != 'I' ||
895 c[3] != 0) {
896 return false;
897 }
898
899 // temporarily replace the first letter with \0 to
900 // use atoi.
901 char tmp = c[0];
902 c[0] = '\0';
903
904 int d = atoi(name);
905 c[0] = tmp;
906
907 if (d != 0) {
908 if (out) out->density = d;
909 return true;
910 }
911
912 return false;
913 }
914
915 bool AaptGroupEntry::getTouchscreenName(const char* name,
916 ResTable_config* out)
917 {
918 if (strcmp(name, kWildcardName) == 0) {
919 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
920 return true;
921 } else if (strcmp(name, "notouch") == 0) {
922 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
923 return true;
924 } else if (strcmp(name, "stylus") == 0) {
925 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
926 return true;
927 } else if (strcmp(name, "finger") == 0) {
928 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
929 return true;
930 }
931
932 return false;
933 }
934
935 bool AaptGroupEntry::getKeysHiddenName(const char* name,
936 ResTable_config* out)
937 {
938 uint8_t mask = 0;
939 uint8_t value = 0;
940 if (strcmp(name, kWildcardName) == 0) {
941 mask = ResTable_config::MASK_KEYSHIDDEN;
942 value = ResTable_config::KEYSHIDDEN_ANY;
943 } else if (strcmp(name, "keysexposed") == 0) {
944 mask = ResTable_config::MASK_KEYSHIDDEN;
945 value = ResTable_config::KEYSHIDDEN_NO;
946 } else if (strcmp(name, "keyshidden") == 0) {
947 mask = ResTable_config::MASK_KEYSHIDDEN;
948 value = ResTable_config::KEYSHIDDEN_YES;
949 } else if (strcmp(name, "keyssoft") == 0) {
950 mask = ResTable_config::MASK_KEYSHIDDEN;
951 value = ResTable_config::KEYSHIDDEN_SOFT;
952 }
953
954 if (mask != 0) {
955 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
956 return true;
957 }
958
959 return false;
960 }
961
962 bool AaptGroupEntry::getKeyboardName(const char* name,
963 ResTable_config* out)
964 {
965 if (strcmp(name, kWildcardName) == 0) {
966 if (out) out->keyboard = out->KEYBOARD_ANY;
967 return true;
968 } else if (strcmp(name, "nokeys") == 0) {
969 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
970 return true;
971 } else if (strcmp(name, "qwerty") == 0) {
972 if (out) out->keyboard = out->KEYBOARD_QWERTY;
973 return true;
974 } else if (strcmp(name, "12key") == 0) {
975 if (out) out->keyboard = out->KEYBOARD_12KEY;
976 return true;
977 }
978
979 return false;
980 }
981
982 bool AaptGroupEntry::getNavHiddenName(const char* name,
983 ResTable_config* out)
984 {
985 uint8_t mask = 0;
986 uint8_t value = 0;
987 if (strcmp(name, kWildcardName) == 0) {
988 mask = ResTable_config::MASK_NAVHIDDEN;
989 value = ResTable_config::NAVHIDDEN_ANY;
990 } else if (strcmp(name, "navexposed") == 0) {
991 mask = ResTable_config::MASK_NAVHIDDEN;
992 value = ResTable_config::NAVHIDDEN_NO;
993 } else if (strcmp(name, "navhidden") == 0) {
994 mask = ResTable_config::MASK_NAVHIDDEN;
995 value = ResTable_config::NAVHIDDEN_YES;
996 }
997
998 if (mask != 0) {
999 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1000 return true;
1001 }
1002
1003 return false;
1004 }
1005
1006 bool AaptGroupEntry::getNavigationName(const char* name,
1007 ResTable_config* out)
1008 {
1009 if (strcmp(name, kWildcardName) == 0) {
1010 if (out) out->navigation = out->NAVIGATION_ANY;
1011 return true;
1012 } else if (strcmp(name, "nonav") == 0) {
1013 if (out) out->navigation = out->NAVIGATION_NONAV;
1014 return true;
1015 } else if (strcmp(name, "dpad") == 0) {
1016 if (out) out->navigation = out->NAVIGATION_DPAD;
1017 return true;
1018 } else if (strcmp(name, "trackball") == 0) {
1019 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
1020 return true;
1021 } else if (strcmp(name, "wheel") == 0) {
1022 if (out) out->navigation = out->NAVIGATION_WHEEL;
1023 return true;
1024 }
1025
1026 return false;
1027 }
1028
1029 bool AaptGroupEntry::getScreenSizeName(const char* name,
1030 ResTable_config* out)
1031 {
1032 if (strcmp(name, kWildcardName) == 0) {
1033 if (out) {
1034 out->screenWidth = out->SCREENWIDTH_ANY;
1035 out->screenHeight = out->SCREENHEIGHT_ANY;
1036 }
1037 return true;
1038 }
1039
1040 const char* x = name;
1041 while (*x >= '0' && *x <= '9') x++;
1042 if (x == name || *x != 'x') return false;
1043 String8 xName(name, x-name);
1044 x++;
1045
1046 const char* y = x;
1047 while (*y >= '0' && *y <= '9') y++;
1048 if (y == name || *y != 0) return false;
1049 String8 yName(x, y-x);
1050
1051 uint16_t w = (uint16_t)atoi(xName.string());
1052 uint16_t h = (uint16_t)atoi(yName.string());
1053 if (w < h) {
1054 return false;
1055 }
1056
1057 if (out) {
1058 out->screenWidth = w;
1059 out->screenHeight = h;
1060 }
1061
1062 return true;
1063 }
1064
1065 bool AaptGroupEntry::getVersionName(const char* name,
1066 ResTable_config* out)
1067 {
1068 if (strcmp(name, kWildcardName) == 0) {
1069 if (out) {
1070 out->sdkVersion = out->SDKVERSION_ANY;
1071 out->minorVersion = out->MINORVERSION_ANY;
1072 }
1073 return true;
1074 }
1075
1076 if (*name != 'v') {
1077 return false;
1078 }
1079
1080 name++;
1081 const char* s = name;
1082 while (*s >= '0' && *s <= '9') s++;
1083 if (s == name || *s != 0) return false;
1084 String8 sdkName(name, s-name);
1085
1086 if (out) {
1087 out->sdkVersion = (uint16_t)atoi(sdkName.string());
1088 out->minorVersion = 0;
1089 }
1090
1091 return true;
1092 }
1093
1094 int AaptGroupEntry::compare(const AaptGroupEntry& o) const
1095 {
1096 int v = mcc.compare(o.mcc);
1097 if (v == 0) v = mnc.compare(o.mnc);
1098 if (v == 0) v = locale.compare(o.locale);
1099 if (v == 0) v = vendor.compare(o.vendor);
1100 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
1101 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
1102 if (v == 0) v = orientation.compare(o.orientation);
1103 if (v == 0) v = uiModeType.compare(o.uiModeType);
1104 if (v == 0) v = uiModeNight.compare(o.uiModeNight);
1105 if (v == 0) v = density.compare(o.density);
1106 if (v == 0) v = touchscreen.compare(o.touchscreen);
1107 if (v == 0) v = keysHidden.compare(o.keysHidden);
1108 if (v == 0) v = keyboard.compare(o.keyboard);
1109 if (v == 0) v = navHidden.compare(o.navHidden);
1110 if (v == 0) v = navigation.compare(o.navigation);
1111 if (v == 0) v = screenSize.compare(o.screenSize);
1112 if (v == 0) v = version.compare(o.version);
1113 return v;
1114 }
1115
1116 ResTable_config AaptGroupEntry::toParams() const
1117 {
1118 ResTable_config params;
1119 memset(&params, 0, sizeof(params));
1120 getMccName(mcc.string(), &params);
1121 getMncName(mnc.string(), &params);
1122 getLocaleName(locale.string(), &params);
1123 getScreenLayoutSizeName(screenLayoutSize.string(), &params);
1124 getScreenLayoutLongName(screenLayoutLong.string(), &params);
1125 getOrientationName(orientation.string(), &params);
1126 getUiModeTypeName(uiModeType.string(), &params);
1127 getUiModeNightName(uiModeNight.string(), &params);
1128 getDensityName(density.string(), &params);
1129 getTouchscreenName(touchscreen.string(), &params);
1130 getKeysHiddenName(keysHidden.string(), &params);
1131 getKeyboardName(keyboard.string(), &params);
1132 getNavHiddenName(navHidden.string(), &params);
1133 getNavigationName(navigation.string(), &params);
1134 getScreenSizeName(screenSize.string(), &params);
1135 getVersionName(version.string(), &params);
1136
1137 // Fix up version number based on specified parameters.
1138 int minSdk = 0;
1139 if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
1140 != ResTable_config::UI_MODE_TYPE_ANY
1141 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
1142 != ResTable_config::UI_MODE_NIGHT_ANY) {
1143 minSdk = SDK_FROYO;
1144 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
1145 != ResTable_config::SCREENSIZE_ANY
1146 || (params.screenLayout&ResTable_config::MASK_SCREENLONG)
1147 != ResTable_config::SCREENLONG_ANY
1148 || params.density != ResTable_config::DENSITY_DEFAULT) {
1149 minSdk = SDK_DONUT;
1150 }
1151
1152 if (minSdk > params.sdkVersion) {
1153 params.sdkVersion = minSdk;
1154 }
1155
1156 return params;
1157 }
1158
1159 // =========================================================================
1160 // =========================================================================
1161 // =========================================================================
1162
1163 void* AaptFile::editData(size_t size)
1164 {
1165 if (size <= mBufferSize) {
1166 mDataSize = size;
1167 return mData;
1168 }
1169 size_t allocSize = (size*3)/2;
1170 void* buf = realloc(mData, allocSize);
1171 if (buf == NULL) {
1172 return NULL;
1173 }
1174 mData = buf;
1175 mDataSize = size;
1176 mBufferSize = allocSize;
1177 return buf;
1178 }
1179
1180 void* AaptFile::editData(size_t* outSize)
1181 {
1182 if (outSize) {
1183 *outSize = mDataSize;
1184 }
1185 return mData;
1186 }
1187
1188 void* AaptFile::padData(size_t wordSize)
1189 {
1190 const size_t extra = mDataSize%wordSize;
1191 if (extra == 0) {
1192 return mData;
1193 }
1194
1195 size_t initial = mDataSize;
1196 void* data = editData(initial+(wordSize-extra));
1197 if (data != NULL) {
1198 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
1199 }
1200 return data;
1201 }
1202
1203 status_t AaptFile::writeData(const void* data, size_t size)
1204 {
1205 size_t end = mDataSize;
1206 size_t total = size + end;
1207 void* buf = editData(total);
1208 if (buf == NULL) {
1209 return UNKNOWN_ERROR;
1210 }
1211 memcpy(((char*)buf)+end, data, size);
1212 return NO_ERROR;
1213 }
1214
1215 void AaptFile::clearData()
1216 {
1217 if (mData != NULL) free(mData);
1218 mData = NULL;
1219 mDataSize = 0;
1220 mBufferSize = 0;
1221 }
1222
1223 String8 AaptFile::getPrintableSource() const
1224 {
1225 if (hasData()) {
1226 String8 name(mGroupEntry.locale.string());
1227 name.appendPath(mGroupEntry.vendor.string());
1228 name.appendPath(mPath);
1229 name.append(" #generated");
1230 return name;
1231 }
1232 return mSourceFile;
1233 }
1234
1235 // =========================================================================
1236 // =========================================================================
1237 // =========================================================================
1238
1239 status_t AaptGroup::addFile(const sp<AaptFile>& file)
1240 {
1241 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
1242 file->mPath = mPath;
1243 mFiles.add(file->getGroupEntry(), file);
1244 return NO_ERROR;
1245 }
1246
1247 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1248 getPrintableSource().string());
1249 return UNKNOWN_ERROR;
1250 }
1251
1252 void AaptGroup::removeFile(size_t index)
1253 {
1254 mFiles.removeItemsAt(index);
1255 }
1256
1257 void AaptGroup::print() const
1258 {
1259 printf(" %s\n", getPath().string());
1260 const size_t N=mFiles.size();
1261 size_t i;
1262 for (i=0; i<N; i++) {
1263 sp<AaptFile> file = mFiles.valueAt(i);
1264 const AaptGroupEntry& e = file->getGroupEntry();
1265 if (file->hasData()) {
1266 printf(" Gen: (%s) %d bytes\n", e.toString().string(),
1267 (int)file->getSize());
1268 } else {
1269 printf(" Src: %s\n", file->getPrintableSource().string());
1270 }
1271 }
1272 }
1273
1274 String8 AaptGroup::getPrintableSource() const
1275 {
1276 if (mFiles.size() > 0) {
1277 // Arbitrarily pull the first source file out of the list.
1278 return mFiles.valueAt(0)->getPrintableSource();
1279 }
1280
1281 // Should never hit this case, but to be safe...
1282 return getPath();
1283
1284 }
1285
1286 // =========================================================================
1287 // =========================================================================
1288 // =========================================================================
1289
1290 status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1291 {
1292 if (mFiles.indexOfKey(name) >= 0) {
1293 return ALREADY_EXISTS;
1294 }
1295 mFiles.add(name, file);
1296 return NO_ERROR;
1297 }
1298
1299 status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1300 {
1301 if (mDirs.indexOfKey(name) >= 0) {
1302 return ALREADY_EXISTS;
1303 }
1304 mDirs.add(name, dir);
1305 return NO_ERROR;
1306 }
1307
1308 sp<AaptDir> AaptDir::makeDir(const String8& path)
1309 {
1310 String8 name;
1311 String8 remain = path;
1312
1313 sp<AaptDir> subdir = this;
1314 while (name = remain.walkPath(&remain), remain != "") {
1315 subdir = subdir->makeDir(name);
1316 }
1317
1318 ssize_t i = subdir->mDirs.indexOfKey(name);
1319 if (i >= 0) {
1320 return subdir->mDirs.valueAt(i);
1321 }
1322 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1323 subdir->mDirs.add(name, dir);
1324 return dir;
1325 }
1326
1327 void AaptDir::removeFile(const String8& name)
1328 {
1329 mFiles.removeItem(name);
1330 }
1331
1332 void AaptDir::removeDir(const String8& name)
1333 {
1334 mDirs.removeItem(name);
1335 }
1336
1337 status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName)
1338 {
1339 sp<AaptGroup> origGroup;
1340
1341 // Find and remove the given file with shear, brute force!
1342 const size_t NG = mFiles.size();
1343 size_t i;
1344 for (i=0; origGroup == NULL && i<NG; i++) {
1345 sp<AaptGroup> g = mFiles.valueAt(i);
1346 const size_t NF = g->getFiles().size();
1347 for (size_t j=0; j<NF; j++) {
1348 if (g->getFiles().valueAt(j) == file) {
1349 origGroup = g;
1350 g->removeFile(j);
1351 if (NF == 1) {
1352 mFiles.removeItemsAt(i);
1353 }
1354 break;
1355 }
1356 }
1357 }
1358
1359 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1360
1361 // Place the file under its new name.
1362 if (origGroup != NULL) {
1363 return addLeafFile(newName, file);
1364 }
1365
1366 return NO_ERROR;
1367 }
1368
1369 status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1370 {
1371 sp<AaptGroup> group;
1372 if (mFiles.indexOfKey(leafName) >= 0) {
1373 group = mFiles.valueFor(leafName);
1374 } else {
1375 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1376 mFiles.add(leafName, group);
1377 }
1378
1379 return group->addFile(file);
1380 }
1381
1382 ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
1383 const AaptGroupEntry& kind, const String8& resType)
1384 {
1385 Vector<String8> fileNames;
1386
1387 {
1388 DIR* dir = NULL;
1389
1390 dir = opendir(srcDir.string());
1391 if (dir == NULL) {
1392 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1393 return UNKNOWN_ERROR;
1394 }
1395
1396 /*
1397 * Slurp the filenames out of the directory.
1398 */
1399 while (1) {
1400 struct dirent* entry;
1401
1402 entry = readdir(dir);
1403 if (entry == NULL)
1404 break;
1405
1406 if (isHidden(srcDir.string(), entry->d_name))
1407 continue;
1408
1409 fileNames.add(String8(entry->d_name));
1410 }
1411
1412 closedir(dir);
1413 }
1414
1415 ssize_t count = 0;
1416
1417 /*
1418 * Stash away the files and recursively descend into subdirectories.
1419 */
1420 const size_t N = fileNames.size();
1421 size_t i;
1422 for (i = 0; i < N; i++) {
1423 String8 pathName(srcDir);
1424 FileType type;
1425
1426 pathName.appendPath(fileNames[i].string());
1427 type = getFileType(pathName.string());
1428 if (type == kFileTypeDirectory) {
1429 sp<AaptDir> subdir;
1430 bool notAdded = false;
1431 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1432 subdir = mDirs.valueFor(fileNames[i]);
1433 } else {
1434 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1435 notAdded = true;
1436 }
1437 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
1438 resType);
1439 if (res < NO_ERROR) {
1440 return res;
1441 }
1442 if (res > 0 && notAdded) {
1443 mDirs.add(fileNames[i], subdir);
1444 }
1445 count += res;
1446 } else if (type == kFileTypeRegular) {
1447 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1448 status_t err = addLeafFile(fileNames[i], file);
1449 if (err != NO_ERROR) {
1450 return err;
1451 }
1452
1453 count++;
1454
1455 } else {
1456 if (bundle->getVerbose())
1457 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
1458 }
1459 }
1460
1461 return count;
1462 }
1463
1464 status_t AaptDir::validate() const
1465 {
1466 const size_t NF = mFiles.size();
1467 const size_t ND = mDirs.size();
1468 size_t i;
1469 for (i = 0; i < NF; i++) {
1470 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1471 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1472 "Invalid filename. Unable to add.");
1473 return UNKNOWN_ERROR;
1474 }
1475
1476 size_t j;
1477 for (j = i+1; j < NF; j++) {
1478 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1479 mFiles.valueAt(j)->getLeaf().string()) == 0) {
1480 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1481 "File is case-insensitive equivalent to: %s",
1482 mFiles.valueAt(j)->getPrintableSource().string());
1483 return UNKNOWN_ERROR;
1484 }
1485
1486 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1487 // (this is mostly caught by the "marked" stuff, below)
1488 }
1489
1490 for (j = 0; j < ND; j++) {
1491 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1492 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1493 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1494 "File conflicts with dir from: %s",
1495 mDirs.valueAt(j)->getPrintableSource().string());
1496 return UNKNOWN_ERROR;
1497 }
1498 }
1499 }
1500
1501 for (i = 0; i < ND; i++) {
1502 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1503 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1504 "Invalid directory name, unable to add.");
1505 return UNKNOWN_ERROR;
1506 }
1507
1508 size_t j;
1509 for (j = i+1; j < ND; j++) {
1510 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1511 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1512 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1513 "Directory is case-insensitive equivalent to: %s",
1514 mDirs.valueAt(j)->getPrintableSource().string());
1515 return UNKNOWN_ERROR;
1516 }
1517 }
1518
1519 status_t err = mDirs.valueAt(i)->validate();
1520 if (err != NO_ERROR) {
1521 return err;
1522 }
1523 }
1524
1525 return NO_ERROR;
1526 }
1527
1528 void AaptDir::print() const
1529 {
1530 const size_t ND=getDirs().size();
1531 size_t i;
1532 for (i=0; i<ND; i++) {
1533 getDirs().valueAt(i)->print();
1534 }
1535
1536 const size_t NF=getFiles().size();
1537 for (i=0; i<NF; i++) {
1538 getFiles().valueAt(i)->print();
1539 }
1540 }
1541
1542 String8 AaptDir::getPrintableSource() const
1543 {
1544 if (mFiles.size() > 0) {
1545 // Arbitrarily pull the first file out of the list as the source dir.
1546 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1547 }
1548 if (mDirs.size() > 0) {
1549 // Or arbitrarily pull the first dir out of the list as the source dir.
1550 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1551 }
1552
1553 // Should never hit this case, but to be safe...
1554 return mPath;
1555
1556 }
1557
1558 // =========================================================================
1559 // =========================================================================
1560 // =========================================================================
1561
1562 sp<AaptFile> AaptAssets::addFile(
1563 const String8& filePath, const AaptGroupEntry& entry,
1564 const String8& srcDir, sp<AaptGroup>* outGroup,
1565 const String8& resType)
1566 {
1567 sp<AaptDir> dir = this;
1568 sp<AaptGroup> group;
1569 sp<AaptFile> file;
1570 String8 root, remain(filePath), partialPath;
1571 while (remain.length() > 0) {
1572 root = remain.walkPath(&remain);
1573 partialPath.appendPath(root);
1574
1575 const String8 rootStr(root);
1576
1577 if (remain.length() == 0) {
1578 ssize_t i = dir->getFiles().indexOfKey(rootStr);
1579 if (i >= 0) {
1580 group = dir->getFiles().valueAt(i);
1581 } else {
1582 group = new AaptGroup(rootStr, filePath);
1583 status_t res = dir->addFile(rootStr, group);
1584 if (res != NO_ERROR) {
1585 return NULL;
1586 }
1587 }
1588 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
1589 status_t res = group->addFile(file);
1590 if (res != NO_ERROR) {
1591 return NULL;
1592 }
1593 break;
1594
1595 } else {
1596 ssize_t i = dir->getDirs().indexOfKey(rootStr);
1597 if (i >= 0) {
1598 dir = dir->getDirs().valueAt(i);
1599 } else {
1600 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
1601 status_t res = dir->addDir(rootStr, subdir);
1602 if (res != NO_ERROR) {
1603 return NULL;
1604 }
1605 dir = subdir;
1606 }
1607 }
1608 }
1609
1610 mGroupEntries.add(entry);
1611 if (outGroup) *outGroup = group;
1612 return file;
1613 }
1614
1615 void AaptAssets::addResource(const String8& leafName, const String8& path,
1616 const sp<AaptFile>& file, const String8& resType)
1617 {
1618 sp<AaptDir> res = AaptDir::makeDir(kResString);
1619 String8 dirname = file->getGroupEntry().toDirName(resType);
1620 sp<AaptDir> subdir = res->makeDir(dirname);
1621 sp<AaptGroup> grr = new AaptGroup(leafName, path);
1622 grr->addFile(file);
1623
1624 subdir->addFile(leafName, grr);
1625 }
1626
1627
1628 ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
1629 {
1630 int count;
1631 int totalCount = 0;
1632 FileType type;
1633 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
1634 const size_t dirCount =resDirs.size();
1635 sp<AaptAssets> current = this;
1636
1637 const int N = bundle->getFileSpecCount();
1638
1639 /*
1640 * If a package manifest was specified, include that first.
1641 */
1642 if (bundle->getAndroidManifestFile() != NULL) {
1643 // place at root of zip.
1644 String8 srcFile(bundle->getAndroidManifestFile());
1645 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
1646 NULL, String8());
1647 totalCount++;
1648 }
1649
1650 /*
1651 * If a directory of custom assets was supplied, slurp 'em up.
1652 */
1653 if (bundle->getAssetSourceDir()) {
1654 const char* assetDir = bundle->getAssetSourceDir();
1655
1656 FileType type = getFileType(assetDir);
1657 if (type == kFileTypeNonexistent) {
1658 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
1659 return UNKNOWN_ERROR;
1660 }
1661 if (type != kFileTypeDirectory) {
1662 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1663 return UNKNOWN_ERROR;
1664 }
1665
1666 String8 assetRoot(assetDir);
1667 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
1668 AaptGroupEntry group;
1669 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
1670 String8());
1671 if (count < 0) {
1672 totalCount = count;
1673 goto bail;
1674 }
1675 if (count > 0) {
1676 mGroupEntries.add(group);
1677 }
1678 totalCount += count;
1679
1680 if (bundle->getVerbose())
1681 printf("Found %d custom asset file%s in %s\n",
1682 count, (count==1) ? "" : "s", assetDir);
1683 }
1684
1685 /*
1686 * If a directory of resource-specific assets was supplied, slurp 'em up.
1687 */
1688 for (size_t i=0; i<dirCount; i++) {
1689 const char *res = resDirs[i];
1690 if (res) {
1691 type = getFileType(res);
1692 if (type == kFileTypeNonexistent) {
1693 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
1694 return UNKNOWN_ERROR;
1695 }
1696 if (type == kFileTypeDirectory) {
1697 if (i>0) {
1698 sp<AaptAssets> nextOverlay = new AaptAssets();
1699 current->setOverlay(nextOverlay);
1700 current = nextOverlay;
1701 }
1702 count = current->slurpResourceTree(bundle, String8(res));
1703
1704 if (count < 0) {
1705 totalCount = count;
1706 goto bail;
1707 }
1708 totalCount += count;
1709 }
1710 else {
1711 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
1712 return UNKNOWN_ERROR;
1713 }
1714 }
1715
1716 }
1717 /*
1718 * Now do any additional raw files.
1719 */
1720 for (int arg=0; arg<N; arg++) {
1721 const char* assetDir = bundle->getFileSpecEntry(arg);
1722
1723 FileType type = getFileType(assetDir);
1724 if (type == kFileTypeNonexistent) {
1725 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
1726 return UNKNOWN_ERROR;
1727 }
1728 if (type != kFileTypeDirectory) {
1729 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1730 return UNKNOWN_ERROR;
1731 }
1732
1733 String8 assetRoot(assetDir);
1734
1735 if (bundle->getVerbose())
1736 printf("Processing raw dir '%s'\n", (const char*) assetDir);
1737
1738 /*
1739 * Do a recursive traversal of subdir tree. We don't make any
1740 * guarantees about ordering, so we're okay with an inorder search
1741 * using whatever order the OS happens to hand back to us.
1742 */
1743 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8());
1744 if (count < 0) {
1745 /* failure; report error and remove archive */
1746 totalCount = count;
1747 goto bail;
1748 }
1749 totalCount += count;
1750
1751 if (bundle->getVerbose())
1752 printf("Found %d asset file%s in %s\n",
1753 count, (count==1) ? "" : "s", assetDir);
1754 }
1755
1756 count = validate();
1757 if (count != NO_ERROR) {
1758 totalCount = count;
1759 goto bail;
1760 }
1761
1762
1763 bail:
1764 return totalCount;
1765 }
1766
1767 ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
1768 const AaptGroupEntry& kind,
1769 const String8& resType)
1770 {
1771 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType);
1772 if (res > 0) {
1773 mGroupEntries.add(kind);
1774 }
1775
1776 return res;
1777 }
1778
1779 ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
1780 {
1781 ssize_t err = 0;
1782
1783 DIR* dir = opendir(srcDir.string());
1784 if (dir == NULL) {
1785 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1786 return UNKNOWN_ERROR;
1787 }
1788
1789 status_t count = 0;
1790
1791 /*
1792 * Run through the directory, looking for dirs that match the
1793 * expected pattern.
1794 */
1795 while (1) {
1796 struct dirent* entry = readdir(dir);
1797 if (entry == NULL) {
1798 break;
1799 }
1800
1801 if (isHidden(srcDir.string(), entry->d_name)) {
1802 continue;
1803 }
1804
1805 String8 subdirName(srcDir);
1806 subdirName.appendPath(entry->d_name);
1807
1808 AaptGroupEntry group;
1809 String8 resType;
1810 bool b = group.initFromDirName(entry->d_name, &resType);
1811 if (!b) {
1812 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
1813 entry->d_name);
1814 err = -1;
1815 continue;
1816 }
1817
1818 FileType type = getFileType(subdirName.string());
1819
1820 if (type == kFileTypeDirectory) {
1821 sp<AaptDir> dir = makeDir(String8(entry->d_name));
1822 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
1823 resType);
1824 if (res < 0) {
1825 count = res;
1826 goto bail;
1827 }
1828 if (res > 0) {
1829 mGroupEntries.add(group);
1830 count += res;
1831 }
1832
1833 mDirs.add(dir);
1834 } else {
1835 if (bundle->getVerbose()) {
1836 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
1837 }
1838 }
1839 }
1840
1841 bail:
1842 closedir(dir);
1843 dir = NULL;
1844
1845 if (err != 0) {
1846 return err;
1847 }
1848 return count;
1849 }
1850
1851 ssize_t
1852 AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
1853 {
1854 int count = 0;
1855 SortedVector<AaptGroupEntry> entries;
1856
1857 ZipFile* zip = new ZipFile;
1858 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
1859 if (err != NO_ERROR) {
1860 fprintf(stderr, "error opening zip file %s\n", filename);
1861 count = err;
1862 delete zip;
1863 return -1;
1864 }
1865
1866 const int N = zip->getNumEntries();
1867 for (int i=0; i<N; i++) {
1868 ZipEntry* entry = zip->getEntryByIndex(i);
1869 if (entry->getDeleted()) {
1870 continue;
1871 }
1872
1873 String8 entryName(entry->getFileName());
1874
1875 String8 dirName = entryName.getPathDir();
1876 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
1877
1878 String8 resType;
1879 AaptGroupEntry kind;
1880
1881 String8 remain;
1882 if (entryName.walkPath(&remain) == kResourceDir) {
1883 // these are the resources, pull their type out of the directory name
1884 kind.initFromDirName(remain.walkPath().string(), &resType);
1885 } else {
1886 // these are untyped and don't have an AaptGroupEntry
1887 }
1888 if (entries.indexOf(kind) < 0) {
1889 entries.add(kind);
1890 mGroupEntries.add(kind);
1891 }
1892
1893 // use the one from the zip file if they both exist.
1894 dir->removeFile(entryName.getPathLeaf());
1895
1896 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
1897 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
1898 if (err != NO_ERROR) {
1899 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
1900 count = err;
1901 goto bail;
1902 }
1903 file->setCompressionMethod(entry->getCompressionMethod());
1904
1905 #if 0
1906 if (entryName == "AndroidManifest.xml") {
1907 printf("AndroidManifest.xml\n");
1908 }
1909 printf("\n\nfile: %s\n", entryName.string());
1910 #endif
1911
1912 size_t len = entry->getUncompressedLen();
1913 void* data = zip->uncompress(entry);
1914 void* buf = file->editData(len);
1915 memcpy(buf, data, len);
1916
1917 #if 0
1918 const int OFF = 0;
1919 const unsigned char* p = (unsigned char*)data;
1920 const unsigned char* end = p+len;
1921 p += OFF;
1922 for (int i=0; i<32 && p < end; i++) {
1923 printf("0x%03x ", i*0x10 + OFF);
1924 for (int j=0; j<0x10 && p < end; j++) {
1925 printf(" %02x", *p);
1926 p++;
1927 }
1928 printf("\n");
1929 }
1930 #endif
1931
1932 free(data);
1933
1934 count++;
1935 }
1936
1937 bail:
1938 delete zip;
1939 return count;
1940 }
1941
1942 sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
1943 {
1944 sp<AaptSymbols> sym = mSymbols.valueFor(name);
1945 if (sym == NULL) {
1946 sym = new AaptSymbols();
1947 mSymbols.add(name, sym);
1948 }
1949 return sym;
1950 }
1951
1952 status_t AaptAssets::buildIncludedResources(Bundle* bundle)
1953 {
1954 if (!mHaveIncludedAssets) {
1955 // Add in all includes.
1956 const Vector<const char*>& incl = bundle->getPackageIncludes();
1957 const size_t N=incl.size();
1958 for (size_t i=0; i<N; i++) {
1959 if (bundle->getVerbose())
1960 printf("Including resources from package: %s\n", incl[i]);
1961 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
1962 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
1963 incl[i]);
1964 return UNKNOWN_ERROR;
1965 }
1966 }
1967 mHaveIncludedAssets = true;
1968 }
1969
1970 return NO_ERROR;
1971 }
1972
1973 status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
1974 {
1975 const ResTable& res = getIncludedResources();
1976 // XXX dirty!
1977 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
1978 }
1979
1980 const ResTable& AaptAssets::getIncludedResources() const
1981 {
1982 return mIncludedAssets.getResources(false);
1983 }
1984
1985 void AaptAssets::print() const
1986 {
1987 printf("Locale/Vendor pairs:\n");
1988 const size_t N=mGroupEntries.size();
1989 for (size_t i=0; i<N; i++) {
1990 printf(" %s/%s\n",
1991 mGroupEntries.itemAt(i).locale.string(),
1992 mGroupEntries.itemAt(i).vendor.string());
1993 }
1994
1995 printf("\nFiles:\n");
1996 AaptDir::print();
1997 }
1998
1999 sp<AaptDir> AaptAssets::resDir(const String8& name)
2000 {
2001 const Vector<sp<AaptDir> >& dirs = mDirs;
2002 const size_t N = dirs.size();
2003 for (size_t i=0; i<N; i++) {
2004 const sp<AaptDir>& d = dirs.itemAt(i);
2005 if (d->getLeaf() == name) {
2006 return d;
2007 }
2008 }
2009 return NULL;
2010 }
2011
2012 bool
2013 valid_symbol_name(const String8& symbol)
2014 {
2015 static char const * const KEYWORDS[] = {
2016 "abstract", "assert", "boolean", "break",
2017 "byte", "case", "catch", "char", "class", "const", "continue",
2018 "default", "do", "double", "else", "enum", "extends", "final",
2019 "finally", "float", "for", "goto", "if", "implements", "import",
2020 "instanceof", "int", "interface", "long", "native", "new", "package",
2021 "private", "protected", "public", "return", "short", "static",
2022 "strictfp", "super", "switch", "synchronized", "this", "throw",
2023 "throws", "transient", "try", "void", "volatile", "while",
2024 "true", "false", "null",
2025 NULL
2026 };
2027 const char*const* k = KEYWORDS;
2028 const char*const s = symbol.string();
2029 while (*k) {
2030 if (0 == strcmp(s, *k)) {
2031 return false;
2032 }
2033 k++;
2034 }
2035 return true;
2036 }