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