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