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