AaptAssets.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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, "picassa.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 } 699 700 if (mask != 0) { 701 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 702 return true; 703 } 704 705 return false; 706} 707 708bool AaptGroupEntry::getKeyboardName(const char* name, 709 ResTable_config* out) 710{ 711 if (strcmp(name, kWildcardName) == 0) { 712 if (out) out->keyboard = out->KEYBOARD_ANY; 713 return true; 714 } else if (strcmp(name, "nokeys") == 0) { 715 if (out) out->keyboard = out->KEYBOARD_NOKEYS; 716 return true; 717 } else if (strcmp(name, "qwerty") == 0) { 718 if (out) out->keyboard = out->KEYBOARD_QWERTY; 719 return true; 720 } else if (strcmp(name, "12key") == 0) { 721 if (out) out->keyboard = out->KEYBOARD_12KEY; 722 return true; 723 } 724 725 return false; 726} 727 728bool AaptGroupEntry::getNavigationName(const char* name, 729 ResTable_config* out) 730{ 731 if (strcmp(name, kWildcardName) == 0) { 732 if (out) out->navigation = out->NAVIGATION_ANY; 733 return true; 734 } else if (strcmp(name, "nonav") == 0) { 735 if (out) out->navigation = out->NAVIGATION_NONAV; 736 return true; 737 } else if (strcmp(name, "dpad") == 0) { 738 if (out) out->navigation = out->NAVIGATION_DPAD; 739 return true; 740 } else if (strcmp(name, "trackball") == 0) { 741 if (out) out->navigation = out->NAVIGATION_TRACKBALL; 742 return true; 743 } else if (strcmp(name, "wheel") == 0) { 744 if (out) out->navigation = out->NAVIGATION_WHEEL; 745 return true; 746 } 747 748 return false; 749} 750 751bool AaptGroupEntry::getScreenSizeName(const char* name, 752 ResTable_config* out) 753{ 754 if (strcmp(name, kWildcardName) == 0) { 755 if (out) { 756 out->screenWidth = out->SCREENWIDTH_ANY; 757 out->screenHeight = out->SCREENHEIGHT_ANY; 758 } 759 return true; 760 } 761 762 const char* x = name; 763 while (*x >= '0' && *x <= '9') x++; 764 if (x == name || *x != 'x') return false; 765 String8 xName(name, x-name); 766 x++; 767 768 const char* y = x; 769 while (*y >= '0' && *y <= '9') y++; 770 if (y == name || *y != 0) return false; 771 String8 yName(x, y-x); 772 773 uint16_t w = (uint16_t)atoi(xName.string()); 774 uint16_t h = (uint16_t)atoi(yName.string()); 775 if (w < h) { 776 return false; 777 } 778 779 if (out) { 780 out->screenWidth = w; 781 out->screenHeight = h; 782 } 783 784 return true; 785} 786 787bool AaptGroupEntry::getVersionName(const char* name, 788 ResTable_config* out) 789{ 790 if (strcmp(name, kWildcardName) == 0) { 791 if (out) { 792 out->sdkVersion = out->SDKVERSION_ANY; 793 out->minorVersion = out->MINORVERSION_ANY; 794 } 795 return true; 796 } 797 798 if (*name != 'v') { 799 return false; 800 } 801 802 name++; 803 const char* s = name; 804 while (*s >= '0' && *s <= '9') s++; 805 if (s == name || *s != 0) return false; 806 String8 sdkName(name, s-name); 807 808 if (out) { 809 out->sdkVersion = (uint16_t)atoi(sdkName.string()); 810 out->minorVersion = 0; 811 } 812 813 return true; 814} 815 816int AaptGroupEntry::compare(const AaptGroupEntry& o) const 817{ 818 int v = mcc.compare(o.mcc); 819 if (v == 0) v = mnc.compare(o.mnc); 820 if (v == 0) v = locale.compare(o.locale); 821 if (v == 0) v = vendor.compare(o.vendor); 822 if (v == 0) v = orientation.compare(o.orientation); 823 if (v == 0) v = density.compare(o.density); 824 if (v == 0) v = touchscreen.compare(o.touchscreen); 825 if (v == 0) v = keysHidden.compare(o.keysHidden); 826 if (v == 0) v = keyboard.compare(o.keyboard); 827 if (v == 0) v = navigation.compare(o.navigation); 828 if (v == 0) v = screenSize.compare(o.screenSize); 829 if (v == 0) v = version.compare(o.version); 830 return v; 831} 832 833ResTable_config AaptGroupEntry::toParams() const 834{ 835 ResTable_config params; 836 memset(¶ms, 0, sizeof(params)); 837 getMccName(mcc.string(), ¶ms); 838 getMncName(mnc.string(), ¶ms); 839 getLocaleName(locale.string(), ¶ms); 840 getOrientationName(orientation.string(), ¶ms); 841 getDensityName(density.string(), ¶ms); 842 getTouchscreenName(touchscreen.string(), ¶ms); 843 getKeysHiddenName(keysHidden.string(), ¶ms); 844 getKeyboardName(keyboard.string(), ¶ms); 845 getNavigationName(navigation.string(), ¶ms); 846 getScreenSizeName(screenSize.string(), ¶ms); 847 getVersionName(version.string(), ¶ms); 848 return params; 849} 850 851// ========================================================================= 852// ========================================================================= 853// ========================================================================= 854 855void* AaptFile::editData(size_t size) 856{ 857 if (size <= mBufferSize) { 858 mDataSize = size; 859 return mData; 860 } 861 size_t allocSize = (size*3)/2; 862 void* buf = realloc(mData, allocSize); 863 if (buf == NULL) { 864 return NULL; 865 } 866 mData = buf; 867 mDataSize = size; 868 mBufferSize = allocSize; 869 return buf; 870} 871 872void* AaptFile::editData(size_t* outSize) 873{ 874 if (outSize) { 875 *outSize = mDataSize; 876 } 877 return mData; 878} 879 880void* AaptFile::padData(size_t wordSize) 881{ 882 const size_t extra = mDataSize%wordSize; 883 if (extra == 0) { 884 return mData; 885 } 886 887 size_t initial = mDataSize; 888 void* data = editData(initial+(wordSize-extra)); 889 if (data != NULL) { 890 memset(((uint8_t*)data) + initial, 0, wordSize-extra); 891 } 892 return data; 893} 894 895status_t AaptFile::writeData(const void* data, size_t size) 896{ 897 size_t end = mDataSize; 898 size_t total = size + end; 899 void* buf = editData(total); 900 if (buf == NULL) { 901 return UNKNOWN_ERROR; 902 } 903 memcpy(((char*)buf)+end, data, size); 904 return NO_ERROR; 905} 906 907void AaptFile::clearData() 908{ 909 if (mData != NULL) free(mData); 910 mData = NULL; 911 mDataSize = 0; 912 mBufferSize = 0; 913} 914 915String8 AaptFile::getPrintableSource() const 916{ 917 if (hasData()) { 918 String8 name(mGroupEntry.locale.string()); 919 name.appendPath(mGroupEntry.vendor.string()); 920 name.appendPath(mPath); 921 name.append(" #generated"); 922 return name; 923 } 924 return mSourceFile; 925} 926 927// ========================================================================= 928// ========================================================================= 929// ========================================================================= 930 931status_t AaptGroup::addFile(const sp<AaptFile>& file) 932{ 933 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) { 934 file->mPath = mPath; 935 mFiles.add(file->getGroupEntry(), file); 936 return NO_ERROR; 937 } 938 939 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", 940 getPrintableSource().string()); 941 return UNKNOWN_ERROR; 942} 943 944void AaptGroup::removeFile(size_t index) 945{ 946 mFiles.removeItemsAt(index); 947} 948 949void AaptGroup::print() const 950{ 951 printf(" %s\n", getPath().string()); 952 const size_t N=mFiles.size(); 953 size_t i; 954 for (i=0; i<N; i++) { 955 sp<AaptFile> file = mFiles.valueAt(i); 956 const AaptGroupEntry& e = file->getGroupEntry(); 957 if (file->hasData()) { 958 printf(" Gen: (%s) %d bytes\n", e.toString().string(), 959 (int)file->getSize()); 960 } else { 961 printf(" Src: %s\n", file->getPrintableSource().string()); 962 } 963 } 964} 965 966String8 AaptGroup::getPrintableSource() const 967{ 968 if (mFiles.size() > 0) { 969 // Arbitrarily pull the first source file out of the list. 970 return mFiles.valueAt(0)->getPrintableSource(); 971 } 972 973 // Should never hit this case, but to be safe... 974 return getPath(); 975 976} 977 978// ========================================================================= 979// ========================================================================= 980// ========================================================================= 981 982status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file) 983{ 984 if (mFiles.indexOfKey(name) >= 0) { 985 return ALREADY_EXISTS; 986 } 987 mFiles.add(name, file); 988 return NO_ERROR; 989} 990 991status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir) 992{ 993 if (mDirs.indexOfKey(name) >= 0) { 994 return ALREADY_EXISTS; 995 } 996 mDirs.add(name, dir); 997 return NO_ERROR; 998} 999 1000sp<AaptDir> AaptDir::makeDir(const String8& path) 1001{ 1002 String8 name; 1003 String8 remain = path; 1004 1005 sp<AaptDir> subdir = this; 1006 while (name = remain.walkPath(&remain), remain != "") { 1007 subdir = subdir->makeDir(name); 1008 } 1009 1010 ssize_t i = subdir->mDirs.indexOfKey(name); 1011 if (i >= 0) { 1012 return subdir->mDirs.valueAt(i); 1013 } 1014 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name)); 1015 subdir->mDirs.add(name, dir); 1016 return dir; 1017} 1018 1019void AaptDir::removeFile(const String8& name) 1020{ 1021 mFiles.removeItem(name); 1022} 1023 1024void AaptDir::removeDir(const String8& name) 1025{ 1026 mDirs.removeItem(name); 1027} 1028 1029status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName) 1030{ 1031 sp<AaptGroup> origGroup; 1032 1033 // Find and remove the given file with shear, brute force! 1034 const size_t NG = mFiles.size(); 1035 size_t i; 1036 for (i=0; origGroup == NULL && i<NG; i++) { 1037 sp<AaptGroup> g = mFiles.valueAt(i); 1038 const size_t NF = g->getFiles().size(); 1039 for (size_t j=0; j<NF; j++) { 1040 if (g->getFiles().valueAt(j) == file) { 1041 origGroup = g; 1042 g->removeFile(j); 1043 if (NF == 1) { 1044 mFiles.removeItemsAt(i); 1045 } 1046 break; 1047 } 1048 } 1049 } 1050 1051 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string()); 1052 1053 // Place the file under its new name. 1054 if (origGroup != NULL) { 1055 return addLeafFile(newName, file); 1056 } 1057 1058 return NO_ERROR; 1059} 1060 1061status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file) 1062{ 1063 sp<AaptGroup> group; 1064 if (mFiles.indexOfKey(leafName) >= 0) { 1065 group = mFiles.valueFor(leafName); 1066 } else { 1067 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName)); 1068 mFiles.add(leafName, group); 1069 } 1070 1071 return group->addFile(file); 1072} 1073 1074ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, 1075 const AaptGroupEntry& kind, const String8& resType) 1076{ 1077 Vector<String8> fileNames; 1078 1079 { 1080 DIR* dir = NULL; 1081 1082 dir = opendir(srcDir.string()); 1083 if (dir == NULL) { 1084 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 1085 return UNKNOWN_ERROR; 1086 } 1087 1088 /* 1089 * Slurp the filenames out of the directory. 1090 */ 1091 while (1) { 1092 struct dirent* entry; 1093 1094 entry = readdir(dir); 1095 if (entry == NULL) 1096 break; 1097 1098 if (isHidden(srcDir.string(), entry->d_name)) 1099 continue; 1100 1101 fileNames.add(String8(entry->d_name)); 1102 } 1103 1104 closedir(dir); 1105 } 1106 1107 ssize_t count = 0; 1108 1109 /* 1110 * Stash away the files and recursively descend into subdirectories. 1111 */ 1112 const size_t N = fileNames.size(); 1113 size_t i; 1114 for (i = 0; i < N; i++) { 1115 String8 pathName(srcDir); 1116 FileType type; 1117 1118 pathName.appendPath(fileNames[i].string()); 1119 type = getFileType(pathName.string()); 1120 if (type == kFileTypeDirectory) { 1121 sp<AaptDir> subdir; 1122 bool notAdded = false; 1123 if (mDirs.indexOfKey(fileNames[i]) >= 0) { 1124 subdir = mDirs.valueFor(fileNames[i]); 1125 } else { 1126 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i])); 1127 notAdded = true; 1128 } 1129 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, 1130 resType); 1131 if (res < NO_ERROR) { 1132 return res; 1133 } 1134 if (res > 0 && notAdded) { 1135 mDirs.add(fileNames[i], subdir); 1136 } 1137 count += res; 1138 } else if (type == kFileTypeRegular) { 1139 sp<AaptFile> file = new AaptFile(pathName, kind, resType); 1140 status_t err = addLeafFile(fileNames[i], file); 1141 if (err != NO_ERROR) { 1142 return err; 1143 } 1144 1145 count++; 1146 1147 } else { 1148 if (bundle->getVerbose()) 1149 printf(" (ignoring non-file/dir '%s')\n", pathName.string()); 1150 } 1151 } 1152 1153 return count; 1154} 1155 1156status_t AaptDir::validate() const 1157{ 1158 const size_t NF = mFiles.size(); 1159 const size_t ND = mDirs.size(); 1160 size_t i; 1161 for (i = 0; i < NF; i++) { 1162 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) { 1163 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1164 "Invalid filename. Unable to add."); 1165 return UNKNOWN_ERROR; 1166 } 1167 1168 size_t j; 1169 for (j = i+1; j < NF; j++) { 1170 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1171 mFiles.valueAt(j)->getLeaf().string()) == 0) { 1172 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1173 "File is case-insensitive equivalent to: %s", 1174 mFiles.valueAt(j)->getPrintableSource().string()); 1175 return UNKNOWN_ERROR; 1176 } 1177 1178 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" 1179 // (this is mostly caught by the "marked" stuff, below) 1180 } 1181 1182 for (j = 0; j < ND; j++) { 1183 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(), 1184 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1185 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error( 1186 "File conflicts with dir from: %s", 1187 mDirs.valueAt(j)->getPrintableSource().string()); 1188 return UNKNOWN_ERROR; 1189 } 1190 } 1191 } 1192 1193 for (i = 0; i < ND; i++) { 1194 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) { 1195 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1196 "Invalid directory name, unable to add."); 1197 return UNKNOWN_ERROR; 1198 } 1199 1200 size_t j; 1201 for (j = i+1; j < ND; j++) { 1202 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(), 1203 mDirs.valueAt(j)->getLeaf().string()) == 0) { 1204 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error( 1205 "Directory is case-insensitive equivalent to: %s", 1206 mDirs.valueAt(j)->getPrintableSource().string()); 1207 return UNKNOWN_ERROR; 1208 } 1209 } 1210 1211 status_t err = mDirs.valueAt(i)->validate(); 1212 if (err != NO_ERROR) { 1213 return err; 1214 } 1215 } 1216 1217 return NO_ERROR; 1218} 1219 1220void AaptDir::print() const 1221{ 1222 const size_t ND=getDirs().size(); 1223 size_t i; 1224 for (i=0; i<ND; i++) { 1225 getDirs().valueAt(i)->print(); 1226 } 1227 1228 const size_t NF=getFiles().size(); 1229 for (i=0; i<NF; i++) { 1230 getFiles().valueAt(i)->print(); 1231 } 1232} 1233 1234String8 AaptDir::getPrintableSource() const 1235{ 1236 if (mFiles.size() > 0) { 1237 // Arbitrarily pull the first file out of the list as the source dir. 1238 return mFiles.valueAt(0)->getPrintableSource().getPathDir(); 1239 } 1240 if (mDirs.size() > 0) { 1241 // Or arbitrarily pull the first dir out of the list as the source dir. 1242 return mDirs.valueAt(0)->getPrintableSource().getPathDir(); 1243 } 1244 1245 // Should never hit this case, but to be safe... 1246 return mPath; 1247 1248} 1249 1250// ========================================================================= 1251// ========================================================================= 1252// ========================================================================= 1253 1254sp<AaptFile> AaptAssets::addFile( 1255 const String8& filePath, const AaptGroupEntry& entry, 1256 const String8& srcDir, sp<AaptGroup>* outGroup, 1257 const String8& resType) 1258{ 1259 sp<AaptDir> dir = this; 1260 sp<AaptGroup> group; 1261 sp<AaptFile> file; 1262 String8 root, remain(filePath), partialPath; 1263 while (remain.length() > 0) { 1264 root = remain.walkPath(&remain); 1265 partialPath.appendPath(root); 1266 1267 const String8 rootStr(root); 1268 1269 if (remain.length() == 0) { 1270 ssize_t i = dir->getFiles().indexOfKey(rootStr); 1271 if (i >= 0) { 1272 group = dir->getFiles().valueAt(i); 1273 } else { 1274 group = new AaptGroup(rootStr, filePath); 1275 status_t res = dir->addFile(rootStr, group); 1276 if (res != NO_ERROR) { 1277 return NULL; 1278 } 1279 } 1280 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType); 1281 status_t res = group->addFile(file); 1282 if (res != NO_ERROR) { 1283 return NULL; 1284 } 1285 break; 1286 1287 } else { 1288 ssize_t i = dir->getDirs().indexOfKey(rootStr); 1289 if (i >= 0) { 1290 dir = dir->getDirs().valueAt(i); 1291 } else { 1292 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath); 1293 status_t res = dir->addDir(rootStr, subdir); 1294 if (res != NO_ERROR) { 1295 return NULL; 1296 } 1297 dir = subdir; 1298 } 1299 } 1300 } 1301 1302 mGroupEntries.add(entry); 1303 if (outGroup) *outGroup = group; 1304 return file; 1305} 1306 1307void AaptAssets::addResource(const String8& leafName, const String8& path, 1308 const sp<AaptFile>& file, const String8& resType) 1309{ 1310 sp<AaptDir> res = AaptDir::makeDir(kResString); 1311 String8 dirname = file->getGroupEntry().toDirName(resType); 1312 sp<AaptDir> subdir = res->makeDir(dirname); 1313 sp<AaptGroup> grr = new AaptGroup(leafName, path); 1314 grr->addFile(file); 1315 1316 subdir->addFile(leafName, grr); 1317} 1318 1319 1320ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) 1321{ 1322 int count; 1323 int totalCount = 0; 1324 int i; 1325 int arg = 0; 1326 FileType type; 1327 const char* res; 1328 1329 const int N = bundle->getFileSpecCount(); 1330 1331 /* 1332 * If a package manifest was specified, include that first. 1333 */ 1334 if (bundle->getAndroidManifestFile() != NULL) { 1335 // place at root of zip. 1336 String8 srcFile(bundle->getAndroidManifestFile()); 1337 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(), 1338 NULL, String8()); 1339 totalCount++; 1340 } 1341 1342 /* 1343 * If a directory of custom assets was supplied, slurp 'em up. 1344 */ 1345 if (bundle->getAssetSourceDir()) { 1346 const char* assetDir = bundle->getAssetSourceDir(); 1347 1348 FileType type = getFileType(assetDir); 1349 if (type == kFileTypeNonexistent) { 1350 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir); 1351 return UNKNOWN_ERROR; 1352 } 1353 if (type != kFileTypeDirectory) { 1354 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 1355 return UNKNOWN_ERROR; 1356 } 1357 1358 String8 assetRoot(assetDir); 1359 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir)); 1360 AaptGroupEntry group; 1361 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, 1362 String8()); 1363 if (count < 0) { 1364 totalCount = count; 1365 goto bail; 1366 } 1367 if (count > 0) { 1368 mGroupEntries.add(group); 1369 } 1370 totalCount += count; 1371 1372 if (bundle->getVerbose()) 1373 printf("Found %d custom asset file%s in %s\n", 1374 count, (count==1) ? "" : "s", assetDir); 1375 } 1376 1377 /* 1378 * If a directory of resource-specific assets was supplied, slurp 'em up. 1379 */ 1380 res = bundle->getResourceSourceDir(); 1381 if (res) { 1382 type = getFileType(res); 1383 if (type == kFileTypeNonexistent) { 1384 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res); 1385 return UNKNOWN_ERROR; 1386 } 1387 if (type == kFileTypeDirectory) { 1388 count = slurpResourceTree(bundle, String8(res)); 1389 1390 if (count < 0) { 1391 totalCount = count; 1392 goto bail; 1393 } 1394 totalCount += count; 1395 } 1396 else { 1397 fprintf(stderr, "ERROR: '%s' is not a directory\n", res); 1398 return UNKNOWN_ERROR; 1399 } 1400 } 1401 1402 /* 1403 * Now do any additional raw files. 1404 */ 1405 for (int arg=0; arg<N; arg++) { 1406 const char* assetDir = bundle->getFileSpecEntry(arg); 1407 1408 FileType type = getFileType(assetDir); 1409 if (type == kFileTypeNonexistent) { 1410 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir); 1411 return UNKNOWN_ERROR; 1412 } 1413 if (type != kFileTypeDirectory) { 1414 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); 1415 return UNKNOWN_ERROR; 1416 } 1417 1418 String8 assetRoot(assetDir); 1419 1420 if (bundle->getVerbose()) 1421 printf("Processing raw dir '%s'\n", (const char*) assetDir); 1422 1423 /* 1424 * Do a recursive traversal of subdir tree. We don't make any 1425 * guarantees about ordering, so we're okay with an inorder search 1426 * using whatever order the OS happens to hand back to us. 1427 */ 1428 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8()); 1429 if (count < 0) { 1430 /* failure; report error and remove archive */ 1431 totalCount = count; 1432 goto bail; 1433 } 1434 totalCount += count; 1435 1436 if (bundle->getVerbose()) 1437 printf("Found %d asset file%s in %s\n", 1438 count, (count==1) ? "" : "s", assetDir); 1439 } 1440 1441 count = validate(); 1442 if (count != NO_ERROR) { 1443 totalCount = count; 1444 goto bail; 1445 } 1446 1447 1448bail: 1449 return totalCount; 1450} 1451 1452ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, 1453 const AaptGroupEntry& kind, 1454 const String8& resType) 1455{ 1456 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType); 1457 if (res > 0) { 1458 mGroupEntries.add(kind); 1459 } 1460 1461 return res; 1462} 1463 1464ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) 1465{ 1466 ssize_t err = 0; 1467 1468 DIR* dir = opendir(srcDir.string()); 1469 if (dir == NULL) { 1470 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno)); 1471 return UNKNOWN_ERROR; 1472 } 1473 1474 status_t count = 0; 1475 1476 /* 1477 * Run through the directory, looking for dirs that match the 1478 * expected pattern. 1479 */ 1480 while (1) { 1481 struct dirent* entry = readdir(dir); 1482 if (entry == NULL) { 1483 break; 1484 } 1485 1486 if (isHidden(srcDir.string(), entry->d_name)) { 1487 continue; 1488 } 1489 1490 String8 subdirName(srcDir); 1491 subdirName.appendPath(entry->d_name); 1492 1493 AaptGroupEntry group; 1494 String8 resType; 1495 bool b = group.initFromDirName(entry->d_name, &resType); 1496 if (!b) { 1497 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(), 1498 entry->d_name); 1499 err = -1; 1500 continue; 1501 } 1502 1503 FileType type = getFileType(subdirName.string()); 1504 1505 if (type == kFileTypeDirectory) { 1506 sp<AaptDir> dir = makeDir(String8(entry->d_name)); 1507 ssize_t res = dir->slurpFullTree(bundle, subdirName, group, 1508 resType); 1509 if (res < 0) { 1510 count = res; 1511 goto bail; 1512 } 1513 if (res > 0) { 1514 mGroupEntries.add(group); 1515 count += res; 1516 } 1517 1518 mDirs.add(dir); 1519 } else { 1520 if (bundle->getVerbose()) { 1521 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string()); 1522 } 1523 } 1524 } 1525 1526bail: 1527 closedir(dir); 1528 dir = NULL; 1529 1530 if (err != 0) { 1531 return err; 1532 } 1533 return count; 1534} 1535 1536ssize_t 1537AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename) 1538{ 1539 int count = 0; 1540 SortedVector<AaptGroupEntry> entries; 1541 1542 ZipFile* zip = new ZipFile; 1543 status_t err = zip->open(filename, ZipFile::kOpenReadOnly); 1544 if (err != NO_ERROR) { 1545 fprintf(stderr, "error opening zip file %s\n", filename); 1546 count = err; 1547 delete zip; 1548 return -1; 1549 } 1550 1551 const int N = zip->getNumEntries(); 1552 for (int i=0; i<N; i++) { 1553 ZipEntry* entry = zip->getEntryByIndex(i); 1554 if (entry->getDeleted()) { 1555 continue; 1556 } 1557 1558 String8 entryName(entry->getFileName()); 1559 1560 String8 dirName = entryName.getPathDir(); 1561 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName); 1562 1563 String8 resType; 1564 AaptGroupEntry kind; 1565 1566 String8 remain; 1567 if (entryName.walkPath(&remain) == kResourceDir) { 1568 // these are the resources, pull their type out of the directory name 1569 kind.initFromDirName(remain.walkPath().string(), &resType); 1570 } else { 1571 // these are untyped and don't have an AaptGroupEntry 1572 } 1573 if (entries.indexOf(kind) < 0) { 1574 entries.add(kind); 1575 mGroupEntries.add(kind); 1576 } 1577 1578 // use the one from the zip file if they both exist. 1579 dir->removeFile(entryName.getPathLeaf()); 1580 1581 sp<AaptFile> file = new AaptFile(entryName, kind, resType); 1582 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file); 1583 if (err != NO_ERROR) { 1584 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string()); 1585 count = err; 1586 goto bail; 1587 } 1588 file->setCompressionMethod(entry->getCompressionMethod()); 1589 1590#if 0 1591 if (entryName == "AndroidManifest.xml") { 1592 printf("AndroidManifest.xml\n"); 1593 } 1594 printf("\n\nfile: %s\n", entryName.string()); 1595#endif 1596 1597 size_t len = entry->getUncompressedLen(); 1598 void* data = zip->uncompress(entry); 1599 void* buf = file->editData(len); 1600 memcpy(buf, data, len); 1601 1602#if 0 1603 const int OFF = 0; 1604 const unsigned char* p = (unsigned char*)data; 1605 const unsigned char* end = p+len; 1606 p += OFF; 1607 for (int i=0; i<32 && p < end; i++) { 1608 printf("0x%03x ", i*0x10 + OFF); 1609 for (int j=0; j<0x10 && p < end; j++) { 1610 printf(" %02x", *p); 1611 p++; 1612 } 1613 printf("\n"); 1614 } 1615#endif 1616 1617 free(data); 1618 1619 count++; 1620 } 1621 1622bail: 1623 delete zip; 1624 return count; 1625} 1626 1627sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name) 1628{ 1629 sp<AaptSymbols> sym = mSymbols.valueFor(name); 1630 if (sym == NULL) { 1631 sym = new AaptSymbols(); 1632 mSymbols.add(name, sym); 1633 } 1634 return sym; 1635} 1636 1637status_t AaptAssets::buildIncludedResources(Bundle* bundle) 1638{ 1639 if (!mHaveIncludedAssets) { 1640 // Add in all includes. 1641 const Vector<const char*>& incl = bundle->getPackageIncludes(); 1642 const size_t N=incl.size(); 1643 for (size_t i=0; i<N; i++) { 1644 if (bundle->getVerbose()) 1645 printf("Including resources from package: %s\n", incl[i]); 1646 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) { 1647 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n", 1648 incl[i]); 1649 return UNKNOWN_ERROR; 1650 } 1651 } 1652 mHaveIncludedAssets = true; 1653 } 1654 1655 return NO_ERROR; 1656} 1657 1658status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file) 1659{ 1660 const ResTable& res = getIncludedResources(); 1661 // XXX dirty! 1662 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL); 1663} 1664 1665const ResTable& AaptAssets::getIncludedResources() const 1666{ 1667 return mIncludedAssets.getResources(false); 1668} 1669 1670void AaptAssets::print() const 1671{ 1672 printf("Locale/Vendor pairs:\n"); 1673 const size_t N=mGroupEntries.size(); 1674 for (size_t i=0; i<N; i++) { 1675 printf(" %s/%s\n", 1676 mGroupEntries.itemAt(i).locale.string(), 1677 mGroupEntries.itemAt(i).vendor.string()); 1678 } 1679 1680 printf("\nFiles:\n"); 1681 AaptDir::print(); 1682} 1683 1684bool 1685valid_symbol_name(const String8& symbol) 1686{ 1687 static char const * const KEYWORDS[] = { 1688 "abstract", "assert", "boolean", "break", 1689 "byte", "case", "catch", "char", "class", "const", "continue", 1690 "default", "do", "double", "else", "enum", "extends", "final", 1691 "finally", "float", "for", "goto", "if", "implements", "import", 1692 "instanceof", "int", "interface", "long", "native", "new", "package", 1693 "private", "protected", "public", "return", "short", "static", 1694 "strictfp", "super", "switch", "synchronized", "this", "throw", 1695 "throws", "transient", "try", "void", "volatile", "while", 1696 "true", "false", "null", 1697 NULL 1698 }; 1699 const char*const* k = KEYWORDS; 1700 const char*const s = symbol.string(); 1701 while (*k) { 1702 if (0 == strcmp(s, *k)) { 1703 return false; 1704 } 1705 k++; 1706 } 1707 return true; 1708} 1709