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