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