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