]> git.saurik.com Git - android/aapt.git/blame - AaptAssets.cpp
Create own reference for minSdkVersion in aapt
[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{
ce704366 58 const char *ext = NULL;
a534180c
TAOSP
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";
ce704366
R
87 } else if ((ext = strrchr(path, '.')) != NULL && strcmp(ext, ".scc") == 0) {
88 // Skip VisualSourceSafe files and don't chatter about it
89 return true;
a534180c
TAOSP
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
111status_t
112AaptGroupEntry::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
784c6915
DH
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
a534180c
TAOSP
159 // orientation
160 if (getOrientationName(part.string(), &config)) {
161 *axis = AXIS_ORIENTATION;
162 *value = config.orientation;
163 return 0;
164 }
165
2ca01a37
TH
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
a534180c
TAOSP
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
0096feb5
DH
208 // navigation hidden
209 if (getNavHiddenName(part.string(), &config)) {
210 *axis = AXIS_NAVHIDDEN;
211 *value = config.inputFlags;
212 return 0;
213 }
214
a534180c
TAOSP
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
239bool
240AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
241{
242 Vector<String8> parts;
243
784c6915 244 String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
0096feb5 245 String8 touch, key, keysHidden, nav, navHidden, size, vers;
2ca01a37 246 String8 uiModeType, uiModeNight;
a534180c
TAOSP
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
784c6915
DH
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
a534180c
TAOSP
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
2ca01a37
TH
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
a534180c
TAOSP
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
0096feb5
DH
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
a534180c
TAOSP
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
500success:
501 this->mcc = mcc;
502 this->mnc = mnc;
503 this->locale = loc;
784c6915
DH
504 this->screenLayoutSize = layoutsize;
505 this->screenLayoutLong = layoutlong;
a534180c 506 this->orientation = orient;
2ca01a37
TH
507 this->uiModeType = uiModeType;
508 this->uiModeNight = uiModeNight;
a534180c
TAOSP
509 this->density = den;
510 this->touchscreen = touch;
511 this->keysHidden = keysHidden;
512 this->keyboard = key;
0096feb5 513 this->navHidden = navHidden;
a534180c
TAOSP
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
524String8
525AaptGroupEntry::toString() const
526{
527 String8 s = this->mcc;
528 s += ",";
529 s += this->mnc;
530 s += ",";
531 s += this->locale;
532 s += ",";
784c6915
DH
533 s += screenLayoutSize;
534 s += ",";
535 s += screenLayoutLong;
536 s += ",";
a534180c
TAOSP
537 s += this->orientation;
538 s += ",";
2ca01a37
TH
539 s += uiModeType;
540 s += ",";
541 s += uiModeNight;
542 s += ",";
a534180c
TAOSP
543 s += density;
544 s += ",";
545 s += touchscreen;
546 s += ",";
547 s += keysHidden;
548 s += ",";
549 s += keyboard;
550 s += ",";
0096feb5
DH
551 s += navHidden;
552 s += ",";
a534180c
TAOSP
553 s += navigation;
554 s += ",";
555 s += screenSize;
556 s += ",";
557 s += version;
558 return s;
559}
560
561String8
562AaptGroupEntry::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 }
784c6915
DH
577 if (this->screenLayoutSize != "") {
578 s += "-";
579 s += screenLayoutSize;
580 }
581 if (this->screenLayoutLong != "") {
582 s += "-";
583 s += screenLayoutLong;
584 }
a534180c
TAOSP
585 if (this->orientation != "") {
586 s += "-";
587 s += orientation;
588 }
2ca01a37
TH
589 if (this->uiModeType != "") {
590 s += "-";
591 s += uiModeType;
592 }
593 if (this->uiModeNight != "") {
594 s += "-";
595 s += uiModeNight;
596 }
a534180c
TAOSP
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 }
0096feb5
DH
613 if (this->navHidden != "") {
614 s += "-";
615 s += navHidden;
616 }
a534180c
TAOSP
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
633bool 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
665bool 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 */
704bool 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
784c6915
DH
746bool 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
774bool 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
a534180c
TAOSP
797bool 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
2ca01a37
TH
817bool 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
835bool 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
a534180c
TAOSP
858bool AaptGroupEntry::getDensityName(const char* name,
859 ResTable_config* out)
860{
861 if (strcmp(name, kWildcardName) == 0) {
41ff305d 862 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
a534180c
TAOSP
863 return true;
864 }
41ff305d
DH
865
866 if (strcmp(name, "nodpi") == 0) {
867 if (out) out->density = ResTable_config::DENSITY_NONE;
868 return true;
869 }
870
784c6915
DH
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
a534180c
TAOSP
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
915bool 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
935bool 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) {
18a923f6
KR
941 mask = ResTable_config::MASK_KEYSHIDDEN;
942 value = ResTable_config::KEYSHIDDEN_ANY;
a534180c 943 } else if (strcmp(name, "keysexposed") == 0) {
18a923f6
KR
944 mask = ResTable_config::MASK_KEYSHIDDEN;
945 value = ResTable_config::KEYSHIDDEN_NO;
a534180c 946 } else if (strcmp(name, "keyshidden") == 0) {
18a923f6
KR
947 mask = ResTable_config::MASK_KEYSHIDDEN;
948 value = ResTable_config::KEYSHIDDEN_YES;
a534180c 949 } else if (strcmp(name, "keyssoft") == 0) {
18a923f6
KR
950 mask = ResTable_config::MASK_KEYSHIDDEN;
951 value = ResTable_config::KEYSHIDDEN_SOFT;
a534180c
TAOSP
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
962bool 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
0096feb5
DH
982bool 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) {
491d9ef0
KR
988 mask = ResTable_config::MASK_NAVHIDDEN;
989 value = ResTable_config::NAVHIDDEN_ANY;
0096feb5 990 } else if (strcmp(name, "navexposed") == 0) {
491d9ef0
KR
991 mask = ResTable_config::MASK_NAVHIDDEN;
992 value = ResTable_config::NAVHIDDEN_NO;
0096feb5 993 } else if (strcmp(name, "navhidden") == 0) {
491d9ef0
KR
994 mask = ResTable_config::MASK_NAVHIDDEN;
995 value = ResTable_config::NAVHIDDEN_YES;
0096feb5
DH
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
a534180c
TAOSP
1006bool 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
1029bool 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
1065bool 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
1094int 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);
784c6915
DH
1100 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
1101 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
a534180c 1102 if (v == 0) v = orientation.compare(o.orientation);
2ca01a37
TH
1103 if (v == 0) v = uiModeType.compare(o.uiModeType);
1104 if (v == 0) v = uiModeNight.compare(o.uiModeNight);
a534180c
TAOSP
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);
0096feb5 1109 if (v == 0) v = navHidden.compare(o.navHidden);
a534180c
TAOSP
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
1116ResTable_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);
784c6915
DH
1123 getScreenLayoutSizeName(screenLayoutSize.string(), &params);
1124 getScreenLayoutLongName(screenLayoutLong.string(), &params);
a534180c 1125 getOrientationName(orientation.string(), &params);
2ca01a37
TH
1126 getUiModeTypeName(uiModeType.string(), &params);
1127 getUiModeNightName(uiModeNight.string(), &params);
a534180c
TAOSP
1128 getDensityName(density.string(), &params);
1129 getTouchscreenName(touchscreen.string(), &params);
1130 getKeysHiddenName(keysHidden.string(), &params);
1131 getKeyboardName(keyboard.string(), &params);
0096feb5 1132 getNavHiddenName(navHidden.string(), &params);
a534180c
TAOSP
1133 getNavigationName(navigation.string(), &params);
1134 getScreenSizeName(screenSize.string(), &params);
1135 getVersionName(version.string(), &params);
1136 return params;
1137}
1138
1139// =========================================================================
1140// =========================================================================
1141// =========================================================================
1142
1143void* AaptFile::editData(size_t size)
1144{
1145 if (size <= mBufferSize) {
1146 mDataSize = size;
1147 return mData;
1148 }
1149 size_t allocSize = (size*3)/2;
1150 void* buf = realloc(mData, allocSize);
1151 if (buf == NULL) {
1152 return NULL;
1153 }
1154 mData = buf;
1155 mDataSize = size;
1156 mBufferSize = allocSize;
1157 return buf;
1158}
1159
1160void* AaptFile::editData(size_t* outSize)
1161{
1162 if (outSize) {
1163 *outSize = mDataSize;
1164 }
1165 return mData;
1166}
1167
1168void* AaptFile::padData(size_t wordSize)
1169{
1170 const size_t extra = mDataSize%wordSize;
1171 if (extra == 0) {
1172 return mData;
1173 }
1174
1175 size_t initial = mDataSize;
1176 void* data = editData(initial+(wordSize-extra));
1177 if (data != NULL) {
1178 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
1179 }
1180 return data;
1181}
1182
1183status_t AaptFile::writeData(const void* data, size_t size)
1184{
1185 size_t end = mDataSize;
1186 size_t total = size + end;
1187 void* buf = editData(total);
1188 if (buf == NULL) {
1189 return UNKNOWN_ERROR;
1190 }
1191 memcpy(((char*)buf)+end, data, size);
1192 return NO_ERROR;
1193}
1194
1195void AaptFile::clearData()
1196{
1197 if (mData != NULL) free(mData);
1198 mData = NULL;
1199 mDataSize = 0;
1200 mBufferSize = 0;
1201}
1202
1203String8 AaptFile::getPrintableSource() const
1204{
1205 if (hasData()) {
1206 String8 name(mGroupEntry.locale.string());
1207 name.appendPath(mGroupEntry.vendor.string());
1208 name.appendPath(mPath);
1209 name.append(" #generated");
1210 return name;
1211 }
1212 return mSourceFile;
1213}
1214
1215// =========================================================================
1216// =========================================================================
1217// =========================================================================
1218
1219status_t AaptGroup::addFile(const sp<AaptFile>& file)
1220{
1221 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
1222 file->mPath = mPath;
1223 mFiles.add(file->getGroupEntry(), file);
1224 return NO_ERROR;
1225 }
1226
1227 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1228 getPrintableSource().string());
1229 return UNKNOWN_ERROR;
1230}
1231
1232void AaptGroup::removeFile(size_t index)
1233{
1234 mFiles.removeItemsAt(index);
1235}
1236
1237void AaptGroup::print() const
1238{
1239 printf(" %s\n", getPath().string());
1240 const size_t N=mFiles.size();
1241 size_t i;
1242 for (i=0; i<N; i++) {
1243 sp<AaptFile> file = mFiles.valueAt(i);
1244 const AaptGroupEntry& e = file->getGroupEntry();
1245 if (file->hasData()) {
1246 printf(" Gen: (%s) %d bytes\n", e.toString().string(),
1247 (int)file->getSize());
1248 } else {
1249 printf(" Src: %s\n", file->getPrintableSource().string());
1250 }
1251 }
1252}
1253
1254String8 AaptGroup::getPrintableSource() const
1255{
1256 if (mFiles.size() > 0) {
1257 // Arbitrarily pull the first source file out of the list.
1258 return mFiles.valueAt(0)->getPrintableSource();
1259 }
1260
1261 // Should never hit this case, but to be safe...
1262 return getPath();
1263
1264}
1265
1266// =========================================================================
1267// =========================================================================
1268// =========================================================================
1269
1270status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1271{
1272 if (mFiles.indexOfKey(name) >= 0) {
1273 return ALREADY_EXISTS;
1274 }
1275 mFiles.add(name, file);
1276 return NO_ERROR;
1277}
1278
1279status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1280{
1281 if (mDirs.indexOfKey(name) >= 0) {
1282 return ALREADY_EXISTS;
1283 }
1284 mDirs.add(name, dir);
1285 return NO_ERROR;
1286}
1287
1288sp<AaptDir> AaptDir::makeDir(const String8& path)
1289{
1290 String8 name;
1291 String8 remain = path;
1292
1293 sp<AaptDir> subdir = this;
1294 while (name = remain.walkPath(&remain), remain != "") {
1295 subdir = subdir->makeDir(name);
1296 }
1297
1298 ssize_t i = subdir->mDirs.indexOfKey(name);
1299 if (i >= 0) {
1300 return subdir->mDirs.valueAt(i);
1301 }
1302 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1303 subdir->mDirs.add(name, dir);
1304 return dir;
1305}
1306
1307void AaptDir::removeFile(const String8& name)
1308{
1309 mFiles.removeItem(name);
1310}
1311
1312void AaptDir::removeDir(const String8& name)
1313{
1314 mDirs.removeItem(name);
1315}
1316
1317status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName)
1318{
1319 sp<AaptGroup> origGroup;
1320
1321 // Find and remove the given file with shear, brute force!
1322 const size_t NG = mFiles.size();
1323 size_t i;
1324 for (i=0; origGroup == NULL && i<NG; i++) {
1325 sp<AaptGroup> g = mFiles.valueAt(i);
1326 const size_t NF = g->getFiles().size();
1327 for (size_t j=0; j<NF; j++) {
1328 if (g->getFiles().valueAt(j) == file) {
1329 origGroup = g;
1330 g->removeFile(j);
1331 if (NF == 1) {
1332 mFiles.removeItemsAt(i);
1333 }
1334 break;
1335 }
1336 }
1337 }
1338
1339 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1340
1341 // Place the file under its new name.
1342 if (origGroup != NULL) {
1343 return addLeafFile(newName, file);
1344 }
1345
1346 return NO_ERROR;
1347}
1348
1349status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1350{
1351 sp<AaptGroup> group;
1352 if (mFiles.indexOfKey(leafName) >= 0) {
1353 group = mFiles.valueFor(leafName);
1354 } else {
1355 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1356 mFiles.add(leafName, group);
1357 }
1358
1359 return group->addFile(file);
1360}
1361
1362ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
1363 const AaptGroupEntry& kind, const String8& resType)
1364{
1365 Vector<String8> fileNames;
1366
1367 {
1368 DIR* dir = NULL;
1369
1370 dir = opendir(srcDir.string());
1371 if (dir == NULL) {
1372 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1373 return UNKNOWN_ERROR;
1374 }
1375
1376 /*
1377 * Slurp the filenames out of the directory.
1378 */
1379 while (1) {
1380 struct dirent* entry;
1381
1382 entry = readdir(dir);
1383 if (entry == NULL)
1384 break;
1385
1386 if (isHidden(srcDir.string(), entry->d_name))
1387 continue;
1388
1389 fileNames.add(String8(entry->d_name));
1390 }
1391
1392 closedir(dir);
1393 }
1394
1395 ssize_t count = 0;
1396
1397 /*
1398 * Stash away the files and recursively descend into subdirectories.
1399 */
1400 const size_t N = fileNames.size();
1401 size_t i;
1402 for (i = 0; i < N; i++) {
1403 String8 pathName(srcDir);
1404 FileType type;
1405
1406 pathName.appendPath(fileNames[i].string());
1407 type = getFileType(pathName.string());
1408 if (type == kFileTypeDirectory) {
1409 sp<AaptDir> subdir;
1410 bool notAdded = false;
1411 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1412 subdir = mDirs.valueFor(fileNames[i]);
1413 } else {
1414 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1415 notAdded = true;
1416 }
1417 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
1418 resType);
1419 if (res < NO_ERROR) {
1420 return res;
1421 }
1422 if (res > 0 && notAdded) {
1423 mDirs.add(fileNames[i], subdir);
1424 }
1425 count += res;
1426 } else if (type == kFileTypeRegular) {
1427 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1428 status_t err = addLeafFile(fileNames[i], file);
1429 if (err != NO_ERROR) {
1430 return err;
1431 }
1432
1433 count++;
1434
1435 } else {
1436 if (bundle->getVerbose())
1437 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
1438 }
1439 }
1440
1441 return count;
1442}
1443
1444status_t AaptDir::validate() const
1445{
1446 const size_t NF = mFiles.size();
1447 const size_t ND = mDirs.size();
1448 size_t i;
1449 for (i = 0; i < NF; i++) {
1450 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1451 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1452 "Invalid filename. Unable to add.");
1453 return UNKNOWN_ERROR;
1454 }
1455
1456 size_t j;
1457 for (j = i+1; j < NF; j++) {
1458 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1459 mFiles.valueAt(j)->getLeaf().string()) == 0) {
1460 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1461 "File is case-insensitive equivalent to: %s",
1462 mFiles.valueAt(j)->getPrintableSource().string());
1463 return UNKNOWN_ERROR;
1464 }
1465
1466 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1467 // (this is mostly caught by the "marked" stuff, below)
1468 }
1469
1470 for (j = 0; j < ND; j++) {
1471 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1472 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1473 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1474 "File conflicts with dir from: %s",
1475 mDirs.valueAt(j)->getPrintableSource().string());
1476 return UNKNOWN_ERROR;
1477 }
1478 }
1479 }
1480
1481 for (i = 0; i < ND; i++) {
1482 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1483 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1484 "Invalid directory name, unable to add.");
1485 return UNKNOWN_ERROR;
1486 }
1487
1488 size_t j;
1489 for (j = i+1; j < ND; j++) {
1490 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1491 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1492 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1493 "Directory is case-insensitive equivalent to: %s",
1494 mDirs.valueAt(j)->getPrintableSource().string());
1495 return UNKNOWN_ERROR;
1496 }
1497 }
1498
1499 status_t err = mDirs.valueAt(i)->validate();
1500 if (err != NO_ERROR) {
1501 return err;
1502 }
1503 }
1504
1505 return NO_ERROR;
1506}
1507
1508void AaptDir::print() const
1509{
1510 const size_t ND=getDirs().size();
1511 size_t i;
1512 for (i=0; i<ND; i++) {
1513 getDirs().valueAt(i)->print();
1514 }
1515
1516 const size_t NF=getFiles().size();
1517 for (i=0; i<NF; i++) {
1518 getFiles().valueAt(i)->print();
1519 }
1520}
1521
1522String8 AaptDir::getPrintableSource() const
1523{
1524 if (mFiles.size() > 0) {
1525 // Arbitrarily pull the first file out of the list as the source dir.
1526 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1527 }
1528 if (mDirs.size() > 0) {
1529 // Or arbitrarily pull the first dir out of the list as the source dir.
1530 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1531 }
1532
1533 // Should never hit this case, but to be safe...
1534 return mPath;
1535
1536}
1537
1538// =========================================================================
1539// =========================================================================
1540// =========================================================================
1541
1542sp<AaptFile> AaptAssets::addFile(
1543 const String8& filePath, const AaptGroupEntry& entry,
1544 const String8& srcDir, sp<AaptGroup>* outGroup,
1545 const String8& resType)
1546{
1547 sp<AaptDir> dir = this;
1548 sp<AaptGroup> group;
1549 sp<AaptFile> file;
1550 String8 root, remain(filePath), partialPath;
1551 while (remain.length() > 0) {
1552 root = remain.walkPath(&remain);
1553 partialPath.appendPath(root);
1554
1555 const String8 rootStr(root);
1556
1557 if (remain.length() == 0) {
1558 ssize_t i = dir->getFiles().indexOfKey(rootStr);
1559 if (i >= 0) {
1560 group = dir->getFiles().valueAt(i);
1561 } else {
1562 group = new AaptGroup(rootStr, filePath);
1563 status_t res = dir->addFile(rootStr, group);
1564 if (res != NO_ERROR) {
1565 return NULL;
1566 }
1567 }
1568 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
1569 status_t res = group->addFile(file);
1570 if (res != NO_ERROR) {
1571 return NULL;
1572 }
1573 break;
1574
1575 } else {
1576 ssize_t i = dir->getDirs().indexOfKey(rootStr);
1577 if (i >= 0) {
1578 dir = dir->getDirs().valueAt(i);
1579 } else {
1580 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
1581 status_t res = dir->addDir(rootStr, subdir);
1582 if (res != NO_ERROR) {
1583 return NULL;
1584 }
1585 dir = subdir;
1586 }
1587 }
1588 }
1589
1590 mGroupEntries.add(entry);
1591 if (outGroup) *outGroup = group;
1592 return file;
1593}
1594
1595void AaptAssets::addResource(const String8& leafName, const String8& path,
1596 const sp<AaptFile>& file, const String8& resType)
1597{
1598 sp<AaptDir> res = AaptDir::makeDir(kResString);
1599 String8 dirname = file->getGroupEntry().toDirName(resType);
1600 sp<AaptDir> subdir = res->makeDir(dirname);
1601 sp<AaptGroup> grr = new AaptGroup(leafName, path);
1602 grr->addFile(file);
1603
1604 subdir->addFile(leafName, grr);
1605}
1606
1607
1608ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
1609{
1610 int count;
1611 int totalCount = 0;
1612 FileType type;
1613 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
1614 const size_t dirCount =resDirs.size();
1615 sp<AaptAssets> current = this;
1616
1617 const int N = bundle->getFileSpecCount();
1618
1619 /*
1620 * If a package manifest was specified, include that first.
1621 */
1622 if (bundle->getAndroidManifestFile() != NULL) {
1623 // place at root of zip.
1624 String8 srcFile(bundle->getAndroidManifestFile());
1625 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
1626 NULL, String8());
1627 totalCount++;
1628 }
1629
1630 /*
1631 * If a directory of custom assets was supplied, slurp 'em up.
1632 */
1633 if (bundle->getAssetSourceDir()) {
1634 const char* assetDir = bundle->getAssetSourceDir();
1635
1636 FileType type = getFileType(assetDir);
1637 if (type == kFileTypeNonexistent) {
1638 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
1639 return UNKNOWN_ERROR;
1640 }
1641 if (type != kFileTypeDirectory) {
1642 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1643 return UNKNOWN_ERROR;
1644 }
1645
1646 String8 assetRoot(assetDir);
1647 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
1648 AaptGroupEntry group;
1649 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
1650 String8());
1651 if (count < 0) {
1652 totalCount = count;
1653 goto bail;
1654 }
1655 if (count > 0) {
1656 mGroupEntries.add(group);
1657 }
1658 totalCount += count;
1659
1660 if (bundle->getVerbose())
1661 printf("Found %d custom asset file%s in %s\n",
1662 count, (count==1) ? "" : "s", assetDir);
1663 }
1664
1665 /*
1666 * If a directory of resource-specific assets was supplied, slurp 'em up.
1667 */
1668 for (size_t i=0; i<dirCount; i++) {
1669 const char *res = resDirs[i];
1670 if (res) {
1671 type = getFileType(res);
1672 if (type == kFileTypeNonexistent) {
1673 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
1674 return UNKNOWN_ERROR;
1675 }
1676 if (type == kFileTypeDirectory) {
1677 if (i>0) {
1678 sp<AaptAssets> nextOverlay = new AaptAssets();
1679 current->setOverlay(nextOverlay);
1680 current = nextOverlay;
1681 }
1682 count = current->slurpResourceTree(bundle, String8(res));
1683
1684 if (count < 0) {
1685 totalCount = count;
1686 goto bail;
1687 }
1688 totalCount += count;
1689 }
1690 else {
1691 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
1692 return UNKNOWN_ERROR;
1693 }
1694 }
1695
1696 }
1697 /*
1698 * Now do any additional raw files.
1699 */
1700 for (int arg=0; arg<N; arg++) {
1701 const char* assetDir = bundle->getFileSpecEntry(arg);
1702
1703 FileType type = getFileType(assetDir);
1704 if (type == kFileTypeNonexistent) {
1705 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
1706 return UNKNOWN_ERROR;
1707 }
1708 if (type != kFileTypeDirectory) {
1709 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
1710 return UNKNOWN_ERROR;
1711 }
1712
1713 String8 assetRoot(assetDir);
1714
1715 if (bundle->getVerbose())
1716 printf("Processing raw dir '%s'\n", (const char*) assetDir);
1717
1718 /*
1719 * Do a recursive traversal of subdir tree. We don't make any
1720 * guarantees about ordering, so we're okay with an inorder search
1721 * using whatever order the OS happens to hand back to us.
1722 */
1723 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8());
1724 if (count < 0) {
1725 /* failure; report error and remove archive */
1726 totalCount = count;
1727 goto bail;
1728 }
1729 totalCount += count;
1730
1731 if (bundle->getVerbose())
1732 printf("Found %d asset file%s in %s\n",
1733 count, (count==1) ? "" : "s", assetDir);
1734 }
1735
1736 count = validate();
1737 if (count != NO_ERROR) {
1738 totalCount = count;
1739 goto bail;
1740 }
1741
1742
1743bail:
1744 return totalCount;
1745}
1746
1747ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
1748 const AaptGroupEntry& kind,
1749 const String8& resType)
1750{
1751 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType);
1752 if (res > 0) {
1753 mGroupEntries.add(kind);
1754 }
1755
1756 return res;
1757}
1758
1759ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
1760{
1761 ssize_t err = 0;
1762
1763 DIR* dir = opendir(srcDir.string());
1764 if (dir == NULL) {
1765 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1766 return UNKNOWN_ERROR;
1767 }
1768
1769 status_t count = 0;
1770
1771 /*
1772 * Run through the directory, looking for dirs that match the
1773 * expected pattern.
1774 */
1775 while (1) {
1776 struct dirent* entry = readdir(dir);
1777 if (entry == NULL) {
1778 break;
1779 }
1780
1781 if (isHidden(srcDir.string(), entry->d_name)) {
1782 continue;
1783 }
1784
1785 String8 subdirName(srcDir);
1786 subdirName.appendPath(entry->d_name);
1787
1788 AaptGroupEntry group;
1789 String8 resType;
1790 bool b = group.initFromDirName(entry->d_name, &resType);
1791 if (!b) {
1792 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
1793 entry->d_name);
1794 err = -1;
1795 continue;
1796 }
1797
1798 FileType type = getFileType(subdirName.string());
1799
1800 if (type == kFileTypeDirectory) {
1801 sp<AaptDir> dir = makeDir(String8(entry->d_name));
1802 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
1803 resType);
1804 if (res < 0) {
1805 count = res;
1806 goto bail;
1807 }
1808 if (res > 0) {
1809 mGroupEntries.add(group);
1810 count += res;
1811 }
1812
1813 mDirs.add(dir);
1814 } else {
1815 if (bundle->getVerbose()) {
1816 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
1817 }
1818 }
1819 }
1820
1821bail:
1822 closedir(dir);
1823 dir = NULL;
1824
1825 if (err != 0) {
1826 return err;
1827 }
1828 return count;
1829}
1830
1831ssize_t
1832AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
1833{
1834 int count = 0;
1835 SortedVector<AaptGroupEntry> entries;
1836
1837 ZipFile* zip = new ZipFile;
1838 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
1839 if (err != NO_ERROR) {
1840 fprintf(stderr, "error opening zip file %s\n", filename);
1841 count = err;
1842 delete zip;
1843 return -1;
1844 }
1845
1846 const int N = zip->getNumEntries();
1847 for (int i=0; i<N; i++) {
1848 ZipEntry* entry = zip->getEntryByIndex(i);
1849 if (entry->getDeleted()) {
1850 continue;
1851 }
1852
1853 String8 entryName(entry->getFileName());
1854
1855 String8 dirName = entryName.getPathDir();
1856 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
1857
1858 String8 resType;
1859 AaptGroupEntry kind;
1860
1861 String8 remain;
1862 if (entryName.walkPath(&remain) == kResourceDir) {
1863 // these are the resources, pull their type out of the directory name
1864 kind.initFromDirName(remain.walkPath().string(), &resType);
1865 } else {
1866 // these are untyped and don't have an AaptGroupEntry
1867 }
1868 if (entries.indexOf(kind) < 0) {
1869 entries.add(kind);
1870 mGroupEntries.add(kind);
1871 }
1872
1873 // use the one from the zip file if they both exist.
1874 dir->removeFile(entryName.getPathLeaf());
1875
1876 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
1877 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
1878 if (err != NO_ERROR) {
1879 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
1880 count = err;
1881 goto bail;
1882 }
1883 file->setCompressionMethod(entry->getCompressionMethod());
1884
1885#if 0
1886 if (entryName == "AndroidManifest.xml") {
1887 printf("AndroidManifest.xml\n");
1888 }
1889 printf("\n\nfile: %s\n", entryName.string());
1890#endif
1891
1892 size_t len = entry->getUncompressedLen();
1893 void* data = zip->uncompress(entry);
1894 void* buf = file->editData(len);
1895 memcpy(buf, data, len);
1896
1897#if 0
1898 const int OFF = 0;
1899 const unsigned char* p = (unsigned char*)data;
1900 const unsigned char* end = p+len;
1901 p += OFF;
1902 for (int i=0; i<32 && p < end; i++) {
1903 printf("0x%03x ", i*0x10 + OFF);
1904 for (int j=0; j<0x10 && p < end; j++) {
1905 printf(" %02x", *p);
1906 p++;
1907 }
1908 printf("\n");
1909 }
1910#endif
1911
1912 free(data);
1913
1914 count++;
1915 }
1916
1917bail:
1918 delete zip;
1919 return count;
1920}
1921
1922sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
1923{
1924 sp<AaptSymbols> sym = mSymbols.valueFor(name);
1925 if (sym == NULL) {
1926 sym = new AaptSymbols();
1927 mSymbols.add(name, sym);
1928 }
1929 return sym;
1930}
1931
1932status_t AaptAssets::buildIncludedResources(Bundle* bundle)
1933{
1934 if (!mHaveIncludedAssets) {
1935 // Add in all includes.
1936 const Vector<const char*>& incl = bundle->getPackageIncludes();
1937 const size_t N=incl.size();
1938 for (size_t i=0; i<N; i++) {
1939 if (bundle->getVerbose())
1940 printf("Including resources from package: %s\n", incl[i]);
1941 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
1942 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
1943 incl[i]);
1944 return UNKNOWN_ERROR;
1945 }
1946 }
1947 mHaveIncludedAssets = true;
1948 }
1949
1950 return NO_ERROR;
1951}
1952
1953status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
1954{
1955 const ResTable& res = getIncludedResources();
1956 // XXX dirty!
1957 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
1958}
1959
1960const ResTable& AaptAssets::getIncludedResources() const
1961{
1962 return mIncludedAssets.getResources(false);
1963}
1964
1965void AaptAssets::print() const
1966{
1967 printf("Locale/Vendor pairs:\n");
1968 const size_t N=mGroupEntries.size();
1969 for (size_t i=0; i<N; i++) {
1970 printf(" %s/%s\n",
1971 mGroupEntries.itemAt(i).locale.string(),
1972 mGroupEntries.itemAt(i).vendor.string());
1973 }
1974
1975 printf("\nFiles:\n");
1976 AaptDir::print();
1977}
1978
6648ff78
JO
1979sp<AaptDir> AaptAssets::resDir(const String8& name)
1980{
1981 const Vector<sp<AaptDir> >& dirs = mDirs;
1982 const size_t N = dirs.size();
1983 for (size_t i=0; i<N; i++) {
1984 const sp<AaptDir>& d = dirs.itemAt(i);
1985 if (d->getLeaf() == name) {
1986 return d;
1987 }
1988 }
1989 return NULL;
1990}
1991
a534180c
TAOSP
1992bool
1993valid_symbol_name(const String8& symbol)
1994{
1995 static char const * const KEYWORDS[] = {
1996 "abstract", "assert", "boolean", "break",
1997 "byte", "case", "catch", "char", "class", "const", "continue",
1998 "default", "do", "double", "else", "enum", "extends", "final",
1999 "finally", "float", "for", "goto", "if", "implements", "import",
2000 "instanceof", "int", "interface", "long", "native", "new", "package",
2001 "private", "protected", "public", "return", "short", "static",
2002 "strictfp", "super", "switch", "synchronized", "this", "throw",
2003 "throws", "transient", "try", "void", "volatile", "while",
2004 "true", "false", "null",
2005 NULL
2006 };
2007 const char*const* k = KEYWORDS;
2008 const char*const s = symbol.string();
2009 while (*k) {
2010 if (0 == strcmp(s, *k)) {
2011 return false;
2012 }
2013 k++;
2014 }
2015 return true;
2016}