AaptAssets.cpp revision 723738cfaec3dd7b0fe152c872c41bebf94074c4
1// 2// Copyright 2006 The Android Open Source Project 3// 4 5#include "AaptAssets.h" 6#include "Main.h" 7 8#include <utils/misc.h> 9#include <utils/SortedVector.h> 10 11#include <ctype.h> 12#include <dirent.h> 13#include <errno.h> 14 15static const char* kDefaultLocale = "default"; 16static const char* kWildcardName = "any"; 17static const char* kAssetDir = "assets"; 18static const char* kResourceDir = "res"; 19static const char* kInvalidChars = "/\\:"; 20static const size_t kMaxAssetFileName = 100; 21 22static const String8 kResString(kResourceDir); 23 24/* 25 * Names of asset files must meet the following criteria: 26 * 27 * - the filename length must be less than kMaxAssetFileName bytes long 28 * (and can't be empty) 29 * - all characters must be 7-bit printable ASCII 30 * - none of { '/' '\\' ':' } 31 * 32 * Pass in just the filename, not the full path. 33 */ 34static bool validateFileName(const char* fileName) 35{ 36 const char* cp = fileName; 37 size_t len = 0; 38 39 while (*cp != '\0') { 40 if ((*cp & 0x80) != 0) 41 return false; // reject high ASCII 42 if (*cp < 0x20 || *cp >= 0x7f) 43 return false; // reject control chars and 0x7f 44 if (strchr(kInvalidChars, *cp) != NULL) 45 return false; // reject path sep chars 46 cp++; 47 len++; 48 } 49 50 if (len < 1 || len > kMaxAssetFileName) 51 return false; // reject empty or too long 52 53 return true; 54} 55 56static bool isHidden(const char *root, const char *path) 57{ 58 const char *type = NULL; 59 60 // Skip all hidden files. 61 if (path[0] == '.') { 62 // Skip ., .. and .svn but don't chatter about it. 63 if (strcmp(path, ".") == 0 64 || strcmp(path, "..") == 0 65 || strcmp(path, ".svn") == 0) { 66 return true; 67 } 68 type = "hidden"; 69 } else if (path[0] == '_') { 70 // skip directories starting with _ (don't chatter about it) 71 String8 subdirName(root); 72 subdirName.appendPath(path); 73 if (getFileType(subdirName.string()) == kFileTypeDirectory) { 74 return true; 75 } 76 } else if (strcmp(path, "CVS") == 0) { 77 // Skip CVS but don't chatter about it. 78 return true; 79 } else if (strcasecmp(path, "thumbs.db") == 0 80 || strcasecmp(path, "picasa.ini") == 0) { 81 // Skip suspected image indexes files. 82 type = "index"; 83 } else if (path[strlen(path)-1] == '~') { 84 // Skip suspected emacs backup files. 85 type = "backup"; 86 } else { 87 // Let everything else through. 88 return false; 89 } 90 91 /* If we get this far, "type" should be set and the file 92 * should be skipped. 93 */ 94 String8 subdirName(root); 95 subdirName.appendPath(path); 96 fprintf(stderr, " (skipping %s %s '%s')\n", type, 97 getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file", 98 subdirName.string()); 99 100 return true; 101} 102 103// ========================================================================= 104// ========================================================================= 105// ========================================================================= 106 107status_t 108AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) 109{ 110 ResTable_config config; 111 112 // IMSI - MCC 113 if (getMccName(part.string(), &config)) { 114 *axis = AXIS_MCC; 115 *value = config.mcc; 116 return 0; 117 } 118 119 // IMSI - MNC 120 if (getMncName(part.string(), &config)) { 121 *axis = AXIS_MNC; 122 *value = config.mnc; 123 return 0; 124 } 125 126 // locale - language 127 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { 128 *axis = AXIS_LANGUAGE; 129 *value = part[1] << 8 | part[0]; 130 return 0; 131 } 132 133 // locale - language_REGION 134 if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1]) 135 && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) { 136 *axis = AXIS_LANGUAGE; 137 *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]); 138 return 0; 139 } 140 141 // orientation 142 if (getOrientationName(part.string(), &config)) { 143 *axis = AXIS_ORIENTATION; 144 *value = config.orientation; 145 return 0; 146 } 147 148 // density 149 if (getDensityName(part.string(), &config)) { 150 *axis = AXIS_DENSITY; 151 *value = config.density; 152 return 0; 153 } 154 155 // touchscreen 156 if (getTouchscreenName(part.string(), &config)) { 157 *axis = AXIS_TOUCHSCREEN; 158 *value = config.touchscreen; 159 return 0; 160 } 161 162 // keyboard hidden 163 if (getKeysHiddenName(part.string(), &config)) { 164 *axis = AXIS_KEYSHIDDEN; 165 *value = config.inputFlags; 166 return 0; 167 } 168 169 // keyboard 170 if (getKeyboardName(part.string(), &config)) { 171 *axis = AXIS_KEYBOARD; 172 *value = config.keyboard; 173 return 0; 174 } 175 176 // navigation 177 if (getNavigationName(part.string(), &config)) { 178 *axis = AXIS_NAVIGATION; 179 *value = config.navigation; 180 return 0; 181 } 182 183 // screen size 184 if (getScreenSizeName(part.string(), &config)) { 185 *axis = AXIS_SCREENSIZE; 186 *value = config.screenSize; 187 return 0; 188 } 189 190 // screen layout 191 if (getScreenLayoutName(part.string(), &config)) { 192 *axis = AXIS_SCREENLAYOUT; 193 *value = config.screenLayout; 194 return 0; 195 } 196 197 // version 198 if (getVersionName(part.string(), &config)) { 199 *axis = AXIS_VERSION; 200 *value = config.version; 201 return 0; 202 } 203 204 return 1; 205} 206 207bool 208AaptGroupEntry::initFromDirName(const char* dir, String8* resType) 209{ 210 Vector<String8> parts; 211 212 String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers; 213 214 const char *p = dir; 215 const char *q; 216 while (NULL != (q = strchr(p, '-'))) { 217 String8 val(p, q-p); 218 val.toLower(); 219 parts.add(val); 220 //printf("part: %s\n", parts[parts.size()-1].string()); 221 p = q+1; 222 } 223 String8 val(p); 224 val.toLower(); 225 parts.add(val); 226 //printf("part: %s\n", parts[parts.size()-1].string()); 227 228 const int N = parts.size(); 229 int index = 0; 230 String8 part = parts[index]; 231 232 // resource type 233 if (!isValidResourceType(part)) { 234 return false; 235 } 236 *resType = part; 237 238 index++; 239 if (index == N) { 240 goto success; 241 } 242 part = parts[index]; 243 244 // imsi - mcc 245 if (getMccName(part.string())) { 246 mcc = part; 247 248 index++; 249 if (index == N) { 250 goto success; 251 } 252 part = parts[index]; 253 } else { 254 //printf("not mcc: %s\n", part.string()); 255 } 256 257 // imsi - mnc 258 if (getMncName(part.string())) { 259 mnc = part; 260 261 index++; 262 if (index == N) { 263 goto success; 264 } 265 part = parts[index]; 266 } else { 267 //printf("not mcc: %s\n", part.string()); 268 } 269 270 // locale - language 271 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) { 272 loc = part; 273 274 index++; 275 if (index == N) { 276 goto success; 277 } 278 part = parts[index]; 279 } else { 280 //printf("not language: %s\n", part.string()); 281 } 282 283 // locale - region 284 if (loc.length() > 0 285 && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) { 286 loc += "-"; 287 part.toUpper(); 288 loc += part.string() + 1; 289 290 index++; 291 if (index == N) { 292 goto success; 293 } 294 part = parts[index]; 295 } else { 296 //printf("not region: %s\n", part.string()); 297 } 298 299 // orientation 300 if (getOrientationName(part.string())) { 301 orient = part; 302 303 index++; 304 if (index == N) { 305 goto success; 306 } 307 part = parts[index]; 308 } else { 309 //printf("not orientation: %s\n", part.string()); 310 } 311 312 // density 313 if (getDensityName(part.string())) { 314 den = part; 315 316 index++; 317 if (index == N) { 318 goto success; 319 } 320 part = parts[index]; 321 } else { 322 //printf("not density: %s\n", part.string()); 323 } 324 325 // touchscreen 326 if (getTouchscreenName(part.string())) { 327 touch = part; 328 329 index++; 330 if (index == N) { 331 goto success; 332 } 333 part = parts[index]; 334 } else { 335 //printf("not touchscreen: %s\n", part.string()); 336 } 337 338 // keyboard hidden 339 if (getKeysHiddenName(part.string())) { 340 keysHidden = part; 341 342 index++; 343 if (index == N) { 344 goto success; 345 } 346 part = parts[index]; 347 } else { 348 //printf("not keysHidden: %s\n", part.string()); 349 } 350 351 // keyboard 352 if (getKeyboardName(part.string())) { 353 key = part; 354 355 index++; 356 if (index == N) { 357 goto success; 358 } 359 part = parts[index]; 360 } else { 361 //printf("not keyboard: %s\n", part.string()); 362 } 363 364 if (getNavigationName(part.string())) { 365 nav = part; 366 367 index++; 368 if (index == N) { 369 goto success; 370 } 371 part = parts[index]; 372 } else { 373 //printf("not navigation: %s\n", part.string()); 374 } 375 376 if (getScreenSizeName(part.string())) { 377 size = part; 378 379 index++; 380 if (index == N) { 381 goto success; 382 } 383 part = parts[index]; 384 } else { 385 //printf("not screen size: %s\n", part.string()); 386 } 387 388 if (getScreenLayoutName(part.string())) { 389 layout = part; 390 391 index++; 392 if (index == N) { 393 goto success; 394 } 395 part = parts[index]; 396 } else { 397 //printf("not screen layout: %s\n", part.string()); 398 } 399 400 if (getVersionName(part.string())) { 401 vers = part; 402 403 index++; 404 if (index == N) { 405 goto success; 406 } 407 part = parts[index]; 408 } else { 409 //printf("not version: %s\n", part.string()); 410 } 411 412 // if there are extra parts, it doesn't match 413 return false; 414 415success: 416 this->mcc = mcc; 417 this->mnc = mnc; 418 this->locale = loc; 419 this->orientation = orient; 420 this->density = den; 421 this->touchscreen = touch; 422 this->keysHidden = keysHidden; 423 this->keyboard = key; 424 this->navigation = nav; 425 this->screenSize = size; 426 this->screenLayout = layout; 427 this->version = vers; 428 429 // what is this anyway? 430 this->vendor = ""; 431 432 return true; 433} 434 435String8 436AaptGroupEntry::toString() const 437{ 438 String8 s = this->mcc; 439 s += ","; 440 s += this->mnc; 441 s += ","; 442 s += this->locale; 443 s += ","; 444 s += this->orientation; 445 s += ","; 446 s += density; 447 s += ","; 448 s += touchscreen; 449 s += ","; 450 s += keysHidden; 451 s += ","; 452 s += keyboard; 453 s += ","; 454 s += navigation; 455 s += ","; 456 s += screenSize; 457 s += ","; 458 s += screenLayout; 459 s += ","; 460 s += version; 461 return s; 462} 463 464String8 465AaptGroupEntry::toDirName(const String8& resType) const 466{ 467 String8 s = resType; 468 if (this->mcc != "") { 469 s += "-"; 470 s += mcc; 471 } 472 if (this->mnc != "") { 473 s += "-"; 474 s += mnc; 475 } 476 if (this->locale != "") { 477 s += "-"; 478 s += locale; 479 } 480 if (this->orientation != "") { 481 s += "-"; 482 s += orientation; 483 } 484 if (this->density != "") { 485 s += "-"; 486 s += density; 487 } 488 if (this->touchscreen != "") { 489 s += "-"; 490 s += touchscreen; 491 } 492 if (this->keysHidden != "") { 493 s += "-"; 494 s += keysHidden; 495 } 496 if (this->keyboard != "") { 497 s += "-"; 498 s += keyboard; 499 } 500 if (this->navigation != "") { 501 s += "-"; 502 s += navigation; 503 } 504 if (this->screenSize != "") { 505 s += "-"; 506 s += screenSize; 507 } 508 if (this->screenLayout != "") { 509 s += "-"; 510 s += screenLayout; 511 } 512 if (this->version != "") { 513 s += "-"; 514 s += version; 515 } 516 517 return s; 518} 519 520bool AaptGroupEntry::getMccName(const char* name, 521 ResTable_config* out) 522{ 523 if (strcmp(name, kWildcardName) == 0) { 524 if (out) out->mcc = 0; 525 return true; 526 } 527 const char* c = name; 528 if (tolower(*c) != 'm') return false; 529 c++; 530 if (tolower(*c) != 'c') return false; 531 c++; 532 if (tolower(*c) != 'c') return false; 533 c++; 534 535 const char* val = c; 536 537 while (*c >= '0' && *c <= '9') { 538 c++; 539 } 540 if (*c != 0) return false; 541 if (c-val != 3) return false; 542 543 int d = atoi(val); 544 if (d != 0) { 545 if (out) out->mcc = d; 546 return true; 547 } 548 549 return false; 550} 551 552bool AaptGroupEntry::getMncName(const char* name, 553 ResTable_config* out) 554{ 555 if (strcmp(name, kWildcardName) == 0) { 556 if (out) out->mcc = 0; 557 return true; 558 } 559 const char* c = name; 560 if (tolower(*c) != 'm') return false; 561 c++; 562 if (tolower(*c) != 'n') return false; 563 c++; 564 if (tolower(*c) != 'c') return false; 565 c++; 566 567 const char* val = c; 568 569 while (*c >= '0' && *c <= '9') { 570 c++; 571 } 572 if (*c != 0) return false; 573 if (c-val == 0 || c-val > 3) return false; 574 575 int d = atoi(val); 576 if (d != 0) { 577 if (out) out->mnc = d; 578 return true; 579 } 580 581 return false; 582} 583 584/* 585 * Does this directory name fit the pattern of a locale dir ("en-rUS" or 586 * "default")? 587 * 588 * TODO: Should insist that the first two letters are lower case, and the 589 * second two are upper. 590 */ 591bool AaptGroupEntry::getLocaleName(const char* fileName, 592 ResTable_config* out) 593{ 594 if (strcmp(fileName, kWildcardName) == 0 595 || strcmp(fileName, kDefaultLocale) == 0) { 596 if (out) { 597 out->language[0] = 0; 598 out->language[1] = 0; 599 out->country[0] = 0; 600 out->country[1] = 0; 601 } 602 return true; 603 } 604 605 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) { 606 if (out) { 607 out->language[0] = fileName[0]; 608 out->language[1] = fileName[1]; 609 out->country[0] = 0; 610 out->country[1] = 0; 611 } 612 return true; 613 } 614 615 if (strlen(fileName) == 5 && 616 isalpha(fileName[0]) && 617 isalpha(fileName[1]) && 618 fileName[2] == '-' && 619 isalpha(fileName[3]) && 620 isalpha(fileName[4])) { 621 if (out) { 622 out->language[0] = fileName[0]; 623 out->language[1] = fileName[1]; 624 out->country[0] = fileName[3]; 625 out->country[1] = fileName[4]; 626 } 627 return true; 628 } 629 630 return false; 631} 632 633bool AaptGroupEntry::getOrientationName(const char* name, 634 ResTable_config* out) 635{ 636 if (strcmp(name, kWildcardName) == 0) { 637 if (out) out->orientation = out->ORIENTATION_ANY; 638 return true; 639 } else if (strcmp(name, "port") == 0) { 640 if (out) out->orientation = out->ORIENTATION_PORT; 641 return true; 642 } else if (strcmp(name, "land") == 0) { 643 if (out) out->orientation = out->ORIENTATION_LAND; 644 return true; 645 } else if (strcmp(name, "square") == 0) { 646 if (out) out->orientation = out->ORIENTATION_SQUARE; 647 return true; 648 } 649 650 return false; 651} 652 653bool AaptGroupEntry::getDensityName(const char* name, 654 ResTable_config* out) 655{ 656 if (strcmp(name, kWildcardName) == 0) { 657 if (out) out->density = 0; 658 return true; 659 } 660 char* c = (char*)name; 661 while (*c >= '0' && *c <= '9') { 662 c++; 663 } 664 665 // check that we have 'dpi' after the last digit. 666 if (toupper(c[0]) != 'D' || 667 toupper(c[1]) != 'P' || 668 toupper(c[2]) != 'I' || 669 c[3] != 0) { 670 return false; 671 } 672 673 // temporarily replace the first letter with \0 to 674 // use atoi. 675 char tmp = c[0]; 676 c[0] = '\0'; 677 678 int d = atoi(name); 679 c[0] = tmp; 680 681 if (d != 0) { 682 if (out) out->density = d; 683 return true; 684 } 685 686 return false; 687} 688 689bool AaptGroupEntry::getTouchscreenName(const char* name, 690 ResTable_config* out) 691{ 692 if (strcmp(name, kWildcardName) == 0) { 693 if (out) out->touchscreen = out->TOUCHSCREEN_ANY; 694 return true; 695 } else if (strcmp(name, "notouch") == 0) { 696 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH; 697 return true; 698 } else if (strcmp(name, "stylus") == 0) { 699 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS; 700 return true; 701 } else if (strcmp(name, "finger") == 0) { 702 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER; 703 return true; 704 } 705 706 return false; 707} 708 709bool AaptGroupEntry::getKeysHiddenName(const char* name, 710 ResTable_config* out) 711{ 712 uint8_t mask = 0; 713 uint8_t value = 0; 714 if (strcmp(name, kWildcardName) == 0) { 715 mask = out->MASK_KEYSHIDDEN; 716 value = out->KEYSHIDDEN_ANY; 717 } else if (strcmp(name, "keysexposed") == 0) { 718 mask = out->MASK_KEYSHIDDEN; 719 value = out->KEYSHIDDEN_NO; 720 } else if (strcmp(name, "keyshidden") == 0) { 721 mask = out->MASK_KEYSHIDDEN; 722 value = out->KEYSHIDDEN_YES; 723 } else if (strcmp(name, "keyssoft") == 0) { 724 mask = out->MASK_KEYSHIDDEN; 725 value = out->KEYSHIDDEN_SOFT; 726 } 727 728 if (mask != 0) { 729 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 730 return true; 731 } 732 733 return false; 734} 735 736bool AaptGroupEntry::getKeyboardName(const char* name, 737 ResTable_config* out) 738{ 739 if (strcmp(name, kWildcardName) == 0) { 740 if (out) out->keyboard = out->KEYBOARD_ANY; 741 return true; 742 } else if (strcmp(name, "nokeys") == 0) { 743 if (out) out->keyboard = out->KEYBOARD_NOKEYS; 744 return true; 745 } else if (strcmp(name, "qwerty") == 0) { 746 if (out) out->keyboard = out->KEYBOARD_QWERTY; 747 return true; 748 } else if (strcmp(name, "12key") == 0) { 749 if (out) out->keyboard = out->KEYBOARD_12KEY; 750 return true; 751 } 752 753 return false; 754} 755 756bool AaptGroupEntry::getNavigationName(const char* name, 757 ResTable_config* out) 758{ 759 if (strcmp(name, kWildcardName) == 0) { 760 if (out) out->navigation = out->NAVIGATION_ANY; 761 return true; 762 } else if (strcmp(name, "nonav") == 0) { 763 if (out) out->navigation = out->NAVIGATION_NONAV; 764 return true; 765 } else if (strcmp(name, "dpad") == 0) { 766 if (out) out->navigation = out->NAVIGATION_DPAD; 767 return true; 768 } else if (strcmp(name, "trackball") == 0) { 769 if (out) out->navigation = out->NAVIGATION_TRACKBALL; 770 return true; 771 } else if (strcmp(name, "wheel") == 0) { 772 if (out) out->navigation = out->NAVIGATION_WHEEL; 773 return true; 774 } 775 776 return false; 777} 778 779bool AaptGroupEntry::getScreenSizeName(const char* name, 780 ResTable_config* out) 781{ 782 if (strcmp(name, kWildcardName) == 0) { 783 if (out) { 784 out->screenWidth = out->SCREENWIDTH_ANY; 785 out->screenHeight = out->SCREENHEIGHT_ANY; 786 } 787 return true; 788 } 789 790 const char* x = name; 791 while (*x >= '0' && *x <= '9') x++; 792 if (x == name || *x != 'x') return false; 793 String8 xName(name, x-name); 794 x++; 795 796 const char* y = x; 797 while (*y >= '0' && *y <= '9') y++; 798 if (y == name || *y != 0) return false; 799 String8 yName(x, y-x); 800 801 uint16_t w = (uint16_t)atoi(xName.string()); 802 uint16_t h = (uint16_t)atoi(yName.string()); 803 if (w < h) { 804 return false; 805 } 806 807 if (out) { 808 out->screenWidth = w; 809 out->screenHeight = h; 810 } 811 812 return true; 813} 814 815bool AaptGroupEntry::getScreenLayoutName(const char* name, 816 ResTable_config* out) 817{ 818 if (strcmp(name, kWildcardName) == 0) { 819 if (out) out->screenLayout = out->SCREENLAYOUT_ANY; 820 return true; 821 } else if (strcmp(name, "smallscreen") == 0) { 822 if (out) out->screenLayout = out->SCREENLAYOUT_SMALL; 823 return true; 824 } else if (strcmp(name, "normalscreen") == 0) { 825 if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL; 826 return true; 827 } else if (strcmp(name, "largescreen") == 0) { 828 if (out) out->screenLayout = out->SCREENLAYOUT_LARGE; 829 return true; 830 } 831 832 return false; 833} 834 835bool AaptGroupEntry::getVersionName(const char* name, 836 ResTable_config* out) 837{ 838 if (strcmp(name, kWildcardName) == 0) { 839 if (out) { 840 out->sdkVersion = out->SDKVERSION_ANY; 841 out->minorVersion = out->MINORVERSION_ANY; 842 } 843 return true; 844 } 845 846 if (*name != 'v') { 847 return false; 848 } 849 850 name++; 851 const char* s = name; 852 while (*s >= '0' && *s <= '9') s++; 853 if (s == name || *s != 0) return false; 854 String8 sdkName(name, s-name); 855 856 if (out) { 857 out->sdkVersion = (uint16_t)atoi(sdkName.string()); 858 out->minorVersion = 0; 859 } 860 861 return true; 862} 863 864int AaptGroupEntry::compare(const AaptGroupEntry& o) const 865{ 866 int v = mcc.compare(o.mcc); 867 if (v == 0) v = mnc.compare(o.mnc); 868 if (v == 0) v = locale.compare(o.locale); 869 if (v == 0) v = vendor.compare(o.vendor); 870 if (v == 0) v = orientation.compare(o.orientation); 871 if (v == 0) v = density.compare(o.density); 872 if (v == 0) v = touchscreen.compare(o.touchscreen); 873 if (v == 0) v = keysHidden.compare(o.keysHidden); 874 if (v == 0) v = keyboard.compare(o.keyboard); 875 if (v == 0) v = navigation.compare(o.navigation); 876 if (v == 0) v = screenSize.compare(o.screenSize); 877 if (v == 0) v = screenLayout.compare(o.screenLayout); 878 if (v == 0) v = version.compare(o.version); 879 return v; 880} 881 882ResTable_config AaptGroupEntry::toParams() const 883{ 884 ResTable_config params; 885 memset(¶ms, 0, sizeof(params)); 886 getMccName(mcc.string(), ¶ms); 887 getMncName(mnc.string(), ¶ms); 888 getLocaleName(locale.string(), ¶ms); 889 getOrientationName(orientation.string(), ¶ms); 890 getDensityName(density.string(), ¶ms); 891 getTouchscreenName(touchscreen.string(), ¶ms); 892 getKeysHiddenName(keysHidden.string(), ¶ms); 893 getKeyboardName(keyboard.string(), ¶ms); 894 getNavigationName(navigation.string(), ¶ms); 895 getScreenSizeName(screenSize.string(), ¶ms); 896 getScreenLayoutName(screenLayout.string(), ¶ms); 897 getVersionName(version.string(), ¶ms); 898 return params; 899} 900 901// ========================================================================= 902// ========================================================================= 903// ========================================================================= 904 905void* AaptFile::editData(size_t size) 906{ 907 if (size <= mBufferSize) { 908 mDataSize = size; 909 return mData; 910 } 911 size_t allocSize = (size*3)/2; 912 void* buf = realloc(mData, allocSize); 913 if (buf == NULL) { 914 return NULL; 915 } 916 mData = buf; 917 mDataSize = size; 918 mBufferSize = allocSize; 919 return buf; 920} 921 922void* AaptFile::editData(size_t* outSize) 923{ 924 if (outSize) { 925 *outSize = mDataSize; 926 } 927 return mData; 928} 929 930void* AaptFile::padData(size_t wordSize) 931{ 932 const size_t extra = mDataSize%wordSize; 933 if (extra == 0) { 934 return mData; 935 } 936 937 size_t initial = mDataSize; 938 void* data = editData(initial+(wordSize-extra)); 939 if (data != NULL) { 940 memset(((uint8_t*)data) + initial, 0, wordSize-extra); 941 } 942 return data; 943} 944 945status_t AaptFile::writeData(const void* data, size_t size) 946{ 947 size_t end = mDataSize; 948 size_t total = size + end; 949 void* buf = editData(total); 950 if (buf == NULL) { 951 return UNKNOWN_ERROR; 952 } 953 memcpy(((char*)buf)+end, data, size); 954 return NO_ERROR; 955} 956 957void AaptFile::clearData() 958{ 959 if (mData != NULL) free(mData); 960 mData = NULL; 961 mDataSize = 0; 962 mBufferSize = 0; 963} 964 965String8 AaptFile::getPrintableSource() const 966{ 967 if (hasData()) { 968 String8 name(mGroupEntry.locale.string()); 969 name.appendPath(mGroupEntry.vendor.string()); 970 name.appendPath(mPath); 971 name.append(" #generated"); 972 return name; 973 } 974 return mSourceFile; 975} 976 977// ========================================================================= 978// ========================================================================= 979// ========================================================================= 980 981status_t AaptGroup::addFile(const sp<AaptFile>& file) 982{ 983 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) { 984 file->mPath = mPath; 985 mFiles.add(file->getGroupEntry(), file); 986 return NO_ERROR; 987 } 988 989 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", 990 getPrintableSource().string()); 991 return UNKNOWN_ERROR; 992} 993 994void AaptGroup::removeFile(size_t index) 995{ 996 mFiles.removeItemsAt(index); 997} 998 999void AaptGroup::print() const 1000{ 1001 printf(" %s\n", getPath().string()); 1002 const size_t N=mFiles.size(); 1003 size_t i; 1004 for (i=0; i<N; i++) { 1005 sp<AaptFile> file = mFiles.valueAt(i); 1006 const AaptGroupEntry& e = file->getGroupEntry(); 1007 if (file->hasData()) { 1008 printf(" Gen: (%s) %d bytes\n", e.toString().string(), 1009 (int)file->getSize()); 1010 } else { 1011 printf(" Src: %s\n", file->getPrintableSource().string()); 1012 } 1013 } 1014} 1015 1016String8 AaptGroup::getPrintableSource() const 1017{ 1018 if (mFiles.size() > 0) { 1019 // Arbitrarily pull the first source file out of the list. 1020 return mFiles.valueAt(0)->getPrintableSource(); 1021 } 1022 1023 // Should never hit this case, but to be safe... 1024 return getPath(); 1025 1026} 1027 1028// ========================================================================= 1029// ========================================================================= 1030// ========================================================================= 1031 1032status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file) 1033{ 1034 if (mFiles.indexOfKey(name) >= 0) { 1035 return ALREADY_EXISTS; 1036 } 1037 mFiles.add(name, file); 1038 return NO_ERROR; 1039} 1040 1041status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir) 1042{ 1043 if (mDirs.indexOfKey(name) >= 0) { 1044 return ALREADY_EXISTS; 1045 } 1046 mDirs.add(name, dir); 1047 return NO_ERROR; 1048} 1049 1050sp<AaptDir> AaptDir::makeDir(const String8& path) 1051{ 1052 String8 name; 1053 String8 remain = path; 1054 1055 sp<AaptDir> subdir = this; 1056 while (name = remain.walkPath(&remain), remain != "") { 1057 subdir = subdir->makeDir(name); 1058 } 1059 1060 ssize_t i = subdir->mDirs.indexOfKey(name); 1061 if (i >= 0) { 1062 return subdir->mDirs.valueAt(i); 1063 } 1064 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name)); 1065 subdir->mDirs.add(name, dir); 1066 return dir; 1067} 1068 1069void AaptDir::removeFile(const String8& name) 1070{ 1071 mFiles.removeItem(name); 1072} 1073 1074void AaptDir::removeDir(const String8& name) 1075{ 1076 mDirs.removeItem(name); 1077} 1078 1079status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName) 1080{ 1081 sp<AaptGroup> origGroup; 1082 1083 // Find and remove the given file with shear, brute force! 1084 const size_t NG = mFiles.size(); 1085 size_t i; 1086 for (i=0; origGroup == NULL && i<NG; i++) { 1087 sp<AaptGroup> g = mFiles.valueAt(i); 1088 const size_t NF = g->getFiles().size(); 1089 for (size_t j=0; j<NF; j++) { 1090 if (g->getFiles().valueAt(j) == file) { 1091 origGroup = g; 1092 g->removeFile(j); 1093 if (NF == 1) { 1094 mFiles.removeItemsAt(i); 1095 } 1096 break; 1097 } 1098 } 1099 } 1100 1101 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string()); 1102 1103 // Place the file under its new name. 1104 if (origGroup != NULL) { 1105 return addLeafFile(newName, file); 1106 } 1107 1108 return NO_ERROR; 1109} 1110 1111status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file) 1112{ 1113 sp<AaptGroup> group; 1114 if (mFiles.indexOfKey(leafName) >= 0) { 1115 group = mFiles.valueFor(leafName); 1116 } else { 1117 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName)); 1118 mFiles.add(leafName, group); 1119 } 1120 1121 return group->addFile(file); 1122} 1123 1124ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, 1125 const AaptGroupEntry& kind, const String8& resType) 1126{ 1127 Vector<String8> fileNames; 1128 1129 { 1130 DIR* dir = NULL; 1131 1132 dir = opendir(srcDir.string()); 1133 if (dir == NULL) { 1134 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 1135 return UNKNOWN_ERROR; 1136 } 1137 1138 /* 1139 * Slurp the filenames out of the directory. 1140 */ 1141 while (1) { 1142 struct dirent* entry; 1143 1144 entry = readdir(dir); 1145 if (entry == NULL) 1146 break; 1147 1148 if (isHidden(srcDir.string(), entry->d_name)) 1149 continue; 1150 1151 fileNames.add(String8(entry->d_name)); 1152 } 1153 1154 closedir(dir); 1155 } 1156 1157 ssize_t count = 0; 1158 1159 /* 1160 * Stash away the files and recursively descend into subdirectories. 1161 */ 1162 const size_t N = fileNames.size(); 1163 size_t i; 1164 for (i = 0; i < N; i++) { 1165 String8 pathName(srcDir); 1166 FileType type; 1167 1168 pathName.appendPath(fileNames[i].string()); 1169 type = getFileType(pathName.string()); 1170 if (type == kFileTypeDirectory) { 1171 sp<AaptDir> subdir; 1172 bool notAdded = false; 1173 if (mDirs.indexOfKey(fileNames[i]) >= 0) { 1174 subdir = mDirs.valueFor(fileNames[i]); 1175 } else { 1176 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i])); 1177 notAdded = true; 1178 } 1179 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, 1180 resType); 1181 if (res < NO_ERROR) { 1182 return res; 1183 } 1184 if (res > 0 && notAdded) { 1185 mDirs.add(fileNames[i], subdir); 1186 } 1187 count += res; 1188 } else if (type == kFileTypeRegular) { 1189 sp<AaptFile> file = new AaptFile(pathName, kind, resType); 1190 status_t err = addLeafFile(fileNames[i], file); 1191 if (err != NO_ERROR) { 1192 return err; 1193 } 1194 1195 count++; 1196 1197 } else { 1198 if (bundle->getVerbose()) 1199 printf(" (ignoring non-file/dir '%s')\n", pathName.string()); 1200 } 1201 } 1202 1203 return count; 1204} 1205 1206status_t AaptDir::validate() const 1207{ 1208 const size_t NF = mFiles.size(); 1209 const size_t ND = mDirs.size(); 1210 size_t i; 1211 for (i = 0; i < NF; i++) { 1212 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) { 1213 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1214 "Invalid filename. Unable to add."); 1215 return UNKNOWN_ERROR; 1216 } 1217 1218 size_t j; 1219 for (j = i+1; j < NF; j++) { 1220 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1221 mFiles.valueAt(j)->getLeaf().string()) == 0) { 1222 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1223 "File is case-insensitive equivalent to: %s", 1224 mFiles.valueAt(j)->getPrintableSource().string()); 1225 return UNKNOWN_ERROR; 1226 } 1227 1228 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" 1229 // (this is mostly caught by the "marked" stuff, below) 1230 } 1231 1232 for (j = 0; j < ND; j++) { 1233 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1234 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1235 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1236 "File conflicts with dir from: %s", 1237 mDirs.valueAt(j)->getPrintableSource().string()); 1238 return UNKNOWN_ERROR; 1239 } 1240 } 1241 } 1242 1243 for (i = 0; i < ND; i++) { 1244 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) { 1245 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1246 "Invalid directory name, unable to add."); 1247 return UNKNOWN_ERROR; 1248 } 1249 1250 size_t j; 1251 for (j = i+1; j < ND; j++) { 1252 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(), 1253 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1254 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1255 "Directory is case-insensitive equivalent to: %s", 1256 mDirs.valueAt(j)->getPrintableSource().string()); 1257 return UNKNOWN_ERROR; 1258 } 1259 } 1260 1261 status_t err = mDirs.valueAt(i)->validate(); 1262 if (err != NO_ERROR) { 1263 return err; 1264 } 1265 } 1266 1267 return NO_ERROR; 1268} 1269 1270void AaptDir::print() const 1271{ 1272 const size_t ND=getDirs().size(); 1273 size_t i; 1274 for (i=0; i<ND; i++) { 1275 getDirs().valueAt(i)->print(); 1276 } 1277 1278 const size_t NF=getFiles().size(); 1279 for (i=0; i<NF; i++) { 1280 getFiles().valueAt(i)->print(); 1281 } 1282} 1283 1284String8 AaptDir::getPrintableSource() const 1285{ 1286 if (mFiles.size() > 0) { 1287 // Arbitrarily pull the first file out of the list as the source dir. 1288 return mFiles.valueAt(0)->getPrintableSource().getPathDir(); 1289 } 1290 if (mDirs.size() > 0) { 1291 // Or arbitrarily pull the first dir out of the list as the source dir. 1292 return mDirs.valueAt(0)->getPrintableSource().getPathDir(); 1293 } 1294 1295 // Should never hit this case, but to be safe... 1296 return mPath; 1297 1298} 1299 1300// ========================================================================= 1301// ========================================================================= 1302// ========================================================================= 1303 1304sp<AaptFile> AaptAssets::addFile( 1305 const String8& filePath, const AaptGroupEntry& entry, 1306 const String8& srcDir, sp<AaptGroup>* outGroup, 1307 const String8& resType) 1308{ 1309 sp<AaptDir> dir = this; 1310 sp<AaptGroup> group; 1311 sp<AaptFile> file; 1312 String8 root, remain(filePath), partialPath; 1313 while (remain.length() > 0) { 1314 root = remain.walkPath(&remain); 1315 partialPath.appendPath(root); 1316 1317 const String8 rootStr(root); 1318 1319 if (remain.length() == 0) { 1320 ssize_t i = dir->getFiles().indexOfKey(rootStr); 1321 if (i >= 0) { 1322 group = dir->getFiles().valueAt(i); 1323 } else { 1324 group = new AaptGroup(rootStr, filePath); 1325 status_t res = dir->addFile(rootStr, group); 1326 if (res != NO_ERROR) { 1327 return NULL; 1328 } 1329 } 1330 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType); 1331 status_t res = group->addFile(file); 1332 if (res != NO_ERROR) { 1333 return NULL; 1334 } 1335 break; 1336 1337 } else { 1338 ssize_t i = dir->getDirs().indexOfKey(rootStr); 1339 if (i >= 0) { 1340 dir = dir->getDirs().valueAt(i); 1341 } else { 1342 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath); 1343 status_t res = dir->addDir(rootStr, subdir); 1344 if (res != NO_ERROR) { 1345 return NULL; 1346 } 1347 dir = subdir; 1348 } 1349 } 1350 } 1351 1352 mGroupEntries.add(entry); 1353 if (outGroup) *outGroup = group; 1354 return file; 1355} 1356 1357void AaptAssets::addResource(const String8& leafName, const String8& path, 1358 const sp<AaptFile>& file, const String8& resType) 1359{ 1360 sp<AaptDir> res = AaptDir::makeDir(kResString); 1361 String8 dirname = file->getGroupEntry().toDirName(resType); 1362 sp<AaptDir> subdir = res->makeDir(dirname); 1363 sp<AaptGroup> grr = new AaptGroup(leafName, path); 1364 grr->addFile(file); 1365 1366 subdir->addFile(leafName, grr); 1367} 1368 1369 1370ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) 1371{ 1372 int count; 1373 int totalCount = 0; 1374 FileType type; 1375 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs(); 1376 const size_t dirCount =resDirs.size(); 1377 sp<AaptAssets> current = this; 1378 1379 const int N = bundle->getFileSpecCount(); 1380 1381 /* 1382 * If a package manifest was specified, include that first. 1383 */ 1384 if (bundle->getAndroidManifestFile() != NULL) { 1385 // place at root of zip. 1386 String8 srcFile(bundle->getAndroidManifestFile()); 1387 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(), 1388 NULL, String8()); 1389 totalCount++; 1390 } 1391 1392 /* 1393 * If a directory of custom assets was supplied, slurp 'em up. 1394 */ 1395 if (bundle->getAssetSourceDir()) { 1396 const char* assetDir = bundle->getAssetSourceDir(); 1397 1398 FileType type = getFileType(assetDir); 1399 if (type == kFileTypeNonexistent) { 1400 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir); 1401 return UNKNOWN_ERROR; 1402 } 1403 if (type != kFileTypeDirectory) { 1404 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 1405 return UNKNOWN_ERROR; 1406 } 1407 1408 String8 assetRoot(assetDir); 1409 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir)); 1410 AaptGroupEntry group; 1411 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, 1412 String8()); 1413 if (count < 0) { 1414 totalCount = count; 1415 goto bail; 1416 } 1417 if (count > 0) { 1418 mGroupEntries.add(group); 1419 } 1420 totalCount += count; 1421 1422 if (bundle->getVerbose()) 1423 printf("Found %d custom asset file%s in %s\n", 1424 count, (count==1) ? "" : "s", assetDir); 1425 } 1426 1427 /* 1428 * If a directory of resource-specific assets was supplied, slurp 'em up. 1429 */ 1430 for (size_t i=0; i<dirCount; i++) { 1431 const char *res = resDirs[i]; 1432 if (res) { 1433 type = getFileType(res); 1434 if (type == kFileTypeNonexistent) { 1435 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res); 1436 return UNKNOWN_ERROR; 1437 } 1438 if (type == kFileTypeDirectory) { 1439 if (i>0) { 1440 sp<AaptAssets> nextOverlay = new AaptAssets(); 1441 current->setOverlay(nextOverlay); 1442 current = nextOverlay; 1443 } 1444 count = current->slurpResourceTree(bundle, String8(res)); 1445 1446 if (count < 0) { 1447 totalCount = count; 1448 goto bail; 1449 } 1450 totalCount += count; 1451 } 1452 else { 1453 fprintf(stderr, "ERROR: '%s' is not a directory\n", res); 1454 return UNKNOWN_ERROR; 1455 } 1456 } 1457 1458 } 1459 /* 1460 * Now do any additional raw files. 1461 */ 1462 for (int arg=0; arg<N; arg++) { 1463 const char* assetDir = bundle->getFileSpecEntry(arg); 1464 1465 FileType type = getFileType(assetDir); 1466 if (type == kFileTypeNonexistent) { 1467 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir); 1468 return UNKNOWN_ERROR; 1469 } 1470 if (type != kFileTypeDirectory) { 1471 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 1472 return UNKNOWN_ERROR; 1473 } 1474 1475 String8 assetRoot(assetDir); 1476 1477 if (bundle->getVerbose()) 1478 printf("Processing raw dir '%s'\n", (const char*) assetDir); 1479 1480 /* 1481 * Do a recursive traversal of subdir tree. We don't make any 1482 * guarantees about ordering, so we're okay with an inorder search 1483 * using whatever order the OS happens to hand back to us. 1484 */ 1485 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8()); 1486 if (count < 0) { 1487 /* failure; report error and remove archive */ 1488 totalCount = count; 1489 goto bail; 1490 } 1491 totalCount += count; 1492 1493 if (bundle->getVerbose()) 1494 printf("Found %d asset file%s in %s\n", 1495 count, (count==1) ? "" : "s", assetDir); 1496 } 1497 1498 count = validate(); 1499 if (count != NO_ERROR) { 1500 totalCount = count; 1501 goto bail; 1502 } 1503 1504 1505bail: 1506 return totalCount; 1507} 1508 1509ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, 1510 const AaptGroupEntry& kind, 1511 const String8& resType) 1512{ 1513 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType); 1514 if (res > 0) { 1515 mGroupEntries.add(kind); 1516 } 1517 1518 return res; 1519} 1520 1521ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) 1522{ 1523 ssize_t err = 0; 1524 1525 DIR* dir = opendir(srcDir.string()); 1526 if (dir == NULL) { 1527 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 1528 return UNKNOWN_ERROR; 1529 } 1530 1531 status_t count = 0; 1532 1533 /* 1534 * Run through the directory, looking for dirs that match the 1535 * expected pattern. 1536 */ 1537 while (1) { 1538 struct dirent* entry = readdir(dir); 1539 if (entry == NULL) { 1540 break; 1541 } 1542 1543 if (isHidden(srcDir.string(), entry->d_name)) { 1544 continue; 1545 } 1546 1547 String8 subdirName(srcDir); 1548 subdirName.appendPath(entry->d_name); 1549 1550 AaptGroupEntry group; 1551 String8 resType; 1552 bool b = group.initFromDirName(entry->d_name, &resType); 1553 if (!b) { 1554 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(), 1555 entry->d_name); 1556 err = -1; 1557 continue; 1558 } 1559 1560 FileType type = getFileType(subdirName.string()); 1561 1562 if (type == kFileTypeDirectory) { 1563 sp<AaptDir> dir = makeDir(String8(entry->d_name)); 1564 ssize_t res = dir->slurpFullTree(bundle, subdirName, group, 1565 resType); 1566 if (res < 0) { 1567 count = res; 1568 goto bail; 1569 } 1570 if (res > 0) { 1571 mGroupEntries.add(group); 1572 count += res; 1573 } 1574 1575 mDirs.add(dir); 1576 } else { 1577 if (bundle->getVerbose()) { 1578 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string()); 1579 } 1580 } 1581 } 1582 1583bail: 1584 closedir(dir); 1585 dir = NULL; 1586 1587 if (err != 0) { 1588 return err; 1589 } 1590 return count; 1591} 1592 1593ssize_t 1594AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename) 1595{ 1596 int count = 0; 1597 SortedVector<AaptGroupEntry> entries; 1598 1599 ZipFile* zip = new ZipFile; 1600 status_t err = zip->open(filename, ZipFile::kOpenReadOnly); 1601 if (err != NO_ERROR) { 1602 fprintf(stderr, "error opening zip file %s\n", filename); 1603 count = err; 1604 delete zip; 1605 return -1; 1606 } 1607 1608 const int N = zip->getNumEntries(); 1609 for (int i=0; i<N; i++) { 1610 ZipEntry* entry = zip->getEntryByIndex(i); 1611 if (entry->getDeleted()) { 1612 continue; 1613 } 1614 1615 String8 entryName(entry->getFileName()); 1616 1617 String8 dirName = entryName.getPathDir(); 1618 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName); 1619 1620 String8 resType; 1621 AaptGroupEntry kind; 1622 1623 String8 remain; 1624 if (entryName.walkPath(&remain) == kResourceDir) { 1625 // these are the resources, pull their type out of the directory name 1626 kind.initFromDirName(remain.walkPath().string(), &resType); 1627 } else { 1628 // these are untyped and don't have an AaptGroupEntry 1629 } 1630 if (entries.indexOf(kind) < 0) { 1631 entries.add(kind); 1632 mGroupEntries.add(kind); 1633 } 1634 1635 // use the one from the zip file if they both exist. 1636 dir->removeFile(entryName.getPathLeaf()); 1637 1638 sp<AaptFile> file = new AaptFile(entryName, kind, resType); 1639 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file); 1640 if (err != NO_ERROR) { 1641 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string()); 1642 count = err; 1643 goto bail; 1644 } 1645 file->setCompressionMethod(entry->getCompressionMethod()); 1646 1647#if 0 1648 if (entryName == "AndroidManifest.xml") { 1649 printf("AndroidManifest.xml\n"); 1650 } 1651 printf("\n\nfile: %s\n", entryName.string()); 1652#endif 1653 1654 size_t len = entry->getUncompressedLen(); 1655 void* data = zip->uncompress(entry); 1656 void* buf = file->editData(len); 1657 memcpy(buf, data, len); 1658 1659#if 0 1660 const int OFF = 0; 1661 const unsigned char* p = (unsigned char*)data; 1662 const unsigned char* end = p+len; 1663 p += OFF; 1664 for (int i=0; i<32 && p < end; i++) { 1665 printf("0x%03x ", i*0x10 + OFF); 1666 for (int j=0; j<0x10 && p < end; j++) { 1667 printf(" %02x", *p); 1668 p++; 1669 } 1670 printf("\n"); 1671 } 1672#endif 1673 1674 free(data); 1675 1676 count++; 1677 } 1678 1679bail: 1680 delete zip; 1681 return count; 1682} 1683 1684sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name) 1685{ 1686 sp<AaptSymbols> sym = mSymbols.valueFor(name); 1687 if (sym == NULL) { 1688 sym = new AaptSymbols(); 1689 mSymbols.add(name, sym); 1690 } 1691 return sym; 1692} 1693 1694status_t AaptAssets::buildIncludedResources(Bundle* bundle) 1695{ 1696 if (!mHaveIncludedAssets) { 1697 // Add in all includes. 1698 const Vector<const char*>& incl = bundle->getPackageIncludes(); 1699 const size_t N=incl.size(); 1700 for (size_t i=0; i<N; i++) { 1701 if (bundle->getVerbose()) 1702 printf("Including resources from package: %s\n", incl[i]); 1703 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) { 1704 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n", 1705 incl[i]); 1706 return UNKNOWN_ERROR; 1707 } 1708 } 1709 mHaveIncludedAssets = true; 1710 } 1711 1712 return NO_ERROR; 1713} 1714 1715status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file) 1716{ 1717 const ResTable& res = getIncludedResources(); 1718 // XXX dirty! 1719 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL); 1720} 1721 1722const ResTable& AaptAssets::getIncludedResources() const 1723{ 1724 return mIncludedAssets.getResources(false); 1725} 1726 1727void AaptAssets::print() const 1728{ 1729 printf("Locale/Vendor pairs:\n"); 1730 const size_t N=mGroupEntries.size(); 1731 for (size_t i=0; i<N; i++) { 1732 printf(" %s/%s\n", 1733 mGroupEntries.itemAt(i).locale.string(), 1734 mGroupEntries.itemAt(i).vendor.string()); 1735 } 1736 1737 printf("\nFiles:\n"); 1738 AaptDir::print(); 1739} 1740 1741bool 1742valid_symbol_name(const String8& symbol) 1743{ 1744 static char const * const KEYWORDS[] = { 1745 "abstract", "assert", "boolean", "break", 1746 "byte", "case", "catch", "char", "class", "const", "continue", 1747 "default", "do", "double", "else", "enum", "extends", "final", 1748 "finally", "float", "for", "goto", "if", "implements", "import", 1749 "instanceof", "int", "interface", "long", "native", "new", "package", 1750 "private", "protected", "public", "return", "short", "static", 1751 "strictfp", "super", "switch", "synchronized", "this", "throw", 1752 "throws", "transient", "try", "void", "volatile", "while", 1753 "true", "false", "null", 1754 NULL 1755 }; 1756 const char*const* k = KEYWORDS; 1757 const char*const s = symbol.string(); 1758 while (*k) { 1759 if (0 == strcmp(s, *k)) { 1760 return false; 1761 } 1762 k++; 1763 } 1764 return true; 1765} 1766