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