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