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