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