ResourceTypes.cpp revision c7400b0ce66e916cf8be239c26cd5acbd15ef745
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "ResourceType" 18//#define LOG_NDEBUG 0 19 20#include <androidfw/ByteBucketArray.h> 21#include <androidfw/ResourceTypes.h> 22#include <androidfw/TypeWrappers.h> 23#include <utils/Atomic.h> 24#include <utils/ByteOrder.h> 25#include <utils/Debug.h> 26#include <utils/Log.h> 27#include <utils/String16.h> 28#include <utils/String8.h> 29 30#include <stdlib.h> 31#include <string.h> 32#include <memory.h> 33#include <ctype.h> 34#include <stdint.h> 35#include <stddef.h> 36 37#ifndef INT32_MAX 38#define INT32_MAX ((int32_t)(2147483647)) 39#endif 40 41#define STRING_POOL_NOISY(x) //x 42#define XML_NOISY(x) //x 43#define TABLE_NOISY(x) //x 44#define TABLE_GETENTRY(x) //x 45#define TABLE_SUPER_NOISY(x) //x 46#define LOAD_TABLE_NOISY(x) //x 47#define TABLE_THEME(x) //x 48#define LIB_NOISY(x) //x 49 50namespace android { 51 52#ifdef HAVE_WINSOCK 53#undef nhtol 54#undef htonl 55 56#ifdef HAVE_LITTLE_ENDIAN 57#define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) 58#define htonl(x) ntohl(x) 59#define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) 60#define htons(x) ntohs(x) 61#else 62#define ntohl(x) (x) 63#define htonl(x) (x) 64#define ntohs(x) (x) 65#define htons(x) (x) 66#endif 67#endif 68 69#define IDMAP_MAGIC 0x504D4449 70#define IDMAP_CURRENT_VERSION 0x00000001 71 72#define APP_PACKAGE_ID 0x7f 73#define SYS_PACKAGE_ID 0x01 74 75// Standard C isspace() is only required to look at the low byte of its input, so 76// produces incorrect results for UTF-16 characters. For safety's sake, assume that 77// any high-byte UTF-16 code point is not whitespace. 78inline int isspace16(char16_t c) { 79 return (c < 0x0080 && isspace(c)); 80} 81 82template<typename T> 83inline static T max(T a, T b) { 84 return a > b ? a : b; 85} 86 87// range checked; guaranteed to NUL-terminate within the stated number of available slots 88// NOTE: if this truncates the dst string due to running out of space, no attempt is 89// made to avoid splitting surrogate pairs. 90static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail) 91{ 92 uint16_t* last = dst + avail - 1; 93 while (*src && (dst < last)) { 94 char16_t s = dtohs(*src); 95 *dst++ = s; 96 src++; 97 } 98 *dst = 0; 99} 100 101static status_t validate_chunk(const ResChunk_header* chunk, 102 size_t minSize, 103 const uint8_t* dataEnd, 104 const char* name) 105{ 106 const uint16_t headerSize = dtohs(chunk->headerSize); 107 const uint32_t size = dtohl(chunk->size); 108 109 if (headerSize >= minSize) { 110 if (headerSize <= size) { 111 if (((headerSize|size)&0x3) == 0) { 112 if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) { 113 return NO_ERROR; 114 } 115 ALOGW("%s data size 0x%x extends beyond resource end %p.", 116 name, size, (void*)(dataEnd-((const uint8_t*)chunk))); 117 return BAD_TYPE; 118 } 119 ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.", 120 name, (int)size, (int)headerSize); 121 return BAD_TYPE; 122 } 123 ALOGW("%s size 0x%x is smaller than header size 0x%x.", 124 name, size, headerSize); 125 return BAD_TYPE; 126 } 127 ALOGW("%s header size 0x%04x is too small.", 128 name, headerSize); 129 return BAD_TYPE; 130} 131 132static void fill9patchOffsets(Res_png_9patch* patch) { 133 patch->xDivsOffset = sizeof(Res_png_9patch); 134 patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t)); 135 patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t)); 136} 137 138inline void Res_value::copyFrom_dtoh(const Res_value& src) 139{ 140 size = dtohs(src.size); 141 res0 = src.res0; 142 dataType = src.dataType; 143 data = dtohl(src.data); 144} 145 146void Res_png_9patch::deviceToFile() 147{ 148 int32_t* xDivs = getXDivs(); 149 for (int i = 0; i < numXDivs; i++) { 150 xDivs[i] = htonl(xDivs[i]); 151 } 152 int32_t* yDivs = getYDivs(); 153 for (int i = 0; i < numYDivs; i++) { 154 yDivs[i] = htonl(yDivs[i]); 155 } 156 paddingLeft = htonl(paddingLeft); 157 paddingRight = htonl(paddingRight); 158 paddingTop = htonl(paddingTop); 159 paddingBottom = htonl(paddingBottom); 160 uint32_t* colors = getColors(); 161 for (int i=0; i<numColors; i++) { 162 colors[i] = htonl(colors[i]); 163 } 164} 165 166void Res_png_9patch::fileToDevice() 167{ 168 int32_t* xDivs = getXDivs(); 169 for (int i = 0; i < numXDivs; i++) { 170 xDivs[i] = ntohl(xDivs[i]); 171 } 172 int32_t* yDivs = getYDivs(); 173 for (int i = 0; i < numYDivs; i++) { 174 yDivs[i] = ntohl(yDivs[i]); 175 } 176 paddingLeft = ntohl(paddingLeft); 177 paddingRight = ntohl(paddingRight); 178 paddingTop = ntohl(paddingTop); 179 paddingBottom = ntohl(paddingBottom); 180 uint32_t* colors = getColors(); 181 for (int i=0; i<numColors; i++) { 182 colors[i] = ntohl(colors[i]); 183 } 184} 185 186size_t Res_png_9patch::serializedSize() const 187{ 188 // The size of this struct is 32 bytes on the 32-bit target system 189 // 4 * int8_t 190 // 4 * int32_t 191 // 3 * uint32_t 192 return 32 193 + numXDivs * sizeof(int32_t) 194 + numYDivs * sizeof(int32_t) 195 + numColors * sizeof(uint32_t); 196} 197 198void* Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs, 199 const int32_t* yDivs, const uint32_t* colors) 200{ 201 // Use calloc since we're going to leave a few holes in the data 202 // and want this to run cleanly under valgrind 203 void* newData = calloc(1, patch.serializedSize()); 204 serialize(patch, xDivs, yDivs, colors, newData); 205 return newData; 206} 207 208void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs, 209 const int32_t* yDivs, const uint32_t* colors, void* outData) 210{ 211 uint8_t* data = (uint8_t*) outData; 212 memcpy(data, &patch.wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors 213 memcpy(data + 12, &patch.paddingLeft, 16); // copy paddingXXXX 214 data += 32; 215 216 memcpy(data, xDivs, patch.numXDivs * sizeof(int32_t)); 217 data += patch.numXDivs * sizeof(int32_t); 218 memcpy(data, yDivs, patch.numYDivs * sizeof(int32_t)); 219 data += patch.numYDivs * sizeof(int32_t); 220 memcpy(data, colors, patch.numColors * sizeof(uint32_t)); 221 222 fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData)); 223} 224 225static bool assertIdmapHeader(const void* idmap, size_t size) { 226 if (reinterpret_cast<uintptr_t>(idmap) & 0x03) { 227 ALOGE("idmap: header is not word aligned"); 228 return false; 229 } 230 231 if (size < ResTable::IDMAP_HEADER_SIZE_BYTES) { 232 ALOGW("idmap: header too small (%d bytes)", (uint32_t) size); 233 return false; 234 } 235 236 const uint32_t magic = htodl(*reinterpret_cast<const uint32_t*>(idmap)); 237 if (magic != IDMAP_MAGIC) { 238 ALOGW("idmap: no magic found in header (is 0x%08x, expected 0x%08x)", 239 magic, IDMAP_MAGIC); 240 return false; 241 } 242 243 const uint32_t version = htodl(*(reinterpret_cast<const uint32_t*>(idmap) + 1)); 244 if (version != IDMAP_CURRENT_VERSION) { 245 // We are strict about versions because files with this format are 246 // auto-generated and don't need backwards compatibility. 247 ALOGW("idmap: version mismatch in header (is 0x%08x, expected 0x%08x)", 248 version, IDMAP_CURRENT_VERSION); 249 return false; 250 } 251 return true; 252} 253 254class IdmapEntries { 255public: 256 IdmapEntries() : mData(NULL) {} 257 258 bool hasEntries() const { 259 if (mData == NULL) { 260 return false; 261 } 262 263 return (dtohs(*mData) > 0); 264 } 265 266 size_t byteSize() const { 267 if (mData == NULL) { 268 return 0; 269 } 270 uint16_t entryCount = dtohs(mData[2]); 271 return (sizeof(uint16_t) * 4) + (sizeof(uint32_t) * static_cast<size_t>(entryCount)); 272 } 273 274 uint8_t targetTypeId() const { 275 if (mData == NULL) { 276 return 0; 277 } 278 return dtohs(mData[0]); 279 } 280 281 uint8_t overlayTypeId() const { 282 if (mData == NULL) { 283 return 0; 284 } 285 return dtohs(mData[1]); 286 } 287 288 status_t setTo(const void* entryHeader, size_t size) { 289 if (reinterpret_cast<uintptr_t>(entryHeader) & 0x03) { 290 ALOGE("idmap: entry header is not word aligned"); 291 return UNKNOWN_ERROR; 292 } 293 294 if (size < sizeof(uint16_t) * 4) { 295 ALOGE("idmap: entry header is too small (%u bytes)", (uint32_t) size); 296 return UNKNOWN_ERROR; 297 } 298 299 const uint16_t* header = reinterpret_cast<const uint16_t*>(entryHeader); 300 const uint16_t targetTypeId = dtohs(header[0]); 301 const uint16_t overlayTypeId = dtohs(header[1]); 302 if (targetTypeId == 0 || overlayTypeId == 0 || targetTypeId > 255 || overlayTypeId > 255) { 303 ALOGE("idmap: invalid type map (%u -> %u)", targetTypeId, overlayTypeId); 304 return UNKNOWN_ERROR; 305 } 306 307 uint16_t entryCount = dtohs(header[2]); 308 if (size < sizeof(uint32_t) * (entryCount + 2)) { 309 ALOGE("idmap: too small (%u bytes) for the number of entries (%u)", 310 (uint32_t) size, (uint32_t) entryCount); 311 return UNKNOWN_ERROR; 312 } 313 mData = header; 314 return NO_ERROR; 315 } 316 317 status_t lookup(uint16_t entryId, uint16_t* outEntryId) const { 318 uint16_t entryCount = dtohs(mData[2]); 319 uint16_t offset = dtohs(mData[3]); 320 321 if (entryId < offset) { 322 // The entry is not present in this idmap 323 return BAD_INDEX; 324 } 325 326 entryId -= offset; 327 328 if (entryId >= entryCount) { 329 // The entry is not present in this idmap 330 return BAD_INDEX; 331 } 332 333 // It is safe to access the type here without checking the size because 334 // we have checked this when it was first loaded. 335 const uint32_t* entries = reinterpret_cast<const uint32_t*>(mData) + 2; 336 uint32_t mappedEntry = dtohl(entries[entryId]); 337 if (mappedEntry == 0xffffffff) { 338 // This entry is not present in this idmap 339 return BAD_INDEX; 340 } 341 *outEntryId = static_cast<uint16_t>(mappedEntry); 342 return NO_ERROR; 343 } 344 345private: 346 const uint16_t* mData; 347}; 348 349status_t parseIdmap(const void* idmap, size_t size, uint8_t* outPackageId, KeyedVector<uint8_t, IdmapEntries>* outMap) { 350 if (!assertIdmapHeader(idmap, size)) { 351 return UNKNOWN_ERROR; 352 } 353 354 size -= ResTable::IDMAP_HEADER_SIZE_BYTES; 355 if (size < sizeof(uint16_t) * 2) { 356 ALOGE("idmap: too small to contain any mapping"); 357 return UNKNOWN_ERROR; 358 } 359 360 const uint16_t* data = reinterpret_cast<const uint16_t*>( 361 reinterpret_cast<const uint8_t*>(idmap) + ResTable::IDMAP_HEADER_SIZE_BYTES); 362 363 uint16_t targetPackageId = dtohs(*(data++)); 364 if (targetPackageId == 0 || targetPackageId > 255) { 365 ALOGE("idmap: target package ID is invalid (%02x)", targetPackageId); 366 return UNKNOWN_ERROR; 367 } 368 369 uint16_t mapCount = dtohs(*(data++)); 370 if (mapCount == 0) { 371 ALOGE("idmap: no mappings"); 372 return UNKNOWN_ERROR; 373 } 374 375 if (mapCount > 255) { 376 ALOGW("idmap: too many mappings. Only 255 are possible but %u are present", (uint32_t) mapCount); 377 } 378 379 while (size > sizeof(uint16_t) * 4) { 380 IdmapEntries entries; 381 status_t err = entries.setTo(data, size); 382 if (err != NO_ERROR) { 383 return err; 384 } 385 386 ssize_t index = outMap->add(entries.overlayTypeId(), entries); 387 if (index < 0) { 388 return NO_MEMORY; 389 } 390 391 data += entries.byteSize() / sizeof(uint16_t); 392 size -= entries.byteSize(); 393 } 394 395 if (outPackageId != NULL) { 396 *outPackageId = static_cast<uint8_t>(targetPackageId); 397 } 398 return NO_ERROR; 399} 400 401Res_png_9patch* Res_png_9patch::deserialize(void* inData) 402{ 403 404 Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(inData); 405 patch->wasDeserialized = true; 406 fill9patchOffsets(patch); 407 408 return patch; 409} 410 411// -------------------------------------------------------------------- 412// -------------------------------------------------------------------- 413// -------------------------------------------------------------------- 414 415ResStringPool::ResStringPool() 416 : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) 417{ 418} 419 420ResStringPool::ResStringPool(const void* data, size_t size, bool copyData) 421 : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) 422{ 423 setTo(data, size, copyData); 424} 425 426ResStringPool::~ResStringPool() 427{ 428 uninit(); 429} 430 431void ResStringPool::setToEmpty() 432{ 433 uninit(); 434 435 mOwnedData = calloc(1, sizeof(ResStringPool_header)); 436 ResStringPool_header* header = (ResStringPool_header*) mOwnedData; 437 mSize = 0; 438 mEntries = NULL; 439 mStrings = NULL; 440 mStringPoolSize = 0; 441 mEntryStyles = NULL; 442 mStyles = NULL; 443 mStylePoolSize = 0; 444 mHeader = (const ResStringPool_header*) header; 445} 446 447status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) 448{ 449 if (!data || !size) { 450 return (mError=BAD_TYPE); 451 } 452 453 uninit(); 454 455 const bool notDeviceEndian = htods(0xf0) != 0xf0; 456 457 if (copyData || notDeviceEndian) { 458 mOwnedData = malloc(size); 459 if (mOwnedData == NULL) { 460 return (mError=NO_MEMORY); 461 } 462 memcpy(mOwnedData, data, size); 463 data = mOwnedData; 464 } 465 466 mHeader = (const ResStringPool_header*)data; 467 468 if (notDeviceEndian) { 469 ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader); 470 h->header.headerSize = dtohs(mHeader->header.headerSize); 471 h->header.type = dtohs(mHeader->header.type); 472 h->header.size = dtohl(mHeader->header.size); 473 h->stringCount = dtohl(mHeader->stringCount); 474 h->styleCount = dtohl(mHeader->styleCount); 475 h->flags = dtohl(mHeader->flags); 476 h->stringsStart = dtohl(mHeader->stringsStart); 477 h->stylesStart = dtohl(mHeader->stylesStart); 478 } 479 480 if (mHeader->header.headerSize > mHeader->header.size 481 || mHeader->header.size > size) { 482 ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n", 483 (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size); 484 return (mError=BAD_TYPE); 485 } 486 mSize = mHeader->header.size; 487 mEntries = (const uint32_t*) 488 (((const uint8_t*)data)+mHeader->header.headerSize); 489 490 if (mHeader->stringCount > 0) { 491 if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow? 492 || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))) 493 > size) { 494 ALOGW("Bad string block: entry of %d items extends past data size %d\n", 495 (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))), 496 (int)size); 497 return (mError=BAD_TYPE); 498 } 499 500 size_t charSize; 501 if (mHeader->flags&ResStringPool_header::UTF8_FLAG) { 502 charSize = sizeof(uint8_t); 503 } else { 504 charSize = sizeof(char16_t); 505 } 506 507 mStrings = (const void*) 508 (((const uint8_t*)data)+mHeader->stringsStart); 509 if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) { 510 ALOGW("Bad string block: string pool starts at %d, after total size %d\n", 511 (int)mHeader->stringsStart, (int)mHeader->header.size); 512 return (mError=BAD_TYPE); 513 } 514 if (mHeader->styleCount == 0) { 515 mStringPoolSize = 516 (mHeader->header.size-mHeader->stringsStart)/charSize; 517 } else { 518 // check invariant: styles starts before end of data 519 if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) { 520 ALOGW("Bad style block: style block starts at %d past data size of %d\n", 521 (int)mHeader->stylesStart, (int)mHeader->header.size); 522 return (mError=BAD_TYPE); 523 } 524 // check invariant: styles follow the strings 525 if (mHeader->stylesStart <= mHeader->stringsStart) { 526 ALOGW("Bad style block: style block starts at %d, before strings at %d\n", 527 (int)mHeader->stylesStart, (int)mHeader->stringsStart); 528 return (mError=BAD_TYPE); 529 } 530 mStringPoolSize = 531 (mHeader->stylesStart-mHeader->stringsStart)/charSize; 532 } 533 534 // check invariant: stringCount > 0 requires a string pool to exist 535 if (mStringPoolSize == 0) { 536 ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount); 537 return (mError=BAD_TYPE); 538 } 539 540 if (notDeviceEndian) { 541 size_t i; 542 uint32_t* e = const_cast<uint32_t*>(mEntries); 543 for (i=0; i<mHeader->stringCount; i++) { 544 e[i] = dtohl(mEntries[i]); 545 } 546 if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) { 547 const char16_t* strings = (const char16_t*)mStrings; 548 char16_t* s = const_cast<char16_t*>(strings); 549 for (i=0; i<mStringPoolSize; i++) { 550 s[i] = dtohs(strings[i]); 551 } 552 } 553 } 554 555 if ((mHeader->flags&ResStringPool_header::UTF8_FLAG && 556 ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) || 557 (!mHeader->flags&ResStringPool_header::UTF8_FLAG && 558 ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) { 559 ALOGW("Bad string block: last string is not 0-terminated\n"); 560 return (mError=BAD_TYPE); 561 } 562 } else { 563 mStrings = NULL; 564 mStringPoolSize = 0; 565 } 566 567 if (mHeader->styleCount > 0) { 568 mEntryStyles = mEntries + mHeader->stringCount; 569 // invariant: integer overflow in calculating mEntryStyles 570 if (mEntryStyles < mEntries) { 571 ALOGW("Bad string block: integer overflow finding styles\n"); 572 return (mError=BAD_TYPE); 573 } 574 575 if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) { 576 ALOGW("Bad string block: entry of %d styles extends past data size %d\n", 577 (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader), 578 (int)size); 579 return (mError=BAD_TYPE); 580 } 581 mStyles = (const uint32_t*) 582 (((const uint8_t*)data)+mHeader->stylesStart); 583 if (mHeader->stylesStart >= mHeader->header.size) { 584 ALOGW("Bad string block: style pool starts %d, after total size %d\n", 585 (int)mHeader->stylesStart, (int)mHeader->header.size); 586 return (mError=BAD_TYPE); 587 } 588 mStylePoolSize = 589 (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t); 590 591 if (notDeviceEndian) { 592 size_t i; 593 uint32_t* e = const_cast<uint32_t*>(mEntryStyles); 594 for (i=0; i<mHeader->styleCount; i++) { 595 e[i] = dtohl(mEntryStyles[i]); 596 } 597 uint32_t* s = const_cast<uint32_t*>(mStyles); 598 for (i=0; i<mStylePoolSize; i++) { 599 s[i] = dtohl(mStyles[i]); 600 } 601 } 602 603 const ResStringPool_span endSpan = { 604 { htodl(ResStringPool_span::END) }, 605 htodl(ResStringPool_span::END), htodl(ResStringPool_span::END) 606 }; 607 if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))], 608 &endSpan, sizeof(endSpan)) != 0) { 609 ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n"); 610 return (mError=BAD_TYPE); 611 } 612 } else { 613 mEntryStyles = NULL; 614 mStyles = NULL; 615 mStylePoolSize = 0; 616 } 617 618 return (mError=NO_ERROR); 619} 620 621status_t ResStringPool::getError() const 622{ 623 return mError; 624} 625 626void ResStringPool::uninit() 627{ 628 mError = NO_INIT; 629 if (mHeader != NULL && mCache != NULL) { 630 for (size_t x = 0; x < mHeader->stringCount; x++) { 631 if (mCache[x] != NULL) { 632 free(mCache[x]); 633 mCache[x] = NULL; 634 } 635 } 636 free(mCache); 637 mCache = NULL; 638 } 639 if (mOwnedData) { 640 free(mOwnedData); 641 mOwnedData = NULL; 642 } 643} 644 645/** 646 * Strings in UTF-16 format have length indicated by a length encoded in the 647 * stored data. It is either 1 or 2 characters of length data. This allows a 648 * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that 649 * much data in a string, you're abusing them. 650 * 651 * If the high bit is set, then there are two characters or 4 bytes of length 652 * data encoded. In that case, drop the high bit of the first character and 653 * add it together with the next character. 654 */ 655static inline size_t 656decodeLength(const char16_t** str) 657{ 658 size_t len = **str; 659 if ((len & 0x8000) != 0) { 660 (*str)++; 661 len = ((len & 0x7FFF) << 16) | **str; 662 } 663 (*str)++; 664 return len; 665} 666 667/** 668 * Strings in UTF-8 format have length indicated by a length encoded in the 669 * stored data. It is either 1 or 2 characters of length data. This allows a 670 * maximum length of 0x7FFF (32767 bytes), but you should consider storing 671 * text in another way if you're using that much data in a single string. 672 * 673 * If the high bit is set, then there are two characters or 2 bytes of length 674 * data encoded. In that case, drop the high bit of the first character and 675 * add it together with the next character. 676 */ 677static inline size_t 678decodeLength(const uint8_t** str) 679{ 680 size_t len = **str; 681 if ((len & 0x80) != 0) { 682 (*str)++; 683 len = ((len & 0x7F) << 8) | **str; 684 } 685 (*str)++; 686 return len; 687} 688 689const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const 690{ 691 if (mError == NO_ERROR && idx < mHeader->stringCount) { 692 const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; 693 const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); 694 if (off < (mStringPoolSize-1)) { 695 if (!isUTF8) { 696 const char16_t* strings = (char16_t*)mStrings; 697 const char16_t* str = strings+off; 698 699 *u16len = decodeLength(&str); 700 if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) { 701 return str; 702 } else { 703 ALOGW("Bad string block: string #%d extends to %d, past end at %d\n", 704 (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize); 705 } 706 } else { 707 const uint8_t* strings = (uint8_t*)mStrings; 708 const uint8_t* u8str = strings+off; 709 710 *u16len = decodeLength(&u8str); 711 size_t u8len = decodeLength(&u8str); 712 713 // encLen must be less than 0x7FFF due to encoding. 714 if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) { 715 AutoMutex lock(mDecodeLock); 716 717 if (mCache == NULL) { 718#ifndef HAVE_ANDROID_OS 719 STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes", 720 mHeader->stringCount*sizeof(char16_t**))); 721#else 722 // We do not want to be in this case when actually running Android. 723 ALOGW("CREATING STRING CACHE OF %d bytes", 724 mHeader->stringCount*sizeof(char16_t**)); 725#endif 726 mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); 727 if (mCache == NULL) { 728 ALOGW("No memory trying to allocate decode cache table of %d bytes\n", 729 (int)(mHeader->stringCount*sizeof(char16_t**))); 730 return NULL; 731 } 732 } 733 734 if (mCache[idx] != NULL) { 735 return mCache[idx]; 736 } 737 738 ssize_t actualLen = utf8_to_utf16_length(u8str, u8len); 739 if (actualLen < 0 || (size_t)actualLen != *u16len) { 740 ALOGW("Bad string block: string #%lld decoded length is not correct " 741 "%lld vs %llu\n", 742 (long long)idx, (long long)actualLen, (long long)*u16len); 743 return NULL; 744 } 745 746 char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t)); 747 if (!u16str) { 748 ALOGW("No memory when trying to allocate decode cache for string #%d\n", 749 (int)idx); 750 return NULL; 751 } 752 753 STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str)); 754 utf8_to_utf16(u8str, u8len, u16str); 755 mCache[idx] = u16str; 756 return u16str; 757 } else { 758 ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n", 759 (long long)idx, (long long)(u8str+u8len-strings), 760 (long long)mStringPoolSize); 761 } 762 } 763 } else { 764 ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n", 765 (int)idx, (int)(off*sizeof(uint16_t)), 766 (int)(mStringPoolSize*sizeof(uint16_t))); 767 } 768 } 769 return NULL; 770} 771 772const char* ResStringPool::string8At(size_t idx, size_t* outLen) const 773{ 774 if (mError == NO_ERROR && idx < mHeader->stringCount) { 775 if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) { 776 return NULL; 777 } 778 const uint32_t off = mEntries[idx]/sizeof(char); 779 if (off < (mStringPoolSize-1)) { 780 const uint8_t* strings = (uint8_t*)mStrings; 781 const uint8_t* str = strings+off; 782 *outLen = decodeLength(&str); 783 size_t encLen = decodeLength(&str); 784 if ((uint32_t)(str+encLen-strings) < mStringPoolSize) { 785 return (const char*)str; 786 } else { 787 ALOGW("Bad string block: string #%d extends to %d, past end at %d\n", 788 (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); 789 } 790 } else { 791 ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n", 792 (int)idx, (int)(off*sizeof(uint16_t)), 793 (int)(mStringPoolSize*sizeof(uint16_t))); 794 } 795 } 796 return NULL; 797} 798 799const String8 ResStringPool::string8ObjectAt(size_t idx) const 800{ 801 size_t len; 802 const char *str = (const char*)string8At(idx, &len); 803 if (str != NULL) { 804 return String8(str); 805 } 806 return String8(stringAt(idx, &len)); 807} 808 809const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const 810{ 811 return styleAt(ref.index); 812} 813 814const ResStringPool_span* ResStringPool::styleAt(size_t idx) const 815{ 816 if (mError == NO_ERROR && idx < mHeader->styleCount) { 817 const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t)); 818 if (off < mStylePoolSize) { 819 return (const ResStringPool_span*)(mStyles+off); 820 } else { 821 ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n", 822 (int)idx, (int)(off*sizeof(uint32_t)), 823 (int)(mStylePoolSize*sizeof(uint32_t))); 824 } 825 } 826 return NULL; 827} 828 829ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const 830{ 831 if (mError != NO_ERROR) { 832 return mError; 833 } 834 835 size_t len; 836 837 if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { 838 STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string())); 839 840 // The string pool contains UTF 8 strings; we don't want to cause 841 // temporary UTF-16 strings to be created as we search. 842 if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { 843 // Do a binary search for the string... this is a little tricky, 844 // because the strings are sorted with strzcmp16(). So to match 845 // the ordering, we need to convert strings in the pool to UTF-16. 846 // But we don't want to hit the cache, so instead we will have a 847 // local temporary allocation for the conversions. 848 char16_t* convBuffer = (char16_t*)malloc(strLen+4); 849 ssize_t l = 0; 850 ssize_t h = mHeader->stringCount-1; 851 852 ssize_t mid; 853 while (l <= h) { 854 mid = l + (h - l)/2; 855 const uint8_t* s = (const uint8_t*)string8At(mid, &len); 856 int c; 857 if (s != NULL) { 858 char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3); 859 *end = 0; 860 c = strzcmp16(convBuffer, end-convBuffer, str, strLen); 861 } else { 862 c = -1; 863 } 864 STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", 865 (const char*)s, c, (int)l, (int)mid, (int)h)); 866 if (c == 0) { 867 STRING_POOL_NOISY(ALOGI("MATCH!")); 868 free(convBuffer); 869 return mid; 870 } else if (c < 0) { 871 l = mid + 1; 872 } else { 873 h = mid - 1; 874 } 875 } 876 free(convBuffer); 877 } else { 878 // It is unusual to get the ID from an unsorted string block... 879 // most often this happens because we want to get IDs for style 880 // span tags; since those always appear at the end of the string 881 // block, start searching at the back. 882 String8 str8(str, strLen); 883 const size_t str8Len = str8.size(); 884 for (int i=mHeader->stringCount-1; i>=0; i--) { 885 const char* s = string8At(i, &len); 886 STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", 887 String8(s).string(), 888 i)); 889 if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) { 890 STRING_POOL_NOISY(ALOGI("MATCH!")); 891 return i; 892 } 893 } 894 } 895 896 } else { 897 STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string())); 898 899 if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { 900 // Do a binary search for the string... 901 ssize_t l = 0; 902 ssize_t h = mHeader->stringCount-1; 903 904 ssize_t mid; 905 while (l <= h) { 906 mid = l + (h - l)/2; 907 const char16_t* s = stringAt(mid, &len); 908 int c = s ? strzcmp16(s, len, str, strLen) : -1; 909 STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", 910 String8(s).string(), 911 c, (int)l, (int)mid, (int)h)); 912 if (c == 0) { 913 STRING_POOL_NOISY(ALOGI("MATCH!")); 914 return mid; 915 } else if (c < 0) { 916 l = mid + 1; 917 } else { 918 h = mid - 1; 919 } 920 } 921 } else { 922 // It is unusual to get the ID from an unsorted string block... 923 // most often this happens because we want to get IDs for style 924 // span tags; since those always appear at the end of the string 925 // block, start searching at the back. 926 for (int i=mHeader->stringCount-1; i>=0; i--) { 927 const char16_t* s = stringAt(i, &len); 928 STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", 929 String8(s).string(), 930 i)); 931 if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) { 932 STRING_POOL_NOISY(ALOGI("MATCH!")); 933 return i; 934 } 935 } 936 } 937 } 938 939 return NAME_NOT_FOUND; 940} 941 942size_t ResStringPool::size() const 943{ 944 return (mError == NO_ERROR) ? mHeader->stringCount : 0; 945} 946 947size_t ResStringPool::styleCount() const 948{ 949 return (mError == NO_ERROR) ? mHeader->styleCount : 0; 950} 951 952size_t ResStringPool::bytes() const 953{ 954 return (mError == NO_ERROR) ? mHeader->header.size : 0; 955} 956 957bool ResStringPool::isSorted() const 958{ 959 return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0; 960} 961 962bool ResStringPool::isUTF8() const 963{ 964 return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0; 965} 966 967// -------------------------------------------------------------------- 968// -------------------------------------------------------------------- 969// -------------------------------------------------------------------- 970 971ResXMLParser::ResXMLParser(const ResXMLTree& tree) 972 : mTree(tree), mEventCode(BAD_DOCUMENT) 973{ 974} 975 976void ResXMLParser::restart() 977{ 978 mCurNode = NULL; 979 mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT; 980} 981const ResStringPool& ResXMLParser::getStrings() const 982{ 983 return mTree.mStrings; 984} 985 986ResXMLParser::event_code_t ResXMLParser::getEventType() const 987{ 988 return mEventCode; 989} 990 991ResXMLParser::event_code_t ResXMLParser::next() 992{ 993 if (mEventCode == START_DOCUMENT) { 994 mCurNode = mTree.mRootNode; 995 mCurExt = mTree.mRootExt; 996 return (mEventCode=mTree.mRootCode); 997 } else if (mEventCode >= FIRST_CHUNK_CODE) { 998 return nextNode(); 999 } 1000 return mEventCode; 1001} 1002 1003int32_t ResXMLParser::getCommentID() const 1004{ 1005 return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1; 1006} 1007 1008const uint16_t* ResXMLParser::getComment(size_t* outLen) const 1009{ 1010 int32_t id = getCommentID(); 1011 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1012} 1013 1014uint32_t ResXMLParser::getLineNumber() const 1015{ 1016 return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1; 1017} 1018 1019int32_t ResXMLParser::getTextID() const 1020{ 1021 if (mEventCode == TEXT) { 1022 return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index); 1023 } 1024 return -1; 1025} 1026 1027const uint16_t* ResXMLParser::getText(size_t* outLen) const 1028{ 1029 int32_t id = getTextID(); 1030 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1031} 1032 1033ssize_t ResXMLParser::getTextValue(Res_value* outValue) const 1034{ 1035 if (mEventCode == TEXT) { 1036 outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData); 1037 return sizeof(Res_value); 1038 } 1039 return BAD_TYPE; 1040} 1041 1042int32_t ResXMLParser::getNamespacePrefixID() const 1043{ 1044 if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) { 1045 return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index); 1046 } 1047 return -1; 1048} 1049 1050const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const 1051{ 1052 int32_t id = getNamespacePrefixID(); 1053 //printf("prefix=%d event=%p\n", id, mEventCode); 1054 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1055} 1056 1057int32_t ResXMLParser::getNamespaceUriID() const 1058{ 1059 if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) { 1060 return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index); 1061 } 1062 return -1; 1063} 1064 1065const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const 1066{ 1067 int32_t id = getNamespaceUriID(); 1068 //printf("uri=%d event=%p\n", id, mEventCode); 1069 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1070} 1071 1072int32_t ResXMLParser::getElementNamespaceID() const 1073{ 1074 if (mEventCode == START_TAG) { 1075 return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index); 1076 } 1077 if (mEventCode == END_TAG) { 1078 return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index); 1079 } 1080 return -1; 1081} 1082 1083const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const 1084{ 1085 int32_t id = getElementNamespaceID(); 1086 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1087} 1088 1089int32_t ResXMLParser::getElementNameID() const 1090{ 1091 if (mEventCode == START_TAG) { 1092 return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index); 1093 } 1094 if (mEventCode == END_TAG) { 1095 return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index); 1096 } 1097 return -1; 1098} 1099 1100const uint16_t* ResXMLParser::getElementName(size_t* outLen) const 1101{ 1102 int32_t id = getElementNameID(); 1103 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1104} 1105 1106size_t ResXMLParser::getAttributeCount() const 1107{ 1108 if (mEventCode == START_TAG) { 1109 return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount); 1110 } 1111 return 0; 1112} 1113 1114int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const 1115{ 1116 if (mEventCode == START_TAG) { 1117 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; 1118 if (idx < dtohs(tag->attributeCount)) { 1119 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) 1120 (((const uint8_t*)tag) 1121 + dtohs(tag->attributeStart) 1122 + (dtohs(tag->attributeSize)*idx)); 1123 return dtohl(attr->ns.index); 1124 } 1125 } 1126 return -2; 1127} 1128 1129const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const 1130{ 1131 int32_t id = getAttributeNamespaceID(idx); 1132 //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); 1133 //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); 1134 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1135} 1136 1137const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const 1138{ 1139 int32_t id = getAttributeNamespaceID(idx); 1140 //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); 1141 //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); 1142 return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; 1143} 1144 1145int32_t ResXMLParser::getAttributeNameID(size_t idx) const 1146{ 1147 if (mEventCode == START_TAG) { 1148 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; 1149 if (idx < dtohs(tag->attributeCount)) { 1150 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) 1151 (((const uint8_t*)tag) 1152 + dtohs(tag->attributeStart) 1153 + (dtohs(tag->attributeSize)*idx)); 1154 return dtohl(attr->name.index); 1155 } 1156 } 1157 return -1; 1158} 1159 1160const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const 1161{ 1162 int32_t id = getAttributeNameID(idx); 1163 //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); 1164 //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); 1165 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1166} 1167 1168const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const 1169{ 1170 int32_t id = getAttributeNameID(idx); 1171 //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); 1172 //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); 1173 return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; 1174} 1175 1176uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const 1177{ 1178 int32_t id = getAttributeNameID(idx); 1179 if (id >= 0 && (size_t)id < mTree.mNumResIds) { 1180 return dtohl(mTree.mResIds[id]); 1181 } 1182 return 0; 1183} 1184 1185int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const 1186{ 1187 if (mEventCode == START_TAG) { 1188 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; 1189 if (idx < dtohs(tag->attributeCount)) { 1190 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) 1191 (((const uint8_t*)tag) 1192 + dtohs(tag->attributeStart) 1193 + (dtohs(tag->attributeSize)*idx)); 1194 return dtohl(attr->rawValue.index); 1195 } 1196 } 1197 return -1; 1198} 1199 1200const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const 1201{ 1202 int32_t id = getAttributeValueStringID(idx); 1203 //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id)); 1204 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; 1205} 1206 1207int32_t ResXMLParser::getAttributeDataType(size_t idx) const 1208{ 1209 if (mEventCode == START_TAG) { 1210 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; 1211 if (idx < dtohs(tag->attributeCount)) { 1212 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) 1213 (((const uint8_t*)tag) 1214 + dtohs(tag->attributeStart) 1215 + (dtohs(tag->attributeSize)*idx)); 1216 uint8_t type = attr->typedValue.dataType; 1217 if (type != Res_value::TYPE_DYNAMIC_REFERENCE) { 1218 return type; 1219 } 1220 1221 // This is a dynamic reference. We adjust those references 1222 // to regular references at this level, so lie to the caller. 1223 return Res_value::TYPE_REFERENCE; 1224 } 1225 } 1226 return Res_value::TYPE_NULL; 1227} 1228 1229int32_t ResXMLParser::getAttributeData(size_t idx) const 1230{ 1231 if (mEventCode == START_TAG) { 1232 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; 1233 if (idx < dtohs(tag->attributeCount)) { 1234 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) 1235 (((const uint8_t*)tag) 1236 + dtohs(tag->attributeStart) 1237 + (dtohs(tag->attributeSize)*idx)); 1238 if (attr->typedValue.dataType != Res_value::TYPE_DYNAMIC_REFERENCE || 1239 mTree.mDynamicRefTable == NULL) { 1240 return dtohl(attr->typedValue.data); 1241 } 1242 1243 uint32_t data = dtohl(attr->typedValue.data); 1244 if (mTree.mDynamicRefTable->lookupResourceId(&data) == NO_ERROR) { 1245 return data; 1246 } 1247 } 1248 } 1249 return 0; 1250} 1251 1252ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const 1253{ 1254 if (mEventCode == START_TAG) { 1255 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; 1256 if (idx < dtohs(tag->attributeCount)) { 1257 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) 1258 (((const uint8_t*)tag) 1259 + dtohs(tag->attributeStart) 1260 + (dtohs(tag->attributeSize)*idx)); 1261 outValue->copyFrom_dtoh(attr->typedValue); 1262 if (mTree.mDynamicRefTable != NULL && 1263 mTree.mDynamicRefTable->lookupResourceValue(outValue) != NO_ERROR) { 1264 return BAD_TYPE; 1265 } 1266 return sizeof(Res_value); 1267 } 1268 } 1269 return BAD_TYPE; 1270} 1271 1272ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const 1273{ 1274 String16 nsStr(ns != NULL ? ns : ""); 1275 String16 attrStr(attr); 1276 return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0, 1277 attrStr.string(), attrStr.size()); 1278} 1279 1280ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen, 1281 const char16_t* attr, size_t attrLen) const 1282{ 1283 if (mEventCode == START_TAG) { 1284 if (attr == NULL) { 1285 return NAME_NOT_FOUND; 1286 } 1287 const size_t N = getAttributeCount(); 1288 if (mTree.mStrings.isUTF8()) { 1289 String8 ns8, attr8; 1290 if (ns != NULL) { 1291 ns8 = String8(ns, nsLen); 1292 } 1293 attr8 = String8(attr, attrLen); 1294 STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen, 1295 attr8.string(), attrLen)); 1296 for (size_t i=0; i<N; i++) { 1297 size_t curNsLen = 0, curAttrLen = 0; 1298 const char* curNs = getAttributeNamespace8(i, &curNsLen); 1299 const char* curAttr = getAttributeName8(i, &curAttrLen); 1300 STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen, 1301 curAttr, curAttrLen)); 1302 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen 1303 && memcmp(attr8.string(), curAttr, attrLen) == 0) { 1304 if (ns == NULL) { 1305 if (curNs == NULL) { 1306 STRING_POOL_NOISY(ALOGI(" FOUND!")); 1307 return i; 1308 } 1309 } else if (curNs != NULL) { 1310 //printf(" --> ns=%s, curNs=%s\n", 1311 // String8(ns).string(), String8(curNs).string()); 1312 if (memcmp(ns8.string(), curNs, nsLen) == 0) { 1313 STRING_POOL_NOISY(ALOGI(" FOUND!")); 1314 return i; 1315 } 1316 } 1317 } 1318 } 1319 } else { 1320 STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)", 1321 String8(ns, nsLen).string(), nsLen, 1322 String8(attr, attrLen).string(), attrLen)); 1323 for (size_t i=0; i<N; i++) { 1324 size_t curNsLen = 0, curAttrLen = 0; 1325 const char16_t* curNs = getAttributeNamespace(i, &curNsLen); 1326 const char16_t* curAttr = getAttributeName(i, &curAttrLen); 1327 STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", 1328 String8(curNs, curNsLen).string(), curNsLen, 1329 String8(curAttr, curAttrLen).string(), curAttrLen)); 1330 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen 1331 && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) { 1332 if (ns == NULL) { 1333 if (curNs == NULL) { 1334 STRING_POOL_NOISY(ALOGI(" FOUND!")); 1335 return i; 1336 } 1337 } else if (curNs != NULL) { 1338 //printf(" --> ns=%s, curNs=%s\n", 1339 // String8(ns).string(), String8(curNs).string()); 1340 if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) { 1341 STRING_POOL_NOISY(ALOGI(" FOUND!")); 1342 return i; 1343 } 1344 } 1345 } 1346 } 1347 } 1348 } 1349 1350 return NAME_NOT_FOUND; 1351} 1352 1353ssize_t ResXMLParser::indexOfID() const 1354{ 1355 if (mEventCode == START_TAG) { 1356 const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex); 1357 if (idx > 0) return (idx-1); 1358 } 1359 return NAME_NOT_FOUND; 1360} 1361 1362ssize_t ResXMLParser::indexOfClass() const 1363{ 1364 if (mEventCode == START_TAG) { 1365 const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex); 1366 if (idx > 0) return (idx-1); 1367 } 1368 return NAME_NOT_FOUND; 1369} 1370 1371ssize_t ResXMLParser::indexOfStyle() const 1372{ 1373 if (mEventCode == START_TAG) { 1374 const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex); 1375 if (idx > 0) return (idx-1); 1376 } 1377 return NAME_NOT_FOUND; 1378} 1379 1380ResXMLParser::event_code_t ResXMLParser::nextNode() 1381{ 1382 if (mEventCode < 0) { 1383 return mEventCode; 1384 } 1385 1386 do { 1387 const ResXMLTree_node* next = (const ResXMLTree_node*) 1388 (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size)); 1389 //ALOGW("Next node: prev=%p, next=%p\n", mCurNode, next); 1390 1391 if (((const uint8_t*)next) >= mTree.mDataEnd) { 1392 mCurNode = NULL; 1393 return (mEventCode=END_DOCUMENT); 1394 } 1395 1396 if (mTree.validateNode(next) != NO_ERROR) { 1397 mCurNode = NULL; 1398 return (mEventCode=BAD_DOCUMENT); 1399 } 1400 1401 mCurNode = next; 1402 const uint16_t headerSize = dtohs(next->header.headerSize); 1403 const uint32_t totalSize = dtohl(next->header.size); 1404 mCurExt = ((const uint8_t*)next) + headerSize; 1405 size_t minExtSize = 0; 1406 event_code_t eventCode = (event_code_t)dtohs(next->header.type); 1407 switch ((mEventCode=eventCode)) { 1408 case RES_XML_START_NAMESPACE_TYPE: 1409 case RES_XML_END_NAMESPACE_TYPE: 1410 minExtSize = sizeof(ResXMLTree_namespaceExt); 1411 break; 1412 case RES_XML_START_ELEMENT_TYPE: 1413 minExtSize = sizeof(ResXMLTree_attrExt); 1414 break; 1415 case RES_XML_END_ELEMENT_TYPE: 1416 minExtSize = sizeof(ResXMLTree_endElementExt); 1417 break; 1418 case RES_XML_CDATA_TYPE: 1419 minExtSize = sizeof(ResXMLTree_cdataExt); 1420 break; 1421 default: 1422 ALOGW("Unknown XML block: header type %d in node at %d\n", 1423 (int)dtohs(next->header.type), 1424 (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader))); 1425 continue; 1426 } 1427 1428 if ((totalSize-headerSize) < minExtSize) { 1429 ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n", 1430 (int)dtohs(next->header.type), 1431 (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)), 1432 (int)(totalSize-headerSize), (int)minExtSize); 1433 return (mEventCode=BAD_DOCUMENT); 1434 } 1435 1436 //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n", 1437 // mCurNode, mCurExt, headerSize, minExtSize); 1438 1439 return eventCode; 1440 } while (true); 1441} 1442 1443void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const 1444{ 1445 pos->eventCode = mEventCode; 1446 pos->curNode = mCurNode; 1447 pos->curExt = mCurExt; 1448} 1449 1450void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos) 1451{ 1452 mEventCode = pos.eventCode; 1453 mCurNode = pos.curNode; 1454 mCurExt = pos.curExt; 1455} 1456 1457// -------------------------------------------------------------------- 1458 1459static volatile int32_t gCount = 0; 1460 1461ResXMLTree::ResXMLTree(const DynamicRefTable* dynamicRefTable) 1462 : ResXMLParser(*this) 1463 , mDynamicRefTable(dynamicRefTable) 1464 , mError(NO_INIT), mOwnedData(NULL) 1465{ 1466 //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1); 1467 restart(); 1468} 1469 1470ResXMLTree::ResXMLTree() 1471 : ResXMLParser(*this) 1472 , mDynamicRefTable(NULL) 1473 , mError(NO_INIT), mOwnedData(NULL) 1474{ 1475 //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1); 1476 restart(); 1477} 1478 1479ResXMLTree::~ResXMLTree() 1480{ 1481 //ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1); 1482 uninit(); 1483} 1484 1485status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData) 1486{ 1487 uninit(); 1488 mEventCode = START_DOCUMENT; 1489 1490 if (!data || !size) { 1491 return (mError=BAD_TYPE); 1492 } 1493 1494 if (copyData) { 1495 mOwnedData = malloc(size); 1496 if (mOwnedData == NULL) { 1497 return (mError=NO_MEMORY); 1498 } 1499 memcpy(mOwnedData, data, size); 1500 data = mOwnedData; 1501 } 1502 1503 mHeader = (const ResXMLTree_header*)data; 1504 mSize = dtohl(mHeader->header.size); 1505 if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) { 1506 ALOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n", 1507 (int)dtohs(mHeader->header.headerSize), 1508 (int)dtohl(mHeader->header.size), (int)size); 1509 mError = BAD_TYPE; 1510 restart(); 1511 return mError; 1512 } 1513 mDataEnd = ((const uint8_t*)mHeader) + mSize; 1514 1515 mStrings.uninit(); 1516 mRootNode = NULL; 1517 mResIds = NULL; 1518 mNumResIds = 0; 1519 1520 // First look for a couple interesting chunks: the string block 1521 // and first XML node. 1522 const ResChunk_header* chunk = 1523 (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize)); 1524 const ResChunk_header* lastChunk = chunk; 1525 while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) && 1526 ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) { 1527 status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML"); 1528 if (err != NO_ERROR) { 1529 mError = err; 1530 goto done; 1531 } 1532 const uint16_t type = dtohs(chunk->type); 1533 const size_t size = dtohl(chunk->size); 1534 XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n", 1535 (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size)); 1536 if (type == RES_STRING_POOL_TYPE) { 1537 mStrings.setTo(chunk, size); 1538 } else if (type == RES_XML_RESOURCE_MAP_TYPE) { 1539 mResIds = (const uint32_t*) 1540 (((const uint8_t*)chunk)+dtohs(chunk->headerSize)); 1541 mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t); 1542 } else if (type >= RES_XML_FIRST_CHUNK_TYPE 1543 && type <= RES_XML_LAST_CHUNK_TYPE) { 1544 if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) { 1545 mError = BAD_TYPE; 1546 goto done; 1547 } 1548 mCurNode = (const ResXMLTree_node*)lastChunk; 1549 if (nextNode() == BAD_DOCUMENT) { 1550 mError = BAD_TYPE; 1551 goto done; 1552 } 1553 mRootNode = mCurNode; 1554 mRootExt = mCurExt; 1555 mRootCode = mEventCode; 1556 break; 1557 } else { 1558 XML_NOISY(printf("Skipping unknown chunk!\n")); 1559 } 1560 lastChunk = chunk; 1561 chunk = (const ResChunk_header*) 1562 (((const uint8_t*)chunk) + size); 1563 } 1564 1565 if (mRootNode == NULL) { 1566 ALOGW("Bad XML block: no root element node found\n"); 1567 mError = BAD_TYPE; 1568 goto done; 1569 } 1570 1571 mError = mStrings.getError(); 1572 1573done: 1574 restart(); 1575 return mError; 1576} 1577 1578status_t ResXMLTree::getError() const 1579{ 1580 return mError; 1581} 1582 1583void ResXMLTree::uninit() 1584{ 1585 mError = NO_INIT; 1586 mStrings.uninit(); 1587 if (mOwnedData) { 1588 free(mOwnedData); 1589 mOwnedData = NULL; 1590 } 1591 restart(); 1592} 1593 1594status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const 1595{ 1596 const uint16_t eventCode = dtohs(node->header.type); 1597 1598 status_t err = validate_chunk( 1599 &node->header, sizeof(ResXMLTree_node), 1600 mDataEnd, "ResXMLTree_node"); 1601 1602 if (err >= NO_ERROR) { 1603 // Only perform additional validation on START nodes 1604 if (eventCode != RES_XML_START_ELEMENT_TYPE) { 1605 return NO_ERROR; 1606 } 1607 1608 const uint16_t headerSize = dtohs(node->header.headerSize); 1609 const uint32_t size = dtohl(node->header.size); 1610 const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*) 1611 (((const uint8_t*)node) + headerSize); 1612 // check for sensical values pulled out of the stream so far... 1613 if ((size >= headerSize + sizeof(ResXMLTree_attrExt)) 1614 && ((void*)attrExt > (void*)node)) { 1615 const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize)) 1616 * dtohs(attrExt->attributeCount); 1617 if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) { 1618 return NO_ERROR; 1619 } 1620 ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n", 1621 (unsigned int)(dtohs(attrExt->attributeStart)+attrSize), 1622 (unsigned int)(size-headerSize)); 1623 } 1624 else { 1625 ALOGW("Bad XML start block: node header size 0x%x, size 0x%x\n", 1626 (unsigned int)headerSize, (unsigned int)size); 1627 } 1628 return BAD_TYPE; 1629 } 1630 1631 return err; 1632 1633#if 0 1634 const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE; 1635 1636 const uint16_t headerSize = dtohs(node->header.headerSize); 1637 const uint32_t size = dtohl(node->header.size); 1638 1639 if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) { 1640 if (size >= headerSize) { 1641 if (((const uint8_t*)node) <= (mDataEnd-size)) { 1642 if (!isStart) { 1643 return NO_ERROR; 1644 } 1645 if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount)) 1646 <= (size-headerSize)) { 1647 return NO_ERROR; 1648 } 1649 ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n", 1650 ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount), 1651 (int)(size-headerSize)); 1652 return BAD_TYPE; 1653 } 1654 ALOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n", 1655 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize); 1656 return BAD_TYPE; 1657 } 1658 ALOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n", 1659 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), 1660 (int)headerSize, (int)size); 1661 return BAD_TYPE; 1662 } 1663 ALOGW("Bad XML block: node at 0x%x header size 0x%x too small\n", 1664 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), 1665 (int)headerSize); 1666 return BAD_TYPE; 1667#endif 1668} 1669 1670// -------------------------------------------------------------------- 1671// -------------------------------------------------------------------- 1672// -------------------------------------------------------------------- 1673 1674void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) { 1675 const size_t size = dtohl(o.size); 1676 if (size >= sizeof(ResTable_config)) { 1677 *this = o; 1678 } else { 1679 memcpy(this, &o, size); 1680 memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size); 1681 } 1682} 1683 1684/* static */ size_t unpackLanguageOrRegion(const char in[2], const char base, 1685 char out[4]) { 1686 if (in[0] & 0x80) { 1687 // The high bit is "1", which means this is a packed three letter 1688 // language code. 1689 1690 // The smallest 5 bits of the second char are the first alphabet. 1691 const uint8_t first = in[1] & 0x1f; 1692 // The last three bits of the second char and the first two bits 1693 // of the first char are the second alphabet. 1694 const uint8_t second = ((in[1] & 0xe0) >> 5) + ((in[0] & 0x03) << 3); 1695 // Bits 3 to 7 (inclusive) of the first char are the third alphabet. 1696 const uint8_t third = (in[0] & 0x7c) >> 2; 1697 1698 out[0] = first + base; 1699 out[1] = second + base; 1700 out[2] = third + base; 1701 out[3] = 0; 1702 1703 return 3; 1704 } 1705 1706 if (in[0]) { 1707 memcpy(out, in, 2); 1708 memset(out + 2, 0, 2); 1709 return 2; 1710 } 1711 1712 memset(out, 0, 4); 1713 return 0; 1714} 1715 1716/* static */ void packLanguageOrRegion(const char* in, const char base, 1717 char out[2]) { 1718 if (in[2] == 0 || in[2] == '-') { 1719 out[0] = in[0]; 1720 out[1] = in[1]; 1721 } else { 1722 uint8_t first = (in[0] - base) & 0x007f; 1723 uint8_t second = (in[1] - base) & 0x007f; 1724 uint8_t third = (in[2] - base) & 0x007f; 1725 1726 out[0] = (0x80 | (third << 2) | (second >> 3)); 1727 out[1] = ((second << 5) | first); 1728 } 1729} 1730 1731 1732void ResTable_config::packLanguage(const char* language) { 1733 packLanguageOrRegion(language, 'a', this->language); 1734} 1735 1736void ResTable_config::packRegion(const char* region) { 1737 packLanguageOrRegion(region, '0', this->country); 1738} 1739 1740size_t ResTable_config::unpackLanguage(char language[4]) const { 1741 return unpackLanguageOrRegion(this->language, 'a', language); 1742} 1743 1744size_t ResTable_config::unpackRegion(char region[4]) const { 1745 return unpackLanguageOrRegion(this->country, '0', region); 1746} 1747 1748 1749void ResTable_config::copyFromDtoH(const ResTable_config& o) { 1750 copyFromDeviceNoSwap(o); 1751 size = sizeof(ResTable_config); 1752 mcc = dtohs(mcc); 1753 mnc = dtohs(mnc); 1754 density = dtohs(density); 1755 screenWidth = dtohs(screenWidth); 1756 screenHeight = dtohs(screenHeight); 1757 sdkVersion = dtohs(sdkVersion); 1758 minorVersion = dtohs(minorVersion); 1759 smallestScreenWidthDp = dtohs(smallestScreenWidthDp); 1760 screenWidthDp = dtohs(screenWidthDp); 1761 screenHeightDp = dtohs(screenHeightDp); 1762} 1763 1764void ResTable_config::swapHtoD() { 1765 size = htodl(size); 1766 mcc = htods(mcc); 1767 mnc = htods(mnc); 1768 density = htods(density); 1769 screenWidth = htods(screenWidth); 1770 screenHeight = htods(screenHeight); 1771 sdkVersion = htods(sdkVersion); 1772 minorVersion = htods(minorVersion); 1773 smallestScreenWidthDp = htods(smallestScreenWidthDp); 1774 screenWidthDp = htods(screenWidthDp); 1775 screenHeightDp = htods(screenHeightDp); 1776} 1777 1778/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) { 1779 if (l.locale != r.locale) { 1780 // NOTE: This is the old behaviour with respect to comparison orders. 1781 // The diff value here doesn't make much sense (given our bit packing scheme) 1782 // but it's stable, and that's all we need. 1783 return l.locale - r.locale; 1784 } 1785 1786 // The language & region are equal, so compare the scripts and variants. 1787 int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript)); 1788 if (script) { 1789 return script; 1790 } 1791 1792 // The language, region and script are equal, so compare variants. 1793 // 1794 // This should happen very infrequently (if at all.) 1795 return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant)); 1796} 1797 1798int ResTable_config::compare(const ResTable_config& o) const { 1799 int32_t diff = (int32_t)(imsi - o.imsi); 1800 if (diff != 0) return diff; 1801 diff = compareLocales(*this, o); 1802 if (diff != 0) return diff; 1803 diff = (int32_t)(screenType - o.screenType); 1804 if (diff != 0) return diff; 1805 diff = (int32_t)(input - o.input); 1806 if (diff != 0) return diff; 1807 diff = (int32_t)(screenSize - o.screenSize); 1808 if (diff != 0) return diff; 1809 diff = (int32_t)(version - o.version); 1810 if (diff != 0) return diff; 1811 diff = (int32_t)(screenLayout - o.screenLayout); 1812 if (diff != 0) return diff; 1813 diff = (int32_t)(uiMode - o.uiMode); 1814 if (diff != 0) return diff; 1815 diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp); 1816 if (diff != 0) return diff; 1817 diff = (int32_t)(screenSizeDp - o.screenSizeDp); 1818 return (int)diff; 1819} 1820 1821int ResTable_config::compareLogical(const ResTable_config& o) const { 1822 if (mcc != o.mcc) { 1823 return mcc < o.mcc ? -1 : 1; 1824 } 1825 if (mnc != o.mnc) { 1826 return mnc < o.mnc ? -1 : 1; 1827 } 1828 1829 int diff = compareLocales(*this, o); 1830 if (diff < 0) { 1831 return -1; 1832 } 1833 if (diff > 0) { 1834 return 1; 1835 } 1836 1837 if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) { 1838 return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1; 1839 } 1840 if (smallestScreenWidthDp != o.smallestScreenWidthDp) { 1841 return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1; 1842 } 1843 if (screenWidthDp != o.screenWidthDp) { 1844 return screenWidthDp < o.screenWidthDp ? -1 : 1; 1845 } 1846 if (screenHeightDp != o.screenHeightDp) { 1847 return screenHeightDp < o.screenHeightDp ? -1 : 1; 1848 } 1849 if (screenWidth != o.screenWidth) { 1850 return screenWidth < o.screenWidth ? -1 : 1; 1851 } 1852 if (screenHeight != o.screenHeight) { 1853 return screenHeight < o.screenHeight ? -1 : 1; 1854 } 1855 if (density != o.density) { 1856 return density < o.density ? -1 : 1; 1857 } 1858 if (orientation != o.orientation) { 1859 return orientation < o.orientation ? -1 : 1; 1860 } 1861 if (touchscreen != o.touchscreen) { 1862 return touchscreen < o.touchscreen ? -1 : 1; 1863 } 1864 if (input != o.input) { 1865 return input < o.input ? -1 : 1; 1866 } 1867 if (screenLayout != o.screenLayout) { 1868 return screenLayout < o.screenLayout ? -1 : 1; 1869 } 1870 if (uiMode != o.uiMode) { 1871 return uiMode < o.uiMode ? -1 : 1; 1872 } 1873 if (version != o.version) { 1874 return version < o.version ? -1 : 1; 1875 } 1876 return 0; 1877} 1878 1879int ResTable_config::diff(const ResTable_config& o) const { 1880 int diffs = 0; 1881 if (mcc != o.mcc) diffs |= CONFIG_MCC; 1882 if (mnc != o.mnc) diffs |= CONFIG_MNC; 1883 if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION; 1884 if (density != o.density) diffs |= CONFIG_DENSITY; 1885 if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN; 1886 if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0) 1887 diffs |= CONFIG_KEYBOARD_HIDDEN; 1888 if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD; 1889 if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION; 1890 if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE; 1891 if (version != o.version) diffs |= CONFIG_VERSION; 1892 if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR; 1893 if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT; 1894 if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE; 1895 if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE; 1896 if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE; 1897 1898 const int diff = compareLocales(*this, o); 1899 if (diff) diffs |= CONFIG_LOCALE; 1900 1901 return diffs; 1902} 1903 1904int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const { 1905 if (locale || o.locale) { 1906 if (language[0] != o.language[0]) { 1907 if (!language[0]) return -1; 1908 if (!o.language[0]) return 1; 1909 } 1910 1911 if (country[0] != o.country[0]) { 1912 if (!country[0]) return -1; 1913 if (!o.country[0]) return 1; 1914 } 1915 } 1916 1917 // There isn't a well specified "importance" order between variants and 1918 // scripts. We can't easily tell whether, say "en-Latn-US" is more or less 1919 // specific than "en-US-POSIX". 1920 // 1921 // We therefore arbitrarily decide to give priority to variants over 1922 // scripts since it seems more useful to do so. We will consider 1923 // "en-US-POSIX" to be more specific than "en-Latn-US". 1924 1925 const int score = ((localeScript[0] != 0) ? 1 : 0) + 1926 ((localeVariant[0] != 0) ? 2 : 0); 1927 1928 const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) + 1929 ((o.localeVariant[0] != 0) ? 2 : 0); 1930 1931 return score - oScore; 1932 1933} 1934 1935bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const { 1936 // The order of the following tests defines the importance of one 1937 // configuration parameter over another. Those tests first are more 1938 // important, trumping any values in those following them. 1939 if (imsi || o.imsi) { 1940 if (mcc != o.mcc) { 1941 if (!mcc) return false; 1942 if (!o.mcc) return true; 1943 } 1944 1945 if (mnc != o.mnc) { 1946 if (!mnc) return false; 1947 if (!o.mnc) return true; 1948 } 1949 } 1950 1951 if (locale || o.locale) { 1952 const int diff = isLocaleMoreSpecificThan(o); 1953 if (diff < 0) { 1954 return false; 1955 } 1956 1957 if (diff > 0) { 1958 return true; 1959 } 1960 } 1961 1962 if (screenLayout || o.screenLayout) { 1963 if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0) { 1964 if (!(screenLayout & MASK_LAYOUTDIR)) return false; 1965 if (!(o.screenLayout & MASK_LAYOUTDIR)) return true; 1966 } 1967 } 1968 1969 if (smallestScreenWidthDp || o.smallestScreenWidthDp) { 1970 if (smallestScreenWidthDp != o.smallestScreenWidthDp) { 1971 if (!smallestScreenWidthDp) return false; 1972 if (!o.smallestScreenWidthDp) return true; 1973 } 1974 } 1975 1976 if (screenSizeDp || o.screenSizeDp) { 1977 if (screenWidthDp != o.screenWidthDp) { 1978 if (!screenWidthDp) return false; 1979 if (!o.screenWidthDp) return true; 1980 } 1981 1982 if (screenHeightDp != o.screenHeightDp) { 1983 if (!screenHeightDp) return false; 1984 if (!o.screenHeightDp) return true; 1985 } 1986 } 1987 1988 if (screenLayout || o.screenLayout) { 1989 if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) { 1990 if (!(screenLayout & MASK_SCREENSIZE)) return false; 1991 if (!(o.screenLayout & MASK_SCREENSIZE)) return true; 1992 } 1993 if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) { 1994 if (!(screenLayout & MASK_SCREENLONG)) return false; 1995 if (!(o.screenLayout & MASK_SCREENLONG)) return true; 1996 } 1997 } 1998 1999 if (orientation != o.orientation) { 2000 if (!orientation) return false; 2001 if (!o.orientation) return true; 2002 } 2003 2004 if (uiMode || o.uiMode) { 2005 if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) { 2006 if (!(uiMode & MASK_UI_MODE_TYPE)) return false; 2007 if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true; 2008 } 2009 if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) { 2010 if (!(uiMode & MASK_UI_MODE_NIGHT)) return false; 2011 if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true; 2012 } 2013 } 2014 2015 // density is never 'more specific' 2016 // as the default just equals 160 2017 2018 if (touchscreen != o.touchscreen) { 2019 if (!touchscreen) return false; 2020 if (!o.touchscreen) return true; 2021 } 2022 2023 if (input || o.input) { 2024 if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) { 2025 if (!(inputFlags & MASK_KEYSHIDDEN)) return false; 2026 if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true; 2027 } 2028 2029 if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) { 2030 if (!(inputFlags & MASK_NAVHIDDEN)) return false; 2031 if (!(o.inputFlags & MASK_NAVHIDDEN)) return true; 2032 } 2033 2034 if (keyboard != o.keyboard) { 2035 if (!keyboard) return false; 2036 if (!o.keyboard) return true; 2037 } 2038 2039 if (navigation != o.navigation) { 2040 if (!navigation) return false; 2041 if (!o.navigation) return true; 2042 } 2043 } 2044 2045 if (screenSize || o.screenSize) { 2046 if (screenWidth != o.screenWidth) { 2047 if (!screenWidth) return false; 2048 if (!o.screenWidth) return true; 2049 } 2050 2051 if (screenHeight != o.screenHeight) { 2052 if (!screenHeight) return false; 2053 if (!o.screenHeight) return true; 2054 } 2055 } 2056 2057 if (version || o.version) { 2058 if (sdkVersion != o.sdkVersion) { 2059 if (!sdkVersion) return false; 2060 if (!o.sdkVersion) return true; 2061 } 2062 2063 if (minorVersion != o.minorVersion) { 2064 if (!minorVersion) return false; 2065 if (!o.minorVersion) return true; 2066 } 2067 } 2068 return false; 2069} 2070 2071bool ResTable_config::isBetterThan(const ResTable_config& o, 2072 const ResTable_config* requested) const { 2073 if (requested) { 2074 if (imsi || o.imsi) { 2075 if ((mcc != o.mcc) && requested->mcc) { 2076 return (mcc); 2077 } 2078 2079 if ((mnc != o.mnc) && requested->mnc) { 2080 return (mnc); 2081 } 2082 } 2083 2084 if (locale || o.locale) { 2085 if ((language[0] != o.language[0]) && requested->language[0]) { 2086 return (language[0]); 2087 } 2088 2089 if ((country[0] != o.country[0]) && requested->country[0]) { 2090 return (country[0]); 2091 } 2092 } 2093 2094 if (localeScript[0] || o.localeScript[0]) { 2095 if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) { 2096 return localeScript[0]; 2097 } 2098 } 2099 2100 if (localeVariant[0] || o.localeVariant[0]) { 2101 if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) { 2102 return localeVariant[0]; 2103 } 2104 } 2105 2106 if (screenLayout || o.screenLayout) { 2107 if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0 2108 && (requested->screenLayout & MASK_LAYOUTDIR)) { 2109 int myLayoutDir = screenLayout & MASK_LAYOUTDIR; 2110 int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR; 2111 return (myLayoutDir > oLayoutDir); 2112 } 2113 } 2114 2115 if (smallestScreenWidthDp || o.smallestScreenWidthDp) { 2116 // The configuration closest to the actual size is best. 2117 // We assume that larger configs have already been filtered 2118 // out at this point. That means we just want the largest one. 2119 if (smallestScreenWidthDp != o.smallestScreenWidthDp) { 2120 return smallestScreenWidthDp > o.smallestScreenWidthDp; 2121 } 2122 } 2123 2124 if (screenSizeDp || o.screenSizeDp) { 2125 // "Better" is based on the sum of the difference between both 2126 // width and height from the requested dimensions. We are 2127 // assuming the invalid configs (with smaller dimens) have 2128 // already been filtered. Note that if a particular dimension 2129 // is unspecified, we will end up with a large value (the 2130 // difference between 0 and the requested dimension), which is 2131 // good since we will prefer a config that has specified a 2132 // dimension value. 2133 int myDelta = 0, otherDelta = 0; 2134 if (requested->screenWidthDp) { 2135 myDelta += requested->screenWidthDp - screenWidthDp; 2136 otherDelta += requested->screenWidthDp - o.screenWidthDp; 2137 } 2138 if (requested->screenHeightDp) { 2139 myDelta += requested->screenHeightDp - screenHeightDp; 2140 otherDelta += requested->screenHeightDp - o.screenHeightDp; 2141 } 2142 //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d", 2143 // screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp, 2144 // requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta); 2145 if (myDelta != otherDelta) { 2146 return myDelta < otherDelta; 2147 } 2148 } 2149 2150 if (screenLayout || o.screenLayout) { 2151 if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0 2152 && (requested->screenLayout & MASK_SCREENSIZE)) { 2153 // A little backwards compatibility here: undefined is 2154 // considered equivalent to normal. But only if the 2155 // requested size is at least normal; otherwise, small 2156 // is better than the default. 2157 int mySL = (screenLayout & MASK_SCREENSIZE); 2158 int oSL = (o.screenLayout & MASK_SCREENSIZE); 2159 int fixedMySL = mySL; 2160 int fixedOSL = oSL; 2161 if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) { 2162 if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL; 2163 if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL; 2164 } 2165 // For screen size, the best match is the one that is 2166 // closest to the requested screen size, but not over 2167 // (the not over part is dealt with in match() below). 2168 if (fixedMySL == fixedOSL) { 2169 // If the two are the same, but 'this' is actually 2170 // undefined, then the other is really a better match. 2171 if (mySL == 0) return false; 2172 return true; 2173 } 2174 if (fixedMySL != fixedOSL) { 2175 return fixedMySL > fixedOSL; 2176 } 2177 } 2178 if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0 2179 && (requested->screenLayout & MASK_SCREENLONG)) { 2180 return (screenLayout & MASK_SCREENLONG); 2181 } 2182 } 2183 2184 if ((orientation != o.orientation) && requested->orientation) { 2185 return (orientation); 2186 } 2187 2188 if (uiMode || o.uiMode) { 2189 if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0 2190 && (requested->uiMode & MASK_UI_MODE_TYPE)) { 2191 return (uiMode & MASK_UI_MODE_TYPE); 2192 } 2193 if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0 2194 && (requested->uiMode & MASK_UI_MODE_NIGHT)) { 2195 return (uiMode & MASK_UI_MODE_NIGHT); 2196 } 2197 } 2198 2199 if (screenType || o.screenType) { 2200 if (density != o.density) { 2201 // density is tough. Any density is potentially useful 2202 // because the system will scale it. Scaling down 2203 // is generally better than scaling up. 2204 // Default density counts as 160dpi (the system default) 2205 // TODO - remove 160 constants 2206 int h = (density?density:160); 2207 int l = (o.density?o.density:160); 2208 bool bImBigger = true; 2209 if (l > h) { 2210 int t = h; 2211 h = l; 2212 l = t; 2213 bImBigger = false; 2214 } 2215 2216 int reqValue = (requested->density?requested->density:160); 2217 if (reqValue >= h) { 2218 // requested value higher than both l and h, give h 2219 return bImBigger; 2220 } 2221 if (l >= reqValue) { 2222 // requested value lower than both l and h, give l 2223 return !bImBigger; 2224 } 2225 // saying that scaling down is 2x better than up 2226 if (((2 * l) - reqValue) * h > reqValue * reqValue) { 2227 return !bImBigger; 2228 } else { 2229 return bImBigger; 2230 } 2231 } 2232 2233 if ((touchscreen != o.touchscreen) && requested->touchscreen) { 2234 return (touchscreen); 2235 } 2236 } 2237 2238 if (input || o.input) { 2239 const int keysHidden = inputFlags & MASK_KEYSHIDDEN; 2240 const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN; 2241 if (keysHidden != oKeysHidden) { 2242 const int reqKeysHidden = 2243 requested->inputFlags & MASK_KEYSHIDDEN; 2244 if (reqKeysHidden) { 2245 2246 if (!keysHidden) return false; 2247 if (!oKeysHidden) return true; 2248 // For compatibility, we count KEYSHIDDEN_NO as being 2249 // the same as KEYSHIDDEN_SOFT. Here we disambiguate 2250 // these by making an exact match more specific. 2251 if (reqKeysHidden == keysHidden) return true; 2252 if (reqKeysHidden == oKeysHidden) return false; 2253 } 2254 } 2255 2256 const int navHidden = inputFlags & MASK_NAVHIDDEN; 2257 const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN; 2258 if (navHidden != oNavHidden) { 2259 const int reqNavHidden = 2260 requested->inputFlags & MASK_NAVHIDDEN; 2261 if (reqNavHidden) { 2262 2263 if (!navHidden) return false; 2264 if (!oNavHidden) return true; 2265 } 2266 } 2267 2268 if ((keyboard != o.keyboard) && requested->keyboard) { 2269 return (keyboard); 2270 } 2271 2272 if ((navigation != o.navigation) && requested->navigation) { 2273 return (navigation); 2274 } 2275 } 2276 2277 if (screenSize || o.screenSize) { 2278 // "Better" is based on the sum of the difference between both 2279 // width and height from the requested dimensions. We are 2280 // assuming the invalid configs (with smaller sizes) have 2281 // already been filtered. Note that if a particular dimension 2282 // is unspecified, we will end up with a large value (the 2283 // difference between 0 and the requested dimension), which is 2284 // good since we will prefer a config that has specified a 2285 // size value. 2286 int myDelta = 0, otherDelta = 0; 2287 if (requested->screenWidth) { 2288 myDelta += requested->screenWidth - screenWidth; 2289 otherDelta += requested->screenWidth - o.screenWidth; 2290 } 2291 if (requested->screenHeight) { 2292 myDelta += requested->screenHeight - screenHeight; 2293 otherDelta += requested->screenHeight - o.screenHeight; 2294 } 2295 if (myDelta != otherDelta) { 2296 return myDelta < otherDelta; 2297 } 2298 } 2299 2300 if (version || o.version) { 2301 if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { 2302 return (sdkVersion > o.sdkVersion); 2303 } 2304 2305 if ((minorVersion != o.minorVersion) && 2306 requested->minorVersion) { 2307 return (minorVersion); 2308 } 2309 } 2310 2311 return false; 2312 } 2313 return isMoreSpecificThan(o); 2314} 2315 2316bool ResTable_config::match(const ResTable_config& settings) const { 2317 if (imsi != 0) { 2318 if (mcc != 0 && mcc != settings.mcc) { 2319 return false; 2320 } 2321 if (mnc != 0 && mnc != settings.mnc) { 2322 return false; 2323 } 2324 } 2325 if (locale != 0) { 2326 // Don't consider the script & variants when deciding matches. 2327 // 2328 // If we two configs differ only in their script or language, they 2329 // can be weeded out in the isMoreSpecificThan test. 2330 if (language[0] != 0 2331 && (language[0] != settings.language[0] 2332 || language[1] != settings.language[1])) { 2333 return false; 2334 } 2335 2336 if (country[0] != 0 2337 && (country[0] != settings.country[0] 2338 || country[1] != settings.country[1])) { 2339 return false; 2340 } 2341 } 2342 2343 if (screenConfig != 0) { 2344 const int layoutDir = screenLayout&MASK_LAYOUTDIR; 2345 const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR; 2346 if (layoutDir != 0 && layoutDir != setLayoutDir) { 2347 return false; 2348 } 2349 2350 const int screenSize = screenLayout&MASK_SCREENSIZE; 2351 const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; 2352 // Any screen sizes for larger screens than the setting do not 2353 // match. 2354 if (screenSize != 0 && screenSize > setScreenSize) { 2355 return false; 2356 } 2357 2358 const int screenLong = screenLayout&MASK_SCREENLONG; 2359 const int setScreenLong = settings.screenLayout&MASK_SCREENLONG; 2360 if (screenLong != 0 && screenLong != setScreenLong) { 2361 return false; 2362 } 2363 2364 const int uiModeType = uiMode&MASK_UI_MODE_TYPE; 2365 const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; 2366 if (uiModeType != 0 && uiModeType != setUiModeType) { 2367 return false; 2368 } 2369 2370 const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; 2371 const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; 2372 if (uiModeNight != 0 && uiModeNight != setUiModeNight) { 2373 return false; 2374 } 2375 2376 if (smallestScreenWidthDp != 0 2377 && smallestScreenWidthDp > settings.smallestScreenWidthDp) { 2378 return false; 2379 } 2380 } 2381 if (screenSizeDp != 0) { 2382 if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) { 2383 //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp); 2384 return false; 2385 } 2386 if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) { 2387 //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp); 2388 return false; 2389 } 2390 } 2391 if (screenType != 0) { 2392 if (orientation != 0 && orientation != settings.orientation) { 2393 return false; 2394 } 2395 // density always matches - we can scale it. See isBetterThan 2396 if (touchscreen != 0 && touchscreen != settings.touchscreen) { 2397 return false; 2398 } 2399 } 2400 if (input != 0) { 2401 const int keysHidden = inputFlags&MASK_KEYSHIDDEN; 2402 const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN; 2403 if (keysHidden != 0 && keysHidden != setKeysHidden) { 2404 // For compatibility, we count a request for KEYSHIDDEN_NO as also 2405 // matching the more recent KEYSHIDDEN_SOFT. Basically 2406 // KEYSHIDDEN_NO means there is some kind of keyboard available. 2407 //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden); 2408 if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) { 2409 //ALOGI("No match!"); 2410 return false; 2411 } 2412 } 2413 const int navHidden = inputFlags&MASK_NAVHIDDEN; 2414 const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; 2415 if (navHidden != 0 && navHidden != setNavHidden) { 2416 return false; 2417 } 2418 if (keyboard != 0 && keyboard != settings.keyboard) { 2419 return false; 2420 } 2421 if (navigation != 0 && navigation != settings.navigation) { 2422 return false; 2423 } 2424 } 2425 if (screenSize != 0) { 2426 if (screenWidth != 0 && screenWidth > settings.screenWidth) { 2427 return false; 2428 } 2429 if (screenHeight != 0 && screenHeight > settings.screenHeight) { 2430 return false; 2431 } 2432 } 2433 if (version != 0) { 2434 if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) { 2435 return false; 2436 } 2437 if (minorVersion != 0 && minorVersion != settings.minorVersion) { 2438 return false; 2439 } 2440 } 2441 return true; 2442} 2443 2444void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const { 2445 memset(str, 0, RESTABLE_MAX_LOCALE_LEN); 2446 2447 // This represents the "any" locale value, which has traditionally been 2448 // represented by the empty string. 2449 if (!language[0] && !country[0]) { 2450 return; 2451 } 2452 2453 size_t charsWritten = 0; 2454 if (language[0]) { 2455 charsWritten += unpackLanguage(str); 2456 } 2457 2458 if (localeScript[0]) { 2459 if (charsWritten) { 2460 str[charsWritten++] = '-'; 2461 } 2462 memcpy(str + charsWritten, localeScript, sizeof(localeScript)); 2463 charsWritten += sizeof(localeScript); 2464 } 2465 2466 if (country[0]) { 2467 if (charsWritten) { 2468 str[charsWritten++] = '-'; 2469 } 2470 charsWritten += unpackRegion(str + charsWritten); 2471 } 2472 2473 if (localeVariant[0]) { 2474 if (charsWritten) { 2475 str[charsWritten++] = '-'; 2476 } 2477 memcpy(str + charsWritten, localeVariant, sizeof(localeVariant)); 2478 } 2479} 2480 2481/* static */ inline bool assignLocaleComponent(ResTable_config* config, 2482 const char* start, size_t size) { 2483 2484 switch (size) { 2485 case 0: 2486 return false; 2487 case 2: 2488 case 3: 2489 config->language[0] ? config->packRegion(start) : config->packLanguage(start); 2490 break; 2491 case 4: 2492 config->localeScript[0] = toupper(start[0]); 2493 for (size_t i = 1; i < 4; ++i) { 2494 config->localeScript[i] = tolower(start[i]); 2495 } 2496 break; 2497 case 5: 2498 case 6: 2499 case 7: 2500 case 8: 2501 for (size_t i = 0; i < size; ++i) { 2502 config->localeVariant[i] = tolower(start[i]); 2503 } 2504 break; 2505 default: 2506 return false; 2507 } 2508 2509 return true; 2510} 2511 2512void ResTable_config::setBcp47Locale(const char* in) { 2513 locale = 0; 2514 memset(localeScript, 0, sizeof(localeScript)); 2515 memset(localeVariant, 0, sizeof(localeVariant)); 2516 2517 const char* separator = in; 2518 const char* start = in; 2519 while ((separator = strchr(start, '-')) != NULL) { 2520 const size_t size = separator - start; 2521 if (!assignLocaleComponent(this, start, size)) { 2522 fprintf(stderr, "Invalid BCP-47 locale string: %s", in); 2523 } 2524 2525 start = (separator + 1); 2526 } 2527 2528 const size_t size = in + strlen(in) - start; 2529 assignLocaleComponent(this, start, size); 2530} 2531 2532String8 ResTable_config::toString() const { 2533 String8 res; 2534 2535 if (mcc != 0) { 2536 if (res.size() > 0) res.append("-"); 2537 res.appendFormat("mcc%d", dtohs(mcc)); 2538 } 2539 if (mnc != 0) { 2540 if (res.size() > 0) res.append("-"); 2541 res.appendFormat("mnc%d", dtohs(mnc)); 2542 } 2543 2544 char localeStr[RESTABLE_MAX_LOCALE_LEN]; 2545 getBcp47Locale(localeStr); 2546 if (strlen(localeStr) > 0) { 2547 if (res.size() > 0) res.append("-"); 2548 res.append(localeStr); 2549 } 2550 2551 if ((screenLayout&MASK_LAYOUTDIR) != 0) { 2552 if (res.size() > 0) res.append("-"); 2553 switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) { 2554 case ResTable_config::LAYOUTDIR_LTR: 2555 res.append("ldltr"); 2556 break; 2557 case ResTable_config::LAYOUTDIR_RTL: 2558 res.append("ldrtl"); 2559 break; 2560 default: 2561 res.appendFormat("layoutDir=%d", 2562 dtohs(screenLayout&ResTable_config::MASK_LAYOUTDIR)); 2563 break; 2564 } 2565 } 2566 if (smallestScreenWidthDp != 0) { 2567 if (res.size() > 0) res.append("-"); 2568 res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp)); 2569 } 2570 if (screenWidthDp != 0) { 2571 if (res.size() > 0) res.append("-"); 2572 res.appendFormat("w%ddp", dtohs(screenWidthDp)); 2573 } 2574 if (screenHeightDp != 0) { 2575 if (res.size() > 0) res.append("-"); 2576 res.appendFormat("h%ddp", dtohs(screenHeightDp)); 2577 } 2578 if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) { 2579 if (res.size() > 0) res.append("-"); 2580 switch (screenLayout&ResTable_config::MASK_SCREENSIZE) { 2581 case ResTable_config::SCREENSIZE_SMALL: 2582 res.append("small"); 2583 break; 2584 case ResTable_config::SCREENSIZE_NORMAL: 2585 res.append("normal"); 2586 break; 2587 case ResTable_config::SCREENSIZE_LARGE: 2588 res.append("large"); 2589 break; 2590 case ResTable_config::SCREENSIZE_XLARGE: 2591 res.append("xlarge"); 2592 break; 2593 default: 2594 res.appendFormat("screenLayoutSize=%d", 2595 dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE)); 2596 break; 2597 } 2598 } 2599 if ((screenLayout&MASK_SCREENLONG) != 0) { 2600 if (res.size() > 0) res.append("-"); 2601 switch (screenLayout&ResTable_config::MASK_SCREENLONG) { 2602 case ResTable_config::SCREENLONG_NO: 2603 res.append("notlong"); 2604 break; 2605 case ResTable_config::SCREENLONG_YES: 2606 res.append("long"); 2607 break; 2608 default: 2609 res.appendFormat("screenLayoutLong=%d", 2610 dtohs(screenLayout&ResTable_config::MASK_SCREENLONG)); 2611 break; 2612 } 2613 } 2614 if (orientation != ORIENTATION_ANY) { 2615 if (res.size() > 0) res.append("-"); 2616 switch (orientation) { 2617 case ResTable_config::ORIENTATION_PORT: 2618 res.append("port"); 2619 break; 2620 case ResTable_config::ORIENTATION_LAND: 2621 res.append("land"); 2622 break; 2623 case ResTable_config::ORIENTATION_SQUARE: 2624 res.append("square"); 2625 break; 2626 default: 2627 res.appendFormat("orientation=%d", dtohs(orientation)); 2628 break; 2629 } 2630 } 2631 if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) { 2632 if (res.size() > 0) res.append("-"); 2633 switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) { 2634 case ResTable_config::UI_MODE_TYPE_DESK: 2635 res.append("desk"); 2636 break; 2637 case ResTable_config::UI_MODE_TYPE_CAR: 2638 res.append("car"); 2639 break; 2640 case ResTable_config::UI_MODE_TYPE_TELEVISION: 2641 res.append("television"); 2642 break; 2643 case ResTable_config::UI_MODE_TYPE_APPLIANCE: 2644 res.append("appliance"); 2645 break; 2646 case ResTable_config::UI_MODE_TYPE_WATCH: 2647 res.append("watch"); 2648 break; 2649 default: 2650 res.appendFormat("uiModeType=%d", 2651 dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE)); 2652 break; 2653 } 2654 } 2655 if ((uiMode&MASK_UI_MODE_NIGHT) != 0) { 2656 if (res.size() > 0) res.append("-"); 2657 switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) { 2658 case ResTable_config::UI_MODE_NIGHT_NO: 2659 res.append("notnight"); 2660 break; 2661 case ResTable_config::UI_MODE_NIGHT_YES: 2662 res.append("night"); 2663 break; 2664 default: 2665 res.appendFormat("uiModeNight=%d", 2666 dtohs(uiMode&MASK_UI_MODE_NIGHT)); 2667 break; 2668 } 2669 } 2670 if (density != DENSITY_DEFAULT) { 2671 if (res.size() > 0) res.append("-"); 2672 switch (density) { 2673 case ResTable_config::DENSITY_LOW: 2674 res.append("ldpi"); 2675 break; 2676 case ResTable_config::DENSITY_MEDIUM: 2677 res.append("mdpi"); 2678 break; 2679 case ResTable_config::DENSITY_TV: 2680 res.append("tvdpi"); 2681 break; 2682 case ResTable_config::DENSITY_HIGH: 2683 res.append("hdpi"); 2684 break; 2685 case ResTable_config::DENSITY_XHIGH: 2686 res.append("xhdpi"); 2687 break; 2688 case ResTable_config::DENSITY_XXHIGH: 2689 res.append("xxhdpi"); 2690 break; 2691 case ResTable_config::DENSITY_NONE: 2692 res.append("nodpi"); 2693 break; 2694 default: 2695 res.appendFormat("%ddpi", dtohs(density)); 2696 break; 2697 } 2698 } 2699 if (touchscreen != TOUCHSCREEN_ANY) { 2700 if (res.size() > 0) res.append("-"); 2701 switch (touchscreen) { 2702 case ResTable_config::TOUCHSCREEN_NOTOUCH: 2703 res.append("notouch"); 2704 break; 2705 case ResTable_config::TOUCHSCREEN_FINGER: 2706 res.append("finger"); 2707 break; 2708 case ResTable_config::TOUCHSCREEN_STYLUS: 2709 res.append("stylus"); 2710 break; 2711 default: 2712 res.appendFormat("touchscreen=%d", dtohs(touchscreen)); 2713 break; 2714 } 2715 } 2716 if ((inputFlags&MASK_KEYSHIDDEN) != 0) { 2717 if (res.size() > 0) res.append("-"); 2718 switch (inputFlags&MASK_KEYSHIDDEN) { 2719 case ResTable_config::KEYSHIDDEN_NO: 2720 res.append("keysexposed"); 2721 break; 2722 case ResTable_config::KEYSHIDDEN_YES: 2723 res.append("keyshidden"); 2724 break; 2725 case ResTable_config::KEYSHIDDEN_SOFT: 2726 res.append("keyssoft"); 2727 break; 2728 } 2729 } 2730 if (keyboard != KEYBOARD_ANY) { 2731 if (res.size() > 0) res.append("-"); 2732 switch (keyboard) { 2733 case ResTable_config::KEYBOARD_NOKEYS: 2734 res.append("nokeys"); 2735 break; 2736 case ResTable_config::KEYBOARD_QWERTY: 2737 res.append("qwerty"); 2738 break; 2739 case ResTable_config::KEYBOARD_12KEY: 2740 res.append("12key"); 2741 break; 2742 default: 2743 res.appendFormat("keyboard=%d", dtohs(keyboard)); 2744 break; 2745 } 2746 } 2747 if ((inputFlags&MASK_NAVHIDDEN) != 0) { 2748 if (res.size() > 0) res.append("-"); 2749 switch (inputFlags&MASK_NAVHIDDEN) { 2750 case ResTable_config::NAVHIDDEN_NO: 2751 res.append("navexposed"); 2752 break; 2753 case ResTable_config::NAVHIDDEN_YES: 2754 res.append("navhidden"); 2755 break; 2756 default: 2757 res.appendFormat("inputFlagsNavHidden=%d", 2758 dtohs(inputFlags&MASK_NAVHIDDEN)); 2759 break; 2760 } 2761 } 2762 if (navigation != NAVIGATION_ANY) { 2763 if (res.size() > 0) res.append("-"); 2764 switch (navigation) { 2765 case ResTable_config::NAVIGATION_NONAV: 2766 res.append("nonav"); 2767 break; 2768 case ResTable_config::NAVIGATION_DPAD: 2769 res.append("dpad"); 2770 break; 2771 case ResTable_config::NAVIGATION_TRACKBALL: 2772 res.append("trackball"); 2773 break; 2774 case ResTable_config::NAVIGATION_WHEEL: 2775 res.append("wheel"); 2776 break; 2777 default: 2778 res.appendFormat("navigation=%d", dtohs(navigation)); 2779 break; 2780 } 2781 } 2782 if (screenSize != 0) { 2783 if (res.size() > 0) res.append("-"); 2784 res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight)); 2785 } 2786 if (version != 0) { 2787 if (res.size() > 0) res.append("-"); 2788 res.appendFormat("v%d", dtohs(sdkVersion)); 2789 if (minorVersion != 0) { 2790 res.appendFormat(".%d", dtohs(minorVersion)); 2791 } 2792 } 2793 2794 return res; 2795} 2796 2797// -------------------------------------------------------------------- 2798// -------------------------------------------------------------------- 2799// -------------------------------------------------------------------- 2800 2801struct ResTable::Header 2802{ 2803 Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL), 2804 resourceIDMap(NULL), resourceIDMapSize(0) { } 2805 2806 ~Header() 2807 { 2808 free(resourceIDMap); 2809 } 2810 2811 const ResTable* const owner; 2812 void* ownedData; 2813 const ResTable_header* header; 2814 size_t size; 2815 const uint8_t* dataEnd; 2816 size_t index; 2817 int32_t cookie; 2818 2819 ResStringPool values; 2820 uint32_t* resourceIDMap; 2821 size_t resourceIDMapSize; 2822}; 2823 2824struct ResTable::Entry { 2825 ResTable_config config; 2826 const ResTable_entry* entry; 2827 const ResTable_type* type; 2828 uint32_t specFlags; 2829 const Package* package; 2830 2831 StringPoolRef typeStr; 2832 StringPoolRef keyStr; 2833}; 2834 2835struct ResTable::Type 2836{ 2837 Type(const Header* _header, const Package* _package, size_t count) 2838 : header(_header), package(_package), entryCount(count), 2839 typeSpec(NULL), typeSpecFlags(NULL) { } 2840 const Header* const header; 2841 const Package* const package; 2842 const size_t entryCount; 2843 const ResTable_typeSpec* typeSpec; 2844 const uint32_t* typeSpecFlags; 2845 IdmapEntries idmapEntries; 2846 Vector<const ResTable_type*> configs; 2847}; 2848 2849struct ResTable::Package 2850{ 2851 Package(ResTable* _owner, const Header* _header, const ResTable_package* _package) 2852 : owner(_owner), header(_header), package(_package), typeIdOffset(0) { 2853 if (dtohs(package->header.headerSize) == sizeof(package)) { 2854 // The package structure is the same size as the definition. 2855 // This means it contains the typeIdOffset field. 2856 typeIdOffset = package->typeIdOffset; 2857 } 2858 } 2859 2860 const ResTable* const owner; 2861 const Header* const header; 2862 const ResTable_package* const package; 2863 2864 ResStringPool typeStrings; 2865 ResStringPool keyStrings; 2866 2867 size_t typeIdOffset; 2868}; 2869 2870// A group of objects describing a particular resource package. 2871// The first in 'package' is always the root object (from the resource 2872// table that defined the package); the ones after are skins on top of it. 2873struct ResTable::PackageGroup 2874{ 2875 PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id) 2876 : owner(_owner) 2877 , name(_name) 2878 , id(_id) 2879 , largestTypeId(0) 2880 , bags(NULL) 2881 , dynamicRefTable(static_cast<uint8_t>(_id)) 2882 { } 2883 2884 ~PackageGroup() { 2885 clearBagCache(); 2886 const size_t numTypes = types.size(); 2887 for (size_t i = 0; i < numTypes; i++) { 2888 const TypeList& typeList = types[i]; 2889 const size_t numInnerTypes = typeList.size(); 2890 for (size_t j = 0; j < numInnerTypes; j++) { 2891 if (typeList[j]->package->owner == owner) { 2892 delete typeList[j]; 2893 } 2894 } 2895 } 2896 2897 const size_t N = packages.size(); 2898 for (size_t i=0; i<N; i++) { 2899 Package* pkg = packages[i]; 2900 if (pkg->owner == owner) { 2901 delete pkg; 2902 } 2903 } 2904 } 2905 2906 void clearBagCache() { 2907 if (bags) { 2908 TABLE_NOISY(printf("bags=%p\n", bags)); 2909 for (size_t i = 0; i < bags->size(); i++) { 2910 TABLE_NOISY(printf("type=%d\n", i)); 2911 const TypeList& typeList = types[i]; 2912 if (typeList.isEmpty()) { 2913 bag_set** typeBags = bags->get(i); 2914 TABLE_NOISY(printf("typeBags=%p\n", typeBags)); 2915 if (typeBags) { 2916 const size_t N = typeList[0]->entryCount; 2917 TABLE_NOISY(printf("type->entryCount=%x\n", N)); 2918 for (size_t j=0; j<N; j++) { 2919 if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) 2920 free(typeBags[j]); 2921 } 2922 free(typeBags); 2923 } 2924 } 2925 } 2926 delete bags; 2927 bags = NULL; 2928 } 2929 } 2930 2931 ssize_t findType16(const char16_t* type, size_t len) const { 2932 const size_t N = packages.size(); 2933 for (size_t i = 0; i < N; i++) { 2934 ssize_t index = packages[i]->typeStrings.indexOfString(type, len); 2935 if (index >= 0) { 2936 return index + packages[i]->typeIdOffset; 2937 } 2938 } 2939 return -1; 2940 } 2941 2942 const ResTable* const owner; 2943 String16 const name; 2944 uint32_t const id; 2945 2946 // This is mainly used to keep track of the loaded packages 2947 // and to clean them up properly. Accessing resources happens from 2948 // the 'types' array. 2949 Vector<Package*> packages; 2950 2951 ByteBucketArray<TypeList> types; 2952 2953 uint8_t largestTypeId; 2954 2955 // Computed attribute bags, first indexed by the type and second 2956 // by the entry in that type. 2957 ByteBucketArray<bag_set**>* bags; 2958 2959 // The table mapping dynamic references to resolved references for 2960 // this package group. 2961 // TODO: We may be able to support dynamic references in overlays 2962 // by having these tables in a per-package scope rather than 2963 // per-package-group. 2964 DynamicRefTable dynamicRefTable; 2965}; 2966 2967struct ResTable::bag_set 2968{ 2969 size_t numAttrs; // number in array 2970 size_t availAttrs; // total space in array 2971 uint32_t typeSpecFlags; 2972 // Followed by 'numAttr' bag_entry structures. 2973}; 2974 2975ResTable::Theme::Theme(const ResTable& table) 2976 : mTable(table) 2977{ 2978 memset(mPackages, 0, sizeof(mPackages)); 2979} 2980 2981ResTable::Theme::~Theme() 2982{ 2983 for (size_t i=0; i<Res_MAXPACKAGE; i++) { 2984 package_info* pi = mPackages[i]; 2985 if (pi != NULL) { 2986 free_package(pi); 2987 } 2988 } 2989} 2990 2991void ResTable::Theme::free_package(package_info* pi) 2992{ 2993 for (size_t j = 0; j <= Res_MAXTYPE; j++) { 2994 theme_entry* te = pi->types[j].entries; 2995 if (te != NULL) { 2996 free(te); 2997 } 2998 } 2999 free(pi); 3000} 3001 3002ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi) 3003{ 3004 package_info* newpi = (package_info*)malloc(sizeof(package_info)); 3005 for (size_t j = 0; j <= Res_MAXTYPE; j++) { 3006 size_t cnt = pi->types[j].numEntries; 3007 newpi->types[j].numEntries = cnt; 3008 theme_entry* te = pi->types[j].entries; 3009 if (te != NULL) { 3010 theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry)); 3011 newpi->types[j].entries = newte; 3012 memcpy(newte, te, cnt*sizeof(theme_entry)); 3013 } else { 3014 newpi->types[j].entries = NULL; 3015 } 3016 } 3017 return newpi; 3018} 3019 3020status_t ResTable::Theme::applyStyle(uint32_t resID, bool force) 3021{ 3022 const bag_entry* bag; 3023 uint32_t bagTypeSpecFlags = 0; 3024 mTable.lock(); 3025 const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags); 3026 TABLE_NOISY(ALOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N)); 3027 if (N < 0) { 3028 mTable.unlock(); 3029 return N; 3030 } 3031 3032 uint32_t curPackage = 0xffffffff; 3033 ssize_t curPackageIndex = 0; 3034 package_info* curPI = NULL; 3035 uint32_t curType = 0xffffffff; 3036 size_t numEntries = 0; 3037 theme_entry* curEntries = NULL; 3038 3039 const bag_entry* end = bag + N; 3040 while (bag < end) { 3041 const uint32_t attrRes = bag->map.name.ident; 3042 const uint32_t p = Res_GETPACKAGE(attrRes); 3043 const uint32_t t = Res_GETTYPE(attrRes); 3044 const uint32_t e = Res_GETENTRY(attrRes); 3045 3046 if (curPackage != p) { 3047 const ssize_t pidx = mTable.getResourcePackageIndex(attrRes); 3048 if (pidx < 0) { 3049 ALOGE("Style contains key with bad package: 0x%08x\n", attrRes); 3050 bag++; 3051 continue; 3052 } 3053 curPackage = p; 3054 curPackageIndex = pidx; 3055 curPI = mPackages[pidx]; 3056 if (curPI == NULL) { 3057 PackageGroup* const grp = mTable.mPackageGroups[pidx]; 3058 curPI = (package_info*)malloc(sizeof(package_info)); 3059 memset(curPI, 0, sizeof(*curPI)); 3060 mPackages[pidx] = curPI; 3061 } 3062 curType = 0xffffffff; 3063 } 3064 if (curType != t) { 3065 if (t > Res_MAXTYPE) { 3066 ALOGE("Style contains key with bad type: 0x%08x\n", attrRes); 3067 bag++; 3068 continue; 3069 } 3070 curType = t; 3071 curEntries = curPI->types[t].entries; 3072 if (curEntries == NULL) { 3073 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex]; 3074 const TypeList& typeList = grp->types[t]; 3075 int cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount; 3076 curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry)); 3077 memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry)); 3078 curPI->types[t].numEntries = cnt; 3079 curPI->types[t].entries = curEntries; 3080 } 3081 numEntries = curPI->types[t].numEntries; 3082 } 3083 if (e >= numEntries) { 3084 ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes); 3085 bag++; 3086 continue; 3087 } 3088 theme_entry* curEntry = curEntries + e; 3089 TABLE_NOISY(ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x", 3090 attrRes, bag->map.value.dataType, bag->map.value.data, 3091 curEntry->value.dataType)); 3092 if (force || curEntry->value.dataType == Res_value::TYPE_NULL) { 3093 curEntry->stringBlock = bag->stringBlock; 3094 curEntry->typeSpecFlags |= bagTypeSpecFlags; 3095 curEntry->value = bag->map.value; 3096 } 3097 3098 bag++; 3099 } 3100 3101 mTable.unlock(); 3102 3103 //ALOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this); 3104 //dumpToLog(); 3105 3106 return NO_ERROR; 3107} 3108 3109status_t ResTable::Theme::setTo(const Theme& other) 3110{ 3111 //ALOGI("Setting theme %p from theme %p...\n", this, &other); 3112 //dumpToLog(); 3113 //other.dumpToLog(); 3114 3115 if (&mTable == &other.mTable) { 3116 for (size_t i=0; i<Res_MAXPACKAGE; i++) { 3117 if (mPackages[i] != NULL) { 3118 free_package(mPackages[i]); 3119 } 3120 if (other.mPackages[i] != NULL) { 3121 mPackages[i] = copy_package(other.mPackages[i]); 3122 } else { 3123 mPackages[i] = NULL; 3124 } 3125 } 3126 } else { 3127 // @todo: need to really implement this, not just copy 3128 // the system package (which is still wrong because it isn't 3129 // fixing up resource references). 3130 for (size_t i=0; i<Res_MAXPACKAGE; i++) { 3131 if (mPackages[i] != NULL) { 3132 free_package(mPackages[i]); 3133 } 3134 if (i == 0 && other.mPackages[i] != NULL) { 3135 mPackages[i] = copy_package(other.mPackages[i]); 3136 } else { 3137 mPackages[i] = NULL; 3138 } 3139 } 3140 } 3141 3142 //ALOGI("Final theme:"); 3143 //dumpToLog(); 3144 3145 return NO_ERROR; 3146} 3147 3148ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue, 3149 uint32_t* outTypeSpecFlags) const 3150{ 3151 int cnt = 20; 3152 3153 if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0; 3154 3155 do { 3156 const ssize_t p = mTable.getResourcePackageIndex(resID); 3157 const uint32_t t = Res_GETTYPE(resID); 3158 const uint32_t e = Res_GETENTRY(resID); 3159 3160 TABLE_THEME(ALOGI("Looking up attr 0x%08x in theme %p", resID, this)); 3161 3162 if (p >= 0) { 3163 const package_info* const pi = mPackages[p]; 3164 TABLE_THEME(ALOGI("Found package: %p", pi)); 3165 if (pi != NULL) { 3166 TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, Res_MAXTYPE + 1)); 3167 if (t <= Res_MAXTYPE) { 3168 const type_info& ti = pi->types[t]; 3169 TABLE_THEME(ALOGI("Desired entry index is %ld in avail %d", e, ti.numEntries)); 3170 if (e < ti.numEntries) { 3171 const theme_entry& te = ti.entries[e]; 3172 if (outTypeSpecFlags != NULL) { 3173 *outTypeSpecFlags |= te.typeSpecFlags; 3174 } 3175 TABLE_THEME(ALOGI("Theme value: type=0x%x, data=0x%08x", 3176 te.value.dataType, te.value.data)); 3177 const uint8_t type = te.value.dataType; 3178 if (type == Res_value::TYPE_ATTRIBUTE) { 3179 if (cnt > 0) { 3180 cnt--; 3181 resID = te.value.data; 3182 continue; 3183 } 3184 ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID); 3185 return BAD_INDEX; 3186 } else if (type != Res_value::TYPE_NULL) { 3187 *outValue = te.value; 3188 return te.stringBlock; 3189 } 3190 return BAD_INDEX; 3191 } 3192 } 3193 } 3194 } 3195 break; 3196 3197 } while (true); 3198 3199 return BAD_INDEX; 3200} 3201 3202ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue, 3203 ssize_t blockIndex, uint32_t* outLastRef, 3204 uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const 3205{ 3206 //printf("Resolving type=0x%x\n", inOutValue->dataType); 3207 if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) { 3208 uint32_t newTypeSpecFlags; 3209 blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags); 3210 TABLE_THEME(ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=%p\n", 3211 (int)blockIndex, (int)inOutValue->dataType, (void*)inOutValue->data)); 3212 if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags; 3213 //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType); 3214 if (blockIndex < 0) { 3215 return blockIndex; 3216 } 3217 } 3218 return mTable.resolveReference(inOutValue, blockIndex, outLastRef, 3219 inoutTypeSpecFlags, inoutConfig); 3220} 3221 3222void ResTable::Theme::dumpToLog() const 3223{ 3224 ALOGI("Theme %p:\n", this); 3225 for (size_t i=0; i<Res_MAXPACKAGE; i++) { 3226 package_info* pi = mPackages[i]; 3227 if (pi == NULL) continue; 3228 3229 ALOGI(" Package #0x%02x:\n", (int)(i + 1)); 3230 for (size_t j = 0; j <= Res_MAXTYPE; j++) { 3231 type_info& ti = pi->types[j]; 3232 if (ti.numEntries == 0) continue; 3233 ALOGI(" Type #0x%02x:\n", (int)(j + 1)); 3234 for (size_t k = 0; k < ti.numEntries; k++) { 3235 const theme_entry& te = ti.entries[k]; 3236 if (te.value.dataType == Res_value::TYPE_NULL) continue; 3237 ALOGI(" 0x%08x: t=0x%x, d=0x%08x (block=%d)\n", 3238 (int)Res_MAKEID(i, j, k), 3239 te.value.dataType, (int)te.value.data, (int)te.stringBlock); 3240 } 3241 } 3242 } 3243} 3244 3245ResTable::ResTable() 3246 : mError(NO_INIT), mNextPackageId(2) 3247{ 3248 memset(&mParams, 0, sizeof(mParams)); 3249 memset(mPackageMap, 0, sizeof(mPackageMap)); 3250 //ALOGI("Creating ResTable %p\n", this); 3251} 3252 3253ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData) 3254 : mError(NO_INIT), mNextPackageId(2) 3255{ 3256 memset(&mParams, 0, sizeof(mParams)); 3257 memset(mPackageMap, 0, sizeof(mPackageMap)); 3258 addInternal(data, size, NULL, 0, cookie, copyData); 3259 LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table"); 3260 //ALOGI("Creating ResTable %p\n", this); 3261} 3262 3263ResTable::~ResTable() 3264{ 3265 //ALOGI("Destroying ResTable in %p\n", this); 3266 uninit(); 3267} 3268 3269inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const 3270{ 3271 return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1; 3272} 3273 3274status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) { 3275 return addInternal(data, size, NULL, 0, cookie, copyData); 3276} 3277 3278status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, 3279 const int32_t cookie, bool copyData) { 3280 return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData); 3281} 3282 3283status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) { 3284 const void* data = asset->getBuffer(true); 3285 if (data == NULL) { 3286 ALOGW("Unable to get buffer of resource asset file"); 3287 return UNKNOWN_ERROR; 3288 } 3289 3290 return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData); 3291} 3292 3293status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) { 3294 const void* data = asset->getBuffer(true); 3295 if (data == NULL) { 3296 ALOGW("Unable to get buffer of resource asset file"); 3297 return UNKNOWN_ERROR; 3298 } 3299 3300 size_t idmapSize = 0; 3301 const void* idmapData = NULL; 3302 if (idmapAsset != NULL) { 3303 idmapData = idmapAsset->getBuffer(true); 3304 if (idmapData == NULL) { 3305 ALOGW("Unable to get buffer of idmap asset file"); 3306 return UNKNOWN_ERROR; 3307 } 3308 idmapSize = static_cast<size_t>(idmapAsset->getLength()); 3309 } 3310 3311 return addInternal(data, static_cast<size_t>(asset->getLength()), 3312 idmapData, idmapSize, cookie, copyData); 3313} 3314 3315status_t ResTable::add(ResTable* src) 3316{ 3317 mError = src->mError; 3318 3319 for (size_t i=0; i<src->mHeaders.size(); i++) { 3320 mHeaders.add(src->mHeaders[i]); 3321 } 3322 3323 for (size_t i=0; i<src->mPackageGroups.size(); i++) { 3324 PackageGroup* srcPg = src->mPackageGroups[i]; 3325 PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id); 3326 for (size_t j=0; j<srcPg->packages.size(); j++) { 3327 pg->packages.add(srcPg->packages[j]); 3328 } 3329 3330 for (size_t j = 0; j < srcPg->types.size(); j++) { 3331 if (srcPg->types[j].isEmpty()) { 3332 continue; 3333 } 3334 3335 TypeList& typeList = pg->types.editItemAt(j); 3336 typeList.appendVector(srcPg->types[j]); 3337 } 3338 pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId); 3339 mPackageGroups.add(pg); 3340 } 3341 3342 memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap)); 3343 3344 return mError; 3345} 3346 3347status_t ResTable::addEmpty(const int32_t cookie) { 3348 Header* header = new Header(this); 3349 header->index = mHeaders.size(); 3350 header->cookie = cookie; 3351 header->values.setToEmpty(); 3352 header->ownedData = calloc(1, sizeof(ResTable_header)); 3353 3354 ResTable_header* resHeader = (ResTable_header*) header->ownedData; 3355 resHeader->header.type = RES_TABLE_TYPE; 3356 resHeader->header.headerSize = sizeof(ResTable_header); 3357 resHeader->header.size = sizeof(ResTable_header); 3358 3359 header->header = (const ResTable_header*) resHeader; 3360 mHeaders.add(header); 3361 return (mError=NO_ERROR); 3362} 3363 3364status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize, 3365 const int32_t cookie, bool copyData) 3366{ 3367 if (!data) { 3368 return NO_ERROR; 3369 } 3370 3371 Header* header = new Header(this); 3372 header->index = mHeaders.size(); 3373 header->cookie = cookie; 3374 if (idmapData != NULL) { 3375 header->resourceIDMap = (uint32_t*) malloc(idmapDataSize); 3376 if (header->resourceIDMap == NULL) { 3377 delete header; 3378 return (mError = NO_MEMORY); 3379 } 3380 memcpy(header->resourceIDMap, idmapData, idmapDataSize); 3381 header->resourceIDMapSize = idmapDataSize; 3382 } 3383 mHeaders.add(header); 3384 3385 const bool notDeviceEndian = htods(0xf0) != 0xf0; 3386 3387 LOAD_TABLE_NOISY( 3388 ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, copy=%d " 3389 "idmap=%p\n", data, dataSize, cookie, copyData, idmap)); 3390 3391 if (copyData || notDeviceEndian) { 3392 header->ownedData = malloc(dataSize); 3393 if (header->ownedData == NULL) { 3394 return (mError=NO_MEMORY); 3395 } 3396 memcpy(header->ownedData, data, dataSize); 3397 data = header->ownedData; 3398 } 3399 3400 header->header = (const ResTable_header*)data; 3401 header->size = dtohl(header->header->header.size); 3402 //ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size, 3403 // dtohl(header->header->header.size), header->header->header.size); 3404 LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header)); 3405 if (dtohs(header->header->header.headerSize) > header->size 3406 || header->size > dataSize) { 3407 ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n", 3408 (int)dtohs(header->header->header.headerSize), 3409 (int)header->size, (int)dataSize); 3410 return (mError=BAD_TYPE); 3411 } 3412 if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) { 3413 ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n", 3414 (int)dtohs(header->header->header.headerSize), 3415 (int)header->size); 3416 return (mError=BAD_TYPE); 3417 } 3418 header->dataEnd = ((const uint8_t*)header->header) + header->size; 3419 3420 // Iterate through all chunks. 3421 size_t curPackage = 0; 3422 3423 const ResChunk_header* chunk = 3424 (const ResChunk_header*)(((const uint8_t*)header->header) 3425 + dtohs(header->header->header.headerSize)); 3426 while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) && 3427 ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) { 3428 status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable"); 3429 if (err != NO_ERROR) { 3430 return (mError=err); 3431 } 3432 TABLE_NOISY(ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n", 3433 dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size), 3434 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)))); 3435 const size_t csize = dtohl(chunk->size); 3436 const uint16_t ctype = dtohs(chunk->type); 3437 if (ctype == RES_STRING_POOL_TYPE) { 3438 if (header->values.getError() != NO_ERROR) { 3439 // Only use the first string chunk; ignore any others that 3440 // may appear. 3441 status_t err = header->values.setTo(chunk, csize); 3442 if (err != NO_ERROR) { 3443 return (mError=err); 3444 } 3445 } else { 3446 ALOGW("Multiple string chunks found in resource table."); 3447 } 3448 } else if (ctype == RES_TABLE_PACKAGE_TYPE) { 3449 if (curPackage >= dtohl(header->header->packageCount)) { 3450 ALOGW("More package chunks were found than the %d declared in the header.", 3451 dtohl(header->header->packageCount)); 3452 return (mError=BAD_TYPE); 3453 } 3454 3455 if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) { 3456 return mError; 3457 } 3458 curPackage++; 3459 } else { 3460 ALOGW("Unknown chunk type 0x%x in table at %p.\n", 3461 ctype, 3462 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))); 3463 } 3464 chunk = (const ResChunk_header*) 3465 (((const uint8_t*)chunk) + csize); 3466 } 3467 3468 if (curPackage < dtohl(header->header->packageCount)) { 3469 ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.", 3470 (int)curPackage, dtohl(header->header->packageCount)); 3471 return (mError=BAD_TYPE); 3472 } 3473 mError = header->values.getError(); 3474 if (mError != NO_ERROR) { 3475 ALOGW("No string values found in resource table!"); 3476 } 3477 3478 TABLE_NOISY(ALOGV("Returning from add with mError=%d\n", mError)); 3479 return mError; 3480} 3481 3482status_t ResTable::getError() const 3483{ 3484 return mError; 3485} 3486 3487void ResTable::uninit() 3488{ 3489 mError = NO_INIT; 3490 size_t N = mPackageGroups.size(); 3491 for (size_t i=0; i<N; i++) { 3492 PackageGroup* g = mPackageGroups[i]; 3493 delete g; 3494 } 3495 N = mHeaders.size(); 3496 for (size_t i=0; i<N; i++) { 3497 Header* header = mHeaders[i]; 3498 if (header->owner == this) { 3499 if (header->ownedData) { 3500 free(header->ownedData); 3501 } 3502 delete header; 3503 } 3504 } 3505 3506 mPackageGroups.clear(); 3507 mHeaders.clear(); 3508} 3509 3510bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const 3511{ 3512 if (mError != NO_ERROR) { 3513 return false; 3514 } 3515 3516 const ssize_t p = getResourcePackageIndex(resID); 3517 const int t = Res_GETTYPE(resID); 3518 const int e = Res_GETENTRY(resID); 3519 3520 if (p < 0) { 3521 if (Res_GETPACKAGE(resID)+1 == 0) { 3522 ALOGW("No package identifier when getting name for resource number 0x%08x", resID); 3523 } else { 3524 ALOGW("No known package when getting name for resource number 0x%08x", resID); 3525 } 3526 return false; 3527 } 3528 if (t < 0) { 3529 ALOGW("No type identifier when getting name for resource number 0x%08x", resID); 3530 return false; 3531 } 3532 3533 const PackageGroup* const grp = mPackageGroups[p]; 3534 if (grp == NULL) { 3535 ALOGW("Bad identifier when getting name for resource number 0x%08x", resID); 3536 return false; 3537 } 3538 3539 Entry entry; 3540 status_t err = getEntry(grp, t, e, NULL, &entry); 3541 if (err != NO_ERROR) { 3542 return false; 3543 } 3544 3545 outName->package = grp->name.string(); 3546 outName->packageLen = grp->name.size(); 3547 if (allowUtf8) { 3548 outName->type8 = entry.typeStr.string8(&outName->typeLen); 3549 outName->name8 = entry.keyStr.string8(&outName->nameLen); 3550 } else { 3551 outName->type8 = NULL; 3552 outName->name8 = NULL; 3553 } 3554 if (outName->type8 == NULL) { 3555 outName->type = entry.typeStr.string16(&outName->typeLen); 3556 // If we have a bad index for some reason, we should abort. 3557 if (outName->type == NULL) { 3558 return false; 3559 } 3560 } 3561 if (outName->name8 == NULL) { 3562 outName->name = entry.keyStr.string16(&outName->nameLen); 3563 // If we have a bad index for some reason, we should abort. 3564 if (outName->name == NULL) { 3565 return false; 3566 } 3567 } 3568 3569 return true; 3570} 3571 3572ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density, 3573 uint32_t* outSpecFlags, ResTable_config* outConfig) const 3574{ 3575 if (mError != NO_ERROR) { 3576 return mError; 3577 } 3578 3579 const ssize_t p = getResourcePackageIndex(resID); 3580 const int t = Res_GETTYPE(resID); 3581 const int e = Res_GETENTRY(resID); 3582 3583 if (p < 0) { 3584 if (Res_GETPACKAGE(resID)+1 == 0) { 3585 ALOGW("No package identifier when getting value for resource number 0x%08x", resID); 3586 } else { 3587 ALOGW("No known package when getting value for resource number 0x%08x", resID); 3588 } 3589 return BAD_INDEX; 3590 } 3591 if (t < 0) { 3592 ALOGW("No type identifier when getting value for resource number 0x%08x", resID); 3593 return BAD_INDEX; 3594 } 3595 3596 const PackageGroup* const grp = mPackageGroups[p]; 3597 if (grp == NULL) { 3598 ALOGW("Bad identifier when getting value for resource number 0x%08x", resID); 3599 return BAD_INDEX; 3600 } 3601 3602 // Allow overriding density 3603 ResTable_config desiredConfig = mParams; 3604 if (density > 0) { 3605 desiredConfig.density = density; 3606 } 3607 3608 Entry entry; 3609 status_t err = getEntry(grp, t, e, &desiredConfig, &entry); 3610 if (err != NO_ERROR) { 3611 ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n", 3612 resID, t, e, err); 3613 return err; 3614 } 3615 3616 if ((dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) != 0) { 3617 if (!mayBeBag) { 3618 ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID); 3619 } 3620 return BAD_VALUE; 3621 } 3622 3623 const Res_value* value = reinterpret_cast<const Res_value*>( 3624 reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size); 3625 3626 outValue->size = dtohs(value->size); 3627 outValue->res0 = value->res0; 3628 outValue->dataType = value->dataType; 3629 outValue->data = dtohl(value->data); 3630 3631 // The reference may be pointing to a resource in a shared library. These 3632 // references have build-time generated package IDs. These ids may not match 3633 // the actual package IDs of the corresponding packages in this ResTable. 3634 // We need to fix the package ID based on a mapping. 3635 if (grp->dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) { 3636 ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data); 3637 return BAD_VALUE; 3638 } 3639 3640 TABLE_NOISY(size_t len; 3641 printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n", 3642 entry.package->header->index, 3643 outValue->dataType, 3644 outValue->dataType == Res_value::TYPE_STRING 3645 ? String8(entry.package->header->values.stringAt( 3646 outValue->data, &len)).string() 3647 : "", 3648 outValue->data)); 3649 3650 if (outSpecFlags != NULL) { 3651 *outSpecFlags = entry.specFlags; 3652 } 3653 3654 if (outConfig != NULL) { 3655 *outConfig = entry.config; 3656 } 3657 3658 return entry.package->header->index; 3659} 3660 3661ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, 3662 uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags, 3663 ResTable_config* outConfig) const 3664{ 3665 int count=0; 3666 while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE 3667 && value->data != 0 && count < 20) { 3668 if (outLastRef) *outLastRef = value->data; 3669 uint32_t lastRef = value->data; 3670 uint32_t newFlags = 0; 3671 const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags, 3672 outConfig); 3673 if (newIndex == BAD_INDEX) { 3674 return BAD_INDEX; 3675 } 3676 TABLE_THEME(ALOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n", 3677 (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data)); 3678 //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex); 3679 if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags; 3680 if (newIndex < 0) { 3681 // This can fail if the resource being referenced is a style... 3682 // in this case, just return the reference, and expect the 3683 // caller to deal with. 3684 return blockIndex; 3685 } 3686 blockIndex = newIndex; 3687 count++; 3688 } 3689 return blockIndex; 3690} 3691 3692const char16_t* ResTable::valueToString( 3693 const Res_value* value, size_t stringBlock, 3694 char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen) 3695{ 3696 if (!value) { 3697 return NULL; 3698 } 3699 if (value->dataType == value->TYPE_STRING) { 3700 return getTableStringBlock(stringBlock)->stringAt(value->data, outLen); 3701 } 3702 // XXX do int to string conversions. 3703 return NULL; 3704} 3705 3706ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const 3707{ 3708 mLock.lock(); 3709 ssize_t err = getBagLocked(resID, outBag); 3710 if (err < NO_ERROR) { 3711 //printf("*** get failed! unlocking\n"); 3712 mLock.unlock(); 3713 } 3714 return err; 3715} 3716 3717void ResTable::unlockBag(const bag_entry* /*bag*/) const 3718{ 3719 //printf("<<< unlockBag %p\n", this); 3720 mLock.unlock(); 3721} 3722 3723void ResTable::lock() const 3724{ 3725 mLock.lock(); 3726} 3727 3728void ResTable::unlock() const 3729{ 3730 mLock.unlock(); 3731} 3732 3733ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, 3734 uint32_t* outTypeSpecFlags) const 3735{ 3736 if (mError != NO_ERROR) { 3737 return mError; 3738 } 3739 3740 const ssize_t p = getResourcePackageIndex(resID); 3741 const int t = Res_GETTYPE(resID); 3742 const int e = Res_GETENTRY(resID); 3743 3744 if (p < 0) { 3745 ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID); 3746 return BAD_INDEX; 3747 } 3748 if (t < 0) { 3749 ALOGW("No type identifier when getting bag for resource number 0x%08x", resID); 3750 return BAD_INDEX; 3751 } 3752 3753 //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t); 3754 PackageGroup* const grp = mPackageGroups[p]; 3755 if (grp == NULL) { 3756 ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID); 3757 return BAD_INDEX; 3758 } 3759 3760 const TypeList& typeConfigs = grp->types[t]; 3761 if (typeConfigs.isEmpty()) { 3762 ALOGW("Type identifier 0x%x does not exist.", t+1); 3763 return BAD_INDEX; 3764 } 3765 3766 const size_t NENTRY = typeConfigs[0]->entryCount; 3767 if (e >= (int)NENTRY) { 3768 ALOGW("Entry identifier 0x%x is larger than entry count 0x%x", 3769 e, (int)typeConfigs[0]->entryCount); 3770 return BAD_INDEX; 3771 } 3772 3773 // First see if we've already computed this bag... 3774 if (grp->bags) { 3775 bag_set** typeSet = grp->bags->get(t); 3776 if (typeSet) { 3777 bag_set* set = typeSet[e]; 3778 if (set) { 3779 if (set != (bag_set*)0xFFFFFFFF) { 3780 if (outTypeSpecFlags != NULL) { 3781 *outTypeSpecFlags = set->typeSpecFlags; 3782 } 3783 *outBag = (bag_entry*)(set+1); 3784 //ALOGI("Found existing bag for: %p\n", (void*)resID); 3785 return set->numAttrs; 3786 } 3787 ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.", 3788 resID); 3789 return BAD_INDEX; 3790 } 3791 } 3792 } 3793 3794 // Bag not found, we need to compute it! 3795 if (!grp->bags) { 3796 grp->bags = new ByteBucketArray<bag_set**>(); 3797 if (!grp->bags) return NO_MEMORY; 3798 } 3799 3800 bag_set** typeSet = grp->bags->get(t); 3801 if (!typeSet) { 3802 typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*)); 3803 if (!typeSet) return NO_MEMORY; 3804 grp->bags->set(t, typeSet); 3805 } 3806 3807 // Mark that we are currently working on this one. 3808 typeSet[e] = (bag_set*)0xFFFFFFFF; 3809 3810 TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID)); 3811 3812 // Now collect all bag attributes 3813 Entry entry; 3814 status_t err = getEntry(grp, t, e, &mParams, &entry); 3815 if (err != NO_ERROR) { 3816 return err; 3817 } 3818 3819 const uint16_t entrySize = dtohs(entry.entry->size); 3820 const uint32_t parent = entrySize >= sizeof(ResTable_map_entry) 3821 ? dtohl(((const ResTable_map_entry*)entry.entry)->parent.ident) : 0; 3822 const uint32_t count = entrySize >= sizeof(ResTable_map_entry) 3823 ? dtohl(((const ResTable_map_entry*)entry.entry)->count) : 0; 3824 3825 size_t N = count; 3826 3827 TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n", 3828 entrySize, parent, count)); 3829 3830 // If this map inherits from another, we need to start 3831 // with its parent's values. Otherwise start out empty. 3832 TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", 3833 entrySize, parent)); 3834 3835 // This is what we are building. 3836 bag_set* set = NULL; 3837 3838 if (parent) { 3839 uint32_t resolvedParent = parent; 3840 3841 // Bags encode a parent reference without using the standard 3842 // Res_value structure. That means we must always try to 3843 // resolve a parent reference in case it is actually a 3844 // TYPE_DYNAMIC_REFERENCE. 3845 status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent); 3846 if (err != NO_ERROR) { 3847 ALOGE("Failed resolving bag parent id 0x%08x", parent); 3848 return UNKNOWN_ERROR; 3849 } 3850 3851 const bag_entry* parentBag; 3852 uint32_t parentTypeSpecFlags = 0; 3853 const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags); 3854 const size_t NT = ((NP >= 0) ? NP : 0) + N; 3855 set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT); 3856 if (set == NULL) { 3857 return NO_MEMORY; 3858 } 3859 if (NP > 0) { 3860 memcpy(set+1, parentBag, NP*sizeof(bag_entry)); 3861 set->numAttrs = NP; 3862 TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP)); 3863 } else { 3864 TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n")); 3865 set->numAttrs = 0; 3866 } 3867 set->availAttrs = NT; 3868 set->typeSpecFlags = parentTypeSpecFlags; 3869 } else { 3870 set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N); 3871 if (set == NULL) { 3872 return NO_MEMORY; 3873 } 3874 set->numAttrs = 0; 3875 set->availAttrs = N; 3876 set->typeSpecFlags = 0; 3877 } 3878 3879 set->typeSpecFlags |= entry.specFlags; 3880 3881 // Now merge in the new attributes... 3882 size_t curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type)) 3883 + dtohs(entry.entry->size); 3884 const ResTable_map* map; 3885 bag_entry* entries = (bag_entry*)(set+1); 3886 size_t curEntry = 0; 3887 uint32_t pos = 0; 3888 TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n", 3889 set, entries, set->availAttrs)); 3890 while (pos < count) { 3891 TABLE_NOISY(printf("Now at %p\n", (void*)curOff)); 3892 3893 if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) { 3894 ALOGW("ResTable_map at %d is beyond type chunk data %d", 3895 (int)curOff, dtohl(entry.type->header.size)); 3896 return BAD_TYPE; 3897 } 3898 map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff); 3899 N++; 3900 3901 const uint32_t newName = htodl(map->name.ident); 3902 bool isInside; 3903 uint32_t oldName = 0; 3904 while ((isInside=(curEntry < set->numAttrs)) 3905 && (oldName=entries[curEntry].map.name.ident) < newName) { 3906 TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n", 3907 curEntry, entries[curEntry].map.name.ident)); 3908 curEntry++; 3909 } 3910 3911 if ((!isInside) || oldName != newName) { 3912 // This is a new attribute... figure out what to do with it. 3913 if (set->numAttrs >= set->availAttrs) { 3914 // Need to alloc more memory... 3915 const size_t newAvail = set->availAttrs+N; 3916 set = (bag_set*)realloc(set, 3917 sizeof(bag_set) 3918 + sizeof(bag_entry)*newAvail); 3919 if (set == NULL) { 3920 return NO_MEMORY; 3921 } 3922 set->availAttrs = newAvail; 3923 entries = (bag_entry*)(set+1); 3924 TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n", 3925 set, entries, set->availAttrs)); 3926 } 3927 if (isInside) { 3928 // Going in the middle, need to make space. 3929 memmove(entries+curEntry+1, entries+curEntry, 3930 sizeof(bag_entry)*(set->numAttrs-curEntry)); 3931 set->numAttrs++; 3932 } 3933 TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n", 3934 curEntry, newName)); 3935 } else { 3936 TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n", 3937 curEntry, oldName)); 3938 } 3939 3940 bag_entry* cur = entries+curEntry; 3941 3942 cur->stringBlock = entry.package->header->index; 3943 cur->map.name.ident = newName; 3944 cur->map.value.copyFrom_dtoh(map->value); 3945 status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value); 3946 if (err != NO_ERROR) { 3947 ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data); 3948 return UNKNOWN_ERROR; 3949 } 3950 3951 TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n", 3952 curEntry, cur, cur->stringBlock, cur->map.name.ident, 3953 cur->map.value.dataType, cur->map.value.data)); 3954 3955 // On to the next! 3956 curEntry++; 3957 pos++; 3958 const size_t size = dtohs(map->value.size); 3959 curOff += size + sizeof(*map)-sizeof(map->value); 3960 }; 3961 3962 if (curEntry > set->numAttrs) { 3963 set->numAttrs = curEntry; 3964 } 3965 3966 // And this is it... 3967 typeSet[e] = set; 3968 if (set) { 3969 if (outTypeSpecFlags != NULL) { 3970 *outTypeSpecFlags = set->typeSpecFlags; 3971 } 3972 *outBag = (bag_entry*)(set+1); 3973 TABLE_NOISY(ALOGI("Returning %d attrs\n", set->numAttrs)); 3974 return set->numAttrs; 3975 } 3976 return BAD_INDEX; 3977} 3978 3979void ResTable::setParameters(const ResTable_config* params) 3980{ 3981 mLock.lock(); 3982 TABLE_GETENTRY(ALOGI("Setting parameters: %s\n", params->toString().string())); 3983 mParams = *params; 3984 for (size_t i=0; i<mPackageGroups.size(); i++) { 3985 TABLE_NOISY(ALOGI("CLEARING BAGS FOR GROUP %d!", i)); 3986 mPackageGroups[i]->clearBagCache(); 3987 } 3988 mLock.unlock(); 3989} 3990 3991void ResTable::getParameters(ResTable_config* params) const 3992{ 3993 mLock.lock(); 3994 *params = mParams; 3995 mLock.unlock(); 3996} 3997 3998struct id_name_map { 3999 uint32_t id; 4000 size_t len; 4001 char16_t name[6]; 4002}; 4003 4004const static id_name_map ID_NAMES[] = { 4005 { ResTable_map::ATTR_TYPE, 5, { '^', 't', 'y', 'p', 'e' } }, 4006 { ResTable_map::ATTR_L10N, 5, { '^', 'l', '1', '0', 'n' } }, 4007 { ResTable_map::ATTR_MIN, 4, { '^', 'm', 'i', 'n' } }, 4008 { ResTable_map::ATTR_MAX, 4, { '^', 'm', 'a', 'x' } }, 4009 { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } }, 4010 { ResTable_map::ATTR_ZERO, 5, { '^', 'z', 'e', 'r', 'o' } }, 4011 { ResTable_map::ATTR_ONE, 4, { '^', 'o', 'n', 'e' } }, 4012 { ResTable_map::ATTR_TWO, 4, { '^', 't', 'w', 'o' } }, 4013 { ResTable_map::ATTR_FEW, 4, { '^', 'f', 'e', 'w' } }, 4014 { ResTable_map::ATTR_MANY, 5, { '^', 'm', 'a', 'n', 'y' } }, 4015}; 4016 4017uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen, 4018 const char16_t* type, size_t typeLen, 4019 const char16_t* package, 4020 size_t packageLen, 4021 uint32_t* outTypeSpecFlags) const 4022{ 4023 TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError)); 4024 4025 // Check for internal resource identifier as the very first thing, so 4026 // that we will always find them even when there are no resources. 4027 if (name[0] == '^') { 4028 const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0])); 4029 size_t len; 4030 for (int i=0; i<N; i++) { 4031 const id_name_map* m = ID_NAMES + i; 4032 len = m->len; 4033 if (len != nameLen) { 4034 continue; 4035 } 4036 for (size_t j=1; j<len; j++) { 4037 if (m->name[j] != name[j]) { 4038 goto nope; 4039 } 4040 } 4041 if (outTypeSpecFlags) { 4042 *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC; 4043 } 4044 return m->id; 4045nope: 4046 ; 4047 } 4048 if (nameLen > 7) { 4049 if (name[1] == 'i' && name[2] == 'n' 4050 && name[3] == 'd' && name[4] == 'e' && name[5] == 'x' 4051 && name[6] == '_') { 4052 int index = atoi(String8(name + 7, nameLen - 7).string()); 4053 if (Res_CHECKID(index)) { 4054 ALOGW("Array resource index: %d is too large.", 4055 index); 4056 return 0; 4057 } 4058 if (outTypeSpecFlags) { 4059 *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC; 4060 } 4061 return Res_MAKEARRAY(index); 4062 } 4063 } 4064 return 0; 4065 } 4066 4067 if (mError != NO_ERROR) { 4068 return 0; 4069 } 4070 4071 bool fakePublic = false; 4072 4073 // Figure out the package and type we are looking in... 4074 4075 const char16_t* packageEnd = NULL; 4076 const char16_t* typeEnd = NULL; 4077 const char16_t* const nameEnd = name+nameLen; 4078 const char16_t* p = name; 4079 while (p < nameEnd) { 4080 if (*p == ':') packageEnd = p; 4081 else if (*p == '/') typeEnd = p; 4082 p++; 4083 } 4084 if (*name == '@') { 4085 name++; 4086 if (*name == '*') { 4087 fakePublic = true; 4088 name++; 4089 } 4090 } 4091 if (name >= nameEnd) { 4092 return 0; 4093 } 4094 4095 if (packageEnd) { 4096 package = name; 4097 packageLen = packageEnd-name; 4098 name = packageEnd+1; 4099 } else if (!package) { 4100 return 0; 4101 } 4102 4103 if (typeEnd) { 4104 type = name; 4105 typeLen = typeEnd-name; 4106 name = typeEnd+1; 4107 } else if (!type) { 4108 return 0; 4109 } 4110 4111 if (name >= nameEnd) { 4112 return 0; 4113 } 4114 nameLen = nameEnd-name; 4115 4116 TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n", 4117 String8(type, typeLen).string(), 4118 String8(name, nameLen).string(), 4119 String8(package, packageLen).string())); 4120 4121 const size_t NG = mPackageGroups.size(); 4122 for (size_t ig=0; ig<NG; ig++) { 4123 const PackageGroup* group = mPackageGroups[ig]; 4124 4125 if (strzcmp16(package, packageLen, 4126 group->name.string(), group->name.size())) { 4127 TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string())); 4128 continue; 4129 } 4130 4131 const ssize_t ti = group->findType16(type, typeLen); 4132 if (ti < 0) { 4133 TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string())); 4134 continue; 4135 } 4136 4137 const TypeList& typeList = group->types[ti]; 4138 if (typeList.isEmpty()) { 4139 TABLE_NOISY(printf("Expected type structure not found in package %s for index %d\n", 4140 String8(group->name).string(), ti)); 4141 continue; 4142 } 4143 4144 const size_t typeCount = typeList.size(); 4145 for (size_t i = 0; i < typeCount; i++) { 4146 const Type* t = typeList[i]; 4147 const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen); 4148 if (ei < 0) { 4149 continue; 4150 } 4151 4152 const size_t configCount = t->configs.size(); 4153 for (size_t j = 0; j < configCount; j++) { 4154 const TypeVariant tv(t->configs[j]); 4155 for (TypeVariant::iterator iter = tv.beginEntries(); 4156 iter != tv.endEntries(); 4157 iter++) { 4158 const ResTable_entry* entry = *iter; 4159 if (entry == NULL) { 4160 continue; 4161 } 4162 4163 if (dtohl(entry->key.index) == (size_t) ei) { 4164 uint32_t resId = Res_MAKEID(group->id - 1, ti, iter.index()); 4165 if (outTypeSpecFlags) { 4166 Entry result; 4167 if (getEntry(group, ti, iter.index(), NULL, &result) != NO_ERROR) { 4168 ALOGW("Failed to find spec flags for %s:%s/%s (0x%08x)", 4169 String8(group->name).string(), 4170 String8(String16(type, typeLen)).string(), 4171 String8(String16(name, nameLen)).string(), 4172 resId); 4173 return 0; 4174 } 4175 *outTypeSpecFlags = result.specFlags; 4176 4177 if (fakePublic) { 4178 *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC; 4179 } 4180 } 4181 return resId; 4182 } 4183 } 4184 } 4185 } 4186 break; 4187 } 4188 return 0; 4189} 4190 4191bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen, 4192 String16* outPackage, 4193 String16* outType, 4194 String16* outName, 4195 const String16* defType, 4196 const String16* defPackage, 4197 const char** outErrorMsg, 4198 bool* outPublicOnly) 4199{ 4200 const char16_t* packageEnd = NULL; 4201 const char16_t* typeEnd = NULL; 4202 const char16_t* p = refStr; 4203 const char16_t* const end = p + refLen; 4204 while (p < end) { 4205 if (*p == ':') packageEnd = p; 4206 else if (*p == '/') { 4207 typeEnd = p; 4208 break; 4209 } 4210 p++; 4211 } 4212 p = refStr; 4213 if (*p == '@') p++; 4214 4215 if (outPublicOnly != NULL) { 4216 *outPublicOnly = true; 4217 } 4218 if (*p == '*') { 4219 p++; 4220 if (outPublicOnly != NULL) { 4221 *outPublicOnly = false; 4222 } 4223 } 4224 4225 if (packageEnd) { 4226 *outPackage = String16(p, packageEnd-p); 4227 p = packageEnd+1; 4228 } else { 4229 if (!defPackage) { 4230 if (outErrorMsg) { 4231 *outErrorMsg = "No resource package specified"; 4232 } 4233 return false; 4234 } 4235 *outPackage = *defPackage; 4236 } 4237 if (typeEnd) { 4238 *outType = String16(p, typeEnd-p); 4239 p = typeEnd+1; 4240 } else { 4241 if (!defType) { 4242 if (outErrorMsg) { 4243 *outErrorMsg = "No resource type specified"; 4244 } 4245 return false; 4246 } 4247 *outType = *defType; 4248 } 4249 *outName = String16(p, end-p); 4250 if(**outPackage == 0) { 4251 if(outErrorMsg) { 4252 *outErrorMsg = "Resource package cannot be an empty string"; 4253 } 4254 return false; 4255 } 4256 if(**outType == 0) { 4257 if(outErrorMsg) { 4258 *outErrorMsg = "Resource type cannot be an empty string"; 4259 } 4260 return false; 4261 } 4262 if(**outName == 0) { 4263 if(outErrorMsg) { 4264 *outErrorMsg = "Resource id cannot be an empty string"; 4265 } 4266 return false; 4267 } 4268 return true; 4269} 4270 4271static uint32_t get_hex(char c, bool* outError) 4272{ 4273 if (c >= '0' && c <= '9') { 4274 return c - '0'; 4275 } else if (c >= 'a' && c <= 'f') { 4276 return c - 'a' + 0xa; 4277 } else if (c >= 'A' && c <= 'F') { 4278 return c - 'A' + 0xa; 4279 } 4280 *outError = true; 4281 return 0; 4282} 4283 4284struct unit_entry 4285{ 4286 const char* name; 4287 size_t len; 4288 uint8_t type; 4289 uint32_t unit; 4290 float scale; 4291}; 4292 4293static const unit_entry unitNames[] = { 4294 { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f }, 4295 { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f }, 4296 { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f }, 4297 { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f }, 4298 { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f }, 4299 { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f }, 4300 { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f }, 4301 { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 }, 4302 { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 }, 4303 { NULL, 0, 0, 0, 0 } 4304}; 4305 4306static bool parse_unit(const char* str, Res_value* outValue, 4307 float* outScale, const char** outEnd) 4308{ 4309 const char* end = str; 4310 while (*end != 0 && !isspace((unsigned char)*end)) { 4311 end++; 4312 } 4313 const size_t len = end-str; 4314 4315 const char* realEnd = end; 4316 while (*realEnd != 0 && isspace((unsigned char)*realEnd)) { 4317 realEnd++; 4318 } 4319 if (*realEnd != 0) { 4320 return false; 4321 } 4322 4323 const unit_entry* cur = unitNames; 4324 while (cur->name) { 4325 if (len == cur->len && strncmp(cur->name, str, len) == 0) { 4326 outValue->dataType = cur->type; 4327 outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT; 4328 *outScale = cur->scale; 4329 *outEnd = end; 4330 //printf("Found unit %s for %s\n", cur->name, str); 4331 return true; 4332 } 4333 cur++; 4334 } 4335 4336 return false; 4337} 4338 4339 4340bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue) 4341{ 4342 while (len > 0 && isspace16(*s)) { 4343 s++; 4344 len--; 4345 } 4346 4347 if (len <= 0) { 4348 return false; 4349 } 4350 4351 size_t i = 0; 4352 int32_t val = 0; 4353 bool neg = false; 4354 4355 if (*s == '-') { 4356 neg = true; 4357 i++; 4358 } 4359 4360 if (s[i] < '0' || s[i] > '9') { 4361 return false; 4362 } 4363 4364 // Decimal or hex? 4365 if (s[i] == '0' && s[i+1] == 'x') { 4366 if (outValue) 4367 outValue->dataType = outValue->TYPE_INT_HEX; 4368 i += 2; 4369 bool error = false; 4370 while (i < len && !error) { 4371 val = (val*16) + get_hex(s[i], &error); 4372 i++; 4373 } 4374 if (error) { 4375 return false; 4376 } 4377 } else { 4378 if (outValue) 4379 outValue->dataType = outValue->TYPE_INT_DEC; 4380 while (i < len) { 4381 if (s[i] < '0' || s[i] > '9') { 4382 return false; 4383 } 4384 val = (val*10) + s[i]-'0'; 4385 i++; 4386 } 4387 } 4388 4389 if (neg) val = -val; 4390 4391 while (i < len && isspace16(s[i])) { 4392 i++; 4393 } 4394 4395 if (i == len) { 4396 if (outValue) 4397 outValue->data = val; 4398 return true; 4399 } 4400 4401 return false; 4402} 4403 4404bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue) 4405{ 4406 while (len > 0 && isspace16(*s)) { 4407 s++; 4408 len--; 4409 } 4410 4411 if (len <= 0) { 4412 return false; 4413 } 4414 4415 char buf[128]; 4416 int i=0; 4417 while (len > 0 && *s != 0 && i < 126) { 4418 if (*s > 255) { 4419 return false; 4420 } 4421 buf[i++] = *s++; 4422 len--; 4423 } 4424 4425 if (len > 0) { 4426 return false; 4427 } 4428 if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') { 4429 return false; 4430 } 4431 4432 buf[i] = 0; 4433 const char* end; 4434 float f = strtof(buf, (char**)&end); 4435 4436 if (*end != 0 && !isspace((unsigned char)*end)) { 4437 // Might be a unit... 4438 float scale; 4439 if (parse_unit(end, outValue, &scale, &end)) { 4440 f *= scale; 4441 const bool neg = f < 0; 4442 if (neg) f = -f; 4443 uint64_t bits = (uint64_t)(f*(1<<23)+.5f); 4444 uint32_t radix; 4445 uint32_t shift; 4446 if ((bits&0x7fffff) == 0) { 4447 // Always use 23p0 if there is no fraction, just to make 4448 // things easier to read. 4449 radix = Res_value::COMPLEX_RADIX_23p0; 4450 shift = 23; 4451 } else if ((bits&0xffffffffff800000LL) == 0) { 4452 // Magnitude is zero -- can fit in 0 bits of precision. 4453 radix = Res_value::COMPLEX_RADIX_0p23; 4454 shift = 0; 4455 } else if ((bits&0xffffffff80000000LL) == 0) { 4456 // Magnitude can fit in 8 bits of precision. 4457 radix = Res_value::COMPLEX_RADIX_8p15; 4458 shift = 8; 4459 } else if ((bits&0xffffff8000000000LL) == 0) { 4460 // Magnitude can fit in 16 bits of precision. 4461 radix = Res_value::COMPLEX_RADIX_16p7; 4462 shift = 16; 4463 } else { 4464 // Magnitude needs entire range, so no fractional part. 4465 radix = Res_value::COMPLEX_RADIX_23p0; 4466 shift = 23; 4467 } 4468 int32_t mantissa = (int32_t)( 4469 (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK); 4470 if (neg) { 4471 mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK; 4472 } 4473 outValue->data |= 4474 (radix<<Res_value::COMPLEX_RADIX_SHIFT) 4475 | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT); 4476 //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n", 4477 // f * (neg ? -1 : 1), bits, f*(1<<23), 4478 // radix, shift, outValue->data); 4479 return true; 4480 } 4481 return false; 4482 } 4483 4484 while (*end != 0 && isspace((unsigned char)*end)) { 4485 end++; 4486 } 4487 4488 if (*end == 0) { 4489 if (outValue) { 4490 outValue->dataType = outValue->TYPE_FLOAT; 4491 *(float*)(&outValue->data) = f; 4492 return true; 4493 } 4494 } 4495 4496 return false; 4497} 4498 4499bool ResTable::stringToValue(Res_value* outValue, String16* outString, 4500 const char16_t* s, size_t len, 4501 bool preserveSpaces, bool coerceType, 4502 uint32_t attrID, 4503 const String16* defType, 4504 const String16* defPackage, 4505 Accessor* accessor, 4506 void* accessorCookie, 4507 uint32_t attrType, 4508 bool enforcePrivate) const 4509{ 4510 bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting(); 4511 const char* errorMsg = NULL; 4512 4513 outValue->size = sizeof(Res_value); 4514 outValue->res0 = 0; 4515 4516 // First strip leading/trailing whitespace. Do this before handling 4517 // escapes, so they can be used to force whitespace into the string. 4518 if (!preserveSpaces) { 4519 while (len > 0 && isspace16(*s)) { 4520 s++; 4521 len--; 4522 } 4523 while (len > 0 && isspace16(s[len-1])) { 4524 len--; 4525 } 4526 // If the string ends with '\', then we keep the space after it. 4527 if (len > 0 && s[len-1] == '\\' && s[len] != 0) { 4528 len++; 4529 } 4530 } 4531 4532 //printf("Value for: %s\n", String8(s, len).string()); 4533 4534 uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED; 4535 uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff; 4536 bool fromAccessor = false; 4537 if (attrID != 0 && !Res_INTERNALID(attrID)) { 4538 const ssize_t p = getResourcePackageIndex(attrID); 4539 const bag_entry* bag; 4540 ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; 4541 //printf("For attr 0x%08x got bag of %d\n", attrID, cnt); 4542 if (cnt >= 0) { 4543 while (cnt > 0) { 4544 //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data); 4545 switch (bag->map.name.ident) { 4546 case ResTable_map::ATTR_TYPE: 4547 attrType = bag->map.value.data; 4548 break; 4549 case ResTable_map::ATTR_MIN: 4550 attrMin = bag->map.value.data; 4551 break; 4552 case ResTable_map::ATTR_MAX: 4553 attrMax = bag->map.value.data; 4554 break; 4555 case ResTable_map::ATTR_L10N: 4556 l10nReq = bag->map.value.data; 4557 break; 4558 } 4559 bag++; 4560 cnt--; 4561 } 4562 unlockBag(bag); 4563 } else if (accessor && accessor->getAttributeType(attrID, &attrType)) { 4564 fromAccessor = true; 4565 if (attrType == ResTable_map::TYPE_ENUM 4566 || attrType == ResTable_map::TYPE_FLAGS 4567 || attrType == ResTable_map::TYPE_INTEGER) { 4568 accessor->getAttributeMin(attrID, &attrMin); 4569 accessor->getAttributeMax(attrID, &attrMax); 4570 } 4571 if (localizationSetting) { 4572 l10nReq = accessor->getAttributeL10N(attrID); 4573 } 4574 } 4575 } 4576 4577 const bool canStringCoerce = 4578 coerceType && (attrType&ResTable_map::TYPE_STRING) != 0; 4579 4580 if (*s == '@') { 4581 outValue->dataType = outValue->TYPE_REFERENCE; 4582 4583 // Note: we don't check attrType here because the reference can 4584 // be to any other type; we just need to count on the client making 4585 // sure the referenced type is correct. 4586 4587 //printf("Looking up ref: %s\n", String8(s, len).string()); 4588 4589 // It's a reference! 4590 if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') { 4591 outValue->data = 0; 4592 return true; 4593 } else { 4594 bool createIfNotFound = false; 4595 const char16_t* resourceRefName; 4596 int resourceNameLen; 4597 if (len > 2 && s[1] == '+') { 4598 createIfNotFound = true; 4599 resourceRefName = s + 2; 4600 resourceNameLen = len - 2; 4601 } else if (len > 2 && s[1] == '*') { 4602 enforcePrivate = false; 4603 resourceRefName = s + 2; 4604 resourceNameLen = len - 2; 4605 } else { 4606 createIfNotFound = false; 4607 resourceRefName = s + 1; 4608 resourceNameLen = len - 1; 4609 } 4610 String16 package, type, name; 4611 if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name, 4612 defType, defPackage, &errorMsg)) { 4613 if (accessor != NULL) { 4614 accessor->reportError(accessorCookie, errorMsg); 4615 } 4616 return false; 4617 } 4618 4619 uint32_t specFlags = 0; 4620 uint32_t rid = identifierForName(name.string(), name.size(), type.string(), 4621 type.size(), package.string(), package.size(), &specFlags); 4622 if (rid != 0) { 4623 if (enforcePrivate) { 4624 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) { 4625 if (accessor != NULL) { 4626 accessor->reportError(accessorCookie, "Resource is not public."); 4627 } 4628 return false; 4629 } 4630 } 4631 4632 if (accessor) { 4633 rid = Res_MAKEID( 4634 accessor->getRemappedPackage(Res_GETPACKAGE(rid)), 4635 Res_GETTYPE(rid), Res_GETENTRY(rid)); 4636 TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n", 4637 String8(package).string(), String8(type).string(), 4638 String8(name).string(), rid)); 4639 } 4640 4641 uint32_t packageId = Res_GETPACKAGE(rid) + 1; 4642 if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) { 4643 outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE; 4644 } 4645 outValue->data = rid; 4646 return true; 4647 } 4648 4649 if (accessor) { 4650 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name, 4651 createIfNotFound); 4652 if (rid != 0) { 4653 TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n", 4654 String8(package).string(), String8(type).string(), 4655 String8(name).string(), rid)); 4656 uint32_t packageId = Res_GETPACKAGE(rid) + 1; 4657 if (packageId == 0x00) { 4658 outValue->data = rid; 4659 outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE; 4660 return true; 4661 } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) { 4662 // We accept packageId's generated as 0x01 in order to support 4663 // building the android system resources 4664 outValue->data = rid; 4665 return true; 4666 } 4667 } 4668 } 4669 } 4670 4671 if (accessor != NULL) { 4672 accessor->reportError(accessorCookie, "No resource found that matches the given name"); 4673 } 4674 return false; 4675 } 4676 4677 // if we got to here, and localization is required and it's not a reference, 4678 // complain and bail. 4679 if (l10nReq == ResTable_map::L10N_SUGGESTED) { 4680 if (localizationSetting) { 4681 if (accessor != NULL) { 4682 accessor->reportError(accessorCookie, "This attribute must be localized."); 4683 } 4684 } 4685 } 4686 4687 if (*s == '#') { 4688 // It's a color! Convert to an integer of the form 0xaarrggbb. 4689 uint32_t color = 0; 4690 bool error = false; 4691 if (len == 4) { 4692 outValue->dataType = outValue->TYPE_INT_COLOR_RGB4; 4693 color |= 0xFF000000; 4694 color |= get_hex(s[1], &error) << 20; 4695 color |= get_hex(s[1], &error) << 16; 4696 color |= get_hex(s[2], &error) << 12; 4697 color |= get_hex(s[2], &error) << 8; 4698 color |= get_hex(s[3], &error) << 4; 4699 color |= get_hex(s[3], &error); 4700 } else if (len == 5) { 4701 outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4; 4702 color |= get_hex(s[1], &error) << 28; 4703 color |= get_hex(s[1], &error) << 24; 4704 color |= get_hex(s[2], &error) << 20; 4705 color |= get_hex(s[2], &error) << 16; 4706 color |= get_hex(s[3], &error) << 12; 4707 color |= get_hex(s[3], &error) << 8; 4708 color |= get_hex(s[4], &error) << 4; 4709 color |= get_hex(s[4], &error); 4710 } else if (len == 7) { 4711 outValue->dataType = outValue->TYPE_INT_COLOR_RGB8; 4712 color |= 0xFF000000; 4713 color |= get_hex(s[1], &error) << 20; 4714 color |= get_hex(s[2], &error) << 16; 4715 color |= get_hex(s[3], &error) << 12; 4716 color |= get_hex(s[4], &error) << 8; 4717 color |= get_hex(s[5], &error) << 4; 4718 color |= get_hex(s[6], &error); 4719 } else if (len == 9) { 4720 outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8; 4721 color |= get_hex(s[1], &error) << 28; 4722 color |= get_hex(s[2], &error) << 24; 4723 color |= get_hex(s[3], &error) << 20; 4724 color |= get_hex(s[4], &error) << 16; 4725 color |= get_hex(s[5], &error) << 12; 4726 color |= get_hex(s[6], &error) << 8; 4727 color |= get_hex(s[7], &error) << 4; 4728 color |= get_hex(s[8], &error); 4729 } else { 4730 error = true; 4731 } 4732 if (!error) { 4733 if ((attrType&ResTable_map::TYPE_COLOR) == 0) { 4734 if (!canStringCoerce) { 4735 if (accessor != NULL) { 4736 accessor->reportError(accessorCookie, 4737 "Color types not allowed"); 4738 } 4739 return false; 4740 } 4741 } else { 4742 outValue->data = color; 4743 //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color); 4744 return true; 4745 } 4746 } else { 4747 if ((attrType&ResTable_map::TYPE_COLOR) != 0) { 4748 if (accessor != NULL) { 4749 accessor->reportError(accessorCookie, "Color value not valid --" 4750 " must be #rgb, #argb, #rrggbb, or #aarrggbb"); 4751 } 4752 #if 0 4753 fprintf(stderr, "%s: Color ID %s value %s is not valid\n", 4754 "Resource File", //(const char*)in->getPrintableSource(), 4755 String8(*curTag).string(), 4756 String8(s, len).string()); 4757 #endif 4758 return false; 4759 } 4760 } 4761 } 4762 4763 if (*s == '?') { 4764 outValue->dataType = outValue->TYPE_ATTRIBUTE; 4765 4766 // Note: we don't check attrType here because the reference can 4767 // be to any other type; we just need to count on the client making 4768 // sure the referenced type is correct. 4769 4770 //printf("Looking up attr: %s\n", String8(s, len).string()); 4771 4772 static const String16 attr16("attr"); 4773 String16 package, type, name; 4774 if (!expandResourceRef(s+1, len-1, &package, &type, &name, 4775 &attr16, defPackage, &errorMsg)) { 4776 if (accessor != NULL) { 4777 accessor->reportError(accessorCookie, errorMsg); 4778 } 4779 return false; 4780 } 4781 4782 //printf("Pkg: %s, Type: %s, Name: %s\n", 4783 // String8(package).string(), String8(type).string(), 4784 // String8(name).string()); 4785 uint32_t specFlags = 0; 4786 uint32_t rid = 4787 identifierForName(name.string(), name.size(), 4788 type.string(), type.size(), 4789 package.string(), package.size(), &specFlags); 4790 if (rid != 0) { 4791 if (enforcePrivate) { 4792 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) { 4793 if (accessor != NULL) { 4794 accessor->reportError(accessorCookie, "Attribute is not public."); 4795 } 4796 return false; 4797 } 4798 } 4799 if (!accessor) { 4800 outValue->data = rid; 4801 return true; 4802 } 4803 rid = Res_MAKEID( 4804 accessor->getRemappedPackage(Res_GETPACKAGE(rid)), 4805 Res_GETTYPE(rid), Res_GETENTRY(rid)); 4806 //printf("Incl %s:%s/%s: 0x%08x\n", 4807 // String8(package).string(), String8(type).string(), 4808 // String8(name).string(), rid); 4809 outValue->data = rid; 4810 return true; 4811 } 4812 4813 if (accessor) { 4814 uint32_t rid = accessor->getCustomResource(package, type, name); 4815 if (rid != 0) { 4816 //printf("Mine %s:%s/%s: 0x%08x\n", 4817 // String8(package).string(), String8(type).string(), 4818 // String8(name).string(), rid); 4819 outValue->data = rid; 4820 return true; 4821 } 4822 } 4823 4824 if (accessor != NULL) { 4825 accessor->reportError(accessorCookie, "No resource found that matches the given name"); 4826 } 4827 return false; 4828 } 4829 4830 if (stringToInt(s, len, outValue)) { 4831 if ((attrType&ResTable_map::TYPE_INTEGER) == 0) { 4832 // If this type does not allow integers, but does allow floats, 4833 // fall through on this error case because the float type should 4834 // be able to accept any integer value. 4835 if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) { 4836 if (accessor != NULL) { 4837 accessor->reportError(accessorCookie, "Integer types not allowed"); 4838 } 4839 return false; 4840 } 4841 } else { 4842 if (((int32_t)outValue->data) < ((int32_t)attrMin) 4843 || ((int32_t)outValue->data) > ((int32_t)attrMax)) { 4844 if (accessor != NULL) { 4845 accessor->reportError(accessorCookie, "Integer value out of range"); 4846 } 4847 return false; 4848 } 4849 return true; 4850 } 4851 } 4852 4853 if (stringToFloat(s, len, outValue)) { 4854 if (outValue->dataType == Res_value::TYPE_DIMENSION) { 4855 if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) { 4856 return true; 4857 } 4858 if (!canStringCoerce) { 4859 if (accessor != NULL) { 4860 accessor->reportError(accessorCookie, "Dimension types not allowed"); 4861 } 4862 return false; 4863 } 4864 } else if (outValue->dataType == Res_value::TYPE_FRACTION) { 4865 if ((attrType&ResTable_map::TYPE_FRACTION) != 0) { 4866 return true; 4867 } 4868 if (!canStringCoerce) { 4869 if (accessor != NULL) { 4870 accessor->reportError(accessorCookie, "Fraction types not allowed"); 4871 } 4872 return false; 4873 } 4874 } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) { 4875 if (!canStringCoerce) { 4876 if (accessor != NULL) { 4877 accessor->reportError(accessorCookie, "Float types not allowed"); 4878 } 4879 return false; 4880 } 4881 } else { 4882 return true; 4883 } 4884 } 4885 4886 if (len == 4) { 4887 if ((s[0] == 't' || s[0] == 'T') && 4888 (s[1] == 'r' || s[1] == 'R') && 4889 (s[2] == 'u' || s[2] == 'U') && 4890 (s[3] == 'e' || s[3] == 'E')) { 4891 if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) { 4892 if (!canStringCoerce) { 4893 if (accessor != NULL) { 4894 accessor->reportError(accessorCookie, "Boolean types not allowed"); 4895 } 4896 return false; 4897 } 4898 } else { 4899 outValue->dataType = outValue->TYPE_INT_BOOLEAN; 4900 outValue->data = (uint32_t)-1; 4901 return true; 4902 } 4903 } 4904 } 4905 4906 if (len == 5) { 4907 if ((s[0] == 'f' || s[0] == 'F') && 4908 (s[1] == 'a' || s[1] == 'A') && 4909 (s[2] == 'l' || s[2] == 'L') && 4910 (s[3] == 's' || s[3] == 'S') && 4911 (s[4] == 'e' || s[4] == 'E')) { 4912 if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) { 4913 if (!canStringCoerce) { 4914 if (accessor != NULL) { 4915 accessor->reportError(accessorCookie, "Boolean types not allowed"); 4916 } 4917 return false; 4918 } 4919 } else { 4920 outValue->dataType = outValue->TYPE_INT_BOOLEAN; 4921 outValue->data = 0; 4922 return true; 4923 } 4924 } 4925 } 4926 4927 if ((attrType&ResTable_map::TYPE_ENUM) != 0) { 4928 const ssize_t p = getResourcePackageIndex(attrID); 4929 const bag_entry* bag; 4930 ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; 4931 //printf("Got %d for enum\n", cnt); 4932 if (cnt >= 0) { 4933 resource_name rname; 4934 while (cnt > 0) { 4935 if (!Res_INTERNALID(bag->map.name.ident)) { 4936 //printf("Trying attr #%08x\n", bag->map.name.ident); 4937 if (getResourceName(bag->map.name.ident, false, &rname)) { 4938 #if 0 4939 printf("Matching %s against %s (0x%08x)\n", 4940 String8(s, len).string(), 4941 String8(rname.name, rname.nameLen).string(), 4942 bag->map.name.ident); 4943 #endif 4944 if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) { 4945 outValue->dataType = bag->map.value.dataType; 4946 outValue->data = bag->map.value.data; 4947 unlockBag(bag); 4948 return true; 4949 } 4950 } 4951 4952 } 4953 bag++; 4954 cnt--; 4955 } 4956 unlockBag(bag); 4957 } 4958 4959 if (fromAccessor) { 4960 if (accessor->getAttributeEnum(attrID, s, len, outValue)) { 4961 return true; 4962 } 4963 } 4964 } 4965 4966 if ((attrType&ResTable_map::TYPE_FLAGS) != 0) { 4967 const ssize_t p = getResourcePackageIndex(attrID); 4968 const bag_entry* bag; 4969 ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; 4970 //printf("Got %d for flags\n", cnt); 4971 if (cnt >= 0) { 4972 bool failed = false; 4973 resource_name rname; 4974 outValue->dataType = Res_value::TYPE_INT_HEX; 4975 outValue->data = 0; 4976 const char16_t* end = s + len; 4977 const char16_t* pos = s; 4978 while (pos < end && !failed) { 4979 const char16_t* start = pos; 4980 pos++; 4981 while (pos < end && *pos != '|') { 4982 pos++; 4983 } 4984 //printf("Looking for: %s\n", String8(start, pos-start).string()); 4985 const bag_entry* bagi = bag; 4986 ssize_t i; 4987 for (i=0; i<cnt; i++, bagi++) { 4988 if (!Res_INTERNALID(bagi->map.name.ident)) { 4989 //printf("Trying attr #%08x\n", bagi->map.name.ident); 4990 if (getResourceName(bagi->map.name.ident, false, &rname)) { 4991 #if 0 4992 printf("Matching %s against %s (0x%08x)\n", 4993 String8(start,pos-start).string(), 4994 String8(rname.name, rname.nameLen).string(), 4995 bagi->map.name.ident); 4996 #endif 4997 if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) { 4998 outValue->data |= bagi->map.value.data; 4999 break; 5000 } 5001 } 5002 } 5003 } 5004 if (i >= cnt) { 5005 // Didn't find this flag identifier. 5006 failed = true; 5007 } 5008 if (pos < end) { 5009 pos++; 5010 } 5011 } 5012 unlockBag(bag); 5013 if (!failed) { 5014 //printf("Final flag value: 0x%lx\n", outValue->data); 5015 return true; 5016 } 5017 } 5018 5019 5020 if (fromAccessor) { 5021 if (accessor->getAttributeFlags(attrID, s, len, outValue)) { 5022 //printf("Final flag value: 0x%lx\n", outValue->data); 5023 return true; 5024 } 5025 } 5026 } 5027 5028 if ((attrType&ResTable_map::TYPE_STRING) == 0) { 5029 if (accessor != NULL) { 5030 accessor->reportError(accessorCookie, "String types not allowed"); 5031 } 5032 return false; 5033 } 5034 5035 // Generic string handling... 5036 outValue->dataType = outValue->TYPE_STRING; 5037 if (outString) { 5038 bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg); 5039 if (accessor != NULL) { 5040 accessor->reportError(accessorCookie, errorMsg); 5041 } 5042 return failed; 5043 } 5044 5045 return true; 5046} 5047 5048bool ResTable::collectString(String16* outString, 5049 const char16_t* s, size_t len, 5050 bool preserveSpaces, 5051 const char** outErrorMsg, 5052 bool append) 5053{ 5054 String16 tmp; 5055 5056 char quoted = 0; 5057 const char16_t* p = s; 5058 while (p < (s+len)) { 5059 while (p < (s+len)) { 5060 const char16_t c = *p; 5061 if (c == '\\') { 5062 break; 5063 } 5064 if (!preserveSpaces) { 5065 if (quoted == 0 && isspace16(c) 5066 && (c != ' ' || isspace16(*(p+1)))) { 5067 break; 5068 } 5069 if (c == '"' && (quoted == 0 || quoted == '"')) { 5070 break; 5071 } 5072 if (c == '\'' && (quoted == 0 || quoted == '\'')) { 5073 /* 5074 * In practice, when people write ' instead of \' 5075 * in a string, they are doing it by accident 5076 * instead of really meaning to use ' as a quoting 5077 * character. Warn them so they don't lose it. 5078 */ 5079 if (outErrorMsg) { 5080 *outErrorMsg = "Apostrophe not preceded by \\"; 5081 } 5082 return false; 5083 } 5084 } 5085 p++; 5086 } 5087 if (p < (s+len)) { 5088 if (p > s) { 5089 tmp.append(String16(s, p-s)); 5090 } 5091 if (!preserveSpaces && (*p == '"' || *p == '\'')) { 5092 if (quoted == 0) { 5093 quoted = *p; 5094 } else { 5095 quoted = 0; 5096 } 5097 p++; 5098 } else if (!preserveSpaces && isspace16(*p)) { 5099 // Space outside of a quote -- consume all spaces and 5100 // leave a single plain space char. 5101 tmp.append(String16(" ")); 5102 p++; 5103 while (p < (s+len) && isspace16(*p)) { 5104 p++; 5105 } 5106 } else if (*p == '\\') { 5107 p++; 5108 if (p < (s+len)) { 5109 switch (*p) { 5110 case 't': 5111 tmp.append(String16("\t")); 5112 break; 5113 case 'n': 5114 tmp.append(String16("\n")); 5115 break; 5116 case '#': 5117 tmp.append(String16("#")); 5118 break; 5119 case '@': 5120 tmp.append(String16("@")); 5121 break; 5122 case '?': 5123 tmp.append(String16("?")); 5124 break; 5125 case '"': 5126 tmp.append(String16("\"")); 5127 break; 5128 case '\'': 5129 tmp.append(String16("'")); 5130 break; 5131 case '\\': 5132 tmp.append(String16("\\")); 5133 break; 5134 case 'u': 5135 { 5136 char16_t chr = 0; 5137 int i = 0; 5138 while (i < 4 && p[1] != 0) { 5139 p++; 5140 i++; 5141 int c; 5142 if (*p >= '0' && *p <= '9') { 5143 c = *p - '0'; 5144 } else if (*p >= 'a' && *p <= 'f') { 5145 c = *p - 'a' + 10; 5146 } else if (*p >= 'A' && *p <= 'F') { 5147 c = *p - 'A' + 10; 5148 } else { 5149 if (outErrorMsg) { 5150 *outErrorMsg = "Bad character in \\u unicode escape sequence"; 5151 } 5152 return false; 5153 } 5154 chr = (chr<<4) | c; 5155 } 5156 tmp.append(String16(&chr, 1)); 5157 } break; 5158 default: 5159 // ignore unknown escape chars. 5160 break; 5161 } 5162 p++; 5163 } 5164 } 5165 len -= (p-s); 5166 s = p; 5167 } 5168 } 5169 5170 if (tmp.size() != 0) { 5171 if (len > 0) { 5172 tmp.append(String16(s, len)); 5173 } 5174 if (append) { 5175 outString->append(tmp); 5176 } else { 5177 outString->setTo(tmp); 5178 } 5179 } else { 5180 if (append) { 5181 outString->append(String16(s, len)); 5182 } else { 5183 outString->setTo(s, len); 5184 } 5185 } 5186 5187 return true; 5188} 5189 5190size_t ResTable::getBasePackageCount() const 5191{ 5192 if (mError != NO_ERROR) { 5193 return 0; 5194 } 5195 return mPackageGroups.size(); 5196} 5197 5198const String16 ResTable::getBasePackageName(size_t idx) const 5199{ 5200 if (mError != NO_ERROR) { 5201 return String16(); 5202 } 5203 LOG_FATAL_IF(idx >= mPackageGroups.size(), 5204 "Requested package index %d past package count %d", 5205 (int)idx, (int)mPackageGroups.size()); 5206 return mPackageGroups[idx]->name; 5207} 5208 5209uint32_t ResTable::getBasePackageId(size_t idx) const 5210{ 5211 if (mError != NO_ERROR) { 5212 return 0; 5213 } 5214 LOG_FATAL_IF(idx >= mPackageGroups.size(), 5215 "Requested package index %d past package count %d", 5216 (int)idx, (int)mPackageGroups.size()); 5217 return mPackageGroups[idx]->id; 5218} 5219 5220uint32_t ResTable::getLastTypeIdForPackage(size_t idx) const 5221{ 5222 if (mError != NO_ERROR) { 5223 return 0; 5224 } 5225 LOG_FATAL_IF(idx >= mPackageGroups.size(), 5226 "Requested package index %d past package count %d", 5227 (int)idx, (int)mPackageGroups.size()); 5228 const PackageGroup* const group = mPackageGroups[idx]; 5229 return group->largestTypeId; 5230} 5231 5232size_t ResTable::getTableCount() const 5233{ 5234 return mHeaders.size(); 5235} 5236 5237const ResStringPool* ResTable::getTableStringBlock(size_t index) const 5238{ 5239 return &mHeaders[index]->values; 5240} 5241 5242int32_t ResTable::getTableCookie(size_t index) const 5243{ 5244 return mHeaders[index]->cookie; 5245} 5246 5247const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) const 5248{ 5249 const size_t N = mPackageGroups.size(); 5250 for (size_t i = 0; i < N; i++) { 5251 const PackageGroup* pg = mPackageGroups[i]; 5252 size_t M = pg->packages.size(); 5253 for (size_t j = 0; j < M; j++) { 5254 if (pg->packages[j]->header->cookie == cookie) { 5255 return &pg->dynamicRefTable; 5256 } 5257 } 5258 } 5259 return NULL; 5260} 5261 5262void ResTable::getConfigurations(Vector<ResTable_config>* configs) const 5263{ 5264 const size_t packageCount = mPackageGroups.size(); 5265 for (size_t i = 0; i < packageCount; i++) { 5266 const PackageGroup* packageGroup = mPackageGroups[i]; 5267 const size_t typeCount = packageGroup->types.size(); 5268 for (size_t j = 0; j < typeCount; j++) { 5269 const TypeList& typeList = packageGroup->types[j]; 5270 const size_t numTypes = typeList.size(); 5271 for (size_t k = 0; k < numTypes; k++) { 5272 const Type* type = typeList[k]; 5273 const size_t numConfigs = type->configs.size(); 5274 for (size_t m = 0; m < numConfigs; m++) { 5275 const ResTable_type* config = type->configs[m]; 5276 ResTable_config cfg; 5277 memset(&cfg, 0, sizeof(ResTable_config)); 5278 cfg.copyFromDtoH(config->config); 5279 // only insert unique 5280 const size_t N = configs->size(); 5281 size_t n; 5282 for (n = 0; n < N; n++) { 5283 if (0 == (*configs)[n].compare(cfg)) { 5284 break; 5285 } 5286 } 5287 // if we didn't find it 5288 if (n == N) { 5289 configs->add(cfg); 5290 } 5291 } 5292 } 5293 } 5294 } 5295} 5296 5297void ResTable::getLocales(Vector<String8>* locales) const 5298{ 5299 Vector<ResTable_config> configs; 5300 ALOGV("calling getConfigurations"); 5301 getConfigurations(&configs); 5302 ALOGV("called getConfigurations size=%d", (int)configs.size()); 5303 const size_t I = configs.size(); 5304 5305 char locale[RESTABLE_MAX_LOCALE_LEN]; 5306 for (size_t i=0; i<I; i++) { 5307 configs[i].getBcp47Locale(locale); 5308 const size_t J = locales->size(); 5309 size_t j; 5310 for (j=0; j<J; j++) { 5311 if (0 == strcmp(locale, (*locales)[j].string())) { 5312 break; 5313 } 5314 } 5315 if (j == J) { 5316 locales->add(String8(locale)); 5317 } 5318 } 5319} 5320 5321StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index) 5322 : mPool(pool), mIndex(index) {} 5323 5324StringPoolRef::StringPoolRef() 5325 : mPool(NULL), mIndex(0) {} 5326 5327const char* StringPoolRef::string8(size_t* outLen) const { 5328 if (mPool != NULL) { 5329 return mPool->string8At(mIndex, outLen); 5330 } 5331 if (outLen != NULL) { 5332 *outLen = 0; 5333 } 5334 return NULL; 5335} 5336 5337const char16_t* StringPoolRef::string16(size_t* outLen) const { 5338 if (mPool != NULL) { 5339 return mPool->stringAt(mIndex, outLen); 5340 } 5341 if (outLen != NULL) { 5342 *outLen = 0; 5343 } 5344 return NULL; 5345} 5346 5347status_t ResTable::getEntry( 5348 const PackageGroup* packageGroup, int typeIndex, int entryIndex, 5349 const ResTable_config* config, 5350 Entry* outEntry) const 5351{ 5352 const TypeList& typeList = packageGroup->types[typeIndex]; 5353 if (typeList.isEmpty()) { 5354 ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex); 5355 return BAD_TYPE; 5356 } 5357 5358 const ResTable_type* bestType = NULL; 5359 uint32_t bestOffset = ResTable_type::NO_ENTRY; 5360 const Package* bestPackage = NULL; 5361 uint32_t specFlags = 0; 5362 uint8_t actualTypeIndex = typeIndex; 5363 ResTable_config bestConfig; 5364 memset(&bestConfig, 0, sizeof(bestConfig)); 5365 5366 // Iterate over the Types of each package. 5367 const size_t typeCount = typeList.size(); 5368 for (size_t i = 0; i < typeCount; i++) { 5369 const Type* const typeSpec = typeList[i]; 5370 5371 int realEntryIndex = entryIndex; 5372 int realTypeIndex = typeIndex; 5373 bool currentTypeIsOverlay = false; 5374 5375 // Runtime overlay packages provide a mapping of app resource 5376 // ID to package resource ID. 5377 if (typeSpec->idmapEntries.hasEntries()) { 5378 uint16_t overlayEntryIndex; 5379 if (typeSpec->idmapEntries.lookup(entryIndex, &overlayEntryIndex) != NO_ERROR) { 5380 // No such mapping exists 5381 continue; 5382 } 5383 realEntryIndex = overlayEntryIndex; 5384 realTypeIndex = typeSpec->idmapEntries.overlayTypeId() - 1; 5385 currentTypeIsOverlay = true; 5386 } 5387 5388 if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) { 5389 ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)", 5390 Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex), 5391 entryIndex, static_cast<int>(typeSpec->entryCount)); 5392 // We should normally abort here, but some legacy apps declare 5393 // resources in the 'android' package (old bug in AAPT). 5394 continue; 5395 } 5396 5397 // Aggregate all the flags for each package that defines this entry. 5398 if (typeSpec->typeSpecFlags != NULL) { 5399 specFlags |= dtohl(typeSpec->typeSpecFlags[realEntryIndex]); 5400 } else { 5401 specFlags = -1; 5402 } 5403 5404 const size_t numConfigs = typeSpec->configs.size(); 5405 for (size_t c = 0; c < numConfigs; c++) { 5406 const ResTable_type* const thisType = typeSpec->configs[c]; 5407 if (thisType == NULL) { 5408 continue; 5409 } 5410 5411 ResTable_config thisConfig; 5412 thisConfig.copyFromDtoH(thisType->config); 5413 5414 // Check to make sure this one is valid for the current parameters. 5415 if (config != NULL && !thisConfig.match(*config)) { 5416 continue; 5417 } 5418 5419 // Check if there is the desired entry in this type. 5420 const uint8_t* const end = reinterpret_cast<const uint8_t*>(thisType) 5421 + dtohl(thisType->header.size); 5422 const uint32_t* const eindex = reinterpret_cast<const uint32_t*>( 5423 reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize)); 5424 5425 uint32_t thisOffset = dtohl(eindex[realEntryIndex]); 5426 if (thisOffset == ResTable_type::NO_ENTRY) { 5427 // There is no entry for this index and configuration. 5428 continue; 5429 } 5430 5431 if (bestType != NULL) { 5432 // Check if this one is less specific than the last found. If so, 5433 // we will skip it. We check starting with things we most care 5434 // about to those we least care about. 5435 if (!thisConfig.isBetterThan(bestConfig, config)) { 5436 if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) { 5437 continue; 5438 } 5439 } 5440 } 5441 5442 bestType = thisType; 5443 bestOffset = thisOffset; 5444 bestConfig = thisConfig; 5445 bestPackage = typeSpec->package; 5446 actualTypeIndex = realTypeIndex; 5447 5448 // If no config was specified, any type will do, so skip 5449 if (config == NULL) { 5450 break; 5451 } 5452 } 5453 } 5454 5455 if (bestType == NULL) { 5456 return BAD_INDEX; 5457 } 5458 5459 bestOffset += dtohl(bestType->entriesStart); 5460 5461 if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) { 5462 ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x", 5463 bestOffset, dtohl(bestType->header.size)); 5464 return BAD_TYPE; 5465 } 5466 if ((bestOffset & 0x3) != 0) { 5467 ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset); 5468 return BAD_TYPE; 5469 } 5470 5471 const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>( 5472 reinterpret_cast<const uint8_t*>(bestType) + bestOffset); 5473 if (dtohs(entry->size) < sizeof(*entry)) { 5474 ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size)); 5475 return BAD_TYPE; 5476 } 5477 5478 if (outEntry != NULL) { 5479 outEntry->entry = entry; 5480 outEntry->config = bestConfig; 5481 outEntry->type = bestType; 5482 outEntry->specFlags = specFlags; 5483 outEntry->package = bestPackage; 5484 outEntry->typeStr = StringPoolRef(&bestPackage->typeStrings, actualTypeIndex - bestPackage->typeIdOffset); 5485 outEntry->keyStr = StringPoolRef(&bestPackage->keyStrings, dtohl(entry->key.index)); 5486 } 5487 return NO_ERROR; 5488} 5489 5490status_t ResTable::parsePackage(const ResTable_package* const pkg, 5491 const Header* const header) 5492{ 5493 const uint8_t* base = (const uint8_t*)pkg; 5494 status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset), 5495 header->dataEnd, "ResTable_package"); 5496 if (err != NO_ERROR) { 5497 return (mError=err); 5498 } 5499 5500 const uint32_t pkgSize = dtohl(pkg->header.size); 5501 5502 if (dtohl(pkg->typeStrings) >= pkgSize) { 5503 ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.", 5504 dtohl(pkg->typeStrings), pkgSize); 5505 return (mError=BAD_TYPE); 5506 } 5507 if ((dtohl(pkg->typeStrings)&0x3) != 0) { 5508 ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.", 5509 dtohl(pkg->typeStrings)); 5510 return (mError=BAD_TYPE); 5511 } 5512 if (dtohl(pkg->keyStrings) >= pkgSize) { 5513 ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.", 5514 dtohl(pkg->keyStrings), pkgSize); 5515 return (mError=BAD_TYPE); 5516 } 5517 if ((dtohl(pkg->keyStrings)&0x3) != 0) { 5518 ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.", 5519 dtohl(pkg->keyStrings)); 5520 return (mError=BAD_TYPE); 5521 } 5522 5523 uint32_t id = dtohl(pkg->id); 5524 KeyedVector<uint8_t, IdmapEntries> idmapEntries; 5525 5526 if (header->resourceIDMap != NULL) { 5527 uint8_t targetPackageId = 0; 5528 status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries); 5529 if (err != NO_ERROR) { 5530 ALOGW("Overlay is broken"); 5531 return (mError=err); 5532 } 5533 id = targetPackageId; 5534 } 5535 5536 if (id >= 256) { 5537 LOG_ALWAYS_FATAL("Package id out of range"); 5538 return NO_ERROR; 5539 } else if (id == 0) { 5540 // This is a library so assign an ID 5541 id = mNextPackageId++; 5542 } 5543 5544 PackageGroup* group = NULL; 5545 Package* package = new Package(this, header, pkg); 5546 if (package == NULL) { 5547 return (mError=NO_MEMORY); 5548 } 5549 5550 err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings), 5551 header->dataEnd-(base+dtohl(pkg->typeStrings))); 5552 if (err != NO_ERROR) { 5553 delete group; 5554 delete package; 5555 return (mError=err); 5556 } 5557 5558 err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings), 5559 header->dataEnd-(base+dtohl(pkg->keyStrings))); 5560 if (err != NO_ERROR) { 5561 delete group; 5562 delete package; 5563 return (mError=err); 5564 } 5565 5566 size_t idx = mPackageMap[id]; 5567 if (idx == 0) { 5568 idx = mPackageGroups.size() + 1; 5569 5570 char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)]; 5571 strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t)); 5572 group = new PackageGroup(this, String16(tmpName), id); 5573 if (group == NULL) { 5574 delete package; 5575 return (mError=NO_MEMORY); 5576 } 5577 5578 //printf("Adding new package id %d at index %d\n", id, idx); 5579 err = mPackageGroups.add(group); 5580 if (err < NO_ERROR) { 5581 return (mError=err); 5582 } 5583 5584 mPackageMap[id] = static_cast<uint8_t>(idx); 5585 5586 // Find all packages that reference this package 5587 size_t N = mPackageGroups.size(); 5588 for (size_t i = 0; i < N; i++) { 5589 mPackageGroups[i]->dynamicRefTable.addMapping( 5590 group->name, static_cast<uint8_t>(group->id)); 5591 } 5592 } else { 5593 group = mPackageGroups.itemAt(idx - 1); 5594 if (group == NULL) { 5595 return (mError=UNKNOWN_ERROR); 5596 } 5597 } 5598 5599 err = group->packages.add(package); 5600 if (err < NO_ERROR) { 5601 return (mError=err); 5602 } 5603 5604 // Iterate through all chunks. 5605 const ResChunk_header* chunk = 5606 (const ResChunk_header*)(((const uint8_t*)pkg) 5607 + dtohs(pkg->header.headerSize)); 5608 const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size); 5609 while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) && 5610 ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) { 5611 TABLE_NOISY(ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n", 5612 dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size), 5613 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)))); 5614 const size_t csize = dtohl(chunk->size); 5615 const uint16_t ctype = dtohs(chunk->type); 5616 if (ctype == RES_TABLE_TYPE_SPEC_TYPE) { 5617 const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk); 5618 err = validate_chunk(&typeSpec->header, sizeof(*typeSpec), 5619 endPos, "ResTable_typeSpec"); 5620 if (err != NO_ERROR) { 5621 return (mError=err); 5622 } 5623 5624 const size_t typeSpecSize = dtohl(typeSpec->header.size); 5625 const size_t newEntryCount = dtohl(typeSpec->entryCount); 5626 5627 LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n", 5628 (void*)(base-(const uint8_t*)chunk), 5629 dtohs(typeSpec->header.type), 5630 dtohs(typeSpec->header.headerSize), 5631 (void*)typeSpecSize)); 5632 // look for block overrun or int overflow when multiplying by 4 5633 if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t)) 5634 || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount) 5635 > typeSpecSize)) { 5636 ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.", 5637 (void*)(dtohs(typeSpec->header.headerSize) + (sizeof(uint32_t)*newEntryCount)), 5638 (void*)typeSpecSize); 5639 return (mError=BAD_TYPE); 5640 } 5641 5642 if (typeSpec->id == 0) { 5643 ALOGW("ResTable_type has an id of 0."); 5644 return (mError=BAD_TYPE); 5645 } 5646 5647 if (newEntryCount > 0) { 5648 uint8_t typeIndex = typeSpec->id - 1; 5649 ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id); 5650 if (idmapIndex >= 0) { 5651 typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1; 5652 } 5653 5654 TypeList& typeList = group->types.editItemAt(typeIndex); 5655 if (!typeList.isEmpty()) { 5656 const Type* existingType = typeList[0]; 5657 if (existingType->entryCount != newEntryCount && idmapIndex < 0) { 5658 ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", 5659 (int) newEntryCount, (int) existingType->entryCount); 5660 // We should normally abort here, but some legacy apps declare 5661 // resources in the 'android' package (old bug in AAPT). 5662 } 5663 } 5664 5665 Type* t = new Type(header, package, newEntryCount); 5666 t->typeSpec = typeSpec; 5667 t->typeSpecFlags = (const uint32_t*)( 5668 ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize)); 5669 if (idmapIndex >= 0) { 5670 t->idmapEntries = idmapEntries[idmapIndex]; 5671 } 5672 typeList.add(t); 5673 group->largestTypeId = max(group->largestTypeId, typeSpec->id); 5674 } else { 5675 ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id); 5676 } 5677 5678 } else if (ctype == RES_TABLE_TYPE_TYPE) { 5679 const ResTable_type* type = (const ResTable_type*)(chunk); 5680 err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4, 5681 endPos, "ResTable_type"); 5682 if (err != NO_ERROR) { 5683 return (mError=err); 5684 } 5685 5686 const uint32_t typeSize = dtohl(type->header.size); 5687 const size_t newEntryCount = dtohl(type->entryCount); 5688 5689 LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n", 5690 (void*)(base-(const uint8_t*)chunk), 5691 dtohs(type->header.type), 5692 dtohs(type->header.headerSize), 5693 (void*)typeSize)); 5694 if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount) 5695 > typeSize) { 5696 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.", 5697 (void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)), 5698 typeSize); 5699 return (mError=BAD_TYPE); 5700 } 5701 5702 if (newEntryCount != 0 5703 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) { 5704 ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.", 5705 dtohl(type->entriesStart), typeSize); 5706 return (mError=BAD_TYPE); 5707 } 5708 5709 if (type->id == 0) { 5710 ALOGW("ResTable_type has an id of 0."); 5711 return (mError=BAD_TYPE); 5712 } 5713 5714 if (newEntryCount > 0) { 5715 uint8_t typeIndex = type->id - 1; 5716 ssize_t idmapIndex = idmapEntries.indexOfKey(type->id); 5717 if (idmapIndex >= 0) { 5718 typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1; 5719 } 5720 5721 TypeList& typeList = group->types.editItemAt(typeIndex); 5722 if (typeList.isEmpty()) { 5723 ALOGE("No TypeSpec for type %d", type->id); 5724 return (mError=BAD_TYPE); 5725 } 5726 5727 Type* t = typeList.editItemAt(typeList.size() - 1); 5728 if (newEntryCount != t->entryCount) { 5729 ALOGE("ResTable_type entry count inconsistent: given %d, previously %d", 5730 (int)newEntryCount, (int)t->entryCount); 5731 return (mError=BAD_TYPE); 5732 } 5733 5734 if (t->package != package) { 5735 ALOGE("No TypeSpec for type %d", type->id); 5736 return (mError=BAD_TYPE); 5737 } 5738 5739 t->configs.add(type); 5740 5741 TABLE_GETENTRY( 5742 ResTable_config thisConfig; 5743 thisConfig.copyFromDtoH(type->config); 5744 ALOGI("Adding config to type %d: %s\n", 5745 type->id, thisConfig.toString().string())); 5746 } else { 5747 ALOGV("Skipping empty ResTable_type for type %d", type->id); 5748 } 5749 5750 } else if (ctype == RES_TABLE_LIBRARY_TYPE) { 5751 if (group->dynamicRefTable.entries().size() == 0) { 5752 status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk); 5753 if (err != NO_ERROR) { 5754 return (mError=err); 5755 } 5756 5757 // Fill in the reference table with the entries we already know about. 5758 size_t N = mPackageGroups.size(); 5759 for (size_t i = 0; i < N; i++) { 5760 group->dynamicRefTable.addMapping(mPackageGroups[i]->name, mPackageGroups[i]->id); 5761 } 5762 } else { 5763 ALOGW("Found multiple library tables, ignoring..."); 5764 } 5765 } else { 5766 status_t err = validate_chunk(chunk, sizeof(ResChunk_header), 5767 endPos, "ResTable_package:unknown"); 5768 if (err != NO_ERROR) { 5769 return (mError=err); 5770 } 5771 } 5772 chunk = (const ResChunk_header*) 5773 (((const uint8_t*)chunk) + csize); 5774 } 5775 5776 return NO_ERROR; 5777} 5778 5779DynamicRefTable::DynamicRefTable(uint8_t packageId) 5780 : mAssignedPackageId(packageId) 5781{ 5782 memset(mLookupTable, 0, sizeof(mLookupTable)); 5783 5784 // Reserved package ids 5785 mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID; 5786 mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID; 5787} 5788 5789status_t DynamicRefTable::load(const ResTable_lib_header* const header) 5790{ 5791 const uint32_t entryCount = dtohl(header->count); 5792 const uint32_t sizeOfEntries = sizeof(ResTable_lib_entry) * entryCount; 5793 const uint32_t expectedSize = dtohl(header->header.size) - dtohl(header->header.headerSize); 5794 if (sizeOfEntries > expectedSize) { 5795 ALOGE("ResTable_lib_header size %u is too small to fit %u entries (x %u).", 5796 expectedSize, entryCount, (uint32_t)sizeof(ResTable_lib_entry)); 5797 return UNKNOWN_ERROR; 5798 } 5799 5800 const ResTable_lib_entry* entry = (const ResTable_lib_entry*)(((uint8_t*) header) + 5801 dtohl(header->header.headerSize)); 5802 for (uint32_t entryIndex = 0; entryIndex < entryCount; entryIndex++) { 5803 uint32_t packageId = dtohl(entry->packageId); 5804 char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)]; 5805 strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t)); 5806 LIB_NOISY(ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(), 5807 dtohl(entry->packageId))); 5808 if (packageId >= 256) { 5809 ALOGE("Bad package id 0x%08x", packageId); 5810 return UNKNOWN_ERROR; 5811 } 5812 mEntries.replaceValueFor(String16(tmpName), (uint8_t) packageId); 5813 entry = entry + 1; 5814 } 5815 return NO_ERROR; 5816} 5817 5818status_t DynamicRefTable::addMapping(const String16& packageName, uint8_t packageId) 5819{ 5820 ssize_t index = mEntries.indexOfKey(packageName); 5821 if (index < 0) { 5822 return UNKNOWN_ERROR; 5823 } 5824 mLookupTable[mEntries.valueAt(index)] = packageId; 5825 return NO_ERROR; 5826} 5827 5828status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { 5829 uint32_t res = *resId; 5830 size_t packageId = Res_GETPACKAGE(res) + 1; 5831 5832 if (packageId == APP_PACKAGE_ID) { 5833 // No lookup needs to be done, app package IDs are absolute. 5834 return NO_ERROR; 5835 } 5836 5837 if (packageId == 0) { 5838 // The package ID is 0x00. That means that a shared library is accessing 5839 // its own local resource, so we fix up the resource with the calling 5840 // package ID. 5841 *resId |= ((uint32_t) mAssignedPackageId) << 24; 5842 return NO_ERROR; 5843 } 5844 5845 // Do a proper lookup. 5846 uint8_t translatedId = mLookupTable[packageId]; 5847 if (translatedId == 0) { 5848 ALOGV("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.", 5849 (uint8_t)mAssignedPackageId, (uint8_t)packageId); 5850 for (size_t i = 0; i < 256; i++) { 5851 if (mLookupTable[i] != 0) { 5852 ALOGV("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]); 5853 } 5854 } 5855 return UNKNOWN_ERROR; 5856 } 5857 5858 *resId = (res & 0x00ffffff) | (((uint32_t) translatedId) << 24); 5859 return NO_ERROR; 5860} 5861 5862status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { 5863 if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) { 5864 return NO_ERROR; 5865 } 5866 5867 status_t err = lookupResourceId(&value->data); 5868 if (err != NO_ERROR) { 5869 return err; 5870 } 5871 5872 value->dataType = Res_value::TYPE_REFERENCE; 5873 return NO_ERROR; 5874} 5875 5876struct IdmapTypeMap { 5877 ssize_t overlayTypeId; 5878 size_t entryOffset; 5879 Vector<uint32_t> entryMap; 5880}; 5881 5882status_t ResTable::createIdmap(const ResTable& overlay, 5883 uint32_t targetCrc, uint32_t overlayCrc, 5884 const char* targetPath, const char* overlayPath, 5885 void** outData, size_t* outSize) const 5886{ 5887 // see README for details on the format of map 5888 if (mPackageGroups.size() == 0) { 5889 ALOGW("idmap: target package has no package groups, cannot create idmap\n"); 5890 return UNKNOWN_ERROR; 5891 } 5892 5893 if (mPackageGroups[0]->packages.size() == 0) { 5894 ALOGW("idmap: target package has no packages in its first package group, " 5895 "cannot create idmap\n"); 5896 return UNKNOWN_ERROR; 5897 } 5898 5899 KeyedVector<uint8_t, IdmapTypeMap> map; 5900 5901 // overlaid packages are assumed to contain only one package group 5902 const PackageGroup* pg = mPackageGroups[0]; 5903 5904 // starting size is header 5905 *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; 5906 5907 // target package id and number of types in map 5908 *outSize += 2 * sizeof(uint16_t); 5909 5910 // overlay packages are assumed to contain only one package group 5911 const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name); 5912 5913 for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) { 5914 const TypeList& typeList = pg->types[typeIndex]; 5915 if (typeList.isEmpty()) { 5916 continue; 5917 } 5918 5919 const Type* typeConfigs = typeList[0]; 5920 5921 IdmapTypeMap typeMap; 5922 typeMap.overlayTypeId = -1; 5923 typeMap.entryOffset = 0; 5924 5925 for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) { 5926 uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex); 5927 resource_name resName; 5928 if (!this->getResourceName(resID, false, &resName)) { 5929 if (typeMap.entryMap.isEmpty()) { 5930 typeMap.entryOffset++; 5931 } 5932 continue; 5933 } 5934 5935 const String16 overlayType(resName.type, resName.typeLen); 5936 const String16 overlayName(resName.name, resName.nameLen); 5937 uint32_t overlayResID = overlay.identifierForName(overlayName.string(), 5938 overlayName.size(), 5939 overlayType.string(), 5940 overlayType.size(), 5941 overlayPackage.string(), 5942 overlayPackage.size()); 5943 if (overlayResID == 0) { 5944 if (typeMap.entryMap.isEmpty()) { 5945 typeMap.entryOffset++; 5946 } 5947 continue; 5948 } 5949 5950 if (typeMap.overlayTypeId == -1) { 5951 typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1; 5952 } 5953 5954 if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) { 5955 ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x" 5956 " but entries should map to resources of type %02x", 5957 resID, overlayResID, typeMap.overlayTypeId); 5958 return BAD_TYPE; 5959 } 5960 5961 if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) { 5962 // Resize to accomodate this entry and the 0's in between. 5963 if (typeMap.entryMap.resize((entryIndex - typeMap.entryOffset) + 1) < 0) { 5964 return NO_MEMORY; 5965 } 5966 typeMap.entryMap.editTop() = Res_GETENTRY(overlayResID); 5967 } else { 5968 typeMap.entryMap.add(Res_GETENTRY(overlayResID)); 5969 } 5970 } 5971 5972 if (!typeMap.entryMap.isEmpty()) { 5973 if (map.add(static_cast<uint8_t>(typeIndex), typeMap) < 0) { 5974 return NO_MEMORY; 5975 } 5976 *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t)); 5977 } 5978 } 5979 5980 if (map.isEmpty()) { 5981 ALOGW("idmap: no resources in overlay package present in base package"); 5982 return UNKNOWN_ERROR; 5983 } 5984 5985 if ((*outData = malloc(*outSize)) == NULL) { 5986 return NO_MEMORY; 5987 } 5988 5989 uint32_t* data = (uint32_t*)*outData; 5990 *data++ = htodl(IDMAP_MAGIC); 5991 *data++ = htodl(IDMAP_CURRENT_VERSION); 5992 *data++ = htodl(targetCrc); 5993 *data++ = htodl(overlayCrc); 5994 const char* paths[] = { targetPath, overlayPath }; 5995 for (int j = 0; j < 2; ++j) { 5996 char* p = (char*)data; 5997 const char* path = paths[j]; 5998 const size_t I = strlen(path); 5999 if (I > 255) { 6000 ALOGV("path exceeds expected 255 characters: %s\n", path); 6001 return UNKNOWN_ERROR; 6002 } 6003 for (size_t i = 0; i < 256; ++i) { 6004 *p++ = i < I ? path[i] : '\0'; 6005 } 6006 data += 256 / sizeof(uint32_t); 6007 } 6008 const size_t mapSize = map.size(); 6009 uint16_t* typeData = reinterpret_cast<uint16_t*>(data); 6010 *typeData++ = htods(pg->id); 6011 *typeData++ = htods(mapSize); 6012 for (size_t i = 0; i < mapSize; ++i) { 6013 uint8_t targetTypeId = map.keyAt(i); 6014 const IdmapTypeMap& typeMap = map[i]; 6015 *typeData++ = htods(targetTypeId + 1); 6016 *typeData++ = htods(typeMap.overlayTypeId); 6017 *typeData++ = htods(typeMap.entryMap.size()); 6018 *typeData++ = htods(typeMap.entryOffset); 6019 6020 const size_t entryCount = typeMap.entryMap.size(); 6021 uint32_t* entries = reinterpret_cast<uint32_t*>(typeData); 6022 for (size_t j = 0; j < entryCount; j++) { 6023 entries[j] = htodl(typeMap.entryMap[j]); 6024 } 6025 typeData += entryCount * 2; 6026 } 6027 6028 return NO_ERROR; 6029} 6030 6031bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, 6032 uint32_t* pVersion, 6033 uint32_t* pTargetCrc, uint32_t* pOverlayCrc, 6034 String8* pTargetPath, String8* pOverlayPath) 6035{ 6036 const uint32_t* map = (const uint32_t*)idmap; 6037 if (!assertIdmapHeader(map, sizeBytes)) { 6038 return false; 6039 } 6040 if (pVersion) { 6041 *pVersion = dtohl(map[1]); 6042 } 6043 if (pTargetCrc) { 6044 *pTargetCrc = dtohl(map[2]); 6045 } 6046 if (pOverlayCrc) { 6047 *pOverlayCrc = dtohl(map[3]); 6048 } 6049 if (pTargetPath) { 6050 pTargetPath->setTo(reinterpret_cast<const char*>(map + 4)); 6051 } 6052 if (pOverlayPath) { 6053 pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t))); 6054 } 6055 return true; 6056} 6057 6058 6059#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string()) 6060 6061#define CHAR16_ARRAY_EQ(constant, var, len) \ 6062 ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len)))) 6063 6064static void print_complex(uint32_t complex, bool isFraction) 6065{ 6066 const float MANTISSA_MULT = 6067 1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT); 6068 const float RADIX_MULTS[] = { 6069 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT, 6070 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT 6071 }; 6072 6073 float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK 6074 <<Res_value::COMPLEX_MANTISSA_SHIFT)) 6075 * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT) 6076 & Res_value::COMPLEX_RADIX_MASK]; 6077 printf("%f", value); 6078 6079 if (!isFraction) { 6080 switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) { 6081 case Res_value::COMPLEX_UNIT_PX: printf("px"); break; 6082 case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break; 6083 case Res_value::COMPLEX_UNIT_SP: printf("sp"); break; 6084 case Res_value::COMPLEX_UNIT_PT: printf("pt"); break; 6085 case Res_value::COMPLEX_UNIT_IN: printf("in"); break; 6086 case Res_value::COMPLEX_UNIT_MM: printf("mm"); break; 6087 default: printf(" (unknown unit)"); break; 6088 } 6089 } else { 6090 switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) { 6091 case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break; 6092 case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break; 6093 default: printf(" (unknown unit)"); break; 6094 } 6095 } 6096} 6097 6098// Normalize a string for output 6099String8 ResTable::normalizeForOutput( const char *input ) 6100{ 6101 String8 ret; 6102 char buff[2]; 6103 buff[1] = '\0'; 6104 6105 while (*input != '\0') { 6106 switch (*input) { 6107 // All interesting characters are in the ASCII zone, so we are making our own lives 6108 // easier by scanning the string one byte at a time. 6109 case '\\': 6110 ret += "\\\\"; 6111 break; 6112 case '\n': 6113 ret += "\\n"; 6114 break; 6115 case '"': 6116 ret += "\\\""; 6117 break; 6118 default: 6119 buff[0] = *input; 6120 ret += buff; 6121 break; 6122 } 6123 6124 input++; 6125 } 6126 6127 return ret; 6128} 6129 6130void ResTable::print_value(const Package* pkg, const Res_value& value) const 6131{ 6132 if (value.dataType == Res_value::TYPE_NULL) { 6133 printf("(null)\n"); 6134 } else if (value.dataType == Res_value::TYPE_REFERENCE) { 6135 printf("(reference) 0x%08x\n", value.data); 6136 } else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) { 6137 printf("(dynamic reference) 0x%08x\n", value.data); 6138 } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) { 6139 printf("(attribute) 0x%08x\n", value.data); 6140 } else if (value.dataType == Res_value::TYPE_STRING) { 6141 size_t len; 6142 const char* str8 = pkg->header->values.string8At( 6143 value.data, &len); 6144 if (str8 != NULL) { 6145 printf("(string8) \"%s\"\n", normalizeForOutput(str8).string()); 6146 } else { 6147 const char16_t* str16 = pkg->header->values.stringAt( 6148 value.data, &len); 6149 if (str16 != NULL) { 6150 printf("(string16) \"%s\"\n", 6151 normalizeForOutput(String8(str16, len).string()).string()); 6152 } else { 6153 printf("(string) null\n"); 6154 } 6155 } 6156 } else if (value.dataType == Res_value::TYPE_FLOAT) { 6157 printf("(float) %g\n", *(const float*)&value.data); 6158 } else if (value.dataType == Res_value::TYPE_DIMENSION) { 6159 printf("(dimension) "); 6160 print_complex(value.data, false); 6161 printf("\n"); 6162 } else if (value.dataType == Res_value::TYPE_FRACTION) { 6163 printf("(fraction) "); 6164 print_complex(value.data, true); 6165 printf("\n"); 6166 } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT 6167 || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) { 6168 printf("(color) #%08x\n", value.data); 6169 } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) { 6170 printf("(boolean) %s\n", value.data ? "true" : "false"); 6171 } else if (value.dataType >= Res_value::TYPE_FIRST_INT 6172 || value.dataType <= Res_value::TYPE_LAST_INT) { 6173 printf("(int) 0x%08x or %d\n", value.data, value.data); 6174 } else { 6175 printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n", 6176 (int)value.dataType, (int)value.data, 6177 (int)value.size, (int)value.res0); 6178 } 6179} 6180 6181void ResTable::print(bool inclValues) const 6182{ 6183 if (mError != 0) { 6184 printf("mError=0x%x (%s)\n", mError, strerror(mError)); 6185 } 6186#if 0 6187 char localeStr[RESTABLE_MAX_LOCALE_LEN]; 6188 mParams.getBcp47Locale(localeStr); 6189 printf("mParams=%s,\n" localeStr); 6190#endif 6191 size_t pgCount = mPackageGroups.size(); 6192 printf("Package Groups (%d)\n", (int)pgCount); 6193 for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) { 6194 const PackageGroup* pg = mPackageGroups[pgIndex]; 6195 printf("Package Group %d id=%d packageCount=%d name=%s\n", 6196 (int)pgIndex, pg->id, (int)pg->packages.size(), 6197 String8(pg->name).string()); 6198 6199 size_t pkgCount = pg->packages.size(); 6200 for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) { 6201 const Package* pkg = pg->packages[pkgIndex]; 6202 printf(" Package %d id=%d name=%s\n", (int)pkgIndex, 6203 pkg->package->id, String8(String16(pkg->package->name)).string()); 6204 } 6205 6206 for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) { 6207 const TypeList& typeList = pg->types[typeIndex]; 6208 if (typeList.isEmpty()) { 6209 //printf(" type %d NULL\n", (int)typeIndex); 6210 continue; 6211 } 6212 const Type* typeConfigs = typeList[0]; 6213 const size_t NTC = typeConfigs->configs.size(); 6214 printf(" type %d configCount=%d entryCount=%d\n", 6215 (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount); 6216 if (typeConfigs->typeSpecFlags != NULL) { 6217 for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) { 6218 uint32_t resID = (0xff000000 & ((pg->id)<<24)) 6219 | (0x00ff0000 & ((typeIndex+1)<<16)) 6220 | (0x0000ffff & (entryIndex)); 6221 // Since we are creating resID without actually 6222 // iterating over them, we have no idea which is a 6223 // dynamic reference. We must check. 6224 pg->dynamicRefTable.lookupResourceId(&resID); 6225 6226 resource_name resName; 6227 if (this->getResourceName(resID, true, &resName)) { 6228 String8 type8; 6229 String8 name8; 6230 if (resName.type8 != NULL) { 6231 type8 = String8(resName.type8, resName.typeLen); 6232 } else { 6233 type8 = String8(resName.type, resName.typeLen); 6234 } 6235 if (resName.name8 != NULL) { 6236 name8 = String8(resName.name8, resName.nameLen); 6237 } else { 6238 name8 = String8(resName.name, resName.nameLen); 6239 } 6240 printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", 6241 resID, 6242 CHAR16_TO_CSTR(resName.package, resName.packageLen), 6243 type8.string(), name8.string(), 6244 dtohl(typeConfigs->typeSpecFlags[entryIndex])); 6245 } else { 6246 printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID); 6247 } 6248 } 6249 } 6250 for (size_t configIndex=0; configIndex<NTC; configIndex++) { 6251 const ResTable_type* type = typeConfigs->configs[configIndex]; 6252 if ((((uint64_t)type)&0x3) != 0) { 6253 printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type); 6254 continue; 6255 } 6256 String8 configStr = type->config.toString(); 6257 printf(" config %s:\n", configStr.size() > 0 6258 ? configStr.string() : "(default)"); 6259 size_t entryCount = dtohl(type->entryCount); 6260 uint32_t entriesStart = dtohl(type->entriesStart); 6261 if ((entriesStart&0x3) != 0) { 6262 printf(" NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart); 6263 continue; 6264 } 6265 uint32_t typeSize = dtohl(type->header.size); 6266 if ((typeSize&0x3) != 0) { 6267 printf(" NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize); 6268 continue; 6269 } 6270 for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) { 6271 6272 const uint8_t* const end = ((const uint8_t*)type) 6273 + dtohl(type->header.size); 6274 const uint32_t* const eindex = (const uint32_t*) 6275 (((const uint8_t*)type) + dtohs(type->header.headerSize)); 6276 6277 uint32_t thisOffset = dtohl(eindex[entryIndex]); 6278 if (thisOffset == ResTable_type::NO_ENTRY) { 6279 continue; 6280 } 6281 6282 uint32_t resID = (0xff000000 & ((pg->id)<<24)) 6283 | (0x00ff0000 & ((typeIndex+1)<<16)) 6284 | (0x0000ffff & (entryIndex)); 6285 pg->dynamicRefTable.lookupResourceId(&resID); 6286 resource_name resName; 6287 if (this->getResourceName(resID, true, &resName)) { 6288 String8 type8; 6289 String8 name8; 6290 if (resName.type8 != NULL) { 6291 type8 = String8(resName.type8, resName.typeLen); 6292 } else { 6293 type8 = String8(resName.type, resName.typeLen); 6294 } 6295 if (resName.name8 != NULL) { 6296 name8 = String8(resName.name8, resName.nameLen); 6297 } else { 6298 name8 = String8(resName.name, resName.nameLen); 6299 } 6300 printf(" resource 0x%08x %s:%s/%s: ", resID, 6301 CHAR16_TO_CSTR(resName.package, resName.packageLen), 6302 type8.string(), name8.string()); 6303 } else { 6304 printf(" INVALID RESOURCE 0x%08x: ", resID); 6305 } 6306 if ((thisOffset&0x3) != 0) { 6307 printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset); 6308 continue; 6309 } 6310 if ((thisOffset+sizeof(ResTable_entry)) > typeSize) { 6311 printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n", 6312 entriesStart, thisOffset, typeSize); 6313 continue; 6314 } 6315 6316 const ResTable_entry* ent = (const ResTable_entry*) 6317 (((const uint8_t*)type) + entriesStart + thisOffset); 6318 if (((entriesStart + thisOffset)&0x3) != 0) { 6319 printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n", 6320 (entriesStart + thisOffset)); 6321 continue; 6322 } 6323 6324 uintptr_t esize = dtohs(ent->size); 6325 if ((esize&0x3) != 0) { 6326 printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize); 6327 continue; 6328 } 6329 if ((thisOffset+esize) > typeSize) { 6330 printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n", 6331 entriesStart, thisOffset, (void *)esize, typeSize); 6332 continue; 6333 } 6334 6335 const Res_value* valuePtr = NULL; 6336 const ResTable_map_entry* bagPtr = NULL; 6337 Res_value value; 6338 if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) { 6339 printf("<bag>"); 6340 bagPtr = (const ResTable_map_entry*)ent; 6341 } else { 6342 valuePtr = (const Res_value*) 6343 (((const uint8_t*)ent) + esize); 6344 value.copyFrom_dtoh(*valuePtr); 6345 printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)", 6346 (int)value.dataType, (int)value.data, 6347 (int)value.size, (int)value.res0); 6348 } 6349 6350 if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) { 6351 printf(" (PUBLIC)"); 6352 } 6353 printf("\n"); 6354 6355 if (inclValues) { 6356 if (valuePtr != NULL) { 6357 printf(" "); 6358 print_value(typeConfigs->package, value); 6359 } else if (bagPtr != NULL) { 6360 const int N = dtohl(bagPtr->count); 6361 const uint8_t* baseMapPtr = (const uint8_t*)ent; 6362 size_t mapOffset = esize; 6363 const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset); 6364 const uint32_t parent = dtohl(bagPtr->parent.ident); 6365 uint32_t resolvedParent = parent; 6366 status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent); 6367 if (err != NO_ERROR) { 6368 resolvedParent = 0; 6369 } 6370 printf(" Parent=0x%08x(Resolved=0x%08x), Count=%d\n", 6371 parent, resolvedParent, N); 6372 for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) { 6373 printf(" #%i (Key=0x%08x): ", 6374 i, dtohl(mapPtr->name.ident)); 6375 value.copyFrom_dtoh(mapPtr->value); 6376 print_value(typeConfigs->package, value); 6377 const size_t size = dtohs(mapPtr->value.size); 6378 mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value); 6379 mapPtr = (ResTable_map*)(baseMapPtr+mapOffset); 6380 } 6381 } 6382 } 6383 } 6384 } 6385 } 6386 } 6387} 6388 6389} // namespace android 6390