AaptAssets.cpp revision e0219c8baa9d63b3794f90ab772f1c19ecb74ec4
1// 2// Copyright 2006 The Android Open Source Project 3// 4 5#include "AaptAssets.h" 6#include "ResourceFilter.h" 7#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"; 20static const char* kValuesDir = "values"; 21static const char* kMipmapDir = "mipmap"; 22static 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 59// The default to use if no other ignore pattern is defined. 60const char * const gDefaultIgnoreAssets = 61 "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"; 62// The ignore pattern that can be passed via --ignore-assets in Main.cpp 63const char * gUserIgnoreAssets = NULL; 64 65static bool isHidden(const char *root, const char *path) 66{ 67 // 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. 79 80 if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) { 81 return true; 82 } 83 84 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); 93 94 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 n--; 126 if (n <= plen) { 127 ignore = strncasecmp(token, path + plen - n, n) == 0; 128 } 129 } else if (n > 1 && token[n - 1] == '*') { 130 // Match prefix* 131 ignore = strncasecmp(token, path, n - 1) == 0; 132 } else { 133 ignore = strcasecmp(token, path) == 0; 134 } 135 } 136 137 if (ignore && chatty) { 138 fprintf(stderr, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n", 139 type == kFileTypeDirectory ? "dir" : "file", 140 path, 141 matchedPattern ? matchedPattern : ""); 142 } 143 144 free(patterns); 145 return ignore; 146} 147 148// ========================================================================= 149// ========================================================================= 150// ========================================================================= 151 152status_t 153AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) 154{ 155 ResTable_config config; 156 157 // IMSI - MCC 158 if (getMccName(part.string(), &config)) { 159 *axis = AXIS_MCC; 160 *value = config.mcc; 161 return 0; 162 } 163 164 // IMSI - MNC 165 if (getMncName(part.string(), &config)) { 166 *axis = AXIS_MNC; 167 *value = config.mnc; 168 return 0; 169 } 170 171 // locale - language 172 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { 173 *axis = AXIS_LANGUAGE; 174 *value = part[1] << 8 | part[0]; 175 return 0; 176 } 177 178 // locale - language_REGION 179 if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1]) 180 && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) { 181 *axis = AXIS_LANGUAGE; 182 *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]); 183 return 0; 184 } 185 186 // smallest screen dp width 187 if (getSmallestScreenWidthDpName(part.string(), &config)) { 188 *axis = AXIS_SMALLESTSCREENWIDTHDP; 189 *value = config.smallestScreenWidthDp; 190 return 0; 191 } 192 193 // screen dp width 194 if (getScreenWidthDpName(part.string(), &config)) { 195 *axis = AXIS_SCREENWIDTHDP; 196 *value = config.screenWidthDp; 197 return 0; 198 } 199 200 // screen dp height 201 if (getScreenHeightDpName(part.string(), &config)) { 202 *axis = AXIS_SCREENHEIGHTDP; 203 *value = config.screenHeightDp; 204 return 0; 205 } 206 207 // screen layout size 208 if (getScreenLayoutSizeName(part.string(), &config)) { 209 *axis = AXIS_SCREENLAYOUTSIZE; 210 *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE); 211 return 0; 212 } 213 214 // screen layout long 215 if (getScreenLayoutLongName(part.string(), &config)) { 216 *axis = AXIS_SCREENLAYOUTLONG; 217 *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG); 218 return 0; 219 } 220 221 // orientation 222 if (getOrientationName(part.string(), &config)) { 223 *axis = AXIS_ORIENTATION; 224 *value = config.orientation; 225 return 0; 226 } 227 228 // ui mode type 229 if (getUiModeTypeName(part.string(), &config)) { 230 *axis = AXIS_UIMODETYPE; 231 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); 232 return 0; 233 } 234 235 // ui mode night 236 if (getUiModeNightName(part.string(), &config)) { 237 *axis = AXIS_UIMODENIGHT; 238 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); 239 return 0; 240 } 241 242 // density 243 if (getDensityName(part.string(), &config)) { 244 *axis = AXIS_DENSITY; 245 *value = config.density; 246 return 0; 247 } 248 249 // touchscreen 250 if (getTouchscreenName(part.string(), &config)) { 251 *axis = AXIS_TOUCHSCREEN; 252 *value = config.touchscreen; 253 return 0; 254 } 255 256 // keyboard hidden 257 if (getKeysHiddenName(part.string(), &config)) { 258 *axis = AXIS_KEYSHIDDEN; 259 *value = config.inputFlags; 260 return 0; 261 } 262 263 // keyboard 264 if (getKeyboardName(part.string(), &config)) { 265 *axis = AXIS_KEYBOARD; 266 *value = config.keyboard; 267 return 0; 268 } 269 270 // navigation hidden 271 if (getNavHiddenName(part.string(), &config)) { 272 *axis = AXIS_NAVHIDDEN; 273 *value = config.inputFlags; 274 return 0; 275 } 276 277 // navigation 278 if (getNavigationName(part.string(), &config)) { 279 *axis = AXIS_NAVIGATION; 280 *value = config.navigation; 281 return 0; 282 } 283 284 // screen size 285 if (getScreenSizeName(part.string(), &config)) { 286 *axis = AXIS_SCREENSIZE; 287 *value = config.screenSize; 288 return 0; 289 } 290 291 // version 292 if (getVersionName(part.string(), &config)) { 293 *axis = AXIS_VERSION; 294 *value = config.version; 295 return 0; 296 } 297 298 return 1; 299} 300 301uint32_t 302AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis) 303{ 304 switch (axis) { 305 case AXIS_MCC: 306 return config.mcc; 307 case AXIS_MNC: 308 return config.mnc; 309 case AXIS_LANGUAGE: 310 return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16) 311 | (((uint32_t)config.language[1]) << 8) | (config.language[0]); 312 case AXIS_SCREENLAYOUTSIZE: 313 return config.screenLayout&ResTable_config::MASK_SCREENSIZE; 314 case AXIS_ORIENTATION: 315 return config.orientation; 316 case AXIS_UIMODETYPE: 317 return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); 318 case AXIS_UIMODENIGHT: 319 return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); 320 case AXIS_DENSITY: 321 return config.density; 322 case AXIS_TOUCHSCREEN: 323 return config.touchscreen; 324 case AXIS_KEYSHIDDEN: 325 return config.inputFlags; 326 case AXIS_KEYBOARD: 327 return config.keyboard; 328 case AXIS_NAVIGATION: 329 return config.navigation; 330 case AXIS_SCREENSIZE: 331 return config.screenSize; 332 case AXIS_SMALLESTSCREENWIDTHDP: 333 return config.smallestScreenWidthDp; 334 case AXIS_SCREENWIDTHDP: 335 return config.screenWidthDp; 336 case AXIS_SCREENHEIGHTDP: 337 return config.screenHeightDp; 338 case AXIS_VERSION: 339 return config.version; 340 } 341 return 0; 342} 343 344bool 345AaptGroupEntry::configSameExcept(const ResTable_config& config, 346 const ResTable_config& otherConfig, int axis) 347{ 348 for (int i=AXIS_START; i<=AXIS_END; i++) { 349 if (i == axis) { 350 continue; 351 } 352 if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) { 353 return false; 354 } 355 } 356 return true; 357} 358 359bool 360AaptGroupEntry::initFromDirName(const char* dir, String8* resType) 361{ 362 mParamsChanged = true; 363 364 Vector<String8> parts; 365 366 String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den; 367 String8 touch, key, keysHidden, nav, navHidden, size, vers; 368 String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp; 369 370 const char *p = dir; 371 const char *q; 372 while (NULL != (q = strchr(p, '-'))) { 373 String8 val(p, q-p); 374 val.toLower(); 375 parts.add(val); 376 //printf("part: %s\n", parts[parts.size()-1].string()); 377 p = q+1; 378 } 379 String8 val(p); 380 val.toLower(); 381 parts.add(val); 382 //printf("part: %s\n", parts[parts.size()-1].string()); 383 384 const int N = parts.size(); 385 int index = 0; 386 String8 part = parts[index]; 387 388 // resource type 389 if (!isValidResourceType(part)) { 390 return false; 391 } 392 *resType = part; 393 394 index++; 395 if (index == N) { 396 goto success; 397 } 398 part = parts[index]; 399 400 // imsi - mcc 401 if (getMccName(part.string())) { 402 mcc = part; 403 404 index++; 405 if (index == N) { 406 goto success; 407 } 408 part = parts[index]; 409 } else { 410 //printf("not mcc: %s\n", part.string()); 411 } 412 413 // imsi - mnc 414 if (getMncName(part.string())) { 415 mnc = part; 416 417 index++; 418 if (index == N) { 419 goto success; 420 } 421 part = parts[index]; 422 } else { 423 //printf("not mcc: %s\n", part.string()); 424 } 425 426 // locale - language 427 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { 428 loc = part; 429 430 index++; 431 if (index == N) { 432 goto success; 433 } 434 part = parts[index]; 435 } else { 436 //printf("not language: %s\n", part.string()); 437 } 438 439 // locale - region 440 if (loc.length() > 0 441 && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) { 442 loc += "-"; 443 part.toUpper(); 444 loc += part.string() + 1; 445 446 index++; 447 if (index == N) { 448 goto success; 449 } 450 part = parts[index]; 451 } else { 452 //printf("not region: %s\n", part.string()); 453 } 454 455 if (getSmallestScreenWidthDpName(part.string())) { 456 smallestwidthdp = part; 457 458 index++; 459 if (index == N) { 460 goto success; 461 } 462 part = parts[index]; 463 } else { 464 //printf("not smallest screen width dp: %s\n", part.string()); 465 } 466 467 if (getScreenWidthDpName(part.string())) { 468 widthdp = part; 469 470 index++; 471 if (index == N) { 472 goto success; 473 } 474 part = parts[index]; 475 } else { 476 //printf("not screen width dp: %s\n", part.string()); 477 } 478 479 if (getScreenHeightDpName(part.string())) { 480 heightdp = part; 481 482 index++; 483 if (index == N) { 484 goto success; 485 } 486 part = parts[index]; 487 } else { 488 //printf("not screen height dp: %s\n", part.string()); 489 } 490 491 if (getScreenLayoutSizeName(part.string())) { 492 layoutsize = part; 493 494 index++; 495 if (index == N) { 496 goto success; 497 } 498 part = parts[index]; 499 } else { 500 //printf("not screen layout size: %s\n", part.string()); 501 } 502 503 if (getScreenLayoutLongName(part.string())) { 504 layoutlong = part; 505 506 index++; 507 if (index == N) { 508 goto success; 509 } 510 part = parts[index]; 511 } else { 512 //printf("not screen layout long: %s\n", part.string()); 513 } 514 515 // orientation 516 if (getOrientationName(part.string())) { 517 orient = part; 518 519 index++; 520 if (index == N) { 521 goto success; 522 } 523 part = parts[index]; 524 } else { 525 //printf("not orientation: %s\n", part.string()); 526 } 527 528 // ui mode type 529 if (getUiModeTypeName(part.string())) { 530 uiModeType = part; 531 532 index++; 533 if (index == N) { 534 goto success; 535 } 536 part = parts[index]; 537 } else { 538 //printf("not ui mode type: %s\n", part.string()); 539 } 540 541 // ui mode night 542 if (getUiModeNightName(part.string())) { 543 uiModeNight = part; 544 545 index++; 546 if (index == N) { 547 goto success; 548 } 549 part = parts[index]; 550 } else { 551 //printf("not ui mode night: %s\n", part.string()); 552 } 553 554 // density 555 if (getDensityName(part.string())) { 556 den = part; 557 558 index++; 559 if (index == N) { 560 goto success; 561 } 562 part = parts[index]; 563 } else { 564 //printf("not density: %s\n", part.string()); 565 } 566 567 // touchscreen 568 if (getTouchscreenName(part.string())) { 569 touch = part; 570 571 index++; 572 if (index == N) { 573 goto success; 574 } 575 part = parts[index]; 576 } else { 577 //printf("not touchscreen: %s\n", part.string()); 578 } 579 580 // keyboard hidden 581 if (getKeysHiddenName(part.string())) { 582 keysHidden = part; 583 584 index++; 585 if (index == N) { 586 goto success; 587 } 588 part = parts[index]; 589 } else { 590 //printf("not keysHidden: %s\n", part.string()); 591 } 592 593 // keyboard 594 if (getKeyboardName(part.string())) { 595 key = part; 596 597 index++; 598 if (index == N) { 599 goto success; 600 } 601 part = parts[index]; 602 } else { 603 //printf("not keyboard: %s\n", part.string()); 604 } 605 606 // navigation hidden 607 if (getNavHiddenName(part.string())) { 608 navHidden = part; 609 610 index++; 611 if (index == N) { 612 goto success; 613 } 614 part = parts[index]; 615 } else { 616 //printf("not navHidden: %s\n", part.string()); 617 } 618 619 if (getNavigationName(part.string())) { 620 nav = part; 621 622 index++; 623 if (index == N) { 624 goto success; 625 } 626 part = parts[index]; 627 } else { 628 //printf("not navigation: %s\n", part.string()); 629 } 630 631 if (getScreenSizeName(part.string())) { 632 size = part; 633 634 index++; 635 if (index == N) { 636 goto success; 637 } 638 part = parts[index]; 639 } else { 640 //printf("not screen size: %s\n", part.string()); 641 } 642 643 if (getVersionName(part.string())) { 644 vers = part; 645 646 index++; 647 if (index == N) { 648 goto success; 649 } 650 part = parts[index]; 651 } else { 652 //printf("not version: %s\n", part.string()); 653 } 654 655 // if there are extra parts, it doesn't match 656 return false; 657 658success: 659 this->mcc = mcc; 660 this->mnc = mnc; 661 this->locale = loc; 662 this->screenLayoutSize = layoutsize; 663 this->screenLayoutLong = layoutlong; 664 this->smallestScreenWidthDp = smallestwidthdp; 665 this->screenWidthDp = widthdp; 666 this->screenHeightDp = heightdp; 667 this->orientation = orient; 668 this->uiModeType = uiModeType; 669 this->uiModeNight = uiModeNight; 670 this->density = den; 671 this->touchscreen = touch; 672 this->keysHidden = keysHidden; 673 this->keyboard = key; 674 this->navHidden = navHidden; 675 this->navigation = nav; 676 this->screenSize = size; 677 this->version = vers; 678 679 // what is this anyway? 680 this->vendor = ""; 681 682 return true; 683} 684 685String8 686AaptGroupEntry::toString() const 687{ 688 String8 s = this->mcc; 689 s += ","; 690 s += this->mnc; 691 s += ","; 692 s += this->locale; 693 s += ","; 694 s += smallestScreenWidthDp; 695 s += ","; 696 s += screenWidthDp; 697 s += ","; 698 s += screenHeightDp; 699 s += ","; 700 s += screenLayoutSize; 701 s += ","; 702 s += screenLayoutLong; 703 s += ","; 704 s += this->orientation; 705 s += ","; 706 s += uiModeType; 707 s += ","; 708 s += uiModeNight; 709 s += ","; 710 s += density; 711 s += ","; 712 s += touchscreen; 713 s += ","; 714 s += keysHidden; 715 s += ","; 716 s += keyboard; 717 s += ","; 718 s += navHidden; 719 s += ","; 720 s += navigation; 721 s += ","; 722 s += screenSize; 723 s += ","; 724 s += version; 725 return s; 726} 727 728String8 729AaptGroupEntry::toDirName(const String8& resType) const 730{ 731 String8 s = resType; 732 if (this->mcc != "") { 733 if (s.length() > 0) { 734 s += "-"; 735 } 736 s += mcc; 737 } 738 if (this->mnc != "") { 739 if (s.length() > 0) { 740 s += "-"; 741 } 742 s += mnc; 743 } 744 if (this->locale != "") { 745 if (s.length() > 0) { 746 s += "-"; 747 } 748 s += locale; 749 } 750 if (this->smallestScreenWidthDp != "") { 751 if (s.length() > 0) { 752 s += "-"; 753 } 754 s += smallestScreenWidthDp; 755 } 756 if (this->screenWidthDp != "") { 757 if (s.length() > 0) { 758 s += "-"; 759 } 760 s += screenWidthDp; 761 } 762 if (this->screenHeightDp != "") { 763 if (s.length() > 0) { 764 s += "-"; 765 } 766 s += screenHeightDp; 767 } 768 if (this->screenLayoutSize != "") { 769 if (s.length() > 0) { 770 s += "-"; 771 } 772 s += screenLayoutSize; 773 } 774 if (this->screenLayoutLong != "") { 775 if (s.length() > 0) { 776 s += "-"; 777 } 778 s += screenLayoutLong; 779 } 780 if (this->orientation != "") { 781 if (s.length() > 0) { 782 s += "-"; 783 } 784 s += orientation; 785 } 786 if (this->uiModeType != "") { 787 if (s.length() > 0) { 788 s += "-"; 789 } 790 s += uiModeType; 791 } 792 if (this->uiModeNight != "") { 793 if (s.length() > 0) { 794 s += "-"; 795 } 796 s += uiModeNight; 797 } 798 if (this->density != "") { 799 if (s.length() > 0) { 800 s += "-"; 801 } 802 s += density; 803 } 804 if (this->touchscreen != "") { 805 if (s.length() > 0) { 806 s += "-"; 807 } 808 s += touchscreen; 809 } 810 if (this->keysHidden != "") { 811 if (s.length() > 0) { 812 s += "-"; 813 } 814 s += keysHidden; 815 } 816 if (this->keyboard != "") { 817 if (s.length() > 0) { 818 s += "-"; 819 } 820 s += keyboard; 821 } 822 if (this->navHidden != "") { 823 if (s.length() > 0) { 824 s += "-"; 825 } 826 s += navHidden; 827 } 828 if (this->navigation != "") { 829 if (s.length() > 0) { 830 s += "-"; 831 } 832 s += navigation; 833 } 834 if (this->screenSize != "") { 835 if (s.length() > 0) { 836 s += "-"; 837 } 838 s += screenSize; 839 } 840 if (this->version != "") { 841 if (s.length() > 0) { 842 s += "-"; 843 } 844 s += version; 845 } 846 847 return s; 848} 849 850bool AaptGroupEntry::getMccName(const char* name, 851 ResTable_config* out) 852{ 853 if (strcmp(name, kWildcardName) == 0) { 854 if (out) out->mcc = 0; 855 return true; 856 } 857 const char* c = name; 858 if (tolower(*c) != 'm') return false; 859 c++; 860 if (tolower(*c) != 'c') return false; 861 c++; 862 if (tolower(*c) != 'c') return false; 863 c++; 864 865 const char* val = c; 866 867 while (*c >= '0' && *c <= '9') { 868 c++; 869 } 870 if (*c != 0) return false; 871 if (c-val != 3) return false; 872 873 int d = atoi(val); 874 if (d != 0) { 875 if (out) out->mcc = d; 876 return true; 877 } 878 879 return false; 880} 881 882bool AaptGroupEntry::getMncName(const char* name, 883 ResTable_config* out) 884{ 885 if (strcmp(name, kWildcardName) == 0) { 886 if (out) out->mcc = 0; 887 return true; 888 } 889 const char* c = name; 890 if (tolower(*c) != 'm') return false; 891 c++; 892 if (tolower(*c) != 'n') return false; 893 c++; 894 if (tolower(*c) != 'c') return false; 895 c++; 896 897 const char* val = c; 898 899 while (*c >= '0' && *c <= '9') { 900 c++; 901 } 902 if (*c != 0) return false; 903 if (c-val == 0 || c-val > 3) return false; 904 905 if (out) { 906 out->mnc = atoi(val); 907 } 908 909 return true; 910} 911 912/* 913 * Does this directory name fit the pattern of a locale dir ("en-rUS" or 914 * "default")? 915 * 916 * TODO: Should insist that the first two letters are lower case, and the 917 * second two are upper. 918 */ 919bool AaptGroupEntry::getLocaleName(const char* fileName, 920 ResTable_config* out) 921{ 922 if (strcmp(fileName, kWildcardName) == 0 923 || strcmp(fileName, kDefaultLocale) == 0) { 924 if (out) { 925 out->language[0] = 0; 926 out->language[1] = 0; 927 out->country[0] = 0; 928 out->country[1] = 0; 929 } 930 return true; 931 } 932 933 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) { 934 if (out) { 935 out->language[0] = fileName[0]; 936 out->language[1] = fileName[1]; 937 out->country[0] = 0; 938 out->country[1] = 0; 939 } 940 return true; 941 } 942 943 if (strlen(fileName) == 5 && 944 isalpha(fileName[0]) && 945 isalpha(fileName[1]) && 946 fileName[2] == '-' && 947 isalpha(fileName[3]) && 948 isalpha(fileName[4])) { 949 if (out) { 950 out->language[0] = fileName[0]; 951 out->language[1] = fileName[1]; 952 out->country[0] = fileName[3]; 953 out->country[1] = fileName[4]; 954 } 955 return true; 956 } 957 958 return false; 959} 960 961bool AaptGroupEntry::getScreenLayoutSizeName(const char* name, 962 ResTable_config* out) 963{ 964 if (strcmp(name, kWildcardName) == 0) { 965 if (out) out->screenLayout = 966 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 967 | ResTable_config::SCREENSIZE_ANY; 968 return true; 969 } else if (strcmp(name, "small") == 0) { 970 if (out) out->screenLayout = 971 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 972 | ResTable_config::SCREENSIZE_SMALL; 973 return true; 974 } else if (strcmp(name, "normal") == 0) { 975 if (out) out->screenLayout = 976 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 977 | ResTable_config::SCREENSIZE_NORMAL; 978 return true; 979 } else if (strcmp(name, "large") == 0) { 980 if (out) out->screenLayout = 981 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 982 | ResTable_config::SCREENSIZE_LARGE; 983 return true; 984 } else if (strcmp(name, "xlarge") == 0) { 985 if (out) out->screenLayout = 986 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 987 | ResTable_config::SCREENSIZE_XLARGE; 988 return true; 989 } 990 991 return false; 992} 993 994bool AaptGroupEntry::getScreenLayoutLongName(const char* name, 995 ResTable_config* out) 996{ 997 if (strcmp(name, kWildcardName) == 0) { 998 if (out) out->screenLayout = 999 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 1000 | ResTable_config::SCREENLONG_ANY; 1001 return true; 1002 } else if (strcmp(name, "long") == 0) { 1003 if (out) out->screenLayout = 1004 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 1005 | ResTable_config::SCREENLONG_YES; 1006 return true; 1007 } else if (strcmp(name, "notlong") == 0) { 1008 if (out) out->screenLayout = 1009 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 1010 | ResTable_config::SCREENLONG_NO; 1011 return true; 1012 } 1013 1014 return false; 1015} 1016 1017bool AaptGroupEntry::getOrientationName(const char* name, 1018 ResTable_config* out) 1019{ 1020 if (strcmp(name, kWildcardName) == 0) { 1021 if (out) out->orientation = out->ORIENTATION_ANY; 1022 return true; 1023 } else if (strcmp(name, "port") == 0) { 1024 if (out) out->orientation = out->ORIENTATION_PORT; 1025 return true; 1026 } else if (strcmp(name, "land") == 0) { 1027 if (out) out->orientation = out->ORIENTATION_LAND; 1028 return true; 1029 } else if (strcmp(name, "square") == 0) { 1030 if (out) out->orientation = out->ORIENTATION_SQUARE; 1031 return true; 1032 } 1033 1034 return false; 1035} 1036 1037bool AaptGroupEntry::getUiModeTypeName(const char* name, 1038 ResTable_config* out) 1039{ 1040 if (strcmp(name, kWildcardName) == 0) { 1041 if (out) out->uiMode = 1042 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1043 | ResTable_config::UI_MODE_TYPE_ANY; 1044 return true; 1045 } else if (strcmp(name, "desk") == 0) { 1046 if (out) out->uiMode = 1047 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1048 | ResTable_config::UI_MODE_TYPE_DESK; 1049 return true; 1050 } else if (strcmp(name, "car") == 0) { 1051 if (out) out->uiMode = 1052 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1053 | ResTable_config::UI_MODE_TYPE_CAR; 1054 return true; 1055 } else if (strcmp(name, "television") == 0) { 1056 if (out) out->uiMode = 1057 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1058 | ResTable_config::UI_MODE_TYPE_TELEVISION; 1059 return true; 1060 } 1061 1062 return false; 1063} 1064 1065bool AaptGroupEntry::getUiModeNightName(const char* name, 1066 ResTable_config* out) 1067{ 1068 if (strcmp(name, kWildcardName) == 0) { 1069 if (out) out->uiMode = 1070 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 1071 | ResTable_config::UI_MODE_NIGHT_ANY; 1072 return true; 1073 } else if (strcmp(name, "night") == 0) { 1074 if (out) out->uiMode = 1075 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 1076 | ResTable_config::UI_MODE_NIGHT_YES; 1077 return true; 1078 } else if (strcmp(name, "notnight") == 0) { 1079 if (out) out->uiMode = 1080 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 1081 | ResTable_config::UI_MODE_NIGHT_NO; 1082 return true; 1083 } 1084 1085 return false; 1086} 1087 1088bool AaptGroupEntry::getDensityName(const char* name, 1089 ResTable_config* out) 1090{ 1091 if (strcmp(name, kWildcardName) == 0) { 1092 if (out) out->density = ResTable_config::DENSITY_DEFAULT; 1093 return true; 1094 } 1095 1096 if (strcmp(name, "nodpi") == 0) { 1097 if (out) out->density = ResTable_config::DENSITY_NONE; 1098 return true; 1099 } 1100 1101 if (strcmp(name, "ldpi") == 0) { 1102 if (out) out->density = ResTable_config::DENSITY_LOW; 1103 return true; 1104 } 1105 1106 if (strcmp(name, "mdpi") == 0) { 1107 if (out) out->density = ResTable_config::DENSITY_MEDIUM; 1108 return true; 1109 } 1110 1111 if (strcmp(name, "tvdpi") == 0) { 1112 if (out) out->density = ResTable_config::DENSITY_TV; 1113 return true; 1114 } 1115 1116 if (strcmp(name, "hdpi") == 0) { 1117 if (out) out->density = ResTable_config::DENSITY_HIGH; 1118 return true; 1119 } 1120 1121 if (strcmp(name, "xhdpi") == 0) { 1122 if (out) out->density = ResTable_config::DENSITY_MEDIUM*2; 1123 return true; 1124 } 1125 1126 char* c = (char*)name; 1127 while (*c >= '0' && *c <= '9') { 1128 c++; 1129 } 1130 1131 // check that we have 'dpi' after the last digit. 1132 if (toupper(c[0]) != 'D' || 1133 toupper(c[1]) != 'P' || 1134 toupper(c[2]) != 'I' || 1135 c[3] != 0) { 1136 return false; 1137 } 1138 1139 // temporarily replace the first letter with \0 to 1140 // use atoi. 1141 char tmp = c[0]; 1142 c[0] = '\0'; 1143 1144 int d = atoi(name); 1145 c[0] = tmp; 1146 1147 if (d != 0) { 1148 if (out) out->density = d; 1149 return true; 1150 } 1151 1152 return false; 1153} 1154 1155bool AaptGroupEntry::getTouchscreenName(const char* name, 1156 ResTable_config* out) 1157{ 1158 if (strcmp(name, kWildcardName) == 0) { 1159 if (out) out->touchscreen = out->TOUCHSCREEN_ANY; 1160 return true; 1161 } else if (strcmp(name, "notouch") == 0) { 1162 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH; 1163 return true; 1164 } else if (strcmp(name, "stylus") == 0) { 1165 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS; 1166 return true; 1167 } else if (strcmp(name, "finger") == 0) { 1168 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER; 1169 return true; 1170 } 1171 1172 return false; 1173} 1174 1175bool AaptGroupEntry::getKeysHiddenName(const char* name, 1176 ResTable_config* out) 1177{ 1178 uint8_t mask = 0; 1179 uint8_t value = 0; 1180 if (strcmp(name, kWildcardName) == 0) { 1181 mask = ResTable_config::MASK_KEYSHIDDEN; 1182 value = ResTable_config::KEYSHIDDEN_ANY; 1183 } else if (strcmp(name, "keysexposed") == 0) { 1184 mask = ResTable_config::MASK_KEYSHIDDEN; 1185 value = ResTable_config::KEYSHIDDEN_NO; 1186 } else if (strcmp(name, "keyshidden") == 0) { 1187 mask = ResTable_config::MASK_KEYSHIDDEN; 1188 value = ResTable_config::KEYSHIDDEN_YES; 1189 } else if (strcmp(name, "keyssoft") == 0) { 1190 mask = ResTable_config::MASK_KEYSHIDDEN; 1191 value = ResTable_config::KEYSHIDDEN_SOFT; 1192 } 1193 1194 if (mask != 0) { 1195 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 1196 return true; 1197 } 1198 1199 return false; 1200} 1201 1202bool AaptGroupEntry::getKeyboardName(const char* name, 1203 ResTable_config* out) 1204{ 1205 if (strcmp(name, kWildcardName) == 0) { 1206 if (out) out->keyboard = out->KEYBOARD_ANY; 1207 return true; 1208 } else if (strcmp(name, "nokeys") == 0) { 1209 if (out) out->keyboard = out->KEYBOARD_NOKEYS; 1210 return true; 1211 } else if (strcmp(name, "qwerty") == 0) { 1212 if (out) out->keyboard = out->KEYBOARD_QWERTY; 1213 return true; 1214 } else if (strcmp(name, "12key") == 0) { 1215 if (out) out->keyboard = out->KEYBOARD_12KEY; 1216 return true; 1217 } 1218 1219 return false; 1220} 1221 1222bool AaptGroupEntry::getNavHiddenName(const char* name, 1223 ResTable_config* out) 1224{ 1225 uint8_t mask = 0; 1226 uint8_t value = 0; 1227 if (strcmp(name, kWildcardName) == 0) { 1228 mask = ResTable_config::MASK_NAVHIDDEN; 1229 value = ResTable_config::NAVHIDDEN_ANY; 1230 } else if (strcmp(name, "navexposed") == 0) { 1231 mask = ResTable_config::MASK_NAVHIDDEN; 1232 value = ResTable_config::NAVHIDDEN_NO; 1233 } else if (strcmp(name, "navhidden") == 0) { 1234 mask = ResTable_config::MASK_NAVHIDDEN; 1235 value = ResTable_config::NAVHIDDEN_YES; 1236 } 1237 1238 if (mask != 0) { 1239 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 1240 return true; 1241 } 1242 1243 return false; 1244} 1245 1246bool AaptGroupEntry::getNavigationName(const char* name, 1247 ResTable_config* out) 1248{ 1249 if (strcmp(name, kWildcardName) == 0) { 1250 if (out) out->navigation = out->NAVIGATION_ANY; 1251 return true; 1252 } else if (strcmp(name, "nonav") == 0) { 1253 if (out) out->navigation = out->NAVIGATION_NONAV; 1254 return true; 1255 } else if (strcmp(name, "dpad") == 0) { 1256 if (out) out->navigation = out->NAVIGATION_DPAD; 1257 return true; 1258 } else if (strcmp(name, "trackball") == 0) { 1259 if (out) out->navigation = out->NAVIGATION_TRACKBALL; 1260 return true; 1261 } else if (strcmp(name, "wheel") == 0) { 1262 if (out) out->navigation = out->NAVIGATION_WHEEL; 1263 return true; 1264 } 1265 1266 return false; 1267} 1268 1269bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out) 1270{ 1271 if (strcmp(name, kWildcardName) == 0) { 1272 if (out) { 1273 out->screenWidth = out->SCREENWIDTH_ANY; 1274 out->screenHeight = out->SCREENHEIGHT_ANY; 1275 } 1276 return true; 1277 } 1278 1279 const char* x = name; 1280 while (*x >= '0' && *x <= '9') x++; 1281 if (x == name || *x != 'x') return false; 1282 String8 xName(name, x-name); 1283 x++; 1284 1285 const char* y = x; 1286 while (*y >= '0' && *y <= '9') y++; 1287 if (y == name || *y != 0) return false; 1288 String8 yName(x, y-x); 1289 1290 uint16_t w = (uint16_t)atoi(xName.string()); 1291 uint16_t h = (uint16_t)atoi(yName.string()); 1292 if (w < h) { 1293 return false; 1294 } 1295 1296 if (out) { 1297 out->screenWidth = w; 1298 out->screenHeight = h; 1299 } 1300 1301 return true; 1302} 1303 1304bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out) 1305{ 1306 if (strcmp(name, kWildcardName) == 0) { 1307 if (out) { 1308 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY; 1309 } 1310 return true; 1311 } 1312 1313 if (*name != 's') return false; 1314 name++; 1315 if (*name != 'w') return false; 1316 name++; 1317 const char* x = name; 1318 while (*x >= '0' && *x <= '9') x++; 1319 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 1320 String8 xName(name, x-name); 1321 1322 if (out) { 1323 out->smallestScreenWidthDp = (uint16_t)atoi(xName.string()); 1324 } 1325 1326 return true; 1327} 1328 1329bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out) 1330{ 1331 if (strcmp(name, kWildcardName) == 0) { 1332 if (out) { 1333 out->screenWidthDp = out->SCREENWIDTH_ANY; 1334 } 1335 return true; 1336 } 1337 1338 if (*name != 'w') return false; 1339 name++; 1340 const char* x = name; 1341 while (*x >= '0' && *x <= '9') x++; 1342 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 1343 String8 xName(name, x-name); 1344 1345 if (out) { 1346 out->screenWidthDp = (uint16_t)atoi(xName.string()); 1347 } 1348 1349 return true; 1350} 1351 1352bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out) 1353{ 1354 if (strcmp(name, kWildcardName) == 0) { 1355 if (out) { 1356 out->screenHeightDp = out->SCREENWIDTH_ANY; 1357 } 1358 return true; 1359 } 1360 1361 if (*name != 'h') return false; 1362 name++; 1363 const char* x = name; 1364 while (*x >= '0' && *x <= '9') x++; 1365 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 1366 String8 xName(name, x-name); 1367 1368 if (out) { 1369 out->screenHeightDp = (uint16_t)atoi(xName.string()); 1370 } 1371 1372 return true; 1373} 1374 1375bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out) 1376{ 1377 if (strcmp(name, kWildcardName) == 0) { 1378 if (out) { 1379 out->sdkVersion = out->SDKVERSION_ANY; 1380 out->minorVersion = out->MINORVERSION_ANY; 1381 } 1382 return true; 1383 } 1384 1385 if (*name != 'v') { 1386 return false; 1387 } 1388 1389 name++; 1390 const char* s = name; 1391 while (*s >= '0' && *s <= '9') s++; 1392 if (s == name || *s != 0) return false; 1393 String8 sdkName(name, s-name); 1394 1395 if (out) { 1396 out->sdkVersion = (uint16_t)atoi(sdkName.string()); 1397 out->minorVersion = 0; 1398 } 1399 1400 return true; 1401} 1402 1403int AaptGroupEntry::compare(const AaptGroupEntry& o) const 1404{ 1405 int v = mcc.compare(o.mcc); 1406 if (v == 0) v = mnc.compare(o.mnc); 1407 if (v == 0) v = locale.compare(o.locale); 1408 if (v == 0) v = vendor.compare(o.vendor); 1409 if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp); 1410 if (v == 0) v = screenWidthDp.compare(o.screenWidthDp); 1411 if (v == 0) v = screenHeightDp.compare(o.screenHeightDp); 1412 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize); 1413 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong); 1414 if (v == 0) v = orientation.compare(o.orientation); 1415 if (v == 0) v = uiModeType.compare(o.uiModeType); 1416 if (v == 0) v = uiModeNight.compare(o.uiModeNight); 1417 if (v == 0) v = density.compare(o.density); 1418 if (v == 0) v = touchscreen.compare(o.touchscreen); 1419 if (v == 0) v = keysHidden.compare(o.keysHidden); 1420 if (v == 0) v = keyboard.compare(o.keyboard); 1421 if (v == 0) v = navHidden.compare(o.navHidden); 1422 if (v == 0) v = navigation.compare(o.navigation); 1423 if (v == 0) v = screenSize.compare(o.screenSize); 1424 if (v == 0) v = version.compare(o.version); 1425 return v; 1426} 1427 1428const ResTable_config& AaptGroupEntry::toParams() const 1429{ 1430 if (!mParamsChanged) { 1431 return mParams; 1432 } 1433 1434 mParamsChanged = false; 1435 ResTable_config& params(mParams); 1436 memset(¶ms, 0, sizeof(params)); 1437 getMccName(mcc.string(), ¶ms); 1438 getMncName(mnc.string(), ¶ms); 1439 getLocaleName(locale.string(), ¶ms); 1440 getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), ¶ms); 1441 getScreenWidthDpName(screenWidthDp.string(), ¶ms); 1442 getScreenHeightDpName(screenHeightDp.string(), ¶ms); 1443 getScreenLayoutSizeName(screenLayoutSize.string(), ¶ms); 1444 getScreenLayoutLongName(screenLayoutLong.string(), ¶ms); 1445 getOrientationName(orientation.string(), ¶ms); 1446 getUiModeTypeName(uiModeType.string(), ¶ms); 1447 getUiModeNightName(uiModeNight.string(), ¶ms); 1448 getDensityName(density.string(), ¶ms); 1449 getTouchscreenName(touchscreen.string(), ¶ms); 1450 getKeysHiddenName(keysHidden.string(), ¶ms); 1451 getKeyboardName(keyboard.string(), ¶ms); 1452 getNavHiddenName(navHidden.string(), ¶ms); 1453 getNavigationName(navigation.string(), ¶ms); 1454 getScreenSizeName(screenSize.string(), ¶ms); 1455 getVersionName(version.string(), ¶ms); 1456 1457 // Fix up version number based on specified parameters. 1458 int minSdk = 0; 1459 if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY 1460 || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY 1461 || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) { 1462 minSdk = SDK_HONEYCOMB_MR2; 1463 } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE) 1464 != ResTable_config::UI_MODE_TYPE_ANY 1465 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) 1466 != ResTable_config::UI_MODE_NIGHT_ANY) { 1467 minSdk = SDK_FROYO; 1468 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE) 1469 != ResTable_config::SCREENSIZE_ANY 1470 || (params.screenLayout&ResTable_config::MASK_SCREENLONG) 1471 != ResTable_config::SCREENLONG_ANY 1472 || params.density != ResTable_config::DENSITY_DEFAULT) { 1473 minSdk = SDK_DONUT; 1474 } 1475 1476 if (minSdk > params.sdkVersion) { 1477 params.sdkVersion = minSdk; 1478 } 1479 1480 return params; 1481} 1482 1483// ========================================================================= 1484// ========================================================================= 1485// ========================================================================= 1486 1487void* AaptFile::editData(size_t size) 1488{ 1489 if (size <= mBufferSize) { 1490 mDataSize = size; 1491 return mData; 1492 } 1493 size_t allocSize = (size*3)/2; 1494 void* buf = realloc(mData, allocSize); 1495 if (buf == NULL) { 1496 return NULL; 1497 } 1498 mData = buf; 1499 mDataSize = size; 1500 mBufferSize = allocSize; 1501 return buf; 1502} 1503 1504void* AaptFile::editData(size_t* outSize) 1505{ 1506 if (outSize) { 1507 *outSize = mDataSize; 1508 } 1509 return mData; 1510} 1511 1512void* AaptFile::padData(size_t wordSize) 1513{ 1514 const size_t extra = mDataSize%wordSize; 1515 if (extra == 0) { 1516 return mData; 1517 } 1518 1519 size_t initial = mDataSize; 1520 void* data = editData(initial+(wordSize-extra)); 1521 if (data != NULL) { 1522 memset(((uint8_t*)data) + initial, 0, wordSize-extra); 1523 } 1524 return data; 1525} 1526 1527status_t AaptFile::writeData(const void* data, size_t size) 1528{ 1529 size_t end = mDataSize; 1530 size_t total = size + end; 1531 void* buf = editData(total); 1532 if (buf == NULL) { 1533 return UNKNOWN_ERROR; 1534 } 1535 memcpy(((char*)buf)+end, data, size); 1536 return NO_ERROR; 1537} 1538 1539void AaptFile::clearData() 1540{ 1541 if (mData != NULL) free(mData); 1542 mData = NULL; 1543 mDataSize = 0; 1544 mBufferSize = 0; 1545} 1546 1547String8 AaptFile::getPrintableSource() const 1548{ 1549 if (hasData()) { 1550 String8 name(mGroupEntry.toDirName(String8())); 1551 name.appendPath(mPath); 1552 name.append(" #generated"); 1553 return name; 1554 } 1555 return mSourceFile; 1556} 1557 1558// ========================================================================= 1559// ========================================================================= 1560// ========================================================================= 1561 1562status_t AaptGroup::addFile(const sp<AaptFile>& file) 1563{ 1564 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) { 1565 file->mPath = mPath; 1566 mFiles.add(file->getGroupEntry(), file); 1567 return NO_ERROR; 1568 } 1569 1570#if 0 1571 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n", 1572 file->getSourceFile().string(), 1573 file->getGroupEntry().toDirName(String8()).string(), 1574 mLeaf.string(), mPath.string()); 1575#endif 1576 1577 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", 1578 getPrintableSource().string()); 1579 return UNKNOWN_ERROR; 1580} 1581 1582void AaptGroup::removeFile(size_t index) 1583{ 1584 mFiles.removeItemsAt(index); 1585} 1586 1587void AaptGroup::print(const String8& prefix) const 1588{ 1589 printf("%s%s\n", prefix.string(), getPath().string()); 1590 const size_t N=mFiles.size(); 1591 size_t i; 1592 for (i=0; i<N; i++) { 1593 sp<AaptFile> file = mFiles.valueAt(i); 1594 const AaptGroupEntry& e = file->getGroupEntry(); 1595 if (file->hasData()) { 1596 printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(), 1597 (int)file->getSize()); 1598 } else { 1599 printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(), 1600 file->getPrintableSource().string()); 1601 } 1602 //printf("%s File Group Entry: %s\n", prefix.string(), 1603 // file->getGroupEntry().toDirName(String8()).string()); 1604 } 1605} 1606 1607String8 AaptGroup::getPrintableSource() const 1608{ 1609 if (mFiles.size() > 0) { 1610 // Arbitrarily pull the first source file out of the list. 1611 return mFiles.valueAt(0)->getPrintableSource(); 1612 } 1613 1614 // Should never hit this case, but to be safe... 1615 return getPath(); 1616 1617} 1618 1619// ========================================================================= 1620// ========================================================================= 1621// ========================================================================= 1622 1623status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file) 1624{ 1625 if (mFiles.indexOfKey(name) >= 0) { 1626 return ALREADY_EXISTS; 1627 } 1628 mFiles.add(name, file); 1629 return NO_ERROR; 1630} 1631 1632status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir) 1633{ 1634 if (mDirs.indexOfKey(name) >= 0) { 1635 return ALREADY_EXISTS; 1636 } 1637 mDirs.add(name, dir); 1638 return NO_ERROR; 1639} 1640 1641sp<AaptDir> AaptDir::makeDir(const String8& path) 1642{ 1643 String8 name; 1644 String8 remain = path; 1645 1646 sp<AaptDir> subdir = this; 1647 while (name = remain.walkPath(&remain), remain != "") { 1648 subdir = subdir->makeDir(name); 1649 } 1650 1651 ssize_t i = subdir->mDirs.indexOfKey(name); 1652 if (i >= 0) { 1653 return subdir->mDirs.valueAt(i); 1654 } 1655 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name)); 1656 subdir->mDirs.add(name, dir); 1657 return dir; 1658} 1659 1660void AaptDir::removeFile(const String8& name) 1661{ 1662 mFiles.removeItem(name); 1663} 1664 1665void AaptDir::removeDir(const String8& name) 1666{ 1667 mDirs.removeItem(name); 1668} 1669 1670status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file) 1671{ 1672 sp<AaptGroup> group; 1673 if (mFiles.indexOfKey(leafName) >= 0) { 1674 group = mFiles.valueFor(leafName); 1675 } else { 1676 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName)); 1677 mFiles.add(leafName, group); 1678 } 1679 1680 return group->addFile(file); 1681} 1682 1683ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, 1684 const AaptGroupEntry& kind, const String8& resType, 1685 sp<FilePathStore>& fullResPaths) 1686{ 1687 Vector<String8> fileNames; 1688 { 1689 DIR* dir = NULL; 1690 1691 dir = opendir(srcDir.string()); 1692 if (dir == NULL) { 1693 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 1694 return UNKNOWN_ERROR; 1695 } 1696 1697 /* 1698 * Slurp the filenames out of the directory. 1699 */ 1700 while (1) { 1701 struct dirent* entry; 1702 1703 entry = readdir(dir); 1704 if (entry == NULL) 1705 break; 1706 1707 if (isHidden(srcDir.string(), entry->d_name)) 1708 continue; 1709 1710 String8 name(entry->d_name); 1711 fileNames.add(name); 1712 // Add fully qualified path for dependency purposes 1713 // if we're collecting them 1714 if (fullResPaths != NULL) { 1715 fullResPaths->add(srcDir.appendPathCopy(name)); 1716 } 1717 } 1718 closedir(dir); 1719 } 1720 1721 ssize_t count = 0; 1722 1723 /* 1724 * Stash away the files and recursively descend into subdirectories. 1725 */ 1726 const size_t N = fileNames.size(); 1727 size_t i; 1728 for (i = 0; i < N; i++) { 1729 String8 pathName(srcDir); 1730 FileType type; 1731 1732 pathName.appendPath(fileNames[i].string()); 1733 type = getFileType(pathName.string()); 1734 if (type == kFileTypeDirectory) { 1735 sp<AaptDir> subdir; 1736 bool notAdded = false; 1737 if (mDirs.indexOfKey(fileNames[i]) >= 0) { 1738 subdir = mDirs.valueFor(fileNames[i]); 1739 } else { 1740 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i])); 1741 notAdded = true; 1742 } 1743 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, 1744 resType, fullResPaths); 1745 if (res < NO_ERROR) { 1746 return res; 1747 } 1748 if (res > 0 && notAdded) { 1749 mDirs.add(fileNames[i], subdir); 1750 } 1751 count += res; 1752 } else if (type == kFileTypeRegular) { 1753 sp<AaptFile> file = new AaptFile(pathName, kind, resType); 1754 status_t err = addLeafFile(fileNames[i], file); 1755 if (err != NO_ERROR) { 1756 return err; 1757 } 1758 1759 count++; 1760 1761 } else { 1762 if (bundle->getVerbose()) 1763 printf(" (ignoring non-file/dir '%s')\n", pathName.string()); 1764 } 1765 } 1766 1767 return count; 1768} 1769 1770status_t AaptDir::validate() const 1771{ 1772 const size_t NF = mFiles.size(); 1773 const size_t ND = mDirs.size(); 1774 size_t i; 1775 for (i = 0; i < NF; i++) { 1776 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) { 1777 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1778 "Invalid filename. Unable to add."); 1779 return UNKNOWN_ERROR; 1780 } 1781 1782 size_t j; 1783 for (j = i+1; j < NF; j++) { 1784 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1785 mFiles.valueAt(j)->getLeaf().string()) == 0) { 1786 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1787 "File is case-insensitive equivalent to: %s", 1788 mFiles.valueAt(j)->getPrintableSource().string()); 1789 return UNKNOWN_ERROR; 1790 } 1791 1792 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" 1793 // (this is mostly caught by the "marked" stuff, below) 1794 } 1795 1796 for (j = 0; j < ND; j++) { 1797 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1798 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1799 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1800 "File conflicts with dir from: %s", 1801 mDirs.valueAt(j)->getPrintableSource().string()); 1802 return UNKNOWN_ERROR; 1803 } 1804 } 1805 } 1806 1807 for (i = 0; i < ND; i++) { 1808 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) { 1809 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1810 "Invalid directory name, unable to add."); 1811 return UNKNOWN_ERROR; 1812 } 1813 1814 size_t j; 1815 for (j = i+1; j < ND; j++) { 1816 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(), 1817 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1818 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1819 "Directory is case-insensitive equivalent to: %s", 1820 mDirs.valueAt(j)->getPrintableSource().string()); 1821 return UNKNOWN_ERROR; 1822 } 1823 } 1824 1825 status_t err = mDirs.valueAt(i)->validate(); 1826 if (err != NO_ERROR) { 1827 return err; 1828 } 1829 } 1830 1831 return NO_ERROR; 1832} 1833 1834void AaptDir::print(const String8& prefix) const 1835{ 1836 const size_t ND=getDirs().size(); 1837 size_t i; 1838 for (i=0; i<ND; i++) { 1839 getDirs().valueAt(i)->print(prefix); 1840 } 1841 1842 const size_t NF=getFiles().size(); 1843 for (i=0; i<NF; i++) { 1844 getFiles().valueAt(i)->print(prefix); 1845 } 1846} 1847 1848String8 AaptDir::getPrintableSource() const 1849{ 1850 if (mFiles.size() > 0) { 1851 // Arbitrarily pull the first file out of the list as the source dir. 1852 return mFiles.valueAt(0)->getPrintableSource().getPathDir(); 1853 } 1854 if (mDirs.size() > 0) { 1855 // Or arbitrarily pull the first dir out of the list as the source dir. 1856 return mDirs.valueAt(0)->getPrintableSource().getPathDir(); 1857 } 1858 1859 // Should never hit this case, but to be safe... 1860 return mPath; 1861 1862} 1863 1864// ========================================================================= 1865// ========================================================================= 1866// ========================================================================= 1867 1868AaptAssets::AaptAssets() 1869 : AaptDir(String8(), String8()), 1870 mChanged(false), mHaveIncludedAssets(false), mRes(NULL) 1871{ 1872} 1873 1874const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const { 1875 if (mChanged) { 1876 } 1877 return mGroupEntries; 1878} 1879 1880status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file) 1881{ 1882 mChanged = true; 1883 return AaptDir::addFile(name, file); 1884} 1885 1886sp<AaptFile> AaptAssets::addFile( 1887 const String8& filePath, const AaptGroupEntry& entry, 1888 const String8& srcDir, sp<AaptGroup>* outGroup, 1889 const String8& resType) 1890{ 1891 sp<AaptDir> dir = this; 1892 sp<AaptGroup> group; 1893 sp<AaptFile> file; 1894 String8 root, remain(filePath), partialPath; 1895 while (remain.length() > 0) { 1896 root = remain.walkPath(&remain); 1897 partialPath.appendPath(root); 1898 1899 const String8 rootStr(root); 1900 1901 if (remain.length() == 0) { 1902 ssize_t i = dir->getFiles().indexOfKey(rootStr); 1903 if (i >= 0) { 1904 group = dir->getFiles().valueAt(i); 1905 } else { 1906 group = new AaptGroup(rootStr, filePath); 1907 status_t res = dir->addFile(rootStr, group); 1908 if (res != NO_ERROR) { 1909 return NULL; 1910 } 1911 } 1912 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType); 1913 status_t res = group->addFile(file); 1914 if (res != NO_ERROR) { 1915 return NULL; 1916 } 1917 break; 1918 1919 } else { 1920 ssize_t i = dir->getDirs().indexOfKey(rootStr); 1921 if (i >= 0) { 1922 dir = dir->getDirs().valueAt(i); 1923 } else { 1924 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath); 1925 status_t res = dir->addDir(rootStr, subdir); 1926 if (res != NO_ERROR) { 1927 return NULL; 1928 } 1929 dir = subdir; 1930 } 1931 } 1932 } 1933 1934 mGroupEntries.add(entry); 1935 if (outGroup) *outGroup = group; 1936 return file; 1937} 1938 1939void AaptAssets::addResource(const String8& leafName, const String8& path, 1940 const sp<AaptFile>& file, const String8& resType) 1941{ 1942 sp<AaptDir> res = AaptDir::makeDir(kResString); 1943 String8 dirname = file->getGroupEntry().toDirName(resType); 1944 sp<AaptDir> subdir = res->makeDir(dirname); 1945 sp<AaptGroup> grr = new AaptGroup(leafName, path); 1946 grr->addFile(file); 1947 1948 subdir->addFile(leafName, grr); 1949} 1950 1951 1952ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) 1953{ 1954 int count; 1955 int totalCount = 0; 1956 FileType type; 1957 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs(); 1958 const size_t dirCount =resDirs.size(); 1959 sp<AaptAssets> current = this; 1960 1961 const int N = bundle->getFileSpecCount(); 1962 1963 /* 1964 * If a package manifest was specified, include that first. 1965 */ 1966 if (bundle->getAndroidManifestFile() != NULL) { 1967 // place at root of zip. 1968 String8 srcFile(bundle->getAndroidManifestFile()); 1969 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(), 1970 NULL, String8()); 1971 totalCount++; 1972 } 1973 1974 /* 1975 * If a directory of custom assets was supplied, slurp 'em up. 1976 */ 1977 if (bundle->getAssetSourceDir()) { 1978 const char* assetDir = bundle->getAssetSourceDir(); 1979 1980 FileType type = getFileType(assetDir); 1981 if (type == kFileTypeNonexistent) { 1982 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir); 1983 return UNKNOWN_ERROR; 1984 } 1985 if (type != kFileTypeDirectory) { 1986 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 1987 return UNKNOWN_ERROR; 1988 } 1989 1990 String8 assetRoot(assetDir); 1991 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir)); 1992 AaptGroupEntry group; 1993 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, 1994 String8(), mFullAssetPaths); 1995 if (count < 0) { 1996 totalCount = count; 1997 goto bail; 1998 } 1999 if (count > 0) { 2000 mGroupEntries.add(group); 2001 } 2002 totalCount += count; 2003 2004 if (bundle->getVerbose()) 2005 printf("Found %d custom asset file%s in %s\n", 2006 count, (count==1) ? "" : "s", assetDir); 2007 } 2008 2009 /* 2010 * If a directory of resource-specific assets was supplied, slurp 'em up. 2011 */ 2012 for (size_t i=0; i<dirCount; i++) { 2013 const char *res = resDirs[i]; 2014 if (res) { 2015 type = getFileType(res); 2016 if (type == kFileTypeNonexistent) { 2017 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res); 2018 return UNKNOWN_ERROR; 2019 } 2020 if (type == kFileTypeDirectory) { 2021 if (i>0) { 2022 sp<AaptAssets> nextOverlay = new AaptAssets(); 2023 current->setOverlay(nextOverlay); 2024 current = nextOverlay; 2025 current->setFullResPaths(mFullResPaths); 2026 } 2027 count = current->slurpResourceTree(bundle, String8(res)); 2028 2029 if (count < 0) { 2030 totalCount = count; 2031 goto bail; 2032 } 2033 totalCount += count; 2034 } 2035 else { 2036 fprintf(stderr, "ERROR: '%s' is not a directory\n", res); 2037 return UNKNOWN_ERROR; 2038 } 2039 } 2040 2041 } 2042 /* 2043 * Now do any additional raw files. 2044 */ 2045 for (int arg=0; arg<N; arg++) { 2046 const char* assetDir = bundle->getFileSpecEntry(arg); 2047 2048 FileType type = getFileType(assetDir); 2049 if (type == kFileTypeNonexistent) { 2050 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir); 2051 return UNKNOWN_ERROR; 2052 } 2053 if (type != kFileTypeDirectory) { 2054 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 2055 return UNKNOWN_ERROR; 2056 } 2057 2058 String8 assetRoot(assetDir); 2059 2060 if (bundle->getVerbose()) 2061 printf("Processing raw dir '%s'\n", (const char*) assetDir); 2062 2063 /* 2064 * Do a recursive traversal of subdir tree. We don't make any 2065 * guarantees about ordering, so we're okay with an inorder search 2066 * using whatever order the OS happens to hand back to us. 2067 */ 2068 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths); 2069 if (count < 0) { 2070 /* failure; report error and remove archive */ 2071 totalCount = count; 2072 goto bail; 2073 } 2074 totalCount += count; 2075 2076 if (bundle->getVerbose()) 2077 printf("Found %d asset file%s in %s\n", 2078 count, (count==1) ? "" : "s", assetDir); 2079 } 2080 2081 count = validate(); 2082 if (count != NO_ERROR) { 2083 totalCount = count; 2084 goto bail; 2085 } 2086 2087 count = filter(bundle); 2088 if (count != NO_ERROR) { 2089 totalCount = count; 2090 goto bail; 2091 } 2092 2093bail: 2094 return totalCount; 2095} 2096 2097ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, 2098 const AaptGroupEntry& kind, 2099 const String8& resType, 2100 sp<FilePathStore>& fullResPaths) 2101{ 2102 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths); 2103 if (res > 0) { 2104 mGroupEntries.add(kind); 2105 } 2106 2107 return res; 2108} 2109 2110ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) 2111{ 2112 ssize_t err = 0; 2113 2114 DIR* dir = opendir(srcDir.string()); 2115 if (dir == NULL) { 2116 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 2117 return UNKNOWN_ERROR; 2118 } 2119 2120 status_t count = 0; 2121 2122 /* 2123 * Run through the directory, looking for dirs that match the 2124 * expected pattern. 2125 */ 2126 while (1) { 2127 struct dirent* entry = readdir(dir); 2128 if (entry == NULL) { 2129 break; 2130 } 2131 2132 if (isHidden(srcDir.string(), entry->d_name)) { 2133 continue; 2134 } 2135 2136 String8 subdirName(srcDir); 2137 subdirName.appendPath(entry->d_name); 2138 2139 AaptGroupEntry group; 2140 String8 resType; 2141 bool b = group.initFromDirName(entry->d_name, &resType); 2142 if (!b) { 2143 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(), 2144 entry->d_name); 2145 err = -1; 2146 continue; 2147 } 2148 2149 if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) { 2150 int maxResInt = atoi(bundle->getMaxResVersion()); 2151 const char *verString = group.getVersionString().string(); 2152 int dirVersionInt = atoi(verString + 1); // skip 'v' in version name 2153 if (dirVersionInt > maxResInt) { 2154 fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name); 2155 continue; 2156 } 2157 } 2158 2159 FileType type = getFileType(subdirName.string()); 2160 2161 if (type == kFileTypeDirectory) { 2162 sp<AaptDir> dir = makeDir(resType); 2163 ssize_t res = dir->slurpFullTree(bundle, subdirName, group, 2164 resType, mFullResPaths); 2165 if (res < 0) { 2166 count = res; 2167 goto bail; 2168 } 2169 if (res > 0) { 2170 mGroupEntries.add(group); 2171 count += res; 2172 } 2173 2174 // Only add this directory if we don't already have a resource dir 2175 // for the current type. This ensures that we only add the dir once 2176 // for all configs. 2177 sp<AaptDir> rdir = resDir(resType); 2178 if (rdir == NULL) { 2179 mResDirs.add(dir); 2180 } 2181 } else { 2182 if (bundle->getVerbose()) { 2183 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string()); 2184 } 2185 } 2186 } 2187 2188bail: 2189 closedir(dir); 2190 dir = NULL; 2191 2192 if (err != 0) { 2193 return err; 2194 } 2195 return count; 2196} 2197 2198ssize_t 2199AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename) 2200{ 2201 int count = 0; 2202 SortedVector<AaptGroupEntry> entries; 2203 2204 ZipFile* zip = new ZipFile; 2205 status_t err = zip->open(filename, ZipFile::kOpenReadOnly); 2206 if (err != NO_ERROR) { 2207 fprintf(stderr, "error opening zip file %s\n", filename); 2208 count = err; 2209 delete zip; 2210 return -1; 2211 } 2212 2213 const int N = zip->getNumEntries(); 2214 for (int i=0; i<N; i++) { 2215 ZipEntry* entry = zip->getEntryByIndex(i); 2216 if (entry->getDeleted()) { 2217 continue; 2218 } 2219 2220 String8 entryName(entry->getFileName()); 2221 2222 String8 dirName = entryName.getPathDir(); 2223 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName); 2224 2225 String8 resType; 2226 AaptGroupEntry kind; 2227 2228 String8 remain; 2229 if (entryName.walkPath(&remain) == kResourceDir) { 2230 // these are the resources, pull their type out of the directory name 2231 kind.initFromDirName(remain.walkPath().string(), &resType); 2232 } else { 2233 // these are untyped and don't have an AaptGroupEntry 2234 } 2235 if (entries.indexOf(kind) < 0) { 2236 entries.add(kind); 2237 mGroupEntries.add(kind); 2238 } 2239 2240 // use the one from the zip file if they both exist. 2241 dir->removeFile(entryName.getPathLeaf()); 2242 2243 sp<AaptFile> file = new AaptFile(entryName, kind, resType); 2244 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file); 2245 if (err != NO_ERROR) { 2246 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string()); 2247 count = err; 2248 goto bail; 2249 } 2250 file->setCompressionMethod(entry->getCompressionMethod()); 2251 2252#if 0 2253 if (entryName == "AndroidManifest.xml") { 2254 printf("AndroidManifest.xml\n"); 2255 } 2256 printf("\n\nfile: %s\n", entryName.string()); 2257#endif 2258 2259 size_t len = entry->getUncompressedLen(); 2260 void* data = zip->uncompress(entry); 2261 void* buf = file->editData(len); 2262 memcpy(buf, data, len); 2263 2264#if 0 2265 const int OFF = 0; 2266 const unsigned char* p = (unsigned char*)data; 2267 const unsigned char* end = p+len; 2268 p += OFF; 2269 for (int i=0; i<32 && p < end; i++) { 2270 printf("0x%03x ", i*0x10 + OFF); 2271 for (int j=0; j<0x10 && p < end; j++) { 2272 printf(" %02x", *p); 2273 p++; 2274 } 2275 printf("\n"); 2276 } 2277#endif 2278 2279 free(data); 2280 2281 count++; 2282 } 2283 2284bail: 2285 delete zip; 2286 return count; 2287} 2288 2289status_t AaptAssets::filter(Bundle* bundle) 2290{ 2291 ResourceFilter reqFilter; 2292 status_t err = reqFilter.parse(bundle->getConfigurations()); 2293 if (err != NO_ERROR) { 2294 return err; 2295 } 2296 2297 ResourceFilter prefFilter; 2298 err = prefFilter.parse(bundle->getPreferredConfigurations()); 2299 if (err != NO_ERROR) { 2300 return err; 2301 } 2302 2303 if (reqFilter.isEmpty() && prefFilter.isEmpty()) { 2304 return NO_ERROR; 2305 } 2306 2307 if (bundle->getVerbose()) { 2308 if (!reqFilter.isEmpty()) { 2309 printf("Applying required filter: %s\n", 2310 bundle->getConfigurations()); 2311 } 2312 if (!prefFilter.isEmpty()) { 2313 printf("Applying preferred filter: %s\n", 2314 bundle->getPreferredConfigurations()); 2315 } 2316 } 2317 2318 const Vector<sp<AaptDir> >& resdirs = mResDirs; 2319 const size_t ND = resdirs.size(); 2320 for (size_t i=0; i<ND; i++) { 2321 const sp<AaptDir>& dir = resdirs.itemAt(i); 2322 if (dir->getLeaf() == kValuesDir) { 2323 // The "value" dir is special since a single file defines 2324 // multiple resources, so we can not do filtering on the 2325 // files themselves. 2326 continue; 2327 } 2328 if (dir->getLeaf() == kMipmapDir) { 2329 // We also skip the "mipmap" directory, since the point of this 2330 // is to include all densities without stripping. If you put 2331 // other configurations in here as well they won't be stripped 2332 // either... So don't do that. Seriously. What is wrong with you? 2333 continue; 2334 } 2335 2336 const size_t NG = dir->getFiles().size(); 2337 for (size_t j=0; j<NG; j++) { 2338 sp<AaptGroup> grp = dir->getFiles().valueAt(j); 2339 2340 // First remove any configurations we know we don't need. 2341 for (size_t k=0; k<grp->getFiles().size(); k++) { 2342 sp<AaptFile> file = grp->getFiles().valueAt(k); 2343 if (k == 0 && grp->getFiles().size() == 1) { 2344 // If this is the only file left, we need to keep it. 2345 // Otherwise the resource IDs we are using will be inconsistent 2346 // with what we get when not stripping. Sucky, but at least 2347 // for now we can rely on the back-end doing another filtering 2348 // pass to take this out and leave us with this resource name 2349 // containing no entries. 2350 continue; 2351 } 2352 if (file->getPath().getPathExtension() == ".xml") { 2353 // We can't remove .xml files at this point, because when 2354 // we parse them they may add identifier resources, so 2355 // removing them can cause our resource identifiers to 2356 // become inconsistent. 2357 continue; 2358 } 2359 const ResTable_config& config(file->getGroupEntry().toParams()); 2360 if (!reqFilter.match(config)) { 2361 if (bundle->getVerbose()) { 2362 printf("Pruning unneeded resource: %s\n", 2363 file->getPrintableSource().string()); 2364 } 2365 grp->removeFile(k); 2366 k--; 2367 } 2368 } 2369 2370 // Quick check: no preferred filters, nothing more to do. 2371 if (prefFilter.isEmpty()) { 2372 continue; 2373 } 2374 2375 // Now deal with preferred configurations. 2376 for (int axis=AXIS_START; axis<=AXIS_END; axis++) { 2377 for (size_t k=0; k<grp->getFiles().size(); k++) { 2378 sp<AaptFile> file = grp->getFiles().valueAt(k); 2379 if (k == 0 && grp->getFiles().size() == 1) { 2380 // If this is the only file left, we need to keep it. 2381 // Otherwise the resource IDs we are using will be inconsistent 2382 // with what we get when not stripping. Sucky, but at least 2383 // for now we can rely on the back-end doing another filtering 2384 // pass to take this out and leave us with this resource name 2385 // containing no entries. 2386 continue; 2387 } 2388 if (file->getPath().getPathExtension() == ".xml") { 2389 // We can't remove .xml files at this point, because when 2390 // we parse them they may add identifier resources, so 2391 // removing them can cause our resource identifiers to 2392 // become inconsistent. 2393 continue; 2394 } 2395 const ResTable_config& config(file->getGroupEntry().toParams()); 2396 if (!prefFilter.match(axis, config)) { 2397 // This is a resource we would prefer not to have. Check 2398 // to see if have a similar variation that we would like 2399 // to have and, if so, we can drop it. 2400 for (size_t m=0; m<grp->getFiles().size(); m++) { 2401 if (m == k) continue; 2402 sp<AaptFile> mfile = grp->getFiles().valueAt(m); 2403 const ResTable_config& mconfig(mfile->getGroupEntry().toParams()); 2404 if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) { 2405 if (prefFilter.match(axis, mconfig)) { 2406 if (bundle->getVerbose()) { 2407 printf("Pruning unneeded resource: %s\n", 2408 file->getPrintableSource().string()); 2409 } 2410 grp->removeFile(k); 2411 k--; 2412 break; 2413 } 2414 } 2415 } 2416 } 2417 } 2418 } 2419 } 2420 } 2421 2422 return NO_ERROR; 2423} 2424 2425sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name) 2426{ 2427 sp<AaptSymbols> sym = mSymbols.valueFor(name); 2428 if (sym == NULL) { 2429 sym = new AaptSymbols(); 2430 mSymbols.add(name, sym); 2431 } 2432 return sym; 2433} 2434 2435status_t AaptAssets::buildIncludedResources(Bundle* bundle) 2436{ 2437 if (!mHaveIncludedAssets) { 2438 // Add in all includes. 2439 const Vector<const char*>& incl = bundle->getPackageIncludes(); 2440 const size_t N=incl.size(); 2441 for (size_t i=0; i<N; i++) { 2442 if (bundle->getVerbose()) 2443 printf("Including resources from package: %s\n", incl[i]); 2444 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) { 2445 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n", 2446 incl[i]); 2447 return UNKNOWN_ERROR; 2448 } 2449 } 2450 mHaveIncludedAssets = true; 2451 } 2452 2453 return NO_ERROR; 2454} 2455 2456status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file) 2457{ 2458 const ResTable& res = getIncludedResources(); 2459 // XXX dirty! 2460 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL); 2461} 2462 2463const ResTable& AaptAssets::getIncludedResources() const 2464{ 2465 return mIncludedAssets.getResources(false); 2466} 2467 2468void AaptAssets::print(const String8& prefix) const 2469{ 2470 String8 innerPrefix(prefix); 2471 innerPrefix.append(" "); 2472 String8 innerInnerPrefix(innerPrefix); 2473 innerInnerPrefix.append(" "); 2474 printf("%sConfigurations:\n", prefix.string()); 2475 const size_t N=mGroupEntries.size(); 2476 for (size_t i=0; i<N; i++) { 2477 String8 cname = mGroupEntries.itemAt(i).toDirName(String8()); 2478 printf("%s %s\n", prefix.string(), 2479 cname != "" ? cname.string() : "(default)"); 2480 } 2481 2482 printf("\n%sFiles:\n", prefix.string()); 2483 AaptDir::print(innerPrefix); 2484 2485 printf("\n%sResource Dirs:\n", prefix.string()); 2486 const Vector<sp<AaptDir> >& resdirs = mResDirs; 2487 const size_t NR = resdirs.size(); 2488 for (size_t i=0; i<NR; i++) { 2489 const sp<AaptDir>& d = resdirs.itemAt(i); 2490 printf("%s Type %s\n", prefix.string(), d->getLeaf().string()); 2491 d->print(innerInnerPrefix); 2492 } 2493} 2494 2495sp<AaptDir> AaptAssets::resDir(const String8& name) const 2496{ 2497 const Vector<sp<AaptDir> >& resdirs = mResDirs; 2498 const size_t N = resdirs.size(); 2499 for (size_t i=0; i<N; i++) { 2500 const sp<AaptDir>& d = resdirs.itemAt(i); 2501 if (d->getLeaf() == name) { 2502 return d; 2503 } 2504 } 2505 return NULL; 2506} 2507 2508bool 2509valid_symbol_name(const String8& symbol) 2510{ 2511 static char const * const KEYWORDS[] = { 2512 "abstract", "assert", "boolean", "break", 2513 "byte", "case", "catch", "char", "class", "const", "continue", 2514 "default", "do", "double", "else", "enum", "extends", "final", 2515 "finally", "float", "for", "goto", "if", "implements", "import", 2516 "instanceof", "int", "interface", "long", "native", "new", "package", 2517 "private", "protected", "public", "return", "short", "static", 2518 "strictfp", "super", "switch", "synchronized", "this", "throw", 2519 "throws", "transient", "try", "void", "volatile", "while", 2520 "true", "false", "null", 2521 NULL 2522 }; 2523 const char*const* k = KEYWORDS; 2524 const char*const s = symbol.string(); 2525 while (*k) { 2526 if (0 == strcmp(s, *k)) { 2527 return false; 2528 } 2529 k++; 2530 } 2531 return true; 2532} 2533