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