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