]> git.saurik.com Git - android/aapt.git/blame - AaptAssets.cpp
Merge snapshot variant of donut back into main tree
[android/aapt.git] / AaptAssets.cpp
CommitLineData
a534180c
TAOSP
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
15static const char* kDefaultLocale = "default";
16static const char* kWildcardName = "any";
17static const char* kAssetDir = "assets";
18static const char* kResourceDir = "res";
19static const char* kInvalidChars = "/\\:";
20static const size_t kMaxAssetFileName = 100;
21
22static 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 */
34static 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
56static 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
107status_t
108AaptGroupEntry::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
7ea6703c
DH
190 // screen layout
191 if (getScreenLayoutName(part.string(), &config)) {
192 *axis = AXIS_SCREENLAYOUT;
193 *value = config.screenLayout;
194 return 0;
195 }
196
a534180c
TAOSP
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
207bool
208AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
209{
210 Vector<String8> parts;
211
7ea6703c 212 String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers;
a534180c
TAOSP
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
7ea6703c
DH
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
a534180c
TAOSP
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
415success:
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;
7ea6703c 426 this->screenLayout = layout;
a534180c
TAOSP
427 this->version = vers;
428
429 // what is this anyway?
430 this->vendor = "";
431
432 return true;
433}
434
435String8
436AaptGroupEntry::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 += ",";
7ea6703c
DH
458 s += screenLayout;
459 s += ",";
a534180c
TAOSP
460 s += version;
461 return s;
462}
463
464String8
465AaptGroupEntry::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 }
7ea6703c
DH
508 if (this->screenLayout != "") {
509 s += "-";
510 s += screenLayout;
511 }
a534180c
TAOSP
512 if (this->version != "") {
513 s += "-";
514 s += version;
515 }
516
517 return s;
518}
519
520bool 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
552bool 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 */
591bool 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
633bool 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
653bool AaptGroupEntry::getDensityName(const char* name,
654 ResTable_config* out)
655{
656 if (strcmp(name, kWildcardName) == 0) {
41ff305d 657 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
a534180c
TAOSP
658 return true;
659 }
41ff305d
DH
660
661 if (strcmp(name, "nodpi") == 0) {
662 if (out) out->density = ResTable_config::DENSITY_NONE;
663 return true;
664 }
665
a534180c
TAOSP
666 char* c = (char*)name;
667 while (*c >= '0' && *c <= '9') {
668 c++;
669 }
670
671 // check that we have 'dpi' after the last digit.
672 if (toupper(c[0]) != 'D' ||
673 toupper(c[1]) != 'P' ||
674 toupper(c[2]) != 'I' ||
675 c[3] != 0) {
676 return false;
677 }
678
679 // temporarily replace the first letter with \0 to
680 // use atoi.
681 char tmp = c[0];
682 c[0] = '\0';
683
684 int d = atoi(name);
685 c[0] = tmp;
686
687 if (d != 0) {
688 if (out) out->density = d;
689 return true;
690 }
691
692 return false;
693}
694
695bool AaptGroupEntry::getTouchscreenName(const char* name,
696 ResTable_config* out)
697{
698 if (strcmp(name, kWildcardName) == 0) {
699 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
700 return true;
701 } else if (strcmp(name, "notouch") == 0) {
702 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
703 return true;
704 } else if (strcmp(name, "stylus") == 0) {
705 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
706 return true;
707 } else if (strcmp(name, "finger") == 0) {
708 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
709 return true;
710 }
711
712 return false;
713}
714
715bool AaptGroupEntry::getKeysHiddenName(const char* name,
716 ResTable_config* out)
717{
718 uint8_t mask = 0;
719 uint8_t value = 0;
720 if (strcmp(name, kWildcardName) == 0) {
721 mask = out->MASK_KEYSHIDDEN;
722 value = out->KEYSHIDDEN_ANY;
723 } else if (strcmp(name, "keysexposed") == 0) {
724 mask = out->MASK_KEYSHIDDEN;
725 value = out->KEYSHIDDEN_NO;
726 } else if (strcmp(name, "keyshidden") == 0) {
727 mask = out->MASK_KEYSHIDDEN;
728 value = out->KEYSHIDDEN_YES;
729 } else if (strcmp(name, "keyssoft") == 0) {
730 mask = out->MASK_KEYSHIDDEN;
731 value = out->KEYSHIDDEN_SOFT;
732 }
733
734 if (mask != 0) {
735 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
736 return true;
737 }
738
739 return false;
740}
741
742bool AaptGroupEntry::getKeyboardName(const char* name,
743 ResTable_config* out)
744{
745 if (strcmp(name, kWildcardName) == 0) {
746 if (out) out->keyboard = out->KEYBOARD_ANY;
747 return true;
748 } else if (strcmp(name, "nokeys") == 0) {
749 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
750 return true;
751 } else if (strcmp(name, "qwerty") == 0) {
752 if (out) out->keyboard = out->KEYBOARD_QWERTY;
753 return true;
754 } else if (strcmp(name, "12key") == 0) {
755 if (out) out->keyboard = out->KEYBOARD_12KEY;
756 return true;
757 }
758
759 return false;
760}
761
762bool AaptGroupEntry::getNavigationName(const char* name,
763 ResTable_config* out)
764{
765 if (strcmp(name, kWildcardName) == 0) {
766 if (out) out->navigation = out->NAVIGATION_ANY;
767 return true;
768 } else if (strcmp(name, "nonav") == 0) {
769 if (out) out->navigation = out->NAVIGATION_NONAV;
770 return true;
771 } else if (strcmp(name, "dpad") == 0) {
772 if (out) out->navigation = out->NAVIGATION_DPAD;
773 return true;
774 } else if (strcmp(name, "trackball") == 0) {
775 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
776 return true;
777 } else if (strcmp(name, "wheel") == 0) {
778 if (out) out->navigation = out->NAVIGATION_WHEEL;
779 return true;
780 }
781
782 return false;
783}
784
785bool AaptGroupEntry::getScreenSizeName(const char* name,
786 ResTable_config* out)
787{
788 if (strcmp(name, kWildcardName) == 0) {
789 if (out) {
790 out->screenWidth = out->SCREENWIDTH_ANY;
791 out->screenHeight = out->SCREENHEIGHT_ANY;
792 }
793 return true;
794 }
795
796 const char* x = name;
797 while (*x >= '0' && *x <= '9') x++;
798 if (x == name || *x != 'x') return false;
799 String8 xName(name, x-name);
800 x++;
801
802 const char* y = x;
803 while (*y >= '0' && *y <= '9') y++;
804 if (y == name || *y != 0) return false;
805 String8 yName(x, y-x);
806
807 uint16_t w = (uint16_t)atoi(xName.string());
808 uint16_t h = (uint16_t)atoi(yName.string());
809 if (w < h) {
810 return false;
811 }
812
813 if (out) {
814 out->screenWidth = w;
815 out->screenHeight = h;
816 }
817
818 return true;
819}
820
7ea6703c
DH
821bool AaptGroupEntry::getScreenLayoutName(const char* name,
822 ResTable_config* out)
823{
824 if (strcmp(name, kWildcardName) == 0) {
825 if (out) out->screenLayout = out->SCREENLAYOUT_ANY;
826 return true;
827 } else if (strcmp(name, "smallscreen") == 0) {
828 if (out) out->screenLayout = out->SCREENLAYOUT_SMALL;
829 return true;
830 } else if (strcmp(name, "normalscreen") == 0) {
831 if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL;
832 return true;
833 } else if (strcmp(name, "largescreen") == 0) {
834 if (out) out->screenLayout = out->SCREENLAYOUT_LARGE;
835 return true;
836 }
837
838 return false;
839}
840
a534180c
TAOSP
841bool AaptGroupEntry::getVersionName(const char* name,
842 ResTable_config* out)
843{
844 if (strcmp(name, kWildcardName) == 0) {
845 if (out) {
846 out->sdkVersion = out->SDKVERSION_ANY;
847 out->minorVersion = out->MINORVERSION_ANY;
848 }
849 return true;
850 }
851
852 if (*name != 'v') {
853 return false;
854 }
855
856 name++;
857 const char* s = name;
858 while (*s >= '0' && *s <= '9') s++;
859 if (s == name || *s != 0) return false;
860 String8 sdkName(name, s-name);
861
862 if (out) {
863 out->sdkVersion = (uint16_t)atoi(sdkName.string());
864 out->minorVersion = 0;
865 }
866
867 return true;
868}
869
870int AaptGroupEntry::compare(const AaptGroupEntry& o) const
871{
872 int v = mcc.compare(o.mcc);
873 if (v == 0) v = mnc.compare(o.mnc);
874 if (v == 0) v = locale.compare(o.locale);
875 if (v == 0) v = vendor.compare(o.vendor);
876 if (v == 0) v = orientation.compare(o.orientation);
877 if (v == 0) v = density.compare(o.density);
878 if (v == 0) v = touchscreen.compare(o.touchscreen);
879 if (v == 0) v = keysHidden.compare(o.keysHidden);
880 if (v == 0) v = keyboard.compare(o.keyboard);
881 if (v == 0) v = navigation.compare(o.navigation);
882 if (v == 0) v = screenSize.compare(o.screenSize);
7ea6703c 883 if (v == 0) v = screenLayout.compare(o.screenLayout);
a534180c
TAOSP
884 if (v == 0) v = version.compare(o.version);
885 return v;
886}
887
888ResTable_config AaptGroupEntry::toParams() const
889{
890 ResTable_config params;
891 memset(&params, 0, sizeof(params));
892 getMccName(mcc.string(), &params);
893 getMncName(mnc.string(), &params);
894 getLocaleName(locale.string(), &params);
895 getOrientationName(orientation.string(), &params);
896 getDensityName(density.string(), &params);
897 getTouchscreenName(touchscreen.string(), &params);
898 getKeysHiddenName(keysHidden.string(), &params);
899 getKeyboardName(keyboard.string(), &params);
900 getNavigationName(navigation.string(), &params);
901 getScreenSizeName(screenSize.string(), &params);
7ea6703c 902 getScreenLayoutName(screenLayout.string(), &params);
a534180c
TAOSP
903 getVersionName(version.string(), &params);
904 return params;
905}
906
907// =========================================================================
908// =========================================================================
909// =========================================================================
910
911void* AaptFile::editData(size_t size)
912{
913 if (size <= mBufferSize) {
914 mDataSize = size;
915 return mData;
916 }
917 size_t allocSize = (size*3)/2;
918 void* buf = realloc(mData, allocSize);
919 if (buf == NULL) {
920 return NULL;
921 }
922 mData = buf;
923 mDataSize = size;
924 mBufferSize = allocSize;
925 return buf;
926}
927
928void* AaptFile::editData(size_t* outSize)
929{
930 if (outSize) {
931 *outSize = mDataSize;
932 }
933 return mData;
934}
935
936void* AaptFile::padData(size_t wordSize)
937{
938 const size_t extra = mDataSize%wordSize;
939 if (extra == 0) {
940 return mData;
941 }
942
943 size_t initial = mDataSize;
944 void* data = editData(initial+(wordSize-extra));
945 if (data != NULL) {
946 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
947 }
948 return data;
949}
950
951status_t AaptFile::writeData(const void* data, size_t size)
952{
953 size_t end = mDataSize;
954 size_t total = size + end;
955 void* buf = editData(total);
956 if (buf == NULL) {
957 return UNKNOWN_ERROR;
958 }
959 memcpy(((char*)buf)+end, data, size);
960 return NO_ERROR;
961}
962
963void AaptFile::clearData()
964{
965 if (mData != NULL) free(mData);
966 mData = NULL;
967 mDataSize = 0;
968 mBufferSize = 0;
969}
970
971String8 AaptFile::getPrintableSource() const
972{
973 if (hasData()) {
974 String8 name(mGroupEntry.locale.string());
975 name.appendPath(mGroupEntry.vendor.string());
976 name.appendPath(mPath);
977 name.append(" #generated");
978 return name;
979 }
980 return mSourceFile;
981}
982
983// =========================================================================
984// =========================================================================
985// =========================================================================
986
987status_t AaptGroup::addFile(const sp<AaptFile>& file)
988{
989 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
990 file->mPath = mPath;
991 mFiles.add(file->getGroupEntry(), file);
992 return NO_ERROR;
993 }
994
995 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
996 getPrintableSource().string());
997 return UNKNOWN_ERROR;
998}
999
1000void AaptGroup::removeFile(size_t index)
1001{
1002 mFiles.removeItemsAt(index);
1003}
1004
1005void AaptGroup::print() const
1006{
1007 printf(" %s\n", getPath().string());
1008 const size_t N=mFiles.size();
1009 size_t i;
1010 for (i=0; i<N; i++) {
1011 sp<AaptFile> file = mFiles.valueAt(i);
1012 const AaptGroupEntry& e = file->getGroupEntry();
1013 if (file->hasData()) {
1014 printf(" Gen: (%s) %d bytes\n", e.toString().string(),
1015 (int)file->getSize());
1016 } else {
1017 printf(" Src: %s\n", file->getPrintableSource().string());
1018 }
1019 }
1020}
1021
1022String8 AaptGroup::getPrintableSource() const
1023{
1024 if (mFiles.size() > 0) {
1025 // Arbitrarily pull the first source file out of the list.
1026 return mFiles.valueAt(0)->getPrintableSource();
1027 }
1028
1029 // Should never hit this case, but to be safe...
1030 return getPath();
1031
1032}
1033
1034// =========================================================================
1035// =========================================================================
1036// =========================================================================
1037
1038status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1039{
1040 if (mFiles.indexOfKey(name) >= 0) {
1041 return ALREADY_EXISTS;
1042 }
1043 mFiles.add(name, file);
1044 return NO_ERROR;
1045}
1046
1047status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1048{
1049 if (mDirs.indexOfKey(name) >= 0) {
1050 return ALREADY_EXISTS;
1051 }
1052 mDirs.add(name, dir);
1053 return NO_ERROR;
1054}
1055
1056sp<AaptDir> AaptDir::makeDir(const String8& path)
1057{
1058 String8 name;
1059 String8 remain = path;
1060
1061 sp<AaptDir> subdir = this;
1062 while (name = remain.walkPath(&remain), remain != "") {
1063 subdir = subdir->makeDir(name);
1064 }
1065
1066 ssize_t i = subdir->mDirs.indexOfKey(name);
1067 if (i >= 0) {
1068 return subdir->mDirs.valueAt(i);
1069 }
1070 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1071 subdir->mDirs.add(name, dir);
1072 return dir;
1073}
1074
1075void AaptDir::removeFile(const String8& name)
1076{
1077 mFiles.removeItem(name);
1078}
1079
1080void AaptDir::removeDir(const String8& name)
1081{
1082 mDirs.removeItem(name);
1083}
1084
1085status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName)
1086{
1087 sp<AaptGroup> origGroup;
1088
1089 // Find and remove the given file with shear, brute force!
1090 const size_t NG = mFiles.size();
1091 size_t i;
1092 for (i=0; origGroup == NULL && i<NG; i++) {
1093 sp<AaptGroup> g = mFiles.valueAt(i);
1094 const size_t NF = g->getFiles().size();
1095 for (size_t j=0; j<NF; j++) {
1096 if (g->getFiles().valueAt(j) == file) {
1097 origGroup = g;
1098 g->removeFile(j);
1099 if (NF == 1) {
1100 mFiles.removeItemsAt(i);
1101 }
1102 break;
1103 }
1104 }
1105 }
1106
1107 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1108
1109 // Place the file under its new name.
1110 if (origGroup != NULL) {
1111 return addLeafFile(newName, file);
1112 }
1113
1114 return NO_ERROR;
1115}
1116
1117status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1118{
1119 sp<AaptGroup> group;
1120 if (mFiles.indexOfKey(leafName) >= 0) {
1121 group = mFiles.valueFor(leafName);
1122 } else {
1123 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1124 mFiles.add(leafName, group);
1125 }
1126
1127 return group->addFile(file);
1128}
1129
1130ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
1131 const AaptGroupEntry& kind, const String8& resType)
1132{
1133 Vector<String8> fileNames;
1134
1135 {
1136 DIR* dir = NULL;
1137
1138 dir = opendir(srcDir.string());
1139 if (dir == NULL) {
1140 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1141 return UNKNOWN_ERROR;
1142 }
1143
1144 /*
1145 * Slurp the filenames out of the directory.
1146 */
1147 while (1) {
1148 struct dirent* entry;
1149
1150 entry = readdir(dir);
1151 if (entry == NULL)
1152 break;
1153
1154 if (isHidden(srcDir.string(), entry->d_name))
1155 continue;
1156
1157 fileNames.add(String8(entry->d_name));
1158 }
1159
1160 closedir(dir);
1161 }
1162
1163 ssize_t count = 0;
1164
1165 /*
1166 * Stash away the files and recursively descend into subdirectories.
1167 */
1168 const size_t N = fileNames.size();
1169 size_t i;
1170 for (i = 0; i < N; i++) {
1171 String8 pathName(srcDir);
1172 FileType type;
1173
1174 pathName.appendPath(fileNames[i].string());
1175 type = getFileType(pathName.string());
1176 if (type == kFileTypeDirectory) {
1177 sp<AaptDir> subdir;
1178 bool notAdded = false;
1179 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1180 subdir = mDirs.valueFor(fileNames[i]);
1181 } else {
1182 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1183 notAdded = true;
1184 }
1185 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
1186 resType);
1187 if (res < NO_ERROR) {
1188 return res;
1189 }
1190 if (res > 0 && notAdded) {
1191 mDirs.add(fileNames[i], subdir);
1192 }
1193 count += res;
1194 } else if (type == kFileTypeRegular) {
1195 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1196 status_t err = addLeafFile(fileNames[i], file);
1197 if (err != NO_ERROR) {
1198 return err;
1199 }
1200
1201 count++;
1202
1203 } else {
1204 if (bundle->getVerbose())
1205 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
1206 }
1207 }
1208
1209 return count;
1210}
1211
1212status_t AaptDir::validate() const
1213{
1214 const size_t NF = mFiles.size();
1215 const size_t ND = mDirs.size();
1216 size_t i;
1217 for (i = 0; i < NF; i++) {
1218 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1219 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1220 "Invalid filename. Unable to add.");
1221 return UNKNOWN_ERROR;
1222 }
1223
1224 size_t j;
1225 for (j = i+1; j < NF; j++) {
1226 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1227 mFiles.valueAt(j)->getLeaf().string()) == 0) {
1228 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1229 "File is case-insensitive equivalent to: %s",
1230 mFiles.valueAt(j)->getPrintableSource().string());
1231 return UNKNOWN_ERROR;
1232 }
1233
1234 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1235 // (this is mostly caught by the "marked" stuff, below)
1236 }
1237
1238 for (j = 0; j < ND; j++) {
1239 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1240 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1241 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1242 "File conflicts with dir from: %s",
1243 mDirs.valueAt(j)->getPrintableSource().string());
1244 return UNKNOWN_ERROR;
1245 }
1246 }
1247 }
1248
1249 for (i = 0; i < ND; i++) {
1250 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1251 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1252 "Invalid directory name, unable to add.");
1253 return UNKNOWN_ERROR;
1254 }
1255
1256 size_t j;
1257 for (j = i+1; j < ND; j++) {
1258 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1259 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1260 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1261 "Directory is case-insensitive equivalent to: %s",
1262 mDirs.valueAt(j)->getPrintableSource().string());
1263 return UNKNOWN_ERROR;
1264 }
1265 }
1266
1267 status_t err = mDirs.valueAt(i)->validate();
1268 if (err != NO_ERROR) {
1269 return err;
1270 }
1271 }
1272
1273 return NO_ERROR;
1274}
1275
1276void AaptDir::print() const
1277{
1278 const size_t ND=getDirs().size();
1279 size_t i;
1280 for (i=0; i<ND; i++) {
1281 getDirs().valueAt(i)->print();
1282 }
1283
1284 const size_t NF=getFiles().size();
1285 for (i=0; i<NF; i++) {
1286 getFiles().valueAt(i)->print();
1287 }
1288}
1289
1290String8 AaptDir::getPrintableSource() const
1291{
1292 if (mFiles.size() > 0) {
1293 // Arbitrarily pull the first file out of the list as the source dir.
1294 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1295 }
1296 if (mDirs.size() > 0) {
1297 // Or arbitrarily pull the first dir out of the list as the source dir.
1298 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1299 }
1300
1301 // Should never hit this case, but to be safe...
1302 return mPath;
1303
1304}
1305
1306// =========================================================================
1307// =========================================================================
1308// =========================================================================
1309
1310sp<AaptFile> AaptAssets::addFile(
1311 const String8& filePath, const AaptGroupEntry& entry,
1312 const String8& srcDir, sp<AaptGroup>* outGroup,
1313 const String8& resType)
1314{
1315 sp<AaptDir> dir = this;
1316 sp<AaptGroup> group;
1317 sp<AaptFile> file;
1318 String8 root, remain(filePath), partialPath;
1319 while (remain.length() > 0) {
1320 root = remain.walkPath(&remain);
1321 partialPath.appendPath(root);
1322
1323 const String8 rootStr(root);
1324
1325 if (remain.length() == 0) {
1326 ssize_t i = dir->getFiles().indexOfKey(rootStr);
1327 if (i >= 0) {
1328 group = dir->getFiles().valueAt(i);
1329 } else {
1330 group = new AaptGroup(rootStr, filePath);
1331 status_t res = dir->addFile(rootStr, group);
1332 if (res != NO_ERROR) {
1333 return NULL;
1334 }
1335 }
1336 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
1337 status_t res = group->addFile(file);
1338 if (res != NO_ERROR) {
1339 return NULL;
1340 }
1341 break;
1342
1343 } else {
1344 ssize_t i = dir->getDirs().indexOfKey(rootStr);
1345 if (i >= 0) {
1346 dir = dir->getDirs().valueAt(i);
1347 } else {
1348 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
1349 status_t res = dir->addDir(rootStr, subdir);
1350 if (res != NO_ERROR) {
1351 return NULL;
1352 }
1353 dir = subdir;
1354 }
1355 }
1356 }
1357
1358 mGroupEntries.add(entry);
1359 if (outGroup) *outGroup = group;
1360 return file;
1361}
1362
1363void AaptAssets::addResource(const String8& leafName, const String8& path,
1364 const sp<AaptFile>& file, const String8& resType)
1365{
1366 sp<AaptDir> res = AaptDir::makeDir(kResString);
1367 String8 dirname = file->getGroupEntry().toDirName(resType);
1368 sp<AaptDir> subdir = res->makeDir(dirname);
1369 sp<AaptGroup> grr = new AaptGroup(leafName, path);
1370 grr->addFile(file);
1371
1372 subdir->addFile(leafName, grr);
1373}
1374
1375
1376ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
1377{
1378 int count;
1379 int totalCount = 0;
1380 FileType type;
1381 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
1382 const size_t dirCount =resDirs.size();
1383 sp<AaptAssets> current = this;
1384
1385 const int N = bundle->getFileSpecCount();
1386
1387 /*
1388 * If a package manifest was specified, include that first.
1389 */
1390 if (bundle->getAndroidManifestFile() != NULL) {
1391 // place at root of zip.
1392 String8 srcFile(bundle->getAndroidManifestFile());
1393 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
1394 NULL, String8());
1395 totalCount++;
1396 }
1397
1398 /*
1399 * If a directory of custom assets was supplied, slurp 'em up.
1400 */
1401 if (bundle->getAssetSourceDir()) {
1402 const char* assetDir = bundle->getAssetSourceDir();
1403
1404 FileType type = getFileType(assetDir);
1405 if (type == kFileTypeNonexistent) {
1406 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
1407 return UNKNOWN_ERROR;
1408 }
1409 if (type != kFileTypeDirectory) {
1410 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1411 return UNKNOWN_ERROR;
1412 }
1413
1414 String8 assetRoot(assetDir);
1415 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
1416 AaptGroupEntry group;
1417 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
1418 String8());
1419 if (count < 0) {
1420 totalCount = count;
1421 goto bail;
1422 }
1423 if (count > 0) {
1424 mGroupEntries.add(group);
1425 }
1426 totalCount += count;
1427
1428 if (bundle->getVerbose())
1429 printf("Found %d custom asset file%s in %s\n",
1430 count, (count==1) ? "" : "s", assetDir);
1431 }
1432
1433 /*
1434 * If a directory of resource-specific assets was supplied, slurp 'em up.
1435 */
1436 for (size_t i=0; i<dirCount; i++) {
1437 const char *res = resDirs[i];
1438 if (res) {
1439 type = getFileType(res);
1440 if (type == kFileTypeNonexistent) {
1441 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
1442 return UNKNOWN_ERROR;
1443 }
1444 if (type == kFileTypeDirectory) {
1445 if (i>0) {
1446 sp<AaptAssets> nextOverlay = new AaptAssets();
1447 current->setOverlay(nextOverlay);
1448 current = nextOverlay;
1449 }
1450 count = current->slurpResourceTree(bundle, String8(res));
1451
1452 if (count < 0) {
1453 totalCount = count;
1454 goto bail;
1455 }
1456 totalCount += count;
1457 }
1458 else {
1459 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
1460 return UNKNOWN_ERROR;
1461 }
1462 }
1463
1464 }
1465 /*
1466 * Now do any additional raw files.
1467 */
1468 for (int arg=0; arg<N; arg++) {
1469 const char* assetDir = bundle->getFileSpecEntry(arg);
1470
1471 FileType type = getFileType(assetDir);
1472 if (type == kFileTypeNonexistent) {
1473 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
1474 return UNKNOWN_ERROR;
1475 }
1476 if (type != kFileTypeDirectory) {
1477 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1478 return UNKNOWN_ERROR;
1479 }
1480
1481 String8 assetRoot(assetDir);
1482
1483 if (bundle->getVerbose())
1484 printf("Processing raw dir '%s'\n", (const char*) assetDir);
1485
1486 /*
1487 * Do a recursive traversal of subdir tree. We don't make any
1488 * guarantees about ordering, so we're okay with an inorder search
1489 * using whatever order the OS happens to hand back to us.
1490 */
1491 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8());
1492 if (count < 0) {
1493 /* failure; report error and remove archive */
1494 totalCount = count;
1495 goto bail;
1496 }
1497 totalCount += count;
1498
1499 if (bundle->getVerbose())
1500 printf("Found %d asset file%s in %s\n",
1501 count, (count==1) ? "" : "s", assetDir);
1502 }
1503
1504 count = validate();
1505 if (count != NO_ERROR) {
1506 totalCount = count;
1507 goto bail;
1508 }
1509
1510
1511bail:
1512 return totalCount;
1513}
1514
1515ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
1516 const AaptGroupEntry& kind,
1517 const String8& resType)
1518{
1519 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType);
1520 if (res > 0) {
1521 mGroupEntries.add(kind);
1522 }
1523
1524 return res;
1525}
1526
1527ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
1528{
1529 ssize_t err = 0;
1530
1531 DIR* dir = opendir(srcDir.string());
1532 if (dir == NULL) {
1533 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1534 return UNKNOWN_ERROR;
1535 }
1536
1537 status_t count = 0;
1538
1539 /*
1540 * Run through the directory, looking for dirs that match the
1541 * expected pattern.
1542 */
1543 while (1) {
1544 struct dirent* entry = readdir(dir);
1545 if (entry == NULL) {
1546 break;
1547 }
1548
1549 if (isHidden(srcDir.string(), entry->d_name)) {
1550 continue;
1551 }
1552
1553 String8 subdirName(srcDir);
1554 subdirName.appendPath(entry->d_name);
1555
1556 AaptGroupEntry group;
1557 String8 resType;
1558 bool b = group.initFromDirName(entry->d_name, &resType);
1559 if (!b) {
1560 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
1561 entry->d_name);
1562 err = -1;
1563 continue;
1564 }
1565
1566 FileType type = getFileType(subdirName.string());
1567
1568 if (type == kFileTypeDirectory) {
1569 sp<AaptDir> dir = makeDir(String8(entry->d_name));
1570 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
1571 resType);
1572 if (res < 0) {
1573 count = res;
1574 goto bail;
1575 }
1576 if (res > 0) {
1577 mGroupEntries.add(group);
1578 count += res;
1579 }
1580
1581 mDirs.add(dir);
1582 } else {
1583 if (bundle->getVerbose()) {
1584 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
1585 }
1586 }
1587 }
1588
1589bail:
1590 closedir(dir);
1591 dir = NULL;
1592
1593 if (err != 0) {
1594 return err;
1595 }
1596 return count;
1597}
1598
1599ssize_t
1600AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
1601{
1602 int count = 0;
1603 SortedVector<AaptGroupEntry> entries;
1604
1605 ZipFile* zip = new ZipFile;
1606 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
1607 if (err != NO_ERROR) {
1608 fprintf(stderr, "error opening zip file %s\n", filename);
1609 count = err;
1610 delete zip;
1611 return -1;
1612 }
1613
1614 const int N = zip->getNumEntries();
1615 for (int i=0; i<N; i++) {
1616 ZipEntry* entry = zip->getEntryByIndex(i);
1617 if (entry->getDeleted()) {
1618 continue;
1619 }
1620
1621 String8 entryName(entry->getFileName());
1622
1623 String8 dirName = entryName.getPathDir();
1624 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
1625
1626 String8 resType;
1627 AaptGroupEntry kind;
1628
1629 String8 remain;
1630 if (entryName.walkPath(&remain) == kResourceDir) {
1631 // these are the resources, pull their type out of the directory name
1632 kind.initFromDirName(remain.walkPath().string(), &resType);
1633 } else {
1634 // these are untyped and don't have an AaptGroupEntry
1635 }
1636 if (entries.indexOf(kind) < 0) {
1637 entries.add(kind);
1638 mGroupEntries.add(kind);
1639 }
1640
1641 // use the one from the zip file if they both exist.
1642 dir->removeFile(entryName.getPathLeaf());
1643
1644 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
1645 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
1646 if (err != NO_ERROR) {
1647 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
1648 count = err;
1649 goto bail;
1650 }
1651 file->setCompressionMethod(entry->getCompressionMethod());
1652
1653#if 0
1654 if (entryName == "AndroidManifest.xml") {
1655 printf("AndroidManifest.xml\n");
1656 }
1657 printf("\n\nfile: %s\n", entryName.string());
1658#endif
1659
1660 size_t len = entry->getUncompressedLen();
1661 void* data = zip->uncompress(entry);
1662 void* buf = file->editData(len);
1663 memcpy(buf, data, len);
1664
1665#if 0
1666 const int OFF = 0;
1667 const unsigned char* p = (unsigned char*)data;
1668 const unsigned char* end = p+len;
1669 p += OFF;
1670 for (int i=0; i<32 && p < end; i++) {
1671 printf("0x%03x ", i*0x10 + OFF);
1672 for (int j=0; j<0x10 && p < end; j++) {
1673 printf(" %02x", *p);
1674 p++;
1675 }
1676 printf("\n");
1677 }
1678#endif
1679
1680 free(data);
1681
1682 count++;
1683 }
1684
1685bail:
1686 delete zip;
1687 return count;
1688}
1689
1690sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
1691{
1692 sp<AaptSymbols> sym = mSymbols.valueFor(name);
1693 if (sym == NULL) {
1694 sym = new AaptSymbols();
1695 mSymbols.add(name, sym);
1696 }
1697 return sym;
1698}
1699
1700status_t AaptAssets::buildIncludedResources(Bundle* bundle)
1701{
1702 if (!mHaveIncludedAssets) {
1703 // Add in all includes.
1704 const Vector<const char*>& incl = bundle->getPackageIncludes();
1705 const size_t N=incl.size();
1706 for (size_t i=0; i<N; i++) {
1707 if (bundle->getVerbose())
1708 printf("Including resources from package: %s\n", incl[i]);
1709 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
1710 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
1711 incl[i]);
1712 return UNKNOWN_ERROR;
1713 }
1714 }
1715 mHaveIncludedAssets = true;
1716 }
1717
1718 return NO_ERROR;
1719}
1720
1721status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
1722{
1723 const ResTable& res = getIncludedResources();
1724 // XXX dirty!
1725 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
1726}
1727
1728const ResTable& AaptAssets::getIncludedResources() const
1729{
1730 return mIncludedAssets.getResources(false);
1731}
1732
1733void AaptAssets::print() const
1734{
1735 printf("Locale/Vendor pairs:\n");
1736 const size_t N=mGroupEntries.size();
1737 for (size_t i=0; i<N; i++) {
1738 printf(" %s/%s\n",
1739 mGroupEntries.itemAt(i).locale.string(),
1740 mGroupEntries.itemAt(i).vendor.string());
1741 }
1742
1743 printf("\nFiles:\n");
1744 AaptDir::print();
1745}
1746
1747bool
1748valid_symbol_name(const String8& symbol)
1749{
1750 static char const * const KEYWORDS[] = {
1751 "abstract", "assert", "boolean", "break",
1752 "byte", "case", "catch", "char", "class", "const", "continue",
1753 "default", "do", "double", "else", "enum", "extends", "final",
1754 "finally", "float", "for", "goto", "if", "implements", "import",
1755 "instanceof", "int", "interface", "long", "native", "new", "package",
1756 "private", "protected", "public", "return", "short", "static",
1757 "strictfp", "super", "switch", "synchronized", "this", "throw",
1758 "throws", "transient", "try", "void", "volatile", "while",
1759 "true", "false", "null",
1760 NULL
1761 };
1762 const char*const* k = KEYWORDS;
1763 const char*const s = symbol.string();
1764 while (*k) {
1765 if (0 == strcmp(s, *k)) {
1766 return false;
1767 }
1768 k++;
1769 }
1770 return true;
1771}