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