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