AaptAssets.cpp revision 94c40a4cf90933216e6d656213dfdfa19c68a9c3
1// 2// Copyright 2006 The Android Open Source Project 3// 4 5#include "AaptAssets.h" 6#include "ResourceFilter.h" 7#include "Main.h" 8 9#include <utils/misc.h> 10#include <utils/SortedVector.h> 11 12#include <ctype.h> 13#include <dirent.h> 14#include <errno.h> 15 16static const char* kDefaultLocale = "default"; 17static const char* kWildcardName = "any"; 18static const char* kAssetDir = "assets"; 19static const char* kResourceDir = "res"; 20static const char* kValuesDir = "values"; 21static const char* kMipmapDir = "mipmap"; 22static const char* kInvalidChars = "/\\:"; 23static const size_t kMaxAssetFileName = 100; 24 25static const String8 kResString(kResourceDir); 26 27/* 28 * Names of asset files must meet the following criteria: 29 * 30 * - the filename length must be less than kMaxAssetFileName bytes long 31 * (and can't be empty) 32 * - all characters must be 7-bit printable ASCII 33 * - none of { '/' '\\' ':' } 34 * 35 * Pass in just the filename, not the full path. 36 */ 37static bool validateFileName(const char* fileName) 38{ 39 const char* cp = fileName; 40 size_t len = 0; 41 42 while (*cp != '\0') { 43 if ((*cp & 0x80) != 0) 44 return false; // reject high ASCII 45 if (*cp < 0x20 || *cp >= 0x7f) 46 return false; // reject control chars and 0x7f 47 if (strchr(kInvalidChars, *cp) != NULL) 48 return false; // reject path sep chars 49 cp++; 50 len++; 51 } 52 53 if (len < 1 || len > kMaxAssetFileName) 54 return false; // reject empty or too long 55 56 return true; 57} 58 59// The default to use if no other ignore pattern is defined. 60const char * const gDefaultIgnoreAssets = 61 "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"; 62// The ignore pattern that can be passed via --ignore-assets in Main.cpp 63const char * gUserIgnoreAssets = NULL; 64 65static bool isHidden(const char *root, const char *path) 66{ 67 // Patterns syntax: 68 // - Delimiter is : 69 // - Entry can start with the flag ! to avoid printing a warning 70 // about the file being ignored. 71 // - Entry can have the flag "<dir>" to match only directories 72 // or <file> to match only files. Default is to match both. 73 // - Entry can be a simplified glob "<prefix>*" or "*<suffix>" 74 // where prefix/suffix must have at least 1 character (so that 75 // we don't match a '*' catch-all pattern.) 76 // - The special filenames "." and ".." are always ignored. 77 // - Otherwise the full string is matched. 78 // - match is not case-sensitive. 79 80 if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) { 81 return true; 82 } 83 84 const char *delim = ":"; 85 const char *p = gUserIgnoreAssets; 86 if (!p || !p[0]) { 87 p = getenv("ANDROID_AAPT_IGNORE"); 88 } 89 if (!p || !p[0]) { 90 p = gDefaultIgnoreAssets; 91 } 92 char *patterns = strdup(p); 93 94 bool ignore = false; 95 bool chatty = true; 96 char *matchedPattern = NULL; 97 98 String8 fullPath(root); 99 fullPath.appendPath(path); 100 FileType type = getFileType(fullPath); 101 102 int plen = strlen(path); 103 104 // Note: we don't have strtok_r under mingw. 105 for(char *token = strtok(patterns, delim); 106 !ignore && token != NULL; 107 token = strtok(NULL, delim)) { 108 chatty = token[0] != '!'; 109 if (!chatty) token++; // skip ! 110 if (strncasecmp(token, "<dir>" , 5) == 0) { 111 if (type != kFileTypeDirectory) continue; 112 token += 5; 113 } 114 if (strncasecmp(token, "<file>", 6) == 0) { 115 if (type != kFileTypeRegular) continue; 116 token += 6; 117 } 118 119 matchedPattern = token; 120 int n = strlen(token); 121 122 if (token[0] == '*') { 123 // Match *suffix 124 token++; 125 n--; 126 if (n <= plen) { 127 ignore = strncasecmp(token, path + plen - n, n) == 0; 128 } 129 } else if (n > 1 && token[n - 1] == '*') { 130 // Match prefix* 131 ignore = strncasecmp(token, path, n - 1) == 0; 132 } else { 133 ignore = strcasecmp(token, path) == 0; 134 } 135 } 136 137 if (ignore && chatty) { 138 fprintf(stderr, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n", 139 type == kFileTypeDirectory ? "dir" : "file", 140 path, 141 matchedPattern ? matchedPattern : ""); 142 } 143 144 free(patterns); 145 return ignore; 146} 147 148// ========================================================================= 149// ========================================================================= 150// ========================================================================= 151 152status_t 153AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) 154{ 155 ResTable_config config; 156 157 // IMSI - MCC 158 if (getMccName(part.string(), &config)) { 159 *axis = AXIS_MCC; 160 *value = config.mcc; 161 return 0; 162 } 163 164 // IMSI - MNC 165 if (getMncName(part.string(), &config)) { 166 *axis = AXIS_MNC; 167 *value = config.mnc; 168 return 0; 169 } 170 171 // locale - language 172 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { 173 *axis = AXIS_LANGUAGE; 174 *value = part[1] << 8 | part[0]; 175 return 0; 176 } 177 178 // locale - language_REGION 179 if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1]) 180 && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) { 181 *axis = AXIS_LANGUAGE; 182 *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]); 183 return 0; 184 } 185 186 // 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 308uint32_t 309AaptGroupEntry::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 353bool 354AaptGroupEntry::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 368bool 369AaptGroupEntry::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 679success: 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 707String8 708AaptGroupEntry::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 752String8 753AaptGroupEntry::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 880bool 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 912bool 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 if (out->mnc == 0) { 938 out->mnc = ACONFIGURATION_MNC_ZERO; 939 } 940 } 941 942 return true; 943} 944 945/* 946 * Does this directory name fit the pattern of a locale dir ("en-rUS" or 947 * "default")? 948 * 949 * TODO: Should insist that the first two letters are lower case, and the 950 * second two are upper. 951 */ 952bool AaptGroupEntry::getLocaleName(const char* fileName, 953 ResTable_config* out) 954{ 955 if (strcmp(fileName, kWildcardName) == 0 956 || strcmp(fileName, kDefaultLocale) == 0) { 957 if (out) { 958 out->language[0] = 0; 959 out->language[1] = 0; 960 out->country[0] = 0; 961 out->country[1] = 0; 962 } 963 return true; 964 } 965 966 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) { 967 if (out) { 968 out->language[0] = fileName[0]; 969 out->language[1] = fileName[1]; 970 out->country[0] = 0; 971 out->country[1] = 0; 972 } 973 return true; 974 } 975 976 if (strlen(fileName) == 5 && 977 isalpha(fileName[0]) && 978 isalpha(fileName[1]) && 979 fileName[2] == '-' && 980 isalpha(fileName[3]) && 981 isalpha(fileName[4])) { 982 if (out) { 983 out->language[0] = fileName[0]; 984 out->language[1] = fileName[1]; 985 out->country[0] = fileName[3]; 986 out->country[1] = fileName[4]; 987 } 988 return true; 989 } 990 991 return false; 992} 993 994bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out) 995{ 996 if (strcmp(name, kWildcardName) == 0) { 997 if (out) out->screenLayout = 998 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) 999 | ResTable_config::LAYOUTDIR_ANY; 1000 return true; 1001 } else if (strcmp(name, "ldltr") == 0) { 1002 if (out) out->screenLayout = 1003 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) 1004 | ResTable_config::LAYOUTDIR_LTR; 1005 return true; 1006 } else if (strcmp(name, "ldrtl") == 0) { 1007 if (out) out->screenLayout = 1008 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) 1009 | ResTable_config::LAYOUTDIR_RTL; 1010 return true; 1011 } 1012 1013 return false; 1014} 1015 1016bool AaptGroupEntry::getScreenLayoutSizeName(const char* name, 1017 ResTable_config* out) 1018{ 1019 if (strcmp(name, kWildcardName) == 0) { 1020 if (out) out->screenLayout = 1021 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 1022 | ResTable_config::SCREENSIZE_ANY; 1023 return true; 1024 } else if (strcmp(name, "small") == 0) { 1025 if (out) out->screenLayout = 1026 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 1027 | ResTable_config::SCREENSIZE_SMALL; 1028 return true; 1029 } else if (strcmp(name, "normal") == 0) { 1030 if (out) out->screenLayout = 1031 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 1032 | ResTable_config::SCREENSIZE_NORMAL; 1033 return true; 1034 } else if (strcmp(name, "large") == 0) { 1035 if (out) out->screenLayout = 1036 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 1037 | ResTable_config::SCREENSIZE_LARGE; 1038 return true; 1039 } else if (strcmp(name, "xlarge") == 0) { 1040 if (out) out->screenLayout = 1041 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 1042 | ResTable_config::SCREENSIZE_XLARGE; 1043 return true; 1044 } 1045 1046 return false; 1047} 1048 1049bool AaptGroupEntry::getScreenLayoutLongName(const char* name, 1050 ResTable_config* out) 1051{ 1052 if (strcmp(name, kWildcardName) == 0) { 1053 if (out) out->screenLayout = 1054 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 1055 | ResTable_config::SCREENLONG_ANY; 1056 return true; 1057 } else if (strcmp(name, "long") == 0) { 1058 if (out) out->screenLayout = 1059 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 1060 | ResTable_config::SCREENLONG_YES; 1061 return true; 1062 } else if (strcmp(name, "notlong") == 0) { 1063 if (out) out->screenLayout = 1064 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 1065 | ResTable_config::SCREENLONG_NO; 1066 return true; 1067 } 1068 1069 return false; 1070} 1071 1072bool AaptGroupEntry::getOrientationName(const char* name, 1073 ResTable_config* out) 1074{ 1075 if (strcmp(name, kWildcardName) == 0) { 1076 if (out) out->orientation = out->ORIENTATION_ANY; 1077 return true; 1078 } else if (strcmp(name, "port") == 0) { 1079 if (out) out->orientation = out->ORIENTATION_PORT; 1080 return true; 1081 } else if (strcmp(name, "land") == 0) { 1082 if (out) out->orientation = out->ORIENTATION_LAND; 1083 return true; 1084 } else if (strcmp(name, "square") == 0) { 1085 if (out) out->orientation = out->ORIENTATION_SQUARE; 1086 return true; 1087 } 1088 1089 return false; 1090} 1091 1092bool AaptGroupEntry::getUiModeTypeName(const char* name, 1093 ResTable_config* out) 1094{ 1095 if (strcmp(name, kWildcardName) == 0) { 1096 if (out) out->uiMode = 1097 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1098 | ResTable_config::UI_MODE_TYPE_ANY; 1099 return true; 1100 } else if (strcmp(name, "desk") == 0) { 1101 if (out) out->uiMode = 1102 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1103 | ResTable_config::UI_MODE_TYPE_DESK; 1104 return true; 1105 } else if (strcmp(name, "car") == 0) { 1106 if (out) out->uiMode = 1107 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1108 | ResTable_config::UI_MODE_TYPE_CAR; 1109 return true; 1110 } else if (strcmp(name, "television") == 0) { 1111 if (out) out->uiMode = 1112 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1113 | ResTable_config::UI_MODE_TYPE_TELEVISION; 1114 return true; 1115 } else if (strcmp(name, "appliance") == 0) { 1116 if (out) out->uiMode = 1117 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 1118 | ResTable_config::UI_MODE_TYPE_APPLIANCE; 1119 return true; 1120 } 1121 1122 return false; 1123} 1124 1125bool AaptGroupEntry::getUiModeNightName(const char* name, 1126 ResTable_config* out) 1127{ 1128 if (strcmp(name, kWildcardName) == 0) { 1129 if (out) out->uiMode = 1130 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 1131 | ResTable_config::UI_MODE_NIGHT_ANY; 1132 return true; 1133 } else if (strcmp(name, "night") == 0) { 1134 if (out) out->uiMode = 1135 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 1136 | ResTable_config::UI_MODE_NIGHT_YES; 1137 return true; 1138 } else if (strcmp(name, "notnight") == 0) { 1139 if (out) out->uiMode = 1140 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 1141 | ResTable_config::UI_MODE_NIGHT_NO; 1142 return true; 1143 } 1144 1145 return false; 1146} 1147 1148bool AaptGroupEntry::getDensityName(const char* name, 1149 ResTable_config* out) 1150{ 1151 if (strcmp(name, kWildcardName) == 0) { 1152 if (out) out->density = ResTable_config::DENSITY_DEFAULT; 1153 return true; 1154 } 1155 1156 if (strcmp(name, "nodpi") == 0) { 1157 if (out) out->density = ResTable_config::DENSITY_NONE; 1158 return true; 1159 } 1160 1161 if (strcmp(name, "ldpi") == 0) { 1162 if (out) out->density = ResTable_config::DENSITY_LOW; 1163 return true; 1164 } 1165 1166 if (strcmp(name, "mdpi") == 0) { 1167 if (out) out->density = ResTable_config::DENSITY_MEDIUM; 1168 return true; 1169 } 1170 1171 if (strcmp(name, "tvdpi") == 0) { 1172 if (out) out->density = ResTable_config::DENSITY_TV; 1173 return true; 1174 } 1175 1176 if (strcmp(name, "hdpi") == 0) { 1177 if (out) out->density = ResTable_config::DENSITY_HIGH; 1178 return true; 1179 } 1180 1181 if (strcmp(name, "xhdpi") == 0) { 1182 if (out) out->density = ResTable_config::DENSITY_XHIGH; 1183 return true; 1184 } 1185 1186 if (strcmp(name, "xxhdpi") == 0) { 1187 if (out) out->density = ResTable_config::DENSITY_XXHIGH; 1188 return true; 1189 } 1190 1191 if (strcmp(name, "xxxhdpi") == 0) { 1192 if (out) out->density = ResTable_config::DENSITY_XXXHIGH; 1193 return true; 1194 } 1195 1196 char* c = (char*)name; 1197 while (*c >= '0' && *c <= '9') { 1198 c++; 1199 } 1200 1201 // check that we have 'dpi' after the last digit. 1202 if (toupper(c[0]) != 'D' || 1203 toupper(c[1]) != 'P' || 1204 toupper(c[2]) != 'I' || 1205 c[3] != 0) { 1206 return false; 1207 } 1208 1209 // temporarily replace the first letter with \0 to 1210 // use atoi. 1211 char tmp = c[0]; 1212 c[0] = '\0'; 1213 1214 int d = atoi(name); 1215 c[0] = tmp; 1216 1217 if (d != 0) { 1218 if (out) out->density = d; 1219 return true; 1220 } 1221 1222 return false; 1223} 1224 1225bool AaptGroupEntry::getTouchscreenName(const char* name, 1226 ResTable_config* out) 1227{ 1228 if (strcmp(name, kWildcardName) == 0) { 1229 if (out) out->touchscreen = out->TOUCHSCREEN_ANY; 1230 return true; 1231 } else if (strcmp(name, "notouch") == 0) { 1232 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH; 1233 return true; 1234 } else if (strcmp(name, "stylus") == 0) { 1235 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS; 1236 return true; 1237 } else if (strcmp(name, "finger") == 0) { 1238 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER; 1239 return true; 1240 } 1241 1242 return false; 1243} 1244 1245bool AaptGroupEntry::getKeysHiddenName(const char* name, 1246 ResTable_config* out) 1247{ 1248 uint8_t mask = 0; 1249 uint8_t value = 0; 1250 if (strcmp(name, kWildcardName) == 0) { 1251 mask = ResTable_config::MASK_KEYSHIDDEN; 1252 value = ResTable_config::KEYSHIDDEN_ANY; 1253 } else if (strcmp(name, "keysexposed") == 0) { 1254 mask = ResTable_config::MASK_KEYSHIDDEN; 1255 value = ResTable_config::KEYSHIDDEN_NO; 1256 } else if (strcmp(name, "keyshidden") == 0) { 1257 mask = ResTable_config::MASK_KEYSHIDDEN; 1258 value = ResTable_config::KEYSHIDDEN_YES; 1259 } else if (strcmp(name, "keyssoft") == 0) { 1260 mask = ResTable_config::MASK_KEYSHIDDEN; 1261 value = ResTable_config::KEYSHIDDEN_SOFT; 1262 } 1263 1264 if (mask != 0) { 1265 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 1266 return true; 1267 } 1268 1269 return false; 1270} 1271 1272bool AaptGroupEntry::getKeyboardName(const char* name, 1273 ResTable_config* out) 1274{ 1275 if (strcmp(name, kWildcardName) == 0) { 1276 if (out) out->keyboard = out->KEYBOARD_ANY; 1277 return true; 1278 } else if (strcmp(name, "nokeys") == 0) { 1279 if (out) out->keyboard = out->KEYBOARD_NOKEYS; 1280 return true; 1281 } else if (strcmp(name, "qwerty") == 0) { 1282 if (out) out->keyboard = out->KEYBOARD_QWERTY; 1283 return true; 1284 } else if (strcmp(name, "12key") == 0) { 1285 if (out) out->keyboard = out->KEYBOARD_12KEY; 1286 return true; 1287 } 1288 1289 return false; 1290} 1291 1292bool AaptGroupEntry::getNavHiddenName(const char* name, 1293 ResTable_config* out) 1294{ 1295 uint8_t mask = 0; 1296 uint8_t value = 0; 1297 if (strcmp(name, kWildcardName) == 0) { 1298 mask = ResTable_config::MASK_NAVHIDDEN; 1299 value = ResTable_config::NAVHIDDEN_ANY; 1300 } else if (strcmp(name, "navexposed") == 0) { 1301 mask = ResTable_config::MASK_NAVHIDDEN; 1302 value = ResTable_config::NAVHIDDEN_NO; 1303 } else if (strcmp(name, "navhidden") == 0) { 1304 mask = ResTable_config::MASK_NAVHIDDEN; 1305 value = ResTable_config::NAVHIDDEN_YES; 1306 } 1307 1308 if (mask != 0) { 1309 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 1310 return true; 1311 } 1312 1313 return false; 1314} 1315 1316bool AaptGroupEntry::getNavigationName(const char* name, 1317 ResTable_config* out) 1318{ 1319 if (strcmp(name, kWildcardName) == 0) { 1320 if (out) out->navigation = out->NAVIGATION_ANY; 1321 return true; 1322 } else if (strcmp(name, "nonav") == 0) { 1323 if (out) out->navigation = out->NAVIGATION_NONAV; 1324 return true; 1325 } else if (strcmp(name, "dpad") == 0) { 1326 if (out) out->navigation = out->NAVIGATION_DPAD; 1327 return true; 1328 } else if (strcmp(name, "trackball") == 0) { 1329 if (out) out->navigation = out->NAVIGATION_TRACKBALL; 1330 return true; 1331 } else if (strcmp(name, "wheel") == 0) { 1332 if (out) out->navigation = out->NAVIGATION_WHEEL; 1333 return true; 1334 } 1335 1336 return false; 1337} 1338 1339bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out) 1340{ 1341 if (strcmp(name, kWildcardName) == 0) { 1342 if (out) { 1343 out->screenWidth = out->SCREENWIDTH_ANY; 1344 out->screenHeight = out->SCREENHEIGHT_ANY; 1345 } 1346 return true; 1347 } 1348 1349 const char* x = name; 1350 while (*x >= '0' && *x <= '9') x++; 1351 if (x == name || *x != 'x') return false; 1352 String8 xName(name, x-name); 1353 x++; 1354 1355 const char* y = x; 1356 while (*y >= '0' && *y <= '9') y++; 1357 if (y == name || *y != 0) return false; 1358 String8 yName(x, y-x); 1359 1360 uint16_t w = (uint16_t)atoi(xName.string()); 1361 uint16_t h = (uint16_t)atoi(yName.string()); 1362 if (w < h) { 1363 return false; 1364 } 1365 1366 if (out) { 1367 out->screenWidth = w; 1368 out->screenHeight = h; 1369 } 1370 1371 return true; 1372} 1373 1374bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out) 1375{ 1376 if (strcmp(name, kWildcardName) == 0) { 1377 if (out) { 1378 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY; 1379 } 1380 return true; 1381 } 1382 1383 if (*name != 's') return false; 1384 name++; 1385 if (*name != 'w') return false; 1386 name++; 1387 const char* x = name; 1388 while (*x >= '0' && *x <= '9') x++; 1389 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 1390 String8 xName(name, x-name); 1391 1392 if (out) { 1393 out->smallestScreenWidthDp = (uint16_t)atoi(xName.string()); 1394 } 1395 1396 return true; 1397} 1398 1399bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out) 1400{ 1401 if (strcmp(name, kWildcardName) == 0) { 1402 if (out) { 1403 out->screenWidthDp = out->SCREENWIDTH_ANY; 1404 } 1405 return true; 1406 } 1407 1408 if (*name != 'w') return false; 1409 name++; 1410 const char* x = name; 1411 while (*x >= '0' && *x <= '9') x++; 1412 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 1413 String8 xName(name, x-name); 1414 1415 if (out) { 1416 out->screenWidthDp = (uint16_t)atoi(xName.string()); 1417 } 1418 1419 return true; 1420} 1421 1422bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out) 1423{ 1424 if (strcmp(name, kWildcardName) == 0) { 1425 if (out) { 1426 out->screenHeightDp = out->SCREENWIDTH_ANY; 1427 } 1428 return true; 1429 } 1430 1431 if (*name != 'h') return false; 1432 name++; 1433 const char* x = name; 1434 while (*x >= '0' && *x <= '9') x++; 1435 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 1436 String8 xName(name, x-name); 1437 1438 if (out) { 1439 out->screenHeightDp = (uint16_t)atoi(xName.string()); 1440 } 1441 1442 return true; 1443} 1444 1445bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out) 1446{ 1447 if (strcmp(name, kWildcardName) == 0) { 1448 if (out) { 1449 out->sdkVersion = out->SDKVERSION_ANY; 1450 out->minorVersion = out->MINORVERSION_ANY; 1451 } 1452 return true; 1453 } 1454 1455 if (*name != 'v') { 1456 return false; 1457 } 1458 1459 name++; 1460 const char* s = name; 1461 while (*s >= '0' && *s <= '9') s++; 1462 if (s == name || *s != 0) return false; 1463 String8 sdkName(name, s-name); 1464 1465 if (out) { 1466 out->sdkVersion = (uint16_t)atoi(sdkName.string()); 1467 out->minorVersion = 0; 1468 } 1469 1470 return true; 1471} 1472 1473int AaptGroupEntry::compare(const AaptGroupEntry& o) const 1474{ 1475 int v = mcc.compare(o.mcc); 1476 if (v == 0) v = mnc.compare(o.mnc); 1477 if (v == 0) v = locale.compare(o.locale); 1478 if (v == 0) v = layoutDirection.compare(o.layoutDirection); 1479 if (v == 0) v = vendor.compare(o.vendor); 1480 if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp); 1481 if (v == 0) v = screenWidthDp.compare(o.screenWidthDp); 1482 if (v == 0) v = screenHeightDp.compare(o.screenHeightDp); 1483 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize); 1484 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong); 1485 if (v == 0) v = orientation.compare(o.orientation); 1486 if (v == 0) v = uiModeType.compare(o.uiModeType); 1487 if (v == 0) v = uiModeNight.compare(o.uiModeNight); 1488 if (v == 0) v = density.compare(o.density); 1489 if (v == 0) v = touchscreen.compare(o.touchscreen); 1490 if (v == 0) v = keysHidden.compare(o.keysHidden); 1491 if (v == 0) v = keyboard.compare(o.keyboard); 1492 if (v == 0) v = navHidden.compare(o.navHidden); 1493 if (v == 0) v = navigation.compare(o.navigation); 1494 if (v == 0) v = screenSize.compare(o.screenSize); 1495 if (v == 0) v = version.compare(o.version); 1496 return v; 1497} 1498 1499const ResTable_config& AaptGroupEntry::toParams() const 1500{ 1501 if (!mParamsChanged) { 1502 return mParams; 1503 } 1504 1505 mParamsChanged = false; 1506 ResTable_config& params(mParams); 1507 memset(¶ms, 0, sizeof(params)); 1508 getMccName(mcc.string(), ¶ms); 1509 getMncName(mnc.string(), ¶ms); 1510 getLocaleName(locale.string(), ¶ms); 1511 getLayoutDirectionName(layoutDirection.string(), ¶ms); 1512 getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), ¶ms); 1513 getScreenWidthDpName(screenWidthDp.string(), ¶ms); 1514 getScreenHeightDpName(screenHeightDp.string(), ¶ms); 1515 getScreenLayoutSizeName(screenLayoutSize.string(), ¶ms); 1516 getScreenLayoutLongName(screenLayoutLong.string(), ¶ms); 1517 getOrientationName(orientation.string(), ¶ms); 1518 getUiModeTypeName(uiModeType.string(), ¶ms); 1519 getUiModeNightName(uiModeNight.string(), ¶ms); 1520 getDensityName(density.string(), ¶ms); 1521 getTouchscreenName(touchscreen.string(), ¶ms); 1522 getKeysHiddenName(keysHidden.string(), ¶ms); 1523 getKeyboardName(keyboard.string(), ¶ms); 1524 getNavHiddenName(navHidden.string(), ¶ms); 1525 getNavigationName(navigation.string(), ¶ms); 1526 getScreenSizeName(screenSize.string(), ¶ms); 1527 getVersionName(version.string(), ¶ms); 1528 1529 // Fix up version number based on specified parameters. 1530 int minSdk = 0; 1531 if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY 1532 || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY 1533 || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) { 1534 minSdk = SDK_HONEYCOMB_MR2; 1535 } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE) 1536 != ResTable_config::UI_MODE_TYPE_ANY 1537 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) 1538 != ResTable_config::UI_MODE_NIGHT_ANY) { 1539 minSdk = SDK_FROYO; 1540 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE) 1541 != ResTable_config::SCREENSIZE_ANY 1542 || (params.screenLayout&ResTable_config::MASK_SCREENLONG) 1543 != ResTable_config::SCREENLONG_ANY 1544 || params.density != ResTable_config::DENSITY_DEFAULT) { 1545 minSdk = SDK_DONUT; 1546 } 1547 1548 if (minSdk > params.sdkVersion) { 1549 params.sdkVersion = minSdk; 1550 } 1551 1552 return params; 1553} 1554 1555// ========================================================================= 1556// ========================================================================= 1557// ========================================================================= 1558 1559void* AaptFile::editData(size_t size) 1560{ 1561 if (size <= mBufferSize) { 1562 mDataSize = size; 1563 return mData; 1564 } 1565 size_t allocSize = (size*3)/2; 1566 void* buf = realloc(mData, allocSize); 1567 if (buf == NULL) { 1568 return NULL; 1569 } 1570 mData = buf; 1571 mDataSize = size; 1572 mBufferSize = allocSize; 1573 return buf; 1574} 1575 1576void* AaptFile::editData(size_t* outSize) 1577{ 1578 if (outSize) { 1579 *outSize = mDataSize; 1580 } 1581 return mData; 1582} 1583 1584void* AaptFile::padData(size_t wordSize) 1585{ 1586 const size_t extra = mDataSize%wordSize; 1587 if (extra == 0) { 1588 return mData; 1589 } 1590 1591 size_t initial = mDataSize; 1592 void* data = editData(initial+(wordSize-extra)); 1593 if (data != NULL) { 1594 memset(((uint8_t*)data) + initial, 0, wordSize-extra); 1595 } 1596 return data; 1597} 1598 1599status_t AaptFile::writeData(const void* data, size_t size) 1600{ 1601 size_t end = mDataSize; 1602 size_t total = size + end; 1603 void* buf = editData(total); 1604 if (buf == NULL) { 1605 return UNKNOWN_ERROR; 1606 } 1607 memcpy(((char*)buf)+end, data, size); 1608 return NO_ERROR; 1609} 1610 1611void AaptFile::clearData() 1612{ 1613 if (mData != NULL) free(mData); 1614 mData = NULL; 1615 mDataSize = 0; 1616 mBufferSize = 0; 1617} 1618 1619String8 AaptFile::getPrintableSource() const 1620{ 1621 if (hasData()) { 1622 String8 name(mGroupEntry.toDirName(String8())); 1623 name.appendPath(mPath); 1624 name.append(" #generated"); 1625 return name; 1626 } 1627 return mSourceFile; 1628} 1629 1630// ========================================================================= 1631// ========================================================================= 1632// ========================================================================= 1633 1634status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate) 1635{ 1636 ssize_t index = mFiles.indexOfKey(file->getGroupEntry()); 1637 if (index >= 0 && overwriteDuplicate) { 1638 fprintf(stderr, "warning: overwriting '%s' with '%s'\n", 1639 mFiles[index]->getSourceFile().string(), 1640 file->getSourceFile().string()); 1641 removeFile(index); 1642 index = -1; 1643 } 1644 1645 if (index < 0) { 1646 file->mPath = mPath; 1647 mFiles.add(file->getGroupEntry(), file); 1648 return NO_ERROR; 1649 } 1650 1651#if 0 1652 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n", 1653 file->getSourceFile().string(), 1654 file->getGroupEntry().toDirName(String8()).string(), 1655 mLeaf.string(), mPath.string()); 1656#endif 1657 1658 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", 1659 getPrintableSource().string()); 1660 return UNKNOWN_ERROR; 1661} 1662 1663void AaptGroup::removeFile(size_t index) 1664{ 1665 mFiles.removeItemsAt(index); 1666} 1667 1668void AaptGroup::print(const String8& prefix) const 1669{ 1670 printf("%s%s\n", prefix.string(), getPath().string()); 1671 const size_t N=mFiles.size(); 1672 size_t i; 1673 for (i=0; i<N; i++) { 1674 sp<AaptFile> file = mFiles.valueAt(i); 1675 const AaptGroupEntry& e = file->getGroupEntry(); 1676 if (file->hasData()) { 1677 printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(), 1678 (int)file->getSize()); 1679 } else { 1680 printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(), 1681 file->getPrintableSource().string()); 1682 } 1683 //printf("%s File Group Entry: %s\n", prefix.string(), 1684 // file->getGroupEntry().toDirName(String8()).string()); 1685 } 1686} 1687 1688String8 AaptGroup::getPrintableSource() const 1689{ 1690 if (mFiles.size() > 0) { 1691 // Arbitrarily pull the first source file out of the list. 1692 return mFiles.valueAt(0)->getPrintableSource(); 1693 } 1694 1695 // Should never hit this case, but to be safe... 1696 return getPath(); 1697 1698} 1699 1700// ========================================================================= 1701// ========================================================================= 1702// ========================================================================= 1703 1704status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file) 1705{ 1706 if (mFiles.indexOfKey(name) >= 0) { 1707 return ALREADY_EXISTS; 1708 } 1709 mFiles.add(name, file); 1710 return NO_ERROR; 1711} 1712 1713status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir) 1714{ 1715 if (mDirs.indexOfKey(name) >= 0) { 1716 return ALREADY_EXISTS; 1717 } 1718 mDirs.add(name, dir); 1719 return NO_ERROR; 1720} 1721 1722sp<AaptDir> AaptDir::makeDir(const String8& path) 1723{ 1724 String8 name; 1725 String8 remain = path; 1726 1727 sp<AaptDir> subdir = this; 1728 while (name = remain.walkPath(&remain), remain != "") { 1729 subdir = subdir->makeDir(name); 1730 } 1731 1732 ssize_t i = subdir->mDirs.indexOfKey(name); 1733 if (i >= 0) { 1734 return subdir->mDirs.valueAt(i); 1735 } 1736 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name)); 1737 subdir->mDirs.add(name, dir); 1738 return dir; 1739} 1740 1741void AaptDir::removeFile(const String8& name) 1742{ 1743 mFiles.removeItem(name); 1744} 1745 1746void AaptDir::removeDir(const String8& name) 1747{ 1748 mDirs.removeItem(name); 1749} 1750 1751status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file, 1752 const bool overwrite) 1753{ 1754 sp<AaptGroup> group; 1755 if (mFiles.indexOfKey(leafName) >= 0) { 1756 group = mFiles.valueFor(leafName); 1757 } else { 1758 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName)); 1759 mFiles.add(leafName, group); 1760 } 1761 1762 return group->addFile(file, overwrite); 1763} 1764 1765ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, 1766 const AaptGroupEntry& kind, const String8& resType, 1767 sp<FilePathStore>& fullResPaths, const bool overwrite) 1768{ 1769 Vector<String8> fileNames; 1770 { 1771 DIR* dir = NULL; 1772 1773 dir = opendir(srcDir.string()); 1774 if (dir == NULL) { 1775 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 1776 return UNKNOWN_ERROR; 1777 } 1778 1779 /* 1780 * Slurp the filenames out of the directory. 1781 */ 1782 while (1) { 1783 struct dirent* entry; 1784 1785 entry = readdir(dir); 1786 if (entry == NULL) 1787 break; 1788 1789 if (isHidden(srcDir.string(), entry->d_name)) 1790 continue; 1791 1792 String8 name(entry->d_name); 1793 fileNames.add(name); 1794 // Add fully qualified path for dependency purposes 1795 // if we're collecting them 1796 if (fullResPaths != NULL) { 1797 fullResPaths->add(srcDir.appendPathCopy(name)); 1798 } 1799 } 1800 closedir(dir); 1801 } 1802 1803 ssize_t count = 0; 1804 1805 /* 1806 * Stash away the files and recursively descend into subdirectories. 1807 */ 1808 const size_t N = fileNames.size(); 1809 size_t i; 1810 for (i = 0; i < N; i++) { 1811 String8 pathName(srcDir); 1812 FileType type; 1813 1814 pathName.appendPath(fileNames[i].string()); 1815 type = getFileType(pathName.string()); 1816 if (type == kFileTypeDirectory) { 1817 sp<AaptDir> subdir; 1818 bool notAdded = false; 1819 if (mDirs.indexOfKey(fileNames[i]) >= 0) { 1820 subdir = mDirs.valueFor(fileNames[i]); 1821 } else { 1822 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i])); 1823 notAdded = true; 1824 } 1825 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, 1826 resType, fullResPaths, overwrite); 1827 if (res < NO_ERROR) { 1828 return res; 1829 } 1830 if (res > 0 && notAdded) { 1831 mDirs.add(fileNames[i], subdir); 1832 } 1833 count += res; 1834 } else if (type == kFileTypeRegular) { 1835 sp<AaptFile> file = new AaptFile(pathName, kind, resType); 1836 status_t err = addLeafFile(fileNames[i], file, overwrite); 1837 if (err != NO_ERROR) { 1838 return err; 1839 } 1840 1841 count++; 1842 1843 } else { 1844 if (bundle->getVerbose()) 1845 printf(" (ignoring non-file/dir '%s')\n", pathName.string()); 1846 } 1847 } 1848 1849 return count; 1850} 1851 1852status_t AaptDir::validate() const 1853{ 1854 const size_t NF = mFiles.size(); 1855 const size_t ND = mDirs.size(); 1856 size_t i; 1857 for (i = 0; i < NF; i++) { 1858 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) { 1859 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1860 "Invalid filename. Unable to add."); 1861 return UNKNOWN_ERROR; 1862 } 1863 1864 size_t j; 1865 for (j = i+1; j < NF; j++) { 1866 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1867 mFiles.valueAt(j)->getLeaf().string()) == 0) { 1868 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1869 "File is case-insensitive equivalent to: %s", 1870 mFiles.valueAt(j)->getPrintableSource().string()); 1871 return UNKNOWN_ERROR; 1872 } 1873 1874 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" 1875 // (this is mostly caught by the "marked" stuff, below) 1876 } 1877 1878 for (j = 0; j < ND; j++) { 1879 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1880 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1881 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1882 "File conflicts with dir from: %s", 1883 mDirs.valueAt(j)->getPrintableSource().string()); 1884 return UNKNOWN_ERROR; 1885 } 1886 } 1887 } 1888 1889 for (i = 0; i < ND; i++) { 1890 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) { 1891 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1892 "Invalid directory name, unable to add."); 1893 return UNKNOWN_ERROR; 1894 } 1895 1896 size_t j; 1897 for (j = i+1; j < ND; j++) { 1898 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(), 1899 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1900 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1901 "Directory is case-insensitive equivalent to: %s", 1902 mDirs.valueAt(j)->getPrintableSource().string()); 1903 return UNKNOWN_ERROR; 1904 } 1905 } 1906 1907 status_t err = mDirs.valueAt(i)->validate(); 1908 if (err != NO_ERROR) { 1909 return err; 1910 } 1911 } 1912 1913 return NO_ERROR; 1914} 1915 1916void AaptDir::print(const String8& prefix) const 1917{ 1918 const size_t ND=getDirs().size(); 1919 size_t i; 1920 for (i=0; i<ND; i++) { 1921 getDirs().valueAt(i)->print(prefix); 1922 } 1923 1924 const size_t NF=getFiles().size(); 1925 for (i=0; i<NF; i++) { 1926 getFiles().valueAt(i)->print(prefix); 1927 } 1928} 1929 1930String8 AaptDir::getPrintableSource() const 1931{ 1932 if (mFiles.size() > 0) { 1933 // Arbitrarily pull the first file out of the list as the source dir. 1934 return mFiles.valueAt(0)->getPrintableSource().getPathDir(); 1935 } 1936 if (mDirs.size() > 0) { 1937 // Or arbitrarily pull the first dir out of the list as the source dir. 1938 return mDirs.valueAt(0)->getPrintableSource().getPathDir(); 1939 } 1940 1941 // Should never hit this case, but to be safe... 1942 return mPath; 1943 1944} 1945 1946// ========================================================================= 1947// ========================================================================= 1948// ========================================================================= 1949 1950status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols) 1951{ 1952 status_t err = NO_ERROR; 1953 size_t N = javaSymbols->mSymbols.size(); 1954 for (size_t i=0; i<N; i++) { 1955 const String8& name = javaSymbols->mSymbols.keyAt(i); 1956 const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i); 1957 ssize_t pos = mSymbols.indexOfKey(name); 1958 if (pos < 0) { 1959 entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string()); 1960 err = UNKNOWN_ERROR; 1961 continue; 1962 } 1963 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n", 1964 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0); 1965 mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol; 1966 } 1967 1968 N = javaSymbols->mNestedSymbols.size(); 1969 for (size_t i=0; i<N; i++) { 1970 const String8& name = javaSymbols->mNestedSymbols.keyAt(i); 1971 const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i); 1972 ssize_t pos = mNestedSymbols.indexOfKey(name); 1973 if (pos < 0) { 1974 SourcePos pos; 1975 pos.error("Java symbol dir %s not defined\n", name.string()); 1976 err = UNKNOWN_ERROR; 1977 continue; 1978 } 1979 //printf("**** applying java symbols in dir %s\n", name.string()); 1980 status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols); 1981 if (myerr != NO_ERROR) { 1982 err = myerr; 1983 } 1984 } 1985 1986 return err; 1987} 1988 1989// ========================================================================= 1990// ========================================================================= 1991// ========================================================================= 1992 1993AaptAssets::AaptAssets() 1994 : AaptDir(String8(), String8()), 1995 mChanged(false), mHaveIncludedAssets(false), mRes(NULL) 1996{ 1997} 1998 1999const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const { 2000 if (mChanged) { 2001 } 2002 return mGroupEntries; 2003} 2004 2005status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file) 2006{ 2007 mChanged = true; 2008 return AaptDir::addFile(name, file); 2009} 2010 2011sp<AaptFile> AaptAssets::addFile( 2012 const String8& filePath, const AaptGroupEntry& entry, 2013 const String8& srcDir, sp<AaptGroup>* outGroup, 2014 const String8& resType) 2015{ 2016 sp<AaptDir> dir = this; 2017 sp<AaptGroup> group; 2018 sp<AaptFile> file; 2019 String8 root, remain(filePath), partialPath; 2020 while (remain.length() > 0) { 2021 root = remain.walkPath(&remain); 2022 partialPath.appendPath(root); 2023 2024 const String8 rootStr(root); 2025 2026 if (remain.length() == 0) { 2027 ssize_t i = dir->getFiles().indexOfKey(rootStr); 2028 if (i >= 0) { 2029 group = dir->getFiles().valueAt(i); 2030 } else { 2031 group = new AaptGroup(rootStr, filePath); 2032 status_t res = dir->addFile(rootStr, group); 2033 if (res != NO_ERROR) { 2034 return NULL; 2035 } 2036 } 2037 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType); 2038 status_t res = group->addFile(file); 2039 if (res != NO_ERROR) { 2040 return NULL; 2041 } 2042 break; 2043 2044 } else { 2045 ssize_t i = dir->getDirs().indexOfKey(rootStr); 2046 if (i >= 0) { 2047 dir = dir->getDirs().valueAt(i); 2048 } else { 2049 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath); 2050 status_t res = dir->addDir(rootStr, subdir); 2051 if (res != NO_ERROR) { 2052 return NULL; 2053 } 2054 dir = subdir; 2055 } 2056 } 2057 } 2058 2059 mGroupEntries.add(entry); 2060 if (outGroup) *outGroup = group; 2061 return file; 2062} 2063 2064void AaptAssets::addResource(const String8& leafName, const String8& path, 2065 const sp<AaptFile>& file, const String8& resType) 2066{ 2067 sp<AaptDir> res = AaptDir::makeDir(kResString); 2068 String8 dirname = file->getGroupEntry().toDirName(resType); 2069 sp<AaptDir> subdir = res->makeDir(dirname); 2070 sp<AaptGroup> grr = new AaptGroup(leafName, path); 2071 grr->addFile(file); 2072 2073 subdir->addFile(leafName, grr); 2074} 2075 2076 2077ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) 2078{ 2079 int count; 2080 int totalCount = 0; 2081 FileType type; 2082 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs(); 2083 const size_t dirCount =resDirs.size(); 2084 sp<AaptAssets> current = this; 2085 2086 const int N = bundle->getFileSpecCount(); 2087 2088 /* 2089 * If a package manifest was specified, include that first. 2090 */ 2091 if (bundle->getAndroidManifestFile() != NULL) { 2092 // place at root of zip. 2093 String8 srcFile(bundle->getAndroidManifestFile()); 2094 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(), 2095 NULL, String8()); 2096 totalCount++; 2097 } 2098 2099 /* 2100 * If a directory of custom assets was supplied, slurp 'em up. 2101 */ 2102 const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs(); 2103 const int AN = assetDirs.size(); 2104 for (int i = 0; i < AN; i++) { 2105 FileType type = getFileType(assetDirs[i]); 2106 if (type == kFileTypeNonexistent) { 2107 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]); 2108 return UNKNOWN_ERROR; 2109 } 2110 if (type != kFileTypeDirectory) { 2111 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]); 2112 return UNKNOWN_ERROR; 2113 } 2114 2115 String8 assetRoot(assetDirs[i]); 2116 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir)); 2117 AaptGroupEntry group; 2118 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, 2119 String8(), mFullAssetPaths, true); 2120 if (count < 0) { 2121 totalCount = count; 2122 goto bail; 2123 } 2124 if (count > 0) { 2125 mGroupEntries.add(group); 2126 } 2127 totalCount += count; 2128 2129 if (bundle->getVerbose()) { 2130 printf("Found %d custom asset file%s in %s\n", 2131 count, (count==1) ? "" : "s", assetDirs[i]); 2132 } 2133 } 2134 2135 /* 2136 * If a directory of resource-specific assets was supplied, slurp 'em up. 2137 */ 2138 for (size_t i=0; i<dirCount; i++) { 2139 const char *res = resDirs[i]; 2140 if (res) { 2141 type = getFileType(res); 2142 if (type == kFileTypeNonexistent) { 2143 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res); 2144 return UNKNOWN_ERROR; 2145 } 2146 if (type == kFileTypeDirectory) { 2147 if (i>0) { 2148 sp<AaptAssets> nextOverlay = new AaptAssets(); 2149 current->setOverlay(nextOverlay); 2150 current = nextOverlay; 2151 current->setFullResPaths(mFullResPaths); 2152 } 2153 count = current->slurpResourceTree(bundle, String8(res)); 2154 if (i > 0 && count > 0) { 2155 count = current->filter(bundle); 2156 } 2157 2158 if (count < 0) { 2159 totalCount = count; 2160 goto bail; 2161 } 2162 totalCount += count; 2163 } 2164 else { 2165 fprintf(stderr, "ERROR: '%s' is not a directory\n", res); 2166 return UNKNOWN_ERROR; 2167 } 2168 } 2169 2170 } 2171 /* 2172 * Now do any additional raw files. 2173 */ 2174 for (int arg=0; arg<N; arg++) { 2175 const char* assetDir = bundle->getFileSpecEntry(arg); 2176 2177 FileType type = getFileType(assetDir); 2178 if (type == kFileTypeNonexistent) { 2179 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir); 2180 return UNKNOWN_ERROR; 2181 } 2182 if (type != kFileTypeDirectory) { 2183 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 2184 return UNKNOWN_ERROR; 2185 } 2186 2187 String8 assetRoot(assetDir); 2188 2189 if (bundle->getVerbose()) 2190 printf("Processing raw dir '%s'\n", (const char*) assetDir); 2191 2192 /* 2193 * Do a recursive traversal of subdir tree. We don't make any 2194 * guarantees about ordering, so we're okay with an inorder search 2195 * using whatever order the OS happens to hand back to us. 2196 */ 2197 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths); 2198 if (count < 0) { 2199 /* failure; report error and remove archive */ 2200 totalCount = count; 2201 goto bail; 2202 } 2203 totalCount += count; 2204 2205 if (bundle->getVerbose()) 2206 printf("Found %d asset file%s in %s\n", 2207 count, (count==1) ? "" : "s", assetDir); 2208 } 2209 2210 count = validate(); 2211 if (count != NO_ERROR) { 2212 totalCount = count; 2213 goto bail; 2214 } 2215 2216 count = filter(bundle); 2217 if (count != NO_ERROR) { 2218 totalCount = count; 2219 goto bail; 2220 } 2221 2222bail: 2223 return totalCount; 2224} 2225 2226ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, 2227 const AaptGroupEntry& kind, 2228 const String8& resType, 2229 sp<FilePathStore>& fullResPaths) 2230{ 2231 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths); 2232 if (res > 0) { 2233 mGroupEntries.add(kind); 2234 } 2235 2236 return res; 2237} 2238 2239ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) 2240{ 2241 ssize_t err = 0; 2242 2243 DIR* dir = opendir(srcDir.string()); 2244 if (dir == NULL) { 2245 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 2246 return UNKNOWN_ERROR; 2247 } 2248 2249 status_t count = 0; 2250 2251 /* 2252 * Run through the directory, looking for dirs that match the 2253 * expected pattern. 2254 */ 2255 while (1) { 2256 struct dirent* entry = readdir(dir); 2257 if (entry == NULL) { 2258 break; 2259 } 2260 2261 if (isHidden(srcDir.string(), entry->d_name)) { 2262 continue; 2263 } 2264 2265 String8 subdirName(srcDir); 2266 subdirName.appendPath(entry->d_name); 2267 2268 AaptGroupEntry group; 2269 String8 resType; 2270 bool b = group.initFromDirName(entry->d_name, &resType); 2271 if (!b) { 2272 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(), 2273 entry->d_name); 2274 err = -1; 2275 continue; 2276 } 2277 2278 if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) { 2279 int maxResInt = atoi(bundle->getMaxResVersion()); 2280 const char *verString = group.getVersionString().string(); 2281 int dirVersionInt = atoi(verString + 1); // skip 'v' in version name 2282 if (dirVersionInt > maxResInt) { 2283 fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name); 2284 continue; 2285 } 2286 } 2287 2288 FileType type = getFileType(subdirName.string()); 2289 2290 if (type == kFileTypeDirectory) { 2291 sp<AaptDir> dir = makeDir(resType); 2292 ssize_t res = dir->slurpFullTree(bundle, subdirName, group, 2293 resType, mFullResPaths); 2294 if (res < 0) { 2295 count = res; 2296 goto bail; 2297 } 2298 if (res > 0) { 2299 mGroupEntries.add(group); 2300 count += res; 2301 } 2302 2303 // Only add this directory if we don't already have a resource dir 2304 // for the current type. This ensures that we only add the dir once 2305 // for all configs. 2306 sp<AaptDir> rdir = resDir(resType); 2307 if (rdir == NULL) { 2308 mResDirs.add(dir); 2309 } 2310 } else { 2311 if (bundle->getVerbose()) { 2312 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string()); 2313 } 2314 } 2315 } 2316 2317bail: 2318 closedir(dir); 2319 dir = NULL; 2320 2321 if (err != 0) { 2322 return err; 2323 } 2324 return count; 2325} 2326 2327ssize_t 2328AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename) 2329{ 2330 int count = 0; 2331 SortedVector<AaptGroupEntry> entries; 2332 2333 ZipFile* zip = new ZipFile; 2334 status_t err = zip->open(filename, ZipFile::kOpenReadOnly); 2335 if (err != NO_ERROR) { 2336 fprintf(stderr, "error opening zip file %s\n", filename); 2337 count = err; 2338 delete zip; 2339 return -1; 2340 } 2341 2342 const int N = zip->getNumEntries(); 2343 for (int i=0; i<N; i++) { 2344 ZipEntry* entry = zip->getEntryByIndex(i); 2345 if (entry->getDeleted()) { 2346 continue; 2347 } 2348 2349 String8 entryName(entry->getFileName()); 2350 2351 String8 dirName = entryName.getPathDir(); 2352 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName); 2353 2354 String8 resType; 2355 AaptGroupEntry kind; 2356 2357 String8 remain; 2358 if (entryName.walkPath(&remain) == kResourceDir) { 2359 // these are the resources, pull their type out of the directory name 2360 kind.initFromDirName(remain.walkPath().string(), &resType); 2361 } else { 2362 // these are untyped and don't have an AaptGroupEntry 2363 } 2364 if (entries.indexOf(kind) < 0) { 2365 entries.add(kind); 2366 mGroupEntries.add(kind); 2367 } 2368 2369 // use the one from the zip file if they both exist. 2370 dir->removeFile(entryName.getPathLeaf()); 2371 2372 sp<AaptFile> file = new AaptFile(entryName, kind, resType); 2373 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file); 2374 if (err != NO_ERROR) { 2375 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string()); 2376 count = err; 2377 goto bail; 2378 } 2379 file->setCompressionMethod(entry->getCompressionMethod()); 2380 2381#if 0 2382 if (entryName == "AndroidManifest.xml") { 2383 printf("AndroidManifest.xml\n"); 2384 } 2385 printf("\n\nfile: %s\n", entryName.string()); 2386#endif 2387 2388 size_t len = entry->getUncompressedLen(); 2389 void* data = zip->uncompress(entry); 2390 void* buf = file->editData(len); 2391 memcpy(buf, data, len); 2392 2393#if 0 2394 const int OFF = 0; 2395 const unsigned char* p = (unsigned char*)data; 2396 const unsigned char* end = p+len; 2397 p += OFF; 2398 for (int i=0; i<32 && p < end; i++) { 2399 printf("0x%03x ", i*0x10 + OFF); 2400 for (int j=0; j<0x10 && p < end; j++) { 2401 printf(" %02x", *p); 2402 p++; 2403 } 2404 printf("\n"); 2405 } 2406#endif 2407 2408 free(data); 2409 2410 count++; 2411 } 2412 2413bail: 2414 delete zip; 2415 return count; 2416} 2417 2418status_t AaptAssets::filter(Bundle* bundle) 2419{ 2420 ResourceFilter reqFilter; 2421 status_t err = reqFilter.parse(bundle->getConfigurations()); 2422 if (err != NO_ERROR) { 2423 return err; 2424 } 2425 2426 ResourceFilter prefFilter; 2427 err = prefFilter.parse(bundle->getPreferredConfigurations()); 2428 if (err != NO_ERROR) { 2429 return err; 2430 } 2431 2432 if (reqFilter.isEmpty() && prefFilter.isEmpty()) { 2433 return NO_ERROR; 2434 } 2435 2436 if (bundle->getVerbose()) { 2437 if (!reqFilter.isEmpty()) { 2438 printf("Applying required filter: %s\n", 2439 bundle->getConfigurations()); 2440 } 2441 if (!prefFilter.isEmpty()) { 2442 printf("Applying preferred filter: %s\n", 2443 bundle->getPreferredConfigurations()); 2444 } 2445 } 2446 2447 const Vector<sp<AaptDir> >& resdirs = mResDirs; 2448 const size_t ND = resdirs.size(); 2449 for (size_t i=0; i<ND; i++) { 2450 const sp<AaptDir>& dir = resdirs.itemAt(i); 2451 if (dir->getLeaf() == kValuesDir) { 2452 // The "value" dir is special since a single file defines 2453 // multiple resources, so we can not do filtering on the 2454 // files themselves. 2455 continue; 2456 } 2457 if (dir->getLeaf() == kMipmapDir) { 2458 // We also skip the "mipmap" directory, since the point of this 2459 // is to include all densities without stripping. If you put 2460 // other configurations in here as well they won't be stripped 2461 // either... So don't do that. Seriously. What is wrong with you? 2462 continue; 2463 } 2464 2465 const size_t NG = dir->getFiles().size(); 2466 for (size_t j=0; j<NG; j++) { 2467 sp<AaptGroup> grp = dir->getFiles().valueAt(j); 2468 2469 // First remove any configurations we know we don't need. 2470 for (size_t k=0; k<grp->getFiles().size(); k++) { 2471 sp<AaptFile> file = grp->getFiles().valueAt(k); 2472 if (k == 0 && grp->getFiles().size() == 1) { 2473 // If this is the only file left, we need to keep it. 2474 // Otherwise the resource IDs we are using will be inconsistent 2475 // with what we get when not stripping. Sucky, but at least 2476 // for now we can rely on the back-end doing another filtering 2477 // pass to take this out and leave us with this resource name 2478 // containing no entries. 2479 continue; 2480 } 2481 if (file->getPath().getPathExtension() == ".xml") { 2482 // We can't remove .xml files at this point, because when 2483 // we parse them they may add identifier resources, so 2484 // removing them can cause our resource identifiers to 2485 // become inconsistent. 2486 continue; 2487 } 2488 const ResTable_config& config(file->getGroupEntry().toParams()); 2489 if (!reqFilter.match(config)) { 2490 if (bundle->getVerbose()) { 2491 printf("Pruning unneeded resource: %s\n", 2492 file->getPrintableSource().string()); 2493 } 2494 grp->removeFile(k); 2495 k--; 2496 } 2497 } 2498 2499 // Quick check: no preferred filters, nothing more to do. 2500 if (prefFilter.isEmpty()) { 2501 continue; 2502 } 2503 2504 // Get the preferred density if there is one. We do not match exactly for density. 2505 // If our preferred density is hdpi but we only have mdpi and xhdpi resources, we 2506 // pick xhdpi. 2507 uint32_t preferredDensity = 0; 2508 const SortedVector<uint32_t>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY); 2509 if (preferredConfigs != NULL && preferredConfigs->size() > 0) { 2510 preferredDensity = (*preferredConfigs)[0]; 2511 } 2512 2513 // Now deal with preferred configurations. 2514 for (int axis=AXIS_START; axis<=AXIS_END; axis++) { 2515 for (size_t k=0; k<grp->getFiles().size(); k++) { 2516 sp<AaptFile> file = grp->getFiles().valueAt(k); 2517 if (k == 0 && grp->getFiles().size() == 1) { 2518 // If this is the only file left, we need to keep it. 2519 // Otherwise the resource IDs we are using will be inconsistent 2520 // with what we get when not stripping. Sucky, but at least 2521 // for now we can rely on the back-end doing another filtering 2522 // pass to take this out and leave us with this resource name 2523 // containing no entries. 2524 continue; 2525 } 2526 if (file->getPath().getPathExtension() == ".xml") { 2527 // We can't remove .xml files at this point, because when 2528 // we parse them they may add identifier resources, so 2529 // removing them can cause our resource identifiers to 2530 // become inconsistent. 2531 continue; 2532 } 2533 const ResTable_config& config(file->getGroupEntry().toParams()); 2534 if (!prefFilter.match(axis, config)) { 2535 // This is a resource we would prefer not to have. Check 2536 // to see if have a similar variation that we would like 2537 // to have and, if so, we can drop it. 2538 2539 uint32_t bestDensity = config.density; 2540 2541 for (size_t m=0; m<grp->getFiles().size(); m++) { 2542 if (m == k) continue; 2543 sp<AaptFile> mfile = grp->getFiles().valueAt(m); 2544 const ResTable_config& mconfig(mfile->getGroupEntry().toParams()); 2545 if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) { 2546 if (axis == AXIS_DENSITY && preferredDensity > 0) { 2547 // See if there is a better density resource 2548 if (mconfig.density < bestDensity && 2549 mconfig.density > preferredDensity && 2550 bestDensity > preferredDensity) { 2551 // This density is between our best density and 2552 // the preferred density, therefore it is better. 2553 bestDensity = mconfig.density; 2554 } else if (mconfig.density > bestDensity && 2555 bestDensity < preferredDensity) { 2556 // This density is better than our best density and 2557 // our best density was smaller than our preferred 2558 // density, so it is better. 2559 bestDensity = mconfig.density; 2560 } 2561 } else if (prefFilter.match(axis, mconfig)) { 2562 if (bundle->getVerbose()) { 2563 printf("Pruning unneeded resource: %s\n", 2564 file->getPrintableSource().string()); 2565 } 2566 grp->removeFile(k); 2567 k--; 2568 break; 2569 } 2570 } 2571 } 2572 2573 if (axis == AXIS_DENSITY && preferredDensity > 0 && 2574 bestDensity != config.density) { 2575 if (bundle->getVerbose()) { 2576 printf("Pruning unneeded resource: %s\n", 2577 file->getPrintableSource().string()); 2578 } 2579 grp->removeFile(k); 2580 k--; 2581 } 2582 } 2583 } 2584 } 2585 } 2586 } 2587 2588 return NO_ERROR; 2589} 2590 2591sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name) 2592{ 2593 sp<AaptSymbols> sym = mSymbols.valueFor(name); 2594 if (sym == NULL) { 2595 sym = new AaptSymbols(); 2596 mSymbols.add(name, sym); 2597 } 2598 return sym; 2599} 2600 2601sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name) 2602{ 2603 sp<AaptSymbols> sym = mJavaSymbols.valueFor(name); 2604 if (sym == NULL) { 2605 sym = new AaptSymbols(); 2606 mJavaSymbols.add(name, sym); 2607 } 2608 return sym; 2609} 2610 2611status_t AaptAssets::applyJavaSymbols() 2612{ 2613 size_t N = mJavaSymbols.size(); 2614 for (size_t i=0; i<N; i++) { 2615 const String8& name = mJavaSymbols.keyAt(i); 2616 const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i); 2617 ssize_t pos = mSymbols.indexOfKey(name); 2618 if (pos < 0) { 2619 SourcePos pos; 2620 pos.error("Java symbol dir %s not defined\n", name.string()); 2621 return UNKNOWN_ERROR; 2622 } 2623 //printf("**** applying java symbols in dir %s\n", name.string()); 2624 status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols); 2625 if (err != NO_ERROR) { 2626 return err; 2627 } 2628 } 2629 2630 return NO_ERROR; 2631} 2632 2633bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const { 2634 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n", 2635 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0, 2636 // sym.isJavaSymbol ? 1 : 0); 2637 if (!mHavePrivateSymbols) return true; 2638 if (sym.isPublic) return true; 2639 if (includePrivate && sym.isJavaSymbol) return true; 2640 return false; 2641} 2642 2643status_t AaptAssets::buildIncludedResources(Bundle* bundle) 2644{ 2645 if (!mHaveIncludedAssets) { 2646 // Add in all includes. 2647 const Vector<const char*>& incl = bundle->getPackageIncludes(); 2648 const size_t N=incl.size(); 2649 for (size_t i=0; i<N; i++) { 2650 if (bundle->getVerbose()) 2651 printf("Including resources from package: %s\n", incl[i]); 2652 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) { 2653 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n", 2654 incl[i]); 2655 return UNKNOWN_ERROR; 2656 } 2657 } 2658 mHaveIncludedAssets = true; 2659 } 2660 2661 return NO_ERROR; 2662} 2663 2664status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file) 2665{ 2666 const ResTable& res = getIncludedResources(); 2667 // XXX dirty! 2668 return const_cast<ResTable&>(res).add(file->getData(), file->getSize()); 2669} 2670 2671const ResTable& AaptAssets::getIncludedResources() const 2672{ 2673 return mIncludedAssets.getResources(false); 2674} 2675 2676void AaptAssets::print(const String8& prefix) const 2677{ 2678 String8 innerPrefix(prefix); 2679 innerPrefix.append(" "); 2680 String8 innerInnerPrefix(innerPrefix); 2681 innerInnerPrefix.append(" "); 2682 printf("%sConfigurations:\n", prefix.string()); 2683 const size_t N=mGroupEntries.size(); 2684 for (size_t i=0; i<N; i++) { 2685 String8 cname = mGroupEntries.itemAt(i).toDirName(String8()); 2686 printf("%s %s\n", prefix.string(), 2687 cname != "" ? cname.string() : "(default)"); 2688 } 2689 2690 printf("\n%sFiles:\n", prefix.string()); 2691 AaptDir::print(innerPrefix); 2692 2693 printf("\n%sResource Dirs:\n", prefix.string()); 2694 const Vector<sp<AaptDir> >& resdirs = mResDirs; 2695 const size_t NR = resdirs.size(); 2696 for (size_t i=0; i<NR; i++) { 2697 const sp<AaptDir>& d = resdirs.itemAt(i); 2698 printf("%s Type %s\n", prefix.string(), d->getLeaf().string()); 2699 d->print(innerInnerPrefix); 2700 } 2701} 2702 2703sp<AaptDir> AaptAssets::resDir(const String8& name) const 2704{ 2705 const Vector<sp<AaptDir> >& resdirs = mResDirs; 2706 const size_t N = resdirs.size(); 2707 for (size_t i=0; i<N; i++) { 2708 const sp<AaptDir>& d = resdirs.itemAt(i); 2709 if (d->getLeaf() == name) { 2710 return d; 2711 } 2712 } 2713 return NULL; 2714} 2715 2716bool 2717valid_symbol_name(const String8& symbol) 2718{ 2719 static char const * const KEYWORDS[] = { 2720 "abstract", "assert", "boolean", "break", 2721 "byte", "case", "catch", "char", "class", "const", "continue", 2722 "default", "do", "double", "else", "enum", "extends", "final", 2723 "finally", "float", "for", "goto", "if", "implements", "import", 2724 "instanceof", "int", "interface", "long", "native", "new", "package", 2725 "private", "protected", "public", "return", "short", "static", 2726 "strictfp", "super", "switch", "synchronized", "this", "throw", 2727 "throws", "transient", "try", "void", "volatile", "while", 2728 "true", "false", "null", 2729 NULL 2730 }; 2731 const char*const* k = KEYWORDS; 2732 const char*const s = symbol.string(); 2733 while (*k) { 2734 if (0 == strcmp(s, *k)) { 2735 return false; 2736 } 2737 k++; 2738 } 2739 return true; 2740} 2741