• 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.  Scaling down
2681                 // is generally better than scaling up.
2682                 int h = thisDensity;
2683                 int l = otherDensity;
2684                 bool bImBigger = true;
2685                 if (l > h) {
2686                     int t = h;
2687                     h = l;
2688                     l = t;
2689                     bImBigger = false;
2690                 }
2691 
2692                 if (requestedDensity >= h) {
2693                     // requested value higher than both l and h, give h
2694                     return bImBigger;
2695                 }
2696                 if (l >= requestedDensity) {
2697                     // requested value lower than both l and h, give l
2698                     return !bImBigger;
2699                 }
2700                 // saying that scaling down is 2x better than up
2701                 if (((2 * l) - requestedDensity) * h > requestedDensity * requestedDensity) {
2702                     return !bImBigger;
2703                 } else {
2704                     return bImBigger;
2705                 }
2706             }
2707 
2708             if ((touchscreen != o.touchscreen) && requested->touchscreen) {
2709                 return (touchscreen);
2710             }
2711         }
2712 
2713         if (input || o.input) {
2714             const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
2715             const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
2716             if (keysHidden != oKeysHidden) {
2717                 const int reqKeysHidden =
2718                         requested->inputFlags & MASK_KEYSHIDDEN;
2719                 if (reqKeysHidden) {
2720 
2721                     if (!keysHidden) return false;
2722                     if (!oKeysHidden) return true;
2723                     // For compatibility, we count KEYSHIDDEN_NO as being
2724                     // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
2725                     // these by making an exact match more specific.
2726                     if (reqKeysHidden == keysHidden) return true;
2727                     if (reqKeysHidden == oKeysHidden) return false;
2728                 }
2729             }
2730 
2731             const int navHidden = inputFlags & MASK_NAVHIDDEN;
2732             const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
2733             if (navHidden != oNavHidden) {
2734                 const int reqNavHidden =
2735                         requested->inputFlags & MASK_NAVHIDDEN;
2736                 if (reqNavHidden) {
2737 
2738                     if (!navHidden) return false;
2739                     if (!oNavHidden) return true;
2740                 }
2741             }
2742 
2743             if ((keyboard != o.keyboard) && requested->keyboard) {
2744                 return (keyboard);
2745             }
2746 
2747             if ((navigation != o.navigation) && requested->navigation) {
2748                 return (navigation);
2749             }
2750         }
2751 
2752         if (screenSize || o.screenSize) {
2753             // "Better" is based on the sum of the difference between both
2754             // width and height from the requested dimensions.  We are
2755             // assuming the invalid configs (with smaller sizes) have
2756             // already been filtered.  Note that if a particular dimension
2757             // is unspecified, we will end up with a large value (the
2758             // difference between 0 and the requested dimension), which is
2759             // good since we will prefer a config that has specified a
2760             // size value.
2761             int myDelta = 0, otherDelta = 0;
2762             if (requested->screenWidth) {
2763                 myDelta += requested->screenWidth - screenWidth;
2764                 otherDelta += requested->screenWidth - o.screenWidth;
2765             }
2766             if (requested->screenHeight) {
2767                 myDelta += requested->screenHeight - screenHeight;
2768                 otherDelta += requested->screenHeight - o.screenHeight;
2769             }
2770             if (myDelta != otherDelta) {
2771                 return myDelta < otherDelta;
2772             }
2773         }
2774 
2775         if (version || o.version) {
2776             if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
2777                 return (sdkVersion > o.sdkVersion);
2778             }
2779 
2780             if ((minorVersion != o.minorVersion) &&
2781                     requested->minorVersion) {
2782                 return (minorVersion);
2783             }
2784         }
2785 
2786         return false;
2787     }
2788     return isMoreSpecificThan(o);
2789 }
2790 
match(const ResTable_config & settings) const2791 bool ResTable_config::match(const ResTable_config& settings) const {
2792     if (imsi != 0) {
2793         if (mcc != 0 && mcc != settings.mcc) {
2794             return false;
2795         }
2796         if (mnc != 0 && mnc != settings.mnc) {
2797             return false;
2798         }
2799     }
2800     if (locale != 0) {
2801         // Don't consider country and variants when deciding matches.
2802         // (Theoretically, the variant can also affect the script. For
2803         // example, "ar-alalc97" probably implies the Latin script, but since
2804         // CLDR doesn't support getting likely scripts for that, we'll assume
2805         // the variant doesn't change the script.)
2806         //
2807         // If two configs differ only in their country and variant,
2808         // they can be weeded out in the isMoreSpecificThan test.
2809         if (!langsAreEquivalent(language, settings.language)) {
2810             return false;
2811         }
2812 
2813         // For backward compatibility and supporting private-use locales, we
2814         // fall back to old behavior if we couldn't determine the script for
2815         // either of the desired locale or the provided locale. But if we could determine
2816         // the scripts, they should be the same for the locales to match.
2817         bool countriesMustMatch = false;
2818         char computed_script[4];
2819         const char* script;
2820         if (settings.localeScript[0] == '\0') { // could not determine the request's script
2821             countriesMustMatch = true;
2822         } else {
2823             if (localeScript[0] == '\0' && !localeScriptWasComputed) {
2824                 // script was not provided or computed, so we try to compute it
2825                 localeDataComputeScript(computed_script, language, country);
2826                 if (computed_script[0] == '\0') { // we could not compute the script
2827                     countriesMustMatch = true;
2828                 } else {
2829                     script = computed_script;
2830                 }
2831             } else { // script was provided, so just use it
2832                 script = localeScript;
2833             }
2834         }
2835 
2836         if (countriesMustMatch) {
2837             if (country[0] != '\0' && !areIdentical(country, settings.country)) {
2838                 return false;
2839             }
2840         } else {
2841             if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
2842                 return false;
2843             }
2844         }
2845     }
2846 
2847     if (screenConfig != 0) {
2848         const int layoutDir = screenLayout&MASK_LAYOUTDIR;
2849         const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR;
2850         if (layoutDir != 0 && layoutDir != setLayoutDir) {
2851             return false;
2852         }
2853 
2854         const int screenSize = screenLayout&MASK_SCREENSIZE;
2855         const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
2856         // Any screen sizes for larger screens than the setting do not
2857         // match.
2858         if (screenSize != 0 && screenSize > setScreenSize) {
2859             return false;
2860         }
2861 
2862         const int screenLong = screenLayout&MASK_SCREENLONG;
2863         const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
2864         if (screenLong != 0 && screenLong != setScreenLong) {
2865             return false;
2866         }
2867 
2868         const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
2869         const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
2870         if (uiModeType != 0 && uiModeType != setUiModeType) {
2871             return false;
2872         }
2873 
2874         const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
2875         const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
2876         if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
2877             return false;
2878         }
2879 
2880         if (smallestScreenWidthDp != 0
2881                 && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
2882             return false;
2883         }
2884     }
2885 
2886     if (screenConfig2 != 0) {
2887         const int screenRound = screenLayout2 & MASK_SCREENROUND;
2888         const int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND;
2889         if (screenRound != 0 && screenRound != setScreenRound) {
2890             return false;
2891         }
2892 
2893         const int hdr = colorMode & MASK_HDR;
2894         const int setHdr = settings.colorMode & MASK_HDR;
2895         if (hdr != 0 && hdr != setHdr) {
2896             return false;
2897         }
2898 
2899         const int wideColorGamut = colorMode & MASK_WIDE_COLOR_GAMUT;
2900         const int setWideColorGamut = settings.colorMode & MASK_WIDE_COLOR_GAMUT;
2901         if (wideColorGamut != 0 && wideColorGamut != setWideColorGamut) {
2902             return false;
2903         }
2904     }
2905 
2906     if (screenSizeDp != 0) {
2907         if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
2908             if (kDebugTableSuperNoisy) {
2909                 ALOGI("Filtering out width %d in requested %d", screenWidthDp,
2910                         settings.screenWidthDp);
2911             }
2912             return false;
2913         }
2914         if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
2915             if (kDebugTableSuperNoisy) {
2916                 ALOGI("Filtering out height %d in requested %d", screenHeightDp,
2917                         settings.screenHeightDp);
2918             }
2919             return false;
2920         }
2921     }
2922     if (screenType != 0) {
2923         if (orientation != 0 && orientation != settings.orientation) {
2924             return false;
2925         }
2926         // density always matches - we can scale it.  See isBetterThan
2927         if (touchscreen != 0 && touchscreen != settings.touchscreen) {
2928             return false;
2929         }
2930     }
2931     if (input != 0) {
2932         const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
2933         const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
2934         if (keysHidden != 0 && keysHidden != setKeysHidden) {
2935             // For compatibility, we count a request for KEYSHIDDEN_NO as also
2936             // matching the more recent KEYSHIDDEN_SOFT.  Basically
2937             // KEYSHIDDEN_NO means there is some kind of keyboard available.
2938             if (kDebugTableSuperNoisy) {
2939                 ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
2940             }
2941             if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
2942                 if (kDebugTableSuperNoisy) {
2943                     ALOGI("No match!");
2944                 }
2945                 return false;
2946             }
2947         }
2948         const int navHidden = inputFlags&MASK_NAVHIDDEN;
2949         const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
2950         if (navHidden != 0 && navHidden != setNavHidden) {
2951             return false;
2952         }
2953         if (keyboard != 0 && keyboard != settings.keyboard) {
2954             return false;
2955         }
2956         if (navigation != 0 && navigation != settings.navigation) {
2957             return false;
2958         }
2959     }
2960     if (screenSize != 0) {
2961         if (screenWidth != 0 && screenWidth > settings.screenWidth) {
2962             return false;
2963         }
2964         if (screenHeight != 0 && screenHeight > settings.screenHeight) {
2965             return false;
2966         }
2967     }
2968     if (version != 0) {
2969         if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
2970             return false;
2971         }
2972         if (minorVersion != 0 && minorVersion != settings.minorVersion) {
2973             return false;
2974         }
2975     }
2976     return true;
2977 }
2978 
appendDirLocale(String8 & out) const2979 void ResTable_config::appendDirLocale(String8& out) const {
2980     if (!language[0]) {
2981         return;
2982     }
2983     const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
2984     if (!scriptWasProvided && !localeVariant[0] && !localeNumberingSystem[0]) {
2985         // Legacy format.
2986         if (out.size() > 0) {
2987             out.append("-");
2988         }
2989 
2990         char buf[4];
2991         size_t len = unpackLanguage(buf);
2992         out.append(buf, len);
2993 
2994         if (country[0]) {
2995             out.append("-r");
2996             len = unpackRegion(buf);
2997             out.append(buf, len);
2998         }
2999         return;
3000     }
3001 
3002     // We are writing the modified BCP 47 tag.
3003     // It starts with 'b+' and uses '+' as a separator.
3004 
3005     if (out.size() > 0) {
3006         out.append("-");
3007     }
3008     out.append("b+");
3009 
3010     char buf[4];
3011     size_t len = unpackLanguage(buf);
3012     out.append(buf, len);
3013 
3014     if (scriptWasProvided) {
3015         out.append("+");
3016         out.append(localeScript, sizeof(localeScript));
3017     }
3018 
3019     if (country[0]) {
3020         out.append("+");
3021         len = unpackRegion(buf);
3022         out.append(buf, len);
3023     }
3024 
3025     if (localeVariant[0]) {
3026         out.append("+");
3027         out.append(localeVariant, strnlen(localeVariant, sizeof(localeVariant)));
3028     }
3029 
3030     if (localeNumberingSystem[0]) {
3031         out.append("+u+nu+");
3032         out.append(localeNumberingSystem,
3033                    strnlen(localeNumberingSystem, sizeof(localeNumberingSystem)));
3034     }
3035 }
3036 
getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN],bool canonicalize) const3037 void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool canonicalize) const {
3038     memset(str, 0, RESTABLE_MAX_LOCALE_LEN);
3039 
3040     // This represents the "any" locale value, which has traditionally been
3041     // represented by the empty string.
3042     if (language[0] == '\0' && country[0] == '\0') {
3043         return;
3044     }
3045 
3046     size_t charsWritten = 0;
3047     if (language[0] != '\0') {
3048         if (canonicalize && areIdentical(language, kTagalog)) {
3049             // Replace Tagalog with Filipino if we are canonicalizing
3050             str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = '\0';  // 3-letter code for Filipino
3051             charsWritten += 3;
3052         } else {
3053             charsWritten += unpackLanguage(str);
3054         }
3055     }
3056 
3057     if (localeScript[0] != '\0' && !localeScriptWasComputed) {
3058         if (charsWritten > 0) {
3059             str[charsWritten++] = '-';
3060         }
3061         memcpy(str + charsWritten, localeScript, sizeof(localeScript));
3062         charsWritten += sizeof(localeScript);
3063     }
3064 
3065     if (country[0] != '\0') {
3066         if (charsWritten > 0) {
3067             str[charsWritten++] = '-';
3068         }
3069         charsWritten += unpackRegion(str + charsWritten);
3070     }
3071 
3072     if (localeVariant[0] != '\0') {
3073         if (charsWritten > 0) {
3074             str[charsWritten++] = '-';
3075         }
3076         memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
3077         charsWritten += strnlen(str + charsWritten, sizeof(localeVariant));
3078     }
3079 
3080     // Add Unicode extension only if at least one other locale component is present
3081     if (localeNumberingSystem[0] != '\0' && charsWritten > 0) {
3082         static constexpr char NU_PREFIX[] = "-u-nu-";
3083         static constexpr size_t NU_PREFIX_LEN = sizeof(NU_PREFIX) - 1;
3084         memcpy(str + charsWritten, NU_PREFIX, NU_PREFIX_LEN);
3085         charsWritten += NU_PREFIX_LEN;
3086         memcpy(str + charsWritten, localeNumberingSystem, sizeof(localeNumberingSystem));
3087     }
3088 }
3089 
3090 struct LocaleParserState {
3091     enum State : uint8_t {
3092         BASE, UNICODE_EXTENSION, IGNORE_THE_REST
3093     } parserState;
3094     enum UnicodeState : uint8_t {
3095         /* Initial state after the Unicode singleton is detected. Either a keyword
3096          * or an attribute is expected. */
3097         NO_KEY,
3098         /* Unicode extension key (but not attribute) is expected. Next states:
3099          * NO_KEY, IGNORE_KEY or NUMBERING_SYSTEM. */
3100         EXPECT_KEY,
3101         /* A key is detected, however it is not supported for now. Ignore its
3102          * value. Next states: IGNORE_KEY or NUMBERING_SYSTEM. */
3103         IGNORE_KEY,
3104         /* Numbering system key was detected. Store its value in the configuration
3105          * localeNumberingSystem field. Next state: EXPECT_KEY */
3106         NUMBERING_SYSTEM
3107     } unicodeState;
3108 
LocaleParserStateandroid::LocaleParserState3109     LocaleParserState(): parserState(BASE), unicodeState(NO_KEY) {}
3110 };
3111 
assignLocaleComponent(ResTable_config * config,const char * start,size_t size,LocaleParserState state)3112 /* static */ inline LocaleParserState assignLocaleComponent(ResTable_config* config,
3113         const char* start, size_t size, LocaleParserState state) {
3114 
3115     /* It is assumed that this function is not invoked with state.parserState
3116      * set to IGNORE_THE_REST. The condition is checked by setBcp47Locale
3117      * function. */
3118 
3119     if (state.parserState == LocaleParserState::UNICODE_EXTENSION) {
3120         switch (size) {
3121             case 1:
3122                 /* Other BCP 47 extensions are not supported at the moment */
3123                 state.parserState = LocaleParserState::IGNORE_THE_REST;
3124                 break;
3125             case 2:
3126                 if (state.unicodeState == LocaleParserState::NO_KEY ||
3127                     state.unicodeState == LocaleParserState::EXPECT_KEY) {
3128                     /* Analyze Unicode extension key. Currently only 'nu'
3129                      * (numbering system) is supported.*/
3130                     if ((start[0] == 'n' || start[0] == 'N') &&
3131                         (start[1] == 'u' || start[1] == 'U')) {
3132                         state.unicodeState = LocaleParserState::NUMBERING_SYSTEM;
3133                     } else {
3134                         state.unicodeState = LocaleParserState::IGNORE_KEY;
3135                     }
3136                 } else {
3137                     /* Keys are not allowed in other state allowed, ignore the rest. */
3138                     state.parserState = LocaleParserState::IGNORE_THE_REST;
3139                 }
3140                 break;
3141             case 3:
3142             case 4:
3143             case 5:
3144             case 6:
3145             case 7:
3146             case 8:
3147                 switch (state.unicodeState) {
3148                     case LocaleParserState::NUMBERING_SYSTEM:
3149                         /* Accept only the first occurrence of the numbering system. */
3150                         if (config->localeNumberingSystem[0] == '\0') {
3151                             for (size_t i = 0; i < size; ++i) {
3152                                config->localeNumberingSystem[i] = tolower(start[i]);
3153                             }
3154                             state.unicodeState = LocaleParserState::EXPECT_KEY;
3155                         } else {
3156                             state.parserState = LocaleParserState::IGNORE_THE_REST;
3157                         }
3158                         break;
3159                     case LocaleParserState::IGNORE_KEY:
3160                         /* Unsupported Unicode keyword. Ignore. */
3161                         state.unicodeState = LocaleParserState::EXPECT_KEY;
3162                         break;
3163                     case LocaleParserState::EXPECT_KEY:
3164                         /* A keyword followed by an attribute is not allowed. */
3165                         state.parserState = LocaleParserState::IGNORE_THE_REST;
3166                         break;
3167                     case LocaleParserState::NO_KEY:
3168                         /* Extension attribute. Do nothing. */
3169                         break;
3170                     default:
3171                         break;
3172                 }
3173                 break;
3174             default:
3175                 /* Unexpected field length - ignore the rest and treat as an error */
3176                 state.parserState = LocaleParserState::IGNORE_THE_REST;
3177         }
3178         return state;
3179     }
3180 
3181   switch (size) {
3182        case 0:
3183            state.parserState = LocaleParserState::IGNORE_THE_REST;
3184            break;
3185        case 1:
3186            state.parserState = (start[0] == 'u' || start[0] == 'U')
3187                    ? LocaleParserState::UNICODE_EXTENSION
3188                    : LocaleParserState::IGNORE_THE_REST;
3189            break;
3190        case 2:
3191        case 3:
3192            config->language[0] ? config->packRegion(start) : config->packLanguage(start);
3193            break;
3194        case 4:
3195            if ('0' <= start[0] && start[0] <= '9') {
3196                // this is a variant, so fall through
3197            } else {
3198                config->localeScript[0] = toupper(start[0]);
3199                for (size_t i = 1; i < 4; ++i) {
3200                    config->localeScript[i] = tolower(start[i]);
3201                }
3202                break;
3203            }
3204            FALLTHROUGH_INTENDED;
3205        case 5:
3206        case 6:
3207        case 7:
3208        case 8:
3209            for (size_t i = 0; i < size; ++i) {
3210                config->localeVariant[i] = tolower(start[i]);
3211            }
3212            break;
3213        default:
3214            state.parserState = LocaleParserState::IGNORE_THE_REST;
3215   }
3216 
3217   return state;
3218 }
3219 
setBcp47Locale(const char * in)3220 void ResTable_config::setBcp47Locale(const char* in) {
3221     clearLocale();
3222 
3223     const char* start = in;
3224     LocaleParserState state;
3225     while (const char* separator = strchr(start, '-')) {
3226         const size_t size = separator - start;
3227         state = assignLocaleComponent(this, start, size, state);
3228         if (state.parserState == LocaleParserState::IGNORE_THE_REST) {
3229             fprintf(stderr, "Invalid BCP-47 locale string: %s\n", in);
3230             break;
3231         }
3232         start = (separator + 1);
3233     }
3234 
3235     if (state.parserState != LocaleParserState::IGNORE_THE_REST) {
3236         const size_t size = strlen(start);
3237         assignLocaleComponent(this, start, size, state);
3238     }
3239 
3240     localeScriptWasComputed = (localeScript[0] == '\0');
3241     if (localeScriptWasComputed) {
3242         computeScript();
3243     }
3244 }
3245 
toString() const3246 String8 ResTable_config::toString() const {
3247     String8 res;
3248 
3249     if (mcc != 0) {
3250         if (res.size() > 0) res.append("-");
3251         res.appendFormat("mcc%d", dtohs(mcc));
3252     }
3253     if (mnc != 0) {
3254         if (res.size() > 0) res.append("-");
3255         res.appendFormat("mnc%d", dtohs(mnc));
3256     }
3257 
3258     appendDirLocale(res);
3259 
3260     if ((screenLayout&MASK_LAYOUTDIR) != 0) {
3261         if (res.size() > 0) res.append("-");
3262         switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
3263             case ResTable_config::LAYOUTDIR_LTR:
3264                 res.append("ldltr");
3265                 break;
3266             case ResTable_config::LAYOUTDIR_RTL:
3267                 res.append("ldrtl");
3268                 break;
3269             default:
3270                 res.appendFormat("layoutDir=%d",
3271                         dtohs(screenLayout&ResTable_config::MASK_LAYOUTDIR));
3272                 break;
3273         }
3274     }
3275     if (smallestScreenWidthDp != 0) {
3276         if (res.size() > 0) res.append("-");
3277         res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
3278     }
3279     if (screenWidthDp != 0) {
3280         if (res.size() > 0) res.append("-");
3281         res.appendFormat("w%ddp", dtohs(screenWidthDp));
3282     }
3283     if (screenHeightDp != 0) {
3284         if (res.size() > 0) res.append("-");
3285         res.appendFormat("h%ddp", dtohs(screenHeightDp));
3286     }
3287     if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) {
3288         if (res.size() > 0) res.append("-");
3289         switch (screenLayout&ResTable_config::MASK_SCREENSIZE) {
3290             case ResTable_config::SCREENSIZE_SMALL:
3291                 res.append("small");
3292                 break;
3293             case ResTable_config::SCREENSIZE_NORMAL:
3294                 res.append("normal");
3295                 break;
3296             case ResTable_config::SCREENSIZE_LARGE:
3297                 res.append("large");
3298                 break;
3299             case ResTable_config::SCREENSIZE_XLARGE:
3300                 res.append("xlarge");
3301                 break;
3302             default:
3303                 res.appendFormat("screenLayoutSize=%d",
3304                         dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE));
3305                 break;
3306         }
3307     }
3308     if ((screenLayout&MASK_SCREENLONG) != 0) {
3309         if (res.size() > 0) res.append("-");
3310         switch (screenLayout&ResTable_config::MASK_SCREENLONG) {
3311             case ResTable_config::SCREENLONG_NO:
3312                 res.append("notlong");
3313                 break;
3314             case ResTable_config::SCREENLONG_YES:
3315                 res.append("long");
3316                 break;
3317             default:
3318                 res.appendFormat("screenLayoutLong=%d",
3319                         dtohs(screenLayout&ResTable_config::MASK_SCREENLONG));
3320                 break;
3321         }
3322     }
3323     if ((screenLayout2&MASK_SCREENROUND) != 0) {
3324         if (res.size() > 0) res.append("-");
3325         switch (screenLayout2&MASK_SCREENROUND) {
3326             case SCREENROUND_NO:
3327                 res.append("notround");
3328                 break;
3329             case SCREENROUND_YES:
3330                 res.append("round");
3331                 break;
3332             default:
3333                 res.appendFormat("screenRound=%d", dtohs(screenLayout2&MASK_SCREENROUND));
3334                 break;
3335         }
3336     }
3337     if ((colorMode&MASK_WIDE_COLOR_GAMUT) != 0) {
3338         if (res.size() > 0) res.append("-");
3339         switch (colorMode&MASK_WIDE_COLOR_GAMUT) {
3340             case ResTable_config::WIDE_COLOR_GAMUT_NO:
3341                 res.append("nowidecg");
3342                 break;
3343             case ResTable_config::WIDE_COLOR_GAMUT_YES:
3344                 res.append("widecg");
3345                 break;
3346             default:
3347                 res.appendFormat("wideColorGamut=%d", dtohs(colorMode&MASK_WIDE_COLOR_GAMUT));
3348                 break;
3349         }
3350     }
3351     if ((colorMode&MASK_HDR) != 0) {
3352         if (res.size() > 0) res.append("-");
3353         switch (colorMode&MASK_HDR) {
3354             case ResTable_config::HDR_NO:
3355                 res.append("lowdr");
3356                 break;
3357             case ResTable_config::HDR_YES:
3358                 res.append("highdr");
3359                 break;
3360             default:
3361                 res.appendFormat("hdr=%d", dtohs(colorMode&MASK_HDR));
3362                 break;
3363         }
3364     }
3365     if (orientation != ORIENTATION_ANY) {
3366         if (res.size() > 0) res.append("-");
3367         switch (orientation) {
3368             case ResTable_config::ORIENTATION_PORT:
3369                 res.append("port");
3370                 break;
3371             case ResTable_config::ORIENTATION_LAND:
3372                 res.append("land");
3373                 break;
3374             case ResTable_config::ORIENTATION_SQUARE:
3375                 res.append("square");
3376                 break;
3377             default:
3378                 res.appendFormat("orientation=%d", dtohs(orientation));
3379                 break;
3380         }
3381     }
3382     if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) {
3383         if (res.size() > 0) res.append("-");
3384         switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
3385             case ResTable_config::UI_MODE_TYPE_DESK:
3386                 res.append("desk");
3387                 break;
3388             case ResTable_config::UI_MODE_TYPE_CAR:
3389                 res.append("car");
3390                 break;
3391             case ResTable_config::UI_MODE_TYPE_TELEVISION:
3392                 res.append("television");
3393                 break;
3394             case ResTable_config::UI_MODE_TYPE_APPLIANCE:
3395                 res.append("appliance");
3396                 break;
3397             case ResTable_config::UI_MODE_TYPE_WATCH:
3398                 res.append("watch");
3399                 break;
3400             case ResTable_config::UI_MODE_TYPE_VR_HEADSET:
3401                 res.append("vrheadset");
3402                 break;
3403             default:
3404                 res.appendFormat("uiModeType=%d",
3405                         dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
3406                 break;
3407         }
3408     }
3409     if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
3410         if (res.size() > 0) res.append("-");
3411         switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
3412             case ResTable_config::UI_MODE_NIGHT_NO:
3413                 res.append("notnight");
3414                 break;
3415             case ResTable_config::UI_MODE_NIGHT_YES:
3416                 res.append("night");
3417                 break;
3418             default:
3419                 res.appendFormat("uiModeNight=%d",
3420                         dtohs(uiMode&MASK_UI_MODE_NIGHT));
3421                 break;
3422         }
3423     }
3424     if (density != DENSITY_DEFAULT) {
3425         if (res.size() > 0) res.append("-");
3426         switch (density) {
3427             case ResTable_config::DENSITY_LOW:
3428                 res.append("ldpi");
3429                 break;
3430             case ResTable_config::DENSITY_MEDIUM:
3431                 res.append("mdpi");
3432                 break;
3433             case ResTable_config::DENSITY_TV:
3434                 res.append("tvdpi");
3435                 break;
3436             case ResTable_config::DENSITY_HIGH:
3437                 res.append("hdpi");
3438                 break;
3439             case ResTable_config::DENSITY_XHIGH:
3440                 res.append("xhdpi");
3441                 break;
3442             case ResTable_config::DENSITY_XXHIGH:
3443                 res.append("xxhdpi");
3444                 break;
3445             case ResTable_config::DENSITY_XXXHIGH:
3446                 res.append("xxxhdpi");
3447                 break;
3448             case ResTable_config::DENSITY_NONE:
3449                 res.append("nodpi");
3450                 break;
3451             case ResTable_config::DENSITY_ANY:
3452                 res.append("anydpi");
3453                 break;
3454             default:
3455                 res.appendFormat("%ddpi", dtohs(density));
3456                 break;
3457         }
3458     }
3459     if (touchscreen != TOUCHSCREEN_ANY) {
3460         if (res.size() > 0) res.append("-");
3461         switch (touchscreen) {
3462             case ResTable_config::TOUCHSCREEN_NOTOUCH:
3463                 res.append("notouch");
3464                 break;
3465             case ResTable_config::TOUCHSCREEN_FINGER:
3466                 res.append("finger");
3467                 break;
3468             case ResTable_config::TOUCHSCREEN_STYLUS:
3469                 res.append("stylus");
3470                 break;
3471             default:
3472                 res.appendFormat("touchscreen=%d", dtohs(touchscreen));
3473                 break;
3474         }
3475     }
3476     if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
3477         if (res.size() > 0) res.append("-");
3478         switch (inputFlags&MASK_KEYSHIDDEN) {
3479             case ResTable_config::KEYSHIDDEN_NO:
3480                 res.append("keysexposed");
3481                 break;
3482             case ResTable_config::KEYSHIDDEN_YES:
3483                 res.append("keyshidden");
3484                 break;
3485             case ResTable_config::KEYSHIDDEN_SOFT:
3486                 res.append("keyssoft");
3487                 break;
3488         }
3489     }
3490     if (keyboard != KEYBOARD_ANY) {
3491         if (res.size() > 0) res.append("-");
3492         switch (keyboard) {
3493             case ResTable_config::KEYBOARD_NOKEYS:
3494                 res.append("nokeys");
3495                 break;
3496             case ResTable_config::KEYBOARD_QWERTY:
3497                 res.append("qwerty");
3498                 break;
3499             case ResTable_config::KEYBOARD_12KEY:
3500                 res.append("12key");
3501                 break;
3502             default:
3503                 res.appendFormat("keyboard=%d", dtohs(keyboard));
3504                 break;
3505         }
3506     }
3507     if ((inputFlags&MASK_NAVHIDDEN) != 0) {
3508         if (res.size() > 0) res.append("-");
3509         switch (inputFlags&MASK_NAVHIDDEN) {
3510             case ResTable_config::NAVHIDDEN_NO:
3511                 res.append("navexposed");
3512                 break;
3513             case ResTable_config::NAVHIDDEN_YES:
3514                 res.append("navhidden");
3515                 break;
3516             default:
3517                 res.appendFormat("inputFlagsNavHidden=%d",
3518                         dtohs(inputFlags&MASK_NAVHIDDEN));
3519                 break;
3520         }
3521     }
3522     if (navigation != NAVIGATION_ANY) {
3523         if (res.size() > 0) res.append("-");
3524         switch (navigation) {
3525             case ResTable_config::NAVIGATION_NONAV:
3526                 res.append("nonav");
3527                 break;
3528             case ResTable_config::NAVIGATION_DPAD:
3529                 res.append("dpad");
3530                 break;
3531             case ResTable_config::NAVIGATION_TRACKBALL:
3532                 res.append("trackball");
3533                 break;
3534             case ResTable_config::NAVIGATION_WHEEL:
3535                 res.append("wheel");
3536                 break;
3537             default:
3538                 res.appendFormat("navigation=%d", dtohs(navigation));
3539                 break;
3540         }
3541     }
3542     if (screenSize != 0) {
3543         if (res.size() > 0) res.append("-");
3544         res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
3545     }
3546     if (version != 0) {
3547         if (res.size() > 0) res.append("-");
3548         res.appendFormat("v%d", dtohs(sdkVersion));
3549         if (minorVersion != 0) {
3550             res.appendFormat(".%d", dtohs(minorVersion));
3551         }
3552     }
3553 
3554     return res;
3555 }
3556 
3557 // --------------------------------------------------------------------
3558 // --------------------------------------------------------------------
3559 // --------------------------------------------------------------------
3560 
3561 struct ResTable::Header
3562 {
Headerandroid::ResTable::Header3563     explicit Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
3564         resourceIDMap(NULL), resourceIDMapSize(0) { }
3565 
~Headerandroid::ResTable::Header3566     ~Header()
3567     {
3568         free(resourceIDMap);
3569     }
3570 
3571     const ResTable* const           owner;
3572     void*                           ownedData;
3573     const ResTable_header*          header;
3574     size_t                          size;
3575     const uint8_t*                  dataEnd;
3576     size_t                          index;
3577     int32_t                         cookie;
3578 
3579     ResStringPool                   values;
3580     uint32_t*                       resourceIDMap;
3581     size_t                          resourceIDMapSize;
3582 };
3583 
3584 struct ResTable::Entry {
3585     ResTable_config config;
3586     const ResTable_entry* entry;
3587     const ResTable_type* type;
3588     uint32_t specFlags;
3589     const Package* package;
3590 
3591     StringPoolRef typeStr;
3592     StringPoolRef keyStr;
3593 };
3594 
3595 struct ResTable::Type
3596 {
Typeandroid::ResTable::Type3597     Type(const Header* _header, const Package* _package, size_t count)
3598         : header(_header), package(_package), entryCount(count),
3599           typeSpec(NULL), typeSpecFlags(NULL) { }
3600     const Header* const             header;
3601     const Package* const            package;
3602     const size_t                    entryCount;
3603     const ResTable_typeSpec*        typeSpec;
3604     const uint32_t*                 typeSpecFlags;
3605     IdmapEntries                    idmapEntries;
3606     Vector<const ResTable_type*>    configs;
3607 };
3608 
3609 struct ResTable::Package
3610 {
Packageandroid::ResTable::Package3611     Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
3612         : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
3613         if (dtohs(package->header.headerSize) == sizeof(*package)) {
3614             // The package structure is the same size as the definition.
3615             // This means it contains the typeIdOffset field.
3616             typeIdOffset = package->typeIdOffset;
3617         }
3618     }
3619 
3620     const ResTable* const           owner;
3621     const Header* const             header;
3622     const ResTable_package* const   package;
3623 
3624     ResStringPool                   typeStrings;
3625     ResStringPool                   keyStrings;
3626 
3627     size_t                          typeIdOffset;
3628     bool                            definesOverlayable = false;
3629 };
3630 
3631 // A group of objects describing a particular resource package.
3632 // The first in 'package' is always the root object (from the resource
3633 // table that defined the package); the ones after are skins on top of it.
3634 struct ResTable::PackageGroup
3635 {
PackageGroupandroid::ResTable::PackageGroup3636     PackageGroup(
3637             ResTable* _owner, const String16& _name, uint32_t _id,
3638             bool appAsLib, bool _isSystemAsset, bool _isDynamic)
3639         : owner(_owner)
3640         , name(_name)
3641         , id(_id)
3642         , largestTypeId(0)
3643         , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
3644         , isSystemAsset(_isSystemAsset)
3645         , isDynamic(_isDynamic)
3646     { }
3647 
~PackageGroupandroid::ResTable::PackageGroup3648     ~PackageGroup() {
3649         clearBagCache();
3650         const size_t numTypes = types.size();
3651         for (size_t i = 0; i < numTypes; i++) {
3652             TypeList& typeList = types.editItemAt(i);
3653             const size_t numInnerTypes = typeList.size();
3654             for (size_t j = 0; j < numInnerTypes; j++) {
3655                 if (typeList[j]->package->owner == owner) {
3656                     delete typeList[j];
3657                 }
3658             }
3659             typeList.clear();
3660         }
3661 
3662         const size_t N = packages.size();
3663         for (size_t i=0; i<N; i++) {
3664             Package* pkg = packages[i];
3665             if (pkg->owner == owner) {
3666                 delete pkg;
3667             }
3668         }
3669     }
3670 
3671     /**
3672      * Clear all cache related data that depends on parameters/configuration.
3673      * This includes the bag caches and filtered types.
3674      */
clearBagCacheandroid::ResTable::PackageGroup3675     void clearBagCache() {
3676         for (size_t i = 0; i < typeCacheEntries.size(); i++) {
3677             if (kDebugTableNoisy) {
3678                 printf("type=%zu\n", i);
3679             }
3680             const TypeList& typeList = types[i];
3681             if (!typeList.isEmpty()) {
3682                 TypeCacheEntry& cacheEntry = typeCacheEntries.editItemAt(i);
3683 
3684                 // Reset the filtered configurations.
3685                 cacheEntry.filteredConfigs.clear();
3686 
3687                 bag_set** typeBags = cacheEntry.cachedBags;
3688                 if (kDebugTableNoisy) {
3689                     printf("typeBags=%p\n", typeBags);
3690                 }
3691 
3692                 if (typeBags) {
3693                     const size_t N = typeList[0]->entryCount;
3694                     if (kDebugTableNoisy) {
3695                         printf("type->entryCount=%zu\n", N);
3696                     }
3697                     for (size_t j = 0; j < N; j++) {
3698                         if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) {
3699                             free(typeBags[j]);
3700                         }
3701                     }
3702                     free(typeBags);
3703                     cacheEntry.cachedBags = NULL;
3704                 }
3705             }
3706         }
3707     }
3708 
findType16android::ResTable::PackageGroup3709     ssize_t findType16(const char16_t* type, size_t len) const {
3710         const size_t N = packages.size();
3711         for (size_t i = 0; i < N; i++) {
3712             const base::expected<size_t, NullOrIOError> index =
3713                 packages[i]->typeStrings.indexOfString(type, len);
3714             if (index.has_value()) {
3715                 return *index + packages[i]->typeIdOffset;
3716             }
3717         }
3718         return -1;
3719     }
3720 
3721     const ResTable* const           owner;
3722     String16 const                  name;
3723     uint32_t const                  id;
3724 
3725     // This is mainly used to keep track of the loaded packages
3726     // and to clean them up properly. Accessing resources happens from
3727     // the 'types' array.
3728     Vector<Package*>                packages;
3729 
3730     ByteBucketArray<TypeList>       types;
3731 
3732     uint8_t                         largestTypeId;
3733 
3734     // Cached objects dependent on the parameters/configuration of this ResTable.
3735     // Gets cleared whenever the parameters/configuration changes.
3736     // These are stored here in a parallel structure because the data in `types` may
3737     // be shared by other ResTable's (framework resources are shared this way).
3738     ByteBucketArray<TypeCacheEntry> typeCacheEntries;
3739 
3740     // The table mapping dynamic references to resolved references for
3741     // this package group.
3742     // TODO: We may be able to support dynamic references in overlays
3743     // by having these tables in a per-package scope rather than
3744     // per-package-group.
3745     DynamicRefTable                 dynamicRefTable;
3746 
3747     // If the package group comes from a system asset. Used in
3748     // determining non-system locales.
3749     const bool                      isSystemAsset;
3750     const bool isDynamic;
3751 };
3752 
Theme(const ResTable & table)3753 ResTable::Theme::Theme(const ResTable& table)
3754     : mTable(table)
3755     , mTypeSpecFlags(0)
3756 {
3757     memset(mPackages, 0, sizeof(mPackages));
3758 }
3759 
~Theme()3760 ResTable::Theme::~Theme()
3761 {
3762     for (size_t i=0; i<Res_MAXPACKAGE; i++) {
3763         package_info* pi = mPackages[i];
3764         if (pi != NULL) {
3765             free_package(pi);
3766         }
3767     }
3768 }
3769 
free_package(package_info * pi)3770 void ResTable::Theme::free_package(package_info* pi)
3771 {
3772     for (size_t j = 0; j <= Res_MAXTYPE; j++) {
3773         theme_entry* te = pi->types[j].entries;
3774         if (te != NULL) {
3775             free(te);
3776         }
3777     }
3778     free(pi);
3779 }
3780 
copy_package(package_info * pi)3781 ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
3782 {
3783     package_info* newpi = (package_info*)malloc(sizeof(package_info));
3784     for (size_t j = 0; j <= Res_MAXTYPE; j++) {
3785         size_t cnt = pi->types[j].numEntries;
3786         newpi->types[j].numEntries = cnt;
3787         theme_entry* te = pi->types[j].entries;
3788         size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
3789         if (te != NULL && (cnt < 0xFFFFFFFF-1) && (cnt < cnt_max)) {
3790             theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
3791             newpi->types[j].entries = newte;
3792             memcpy(newte, te, cnt*sizeof(theme_entry));
3793         } else {
3794             newpi->types[j].entries = NULL;
3795         }
3796     }
3797     return newpi;
3798 }
3799 
applyStyle(uint32_t resID,bool force)3800 status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
3801 {
3802     const bag_entry* bag;
3803     uint32_t bagTypeSpecFlags = 0;
3804     mTable.lock();
3805     const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
3806     if (kDebugTableNoisy) {
3807         ALOGV("Applying style 0x%08x to theme %p, count=%zu", resID, this, N);
3808     }
3809     if (N < 0) {
3810         mTable.unlock();
3811         return N;
3812     }
3813 
3814     mTypeSpecFlags |= bagTypeSpecFlags;
3815 
3816     uint32_t curPackage = 0xffffffff;
3817     ssize_t curPackageIndex = 0;
3818     package_info* curPI = NULL;
3819     uint32_t curType = 0xffffffff;
3820     size_t numEntries = 0;
3821     theme_entry* curEntries = NULL;
3822 
3823     const bag_entry* end = bag + N;
3824     while (bag < end) {
3825         const uint32_t attrRes = bag->map.name.ident;
3826         const uint32_t p = Res_GETPACKAGE(attrRes);
3827         const uint32_t t = Res_GETTYPE(attrRes);
3828         const uint32_t e = Res_GETENTRY(attrRes);
3829 
3830         if (curPackage != p) {
3831             const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
3832             if (pidx < 0) {
3833                 ALOGE("Style contains key with bad package: 0x%08x\n", attrRes);
3834                 bag++;
3835                 continue;
3836             }
3837             curPackage = p;
3838             curPackageIndex = pidx;
3839             curPI = mPackages[pidx];
3840             if (curPI == NULL) {
3841                 curPI = (package_info*)malloc(sizeof(package_info));
3842                 memset(curPI, 0, sizeof(*curPI));
3843                 mPackages[pidx] = curPI;
3844             }
3845             curType = 0xffffffff;
3846         }
3847         if (curType != t) {
3848             if (t > Res_MAXTYPE) {
3849                 ALOGE("Style contains key with bad type: 0x%08x\n", attrRes);
3850                 bag++;
3851                 continue;
3852             }
3853             curType = t;
3854             curEntries = curPI->types[t].entries;
3855             if (curEntries == NULL) {
3856                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
3857                 const TypeList& typeList = grp->types[t];
3858                 size_t cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
3859                 size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
3860                 size_t buff_size = (cnt < cnt_max && cnt < 0xFFFFFFFF-1) ?
3861                                           cnt*sizeof(theme_entry) : 0;
3862                 curEntries = (theme_entry*)malloc(buff_size);
3863                 memset(curEntries, Res_value::TYPE_NULL, buff_size);
3864                 curPI->types[t].numEntries = cnt;
3865                 curPI->types[t].entries = curEntries;
3866             }
3867             numEntries = curPI->types[t].numEntries;
3868         }
3869         if (e >= numEntries) {
3870             ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
3871             bag++;
3872             continue;
3873         }
3874         theme_entry* curEntry = curEntries + e;
3875         if (kDebugTableNoisy) {
3876             ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
3877                     attrRes, bag->map.value.dataType, bag->map.value.data,
3878                     curEntry->value.dataType);
3879         }
3880         if (force || (curEntry->value.dataType == Res_value::TYPE_NULL
3881                 && curEntry->value.data != Res_value::DATA_NULL_EMPTY)) {
3882             curEntry->stringBlock = bag->stringBlock;
3883             curEntry->typeSpecFlags |= bagTypeSpecFlags;
3884             curEntry->value = bag->map.value;
3885         }
3886 
3887         bag++;
3888     }
3889 
3890     mTable.unlock();
3891 
3892     if (kDebugTableTheme) {
3893         ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
3894         dumpToLog();
3895     }
3896 
3897     return NO_ERROR;
3898 }
3899 
setTo(const Theme & other)3900 status_t ResTable::Theme::setTo(const Theme& other)
3901 {
3902     if (kDebugTableTheme) {
3903         ALOGI("Setting theme %p from theme %p...\n", this, &other);
3904         dumpToLog();
3905         other.dumpToLog();
3906     }
3907 
3908     if (&mTable == &other.mTable) {
3909         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
3910             if (mPackages[i] != NULL) {
3911                 free_package(mPackages[i]);
3912             }
3913             if (other.mPackages[i] != NULL) {
3914                 mPackages[i] = copy_package(other.mPackages[i]);
3915             } else {
3916                 mPackages[i] = NULL;
3917             }
3918         }
3919     } else {
3920         // @todo: need to really implement this, not just copy
3921         // the system package (which is still wrong because it isn't
3922         // fixing up resource references).
3923         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
3924             if (mPackages[i] != NULL) {
3925                 free_package(mPackages[i]);
3926             }
3927             if (i == 0 && other.mPackages[i] != NULL) {
3928                 mPackages[i] = copy_package(other.mPackages[i]);
3929             } else {
3930                 mPackages[i] = NULL;
3931             }
3932         }
3933     }
3934 
3935     mTypeSpecFlags = other.mTypeSpecFlags;
3936 
3937     if (kDebugTableTheme) {
3938         ALOGI("Final theme:");
3939         dumpToLog();
3940     }
3941 
3942     return NO_ERROR;
3943 }
3944 
clear()3945 status_t ResTable::Theme::clear()
3946 {
3947     if (kDebugTableTheme) {
3948         ALOGI("Clearing theme %p...\n", this);
3949         dumpToLog();
3950     }
3951 
3952     for (size_t i = 0; i < Res_MAXPACKAGE; i++) {
3953         if (mPackages[i] != NULL) {
3954             free_package(mPackages[i]);
3955             mPackages[i] = NULL;
3956         }
3957     }
3958 
3959     mTypeSpecFlags = 0;
3960 
3961     if (kDebugTableTheme) {
3962         ALOGI("Final theme:");
3963         dumpToLog();
3964     }
3965 
3966     return NO_ERROR;
3967 }
3968 
getAttribute(uint32_t resID,Res_value * outValue,uint32_t * outTypeSpecFlags) const3969 ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
3970         uint32_t* outTypeSpecFlags) const
3971 {
3972     int cnt = 20;
3973 
3974     if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
3975 
3976     do {
3977         const ssize_t p = mTable.getResourcePackageIndex(resID);
3978         const uint32_t t = Res_GETTYPE(resID);
3979         const uint32_t e = Res_GETENTRY(resID);
3980 
3981         if (kDebugTableTheme) {
3982             ALOGI("Looking up attr 0x%08x in theme %p", resID, this);
3983         }
3984 
3985         if (p >= 0) {
3986             const package_info* const pi = mPackages[p];
3987             if (kDebugTableTheme) {
3988                 ALOGI("Found package: %p", pi);
3989             }
3990             if (pi != NULL) {
3991                 if (kDebugTableTheme) {
3992                     ALOGI("Desired type index is %u in avail %zu", t, Res_MAXTYPE + 1);
3993                 }
3994                 if (t <= Res_MAXTYPE) {
3995                     const type_info& ti = pi->types[t];
3996                     if (kDebugTableTheme) {
3997                         ALOGI("Desired entry index is %u in avail %zu", e, ti.numEntries);
3998                     }
3999                     if (e < ti.numEntries) {
4000                         const theme_entry& te = ti.entries[e];
4001                         if (outTypeSpecFlags != NULL) {
4002                             *outTypeSpecFlags |= te.typeSpecFlags;
4003                         }
4004                         if (kDebugTableTheme) {
4005                             ALOGI("Theme value: type=0x%x, data=0x%08x",
4006                                     te.value.dataType, te.value.data);
4007                         }
4008                         const uint8_t type = te.value.dataType;
4009                         if (type == Res_value::TYPE_ATTRIBUTE) {
4010                             if (cnt > 0) {
4011                                 cnt--;
4012                                 resID = te.value.data;
4013                                 continue;
4014                             }
4015                             ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
4016                             return BAD_INDEX;
4017                         } else if (type != Res_value::TYPE_NULL
4018                                 || te.value.data == Res_value::DATA_NULL_EMPTY) {
4019                             *outValue = te.value;
4020                             return te.stringBlock;
4021                         }
4022                         return BAD_INDEX;
4023                     }
4024                 }
4025             }
4026         }
4027         break;
4028 
4029     } while (true);
4030 
4031     return BAD_INDEX;
4032 }
4033 
resolveAttributeReference(Res_value * inOutValue,ssize_t blockIndex,uint32_t * outLastRef,uint32_t * inoutTypeSpecFlags,ResTable_config * inoutConfig) const4034 ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
4035         ssize_t blockIndex, uint32_t* outLastRef,
4036         uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
4037 {
4038     //printf("Resolving type=0x%x\n", inOutValue->dataType);
4039     if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
4040         uint32_t newTypeSpecFlags;
4041         blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
4042         if (kDebugTableTheme) {
4043             ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=0x%x\n",
4044                     (int)blockIndex, (int)inOutValue->dataType, inOutValue->data);
4045         }
4046         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
4047         //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
4048         if (blockIndex < 0) {
4049             return blockIndex;
4050         }
4051     }
4052     return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
4053             inoutTypeSpecFlags, inoutConfig);
4054 }
4055 
getChangingConfigurations() const4056 uint32_t ResTable::Theme::getChangingConfigurations() const
4057 {
4058     return mTypeSpecFlags;
4059 }
4060 
dumpToLog() const4061 void ResTable::Theme::dumpToLog() const
4062 {
4063     ALOGI("Theme %p:\n", this);
4064     for (size_t i=0; i<Res_MAXPACKAGE; i++) {
4065         package_info* pi = mPackages[i];
4066         if (pi == NULL) continue;
4067 
4068         ALOGI("  Package #0x%02x:\n", (int)(i + 1));
4069         for (size_t j = 0; j <= Res_MAXTYPE; j++) {
4070             type_info& ti = pi->types[j];
4071             if (ti.numEntries == 0) continue;
4072             ALOGI("    Type #0x%02x:\n", (int)(j + 1));
4073             for (size_t k = 0; k < ti.numEntries; k++) {
4074                 const theme_entry& te = ti.entries[k];
4075                 if (te.value.dataType == Res_value::TYPE_NULL) continue;
4076                 ALOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
4077                      (int)Res_MAKEID(i, j, k),
4078                      te.value.dataType, (int)te.value.data, (int)te.stringBlock);
4079             }
4080         }
4081     }
4082 }
4083 
ResTable()4084 ResTable::ResTable()
4085     : mError(NO_INIT), mNextPackageId(2)
4086 {
4087     memset(&mParams, 0, sizeof(mParams));
4088     memset(mPackageMap, 0, sizeof(mPackageMap));
4089     if (kDebugTableSuperNoisy) {
4090         ALOGI("Creating ResTable %p\n", this);
4091     }
4092 }
4093 
ResTable(const void * data,size_t size,const int32_t cookie,bool copyData)4094 ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
4095     : mError(NO_INIT), mNextPackageId(2)
4096 {
4097     memset(&mParams, 0, sizeof(mParams));
4098     memset(mPackageMap, 0, sizeof(mPackageMap));
4099     addInternal(data, size, NULL, 0, false, cookie, copyData);
4100     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
4101     if (kDebugTableSuperNoisy) {
4102         ALOGI("Creating ResTable %p\n", this);
4103     }
4104 }
4105 
~ResTable()4106 ResTable::~ResTable()
4107 {
4108     if (kDebugTableSuperNoisy) {
4109         ALOGI("Destroying ResTable in %p\n", this);
4110     }
4111     uninit();
4112 }
4113 
getResourcePackageIndex(uint32_t resID) const4114 inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
4115 {
4116     return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
4117 }
4118 
getResourcePackageIndexFromPackage(uint8_t packageID) const4119 inline ssize_t ResTable::getResourcePackageIndexFromPackage(uint8_t packageID) const
4120 {
4121     return ((ssize_t)mPackageMap[packageID])-1;
4122 }
4123 
add(const void * data,size_t size,const int32_t cookie,bool copyData)4124 status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
4125     return addInternal(data, size, NULL, 0, false, cookie, copyData);
4126 }
4127 
add(const void * data,size_t size,const void * idmapData,size_t idmapDataSize,const int32_t cookie,bool copyData,bool appAsLib)4128 status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
4129         const int32_t cookie, bool copyData, bool appAsLib) {
4130     return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData);
4131 }
4132 
add(Asset * asset,const int32_t cookie,bool copyData)4133 status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
4134     const void* data = asset->getBuffer(true);
4135     if (data == NULL) {
4136         ALOGW("Unable to get buffer of resource asset file");
4137         return UNKNOWN_ERROR;
4138     }
4139 
4140     return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, false, 0, cookie,
4141             copyData);
4142 }
4143 
add(Asset * asset,Asset * idmapAsset,const int32_t cookie,bool copyData,bool appAsLib,bool isSystemAsset)4144 status_t ResTable::add(
4145         Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
4146         bool appAsLib, bool isSystemAsset) {
4147     const void* data = asset->getBuffer(true);
4148     if (data == NULL) {
4149         ALOGW("Unable to get buffer of resource asset file");
4150         return UNKNOWN_ERROR;
4151     }
4152 
4153     size_t idmapSize = 0;
4154     const void* idmapData = NULL;
4155     if (idmapAsset != NULL) {
4156         idmapData = idmapAsset->getBuffer(true);
4157         if (idmapData == NULL) {
4158             ALOGW("Unable to get buffer of idmap asset file");
4159             return UNKNOWN_ERROR;
4160         }
4161         idmapSize = static_cast<size_t>(idmapAsset->getLength());
4162     }
4163 
4164     return addInternal(data, static_cast<size_t>(asset->getLength()),
4165             idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
4166 }
4167 
add(ResTable * src,bool isSystemAsset)4168 status_t ResTable::add(ResTable* src, bool isSystemAsset)
4169 {
4170     mError = src->mError;
4171 
4172     for (size_t i=0; i < src->mHeaders.size(); i++) {
4173         mHeaders.add(src->mHeaders[i]);
4174     }
4175 
4176     for (size_t i=0; i < src->mPackageGroups.size(); i++) {
4177         PackageGroup* srcPg = src->mPackageGroups[i];
4178         PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
4179                 false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset, srcPg->isDynamic);
4180         for (size_t j=0; j<srcPg->packages.size(); j++) {
4181             pg->packages.add(srcPg->packages[j]);
4182         }
4183 
4184         for (size_t j = 0; j < srcPg->types.size(); j++) {
4185             if (srcPg->types[j].isEmpty()) {
4186                 continue;
4187             }
4188 
4189             TypeList& typeList = pg->types.editItemAt(j);
4190             typeList.appendVector(srcPg->types[j]);
4191         }
4192         pg->dynamicRefTable.addMappings(srcPg->dynamicRefTable);
4193         pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId);
4194         mPackageGroups.add(pg);
4195     }
4196 
4197     memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
4198 
4199     return mError;
4200 }
4201 
addEmpty(const int32_t cookie)4202 status_t ResTable::addEmpty(const int32_t cookie) {
4203     Header* header = new Header(this);
4204     header->index = mHeaders.size();
4205     header->cookie = cookie;
4206     header->values.setToEmpty();
4207     header->ownedData = calloc(1, sizeof(ResTable_header));
4208 
4209     ResTable_header* resHeader = (ResTable_header*) header->ownedData;
4210     resHeader->header.type = RES_TABLE_TYPE;
4211     resHeader->header.headerSize = sizeof(ResTable_header);
4212     resHeader->header.size = sizeof(ResTable_header);
4213 
4214     header->header = (const ResTable_header*) resHeader;
4215     mHeaders.add(header);
4216     return (mError=NO_ERROR);
4217 }
4218 
addInternal(const void * data,size_t dataSize,const void * idmapData,size_t idmapDataSize,bool appAsLib,const int32_t cookie,bool copyData,bool isSystemAsset)4219 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
4220         bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
4221 {
4222     if (!data) {
4223         return NO_ERROR;
4224     }
4225 
4226     if (dataSize < sizeof(ResTable_header)) {
4227         ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).",
4228                 (int) dataSize, (int) sizeof(ResTable_header));
4229         return UNKNOWN_ERROR;
4230     }
4231 
4232     Header* header = new Header(this);
4233     header->index = mHeaders.size();
4234     header->cookie = cookie;
4235     if (idmapData != NULL) {
4236         header->resourceIDMap = (uint32_t*) malloc(idmapDataSize);
4237         if (header->resourceIDMap == NULL) {
4238             delete header;
4239             return (mError = NO_MEMORY);
4240         }
4241         memcpy(header->resourceIDMap, idmapData, idmapDataSize);
4242         header->resourceIDMapSize = idmapDataSize;
4243     }
4244     mHeaders.add(header);
4245 
4246     const bool notDeviceEndian = htods(0xf0) != 0xf0;
4247 
4248     if (kDebugLoadTableNoisy) {
4249         ALOGV("Adding resources to ResTable: data=%p, size=%zu, cookie=%d, copy=%d "
4250                 "idmap=%p\n", data, dataSize, cookie, copyData, idmapData);
4251     }
4252 
4253     if (copyData || notDeviceEndian) {
4254         header->ownedData = malloc(dataSize);
4255         if (header->ownedData == NULL) {
4256             return (mError=NO_MEMORY);
4257         }
4258         memcpy(header->ownedData, data, dataSize);
4259         data = header->ownedData;
4260     }
4261 
4262     header->header = (const ResTable_header*)data;
4263     header->size = dtohl(header->header->header.size);
4264     if (kDebugLoadTableSuperNoisy) {
4265         ALOGI("Got size %zu, again size 0x%x, raw size 0x%x\n", header->size,
4266                 dtohl(header->header->header.size), header->header->header.size);
4267     }
4268     if (kDebugLoadTableNoisy) {
4269         ALOGV("Loading ResTable @%p:\n", header->header);
4270     }
4271     if (dtohs(header->header->header.headerSize) > header->size
4272             || header->size > dataSize) {
4273         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
4274              (int)dtohs(header->header->header.headerSize),
4275              (int)header->size, (int)dataSize);
4276         return (mError=BAD_TYPE);
4277     }
4278     if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
4279         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
4280              (int)dtohs(header->header->header.headerSize),
4281              (int)header->size);
4282         return (mError=BAD_TYPE);
4283     }
4284     header->dataEnd = ((const uint8_t*)header->header) + header->size;
4285 
4286     // Iterate through all chunks.
4287     size_t curPackage = 0;
4288 
4289     const ResChunk_header* chunk =
4290         (const ResChunk_header*)(((const uint8_t*)header->header)
4291                                  + dtohs(header->header->header.headerSize));
4292     while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
4293            ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
4294         status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
4295         if (err != NO_ERROR) {
4296             return (mError=err);
4297         }
4298         if (kDebugTableNoisy) {
4299             ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
4300                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
4301                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
4302         }
4303         const size_t csize = dtohl(chunk->size);
4304         const uint16_t ctype = dtohs(chunk->type);
4305         if (ctype == RES_STRING_POOL_TYPE) {
4306             if (header->values.getError() != NO_ERROR) {
4307                 // Only use the first string chunk; ignore any others that
4308                 // may appear.
4309                 status_t err = header->values.setTo(chunk, csize);
4310                 if (err != NO_ERROR) {
4311                     return (mError=err);
4312                 }
4313             } else {
4314                 ALOGW("Multiple string chunks found in resource table.");
4315             }
4316         } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
4317             if (curPackage >= dtohl(header->header->packageCount)) {
4318                 ALOGW("More package chunks were found than the %d declared in the header.",
4319                      dtohl(header->header->packageCount));
4320                 return (mError=BAD_TYPE);
4321             }
4322 
4323             if (parsePackage(
4324                     (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
4325                 return mError;
4326             }
4327             curPackage++;
4328         } else {
4329             ALOGW("Unknown chunk type 0x%x in table at %p.\n",
4330                  ctype,
4331                  (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
4332         }
4333         chunk = (const ResChunk_header*)
4334             (((const uint8_t*)chunk) + csize);
4335     }
4336 
4337     if (curPackage < dtohl(header->header->packageCount)) {
4338         ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
4339              (int)curPackage, dtohl(header->header->packageCount));
4340         return (mError=BAD_TYPE);
4341     }
4342     mError = header->values.getError();
4343     if (mError != NO_ERROR) {
4344         ALOGW("No string values found in resource table!");
4345     }
4346 
4347     if (kDebugTableNoisy) {
4348         ALOGV("Returning from add with mError=%d\n", mError);
4349     }
4350     return mError;
4351 }
4352 
getError() const4353 status_t ResTable::getError() const
4354 {
4355     return mError;
4356 }
4357 
uninit()4358 void ResTable::uninit()
4359 {
4360     mError = NO_INIT;
4361     size_t N = mPackageGroups.size();
4362     for (size_t i=0; i<N; i++) {
4363         PackageGroup* g = mPackageGroups[i];
4364         delete g;
4365     }
4366     N = mHeaders.size();
4367     for (size_t i=0; i<N; i++) {
4368         Header* header = mHeaders[i];
4369         if (header->owner == this) {
4370             if (header->ownedData) {
4371                 free(header->ownedData);
4372             }
4373             delete header;
4374         }
4375     }
4376 
4377     mPackageGroups.clear();
4378     mHeaders.clear();
4379 }
4380 
getResourceName(uint32_t resID,bool allowUtf8,resource_name * outName) const4381 bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
4382 {
4383     if (mError != NO_ERROR) {
4384         return false;
4385     }
4386 
4387     const ssize_t p = getResourcePackageIndex(resID);
4388     const int t = Res_GETTYPE(resID);
4389     const int e = Res_GETENTRY(resID);
4390 
4391     if (p < 0) {
4392         if (Res_GETPACKAGE(resID)+1 == 0) {
4393             ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
4394         } else {
4395 #ifndef STATIC_ANDROIDFW_FOR_TOOLS
4396             ALOGW("No known package when getting name for resource number 0x%08x", resID);
4397 #endif
4398         }
4399         return false;
4400     }
4401     if (t < 0) {
4402         ALOGW("No type identifier when getting name for resource number 0x%08x", resID);
4403         return false;
4404     }
4405 
4406     const PackageGroup* const grp = mPackageGroups[p];
4407     if (grp == NULL) {
4408         ALOGW("Bad identifier when getting name for resource number 0x%08x", resID);
4409         return false;
4410     }
4411 
4412     Entry entry;
4413     status_t err = getEntry(grp, t, e, NULL, &entry);
4414     if (err != NO_ERROR) {
4415         return false;
4416     }
4417 
4418     outName->package = grp->name.string();
4419     outName->packageLen = grp->name.size();
4420     if (allowUtf8) {
4421         outName->type8 = UnpackOptionalString(entry.typeStr.string8(), &outName->typeLen);
4422         outName->name8 = UnpackOptionalString(entry.keyStr.string8(), &outName->nameLen);
4423     } else {
4424         outName->type8 = NULL;
4425         outName->name8 = NULL;
4426     }
4427     if (outName->type8 == NULL) {
4428         outName->type = UnpackOptionalString(entry.typeStr.string16(), &outName->typeLen);
4429         // If we have a bad index for some reason, we should abort.
4430         if (outName->type == NULL) {
4431             return false;
4432         }
4433     }
4434     if (outName->name8 == NULL) {
4435         outName->name = UnpackOptionalString(entry.keyStr.string16(), &outName->nameLen);
4436         // If we have a bad index for some reason, we should abort.
4437         if (outName->name == NULL) {
4438             return false;
4439         }
4440     }
4441 
4442     return true;
4443 }
4444 
getResource(uint32_t resID,Res_value * outValue,bool mayBeBag,uint16_t density,uint32_t * outSpecFlags,ResTable_config * outConfig) const4445 ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
4446         uint32_t* outSpecFlags, ResTable_config* outConfig) const
4447 {
4448     if (mError != NO_ERROR) {
4449         return mError;
4450     }
4451 
4452     const ssize_t p = getResourcePackageIndex(resID);
4453     const int t = Res_GETTYPE(resID);
4454     const int e = Res_GETENTRY(resID);
4455 
4456     if (p < 0) {
4457         if (Res_GETPACKAGE(resID)+1 == 0) {
4458             ALOGW("No package identifier when getting value for resource number 0x%08x", resID);
4459         } else {
4460             ALOGW("No known package when getting value for resource number 0x%08x", resID);
4461         }
4462         return BAD_INDEX;
4463     }
4464     if (t < 0) {
4465         ALOGW("No type identifier when getting value for resource number 0x%08x", resID);
4466         return BAD_INDEX;
4467     }
4468 
4469     const PackageGroup* const grp = mPackageGroups[p];
4470     if (grp == NULL) {
4471         ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
4472         return BAD_INDEX;
4473     }
4474 
4475     // Allow overriding density
4476     ResTable_config desiredConfig = mParams;
4477     if (density > 0) {
4478         desiredConfig.density = density;
4479     }
4480 
4481     Entry entry;
4482     status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
4483     if (err != NO_ERROR) {
4484         // Only log the failure when we're not running on the host as
4485         // part of a tool. The caller will do its own logging.
4486 #ifndef STATIC_ANDROIDFW_FOR_TOOLS
4487         ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n",
4488                 resID, t, e, err);
4489 #endif
4490         return err;
4491     }
4492 
4493     if ((dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) != 0) {
4494         if (!mayBeBag) {
4495             ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
4496         }
4497         return BAD_VALUE;
4498     }
4499 
4500     const Res_value* value = reinterpret_cast<const Res_value*>(
4501             reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size);
4502 
4503     outValue->size = dtohs(value->size);
4504     outValue->res0 = value->res0;
4505     outValue->dataType = value->dataType;
4506     outValue->data = dtohl(value->data);
4507 
4508     // The reference may be pointing to a resource in a shared library. These
4509     // references have build-time generated package IDs. These ids may not match
4510     // the actual package IDs of the corresponding packages in this ResTable.
4511     // We need to fix the package ID based on a mapping.
4512     if (grp->dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
4513         ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data);
4514         return BAD_VALUE;
4515     }
4516 
4517     if (kDebugTableNoisy) {
4518         size_t len;
4519         printf("Found value: pkg=%zu, type=%d, str=%s, int=%d\n",
4520                 entry.package->header->index,
4521                 outValue->dataType,
4522                 outValue->dataType == Res_value::TYPE_STRING ?
4523                     String8(UnpackOptionalString(
4524                         entry.package->header->values.stringAt(outValue->data), &len)).string() :
4525                     "",
4526                 outValue->data);
4527     }
4528 
4529     if (outSpecFlags != NULL) {
4530         *outSpecFlags = entry.specFlags;
4531     }
4532 
4533     if (outConfig != NULL) {
4534         *outConfig = entry.config;
4535     }
4536 
4537     return entry.package->header->index;
4538 }
4539 
resolveReference(Res_value * value,ssize_t blockIndex,uint32_t * outLastRef,uint32_t * inoutTypeSpecFlags,ResTable_config * outConfig) const4540 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
4541         uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
4542         ResTable_config* outConfig) const
4543 {
4544     int count=0;
4545     while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE
4546             && value->data != 0 && count < 20) {
4547         if (outLastRef) *outLastRef = value->data;
4548         uint32_t newFlags = 0;
4549         const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
4550                 outConfig);
4551         if (newIndex == BAD_INDEX) {
4552             return BAD_INDEX;
4553         }
4554         if (kDebugTableTheme) {
4555             ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
4556                     value->data, (int)newIndex, (int)value->dataType, value->data);
4557         }
4558         //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
4559         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
4560         if (newIndex < 0) {
4561             // This can fail if the resource being referenced is a style...
4562             // in this case, just return the reference, and expect the
4563             // caller to deal with.
4564             return blockIndex;
4565         }
4566         blockIndex = newIndex;
4567         count++;
4568     }
4569     return blockIndex;
4570 }
4571 
valueToString(const Res_value * value,size_t stringBlock,char16_t[TMP_BUFFER_SIZE],size_t * outLen) const4572 const char16_t* ResTable::valueToString(
4573     const Res_value* value, size_t stringBlock,
4574     char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen) const
4575 {
4576     if (!value) {
4577         return NULL;
4578     }
4579     if (value->dataType == value->TYPE_STRING) {
4580         return UnpackOptionalString(getTableStringBlock(stringBlock)->stringAt(value->data),
4581                                     outLen);
4582     }
4583     // XXX do int to string conversions.
4584     return NULL;
4585 }
4586 
lockBag(uint32_t resID,const bag_entry ** outBag) const4587 ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
4588 {
4589     mLock.lock();
4590     ssize_t err = getBagLocked(resID, outBag);
4591     if (err < NO_ERROR) {
4592         //printf("*** get failed!  unlocking\n");
4593         mLock.unlock();
4594     }
4595     return err;
4596 }
4597 
unlockBag(const bag_entry *) const4598 void ResTable::unlockBag(const bag_entry* /*bag*/) const
4599 {
4600     //printf("<<< unlockBag %p\n", this);
4601     mLock.unlock();
4602 }
4603 
lock() const4604 void ResTable::lock() const
4605 {
4606     mLock.lock();
4607 }
4608 
unlock() const4609 void ResTable::unlock() const
4610 {
4611     mLock.unlock();
4612 }
4613 
getBagLocked(uint32_t resID,const bag_entry ** outBag,uint32_t * outTypeSpecFlags) const4614 ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
4615         uint32_t* outTypeSpecFlags) const
4616 {
4617     if (mError != NO_ERROR) {
4618         return mError;
4619     }
4620 
4621     const ssize_t p = getResourcePackageIndex(resID);
4622     const int t = Res_GETTYPE(resID);
4623     const int e = Res_GETENTRY(resID);
4624 
4625     if (p < 0) {
4626         ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
4627         return BAD_INDEX;
4628     }
4629     if (t < 0) {
4630         ALOGW("No type identifier when getting bag for resource number 0x%08x", resID);
4631         return BAD_INDEX;
4632     }
4633 
4634     //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
4635     PackageGroup* const grp = mPackageGroups[p];
4636     if (grp == NULL) {
4637         ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
4638         return BAD_INDEX;
4639     }
4640 
4641     const TypeList& typeConfigs = grp->types[t];
4642     if (typeConfigs.isEmpty()) {
4643         ALOGW("Type identifier 0x%x does not exist.", t+1);
4644         return BAD_INDEX;
4645     }
4646 
4647     const size_t NENTRY = typeConfigs[0]->entryCount;
4648     if (e >= (int)NENTRY) {
4649         ALOGW("Entry identifier 0x%x is larger than entry count 0x%x",
4650              e, (int)typeConfigs[0]->entryCount);
4651         return BAD_INDEX;
4652     }
4653 
4654     // First see if we've already computed this bag...
4655     TypeCacheEntry& cacheEntry = grp->typeCacheEntries.editItemAt(t);
4656     bag_set** typeSet = cacheEntry.cachedBags;
4657     if (typeSet) {
4658         bag_set* set = typeSet[e];
4659         if (set) {
4660             if (set != (bag_set*)0xFFFFFFFF) {
4661                 if (outTypeSpecFlags != NULL) {
4662                     *outTypeSpecFlags = set->typeSpecFlags;
4663                 }
4664                 *outBag = (bag_entry*)(set+1);
4665                 if (kDebugTableSuperNoisy) {
4666                     ALOGI("Found existing bag for: 0x%x\n", resID);
4667                 }
4668                 return set->numAttrs;
4669             }
4670             ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
4671                  resID);
4672             return BAD_INDEX;
4673         }
4674     }
4675 
4676     // Bag not found, we need to compute it!
4677     if (!typeSet) {
4678         typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
4679         if (!typeSet) return NO_MEMORY;
4680         cacheEntry.cachedBags = typeSet;
4681     }
4682 
4683     // Mark that we are currently working on this one.
4684     typeSet[e] = (bag_set*)0xFFFFFFFF;
4685 
4686     if (kDebugTableNoisy) {
4687         ALOGI("Building bag: %x\n", resID);
4688     }
4689 
4690     // Now collect all bag attributes
4691     Entry entry;
4692     status_t err = getEntry(grp, t, e, &mParams, &entry);
4693     if (err != NO_ERROR) {
4694         return err;
4695     }
4696 
4697     const uint16_t entrySize = dtohs(entry.entry->size);
4698     const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
4699         ? dtohl(((const ResTable_map_entry*)entry.entry)->parent.ident) : 0;
4700     const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
4701         ? dtohl(((const ResTable_map_entry*)entry.entry)->count) : 0;
4702 
4703     size_t N = count;
4704 
4705     if (kDebugTableNoisy) {
4706         ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
4707 
4708     // If this map inherits from another, we need to start
4709     // with its parent's values.  Otherwise start out empty.
4710         ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
4711     }
4712 
4713     // This is what we are building.
4714     bag_set* set = NULL;
4715 
4716     if (parent) {
4717         uint32_t resolvedParent = parent;
4718 
4719         // Bags encode a parent reference without using the standard
4720         // Res_value structure. That means we must always try to
4721         // resolve a parent reference in case it is actually a
4722         // TYPE_DYNAMIC_REFERENCE.
4723         status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent);
4724         if (err != NO_ERROR) {
4725             ALOGE("Failed resolving bag parent id 0x%08x", parent);
4726             return UNKNOWN_ERROR;
4727         }
4728 
4729         const bag_entry* parentBag;
4730         uint32_t parentTypeSpecFlags = 0;
4731         const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
4732         const size_t NT = ((NP >= 0) ? NP : 0) + N;
4733         set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
4734         if (set == NULL) {
4735             return NO_MEMORY;
4736         }
4737         if (NP > 0) {
4738             memcpy(set+1, parentBag, NP*sizeof(bag_entry));
4739             set->numAttrs = NP;
4740             if (kDebugTableNoisy) {
4741                 ALOGI("Initialized new bag with %zd inherited attributes.\n", NP);
4742             }
4743         } else {
4744             if (kDebugTableNoisy) {
4745                 ALOGI("Initialized new bag with no inherited attributes.\n");
4746             }
4747             set->numAttrs = 0;
4748         }
4749         set->availAttrs = NT;
4750         set->typeSpecFlags = parentTypeSpecFlags;
4751     } else {
4752         set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
4753         if (set == NULL) {
4754             return NO_MEMORY;
4755         }
4756         set->numAttrs = 0;
4757         set->availAttrs = N;
4758         set->typeSpecFlags = 0;
4759     }
4760 
4761     set->typeSpecFlags |= entry.specFlags;
4762 
4763     // Now merge in the new attributes...
4764     size_t curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type))
4765         + dtohs(entry.entry->size);
4766     const ResTable_map* map;
4767     bag_entry* entries = (bag_entry*)(set+1);
4768     size_t curEntry = 0;
4769     uint32_t pos = 0;
4770     if (kDebugTableNoisy) {
4771         ALOGI("Starting with set %p, entries=%p, avail=%zu\n", set, entries, set->availAttrs);
4772     }
4773     while (pos < count) {
4774         if (kDebugTableNoisy) {
4775             ALOGI("Now at %p\n", (void*)curOff);
4776         }
4777 
4778         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
4779             ALOGW("ResTable_map at %d is beyond type chunk data %d",
4780                  (int)curOff, dtohl(entry.type->header.size));
4781             free(set);
4782             return BAD_TYPE;
4783         }
4784         map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
4785         N++;
4786 
4787         uint32_t newName = htodl(map->name.ident);
4788         if (!Res_INTERNALID(newName)) {
4789             // Attributes don't have a resource id as the name. They specify
4790             // other data, which would be wrong to change via a lookup.
4791             if (grp->dynamicRefTable.lookupResourceId(&newName) != NO_ERROR) {
4792                 ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x",
4793                         (int) curOff, (int) newName);
4794                 free(set);
4795                 return UNKNOWN_ERROR;
4796             }
4797         }
4798 
4799         bool isInside;
4800         uint32_t oldName = 0;
4801         while ((isInside=(curEntry < set->numAttrs))
4802                 && (oldName=entries[curEntry].map.name.ident) < newName) {
4803             if (kDebugTableNoisy) {
4804                 ALOGI("#%zu: Keeping existing attribute: 0x%08x\n",
4805                         curEntry, entries[curEntry].map.name.ident);
4806             }
4807             curEntry++;
4808         }
4809 
4810         if ((!isInside) || oldName != newName) {
4811             // This is a new attribute...  figure out what to do with it.
4812             if (set->numAttrs >= set->availAttrs) {
4813                 // Need to alloc more memory...
4814                 const size_t newAvail = set->availAttrs+N;
4815                 void *oldSet = set;
4816                 set = (bag_set*)realloc(set,
4817                                         sizeof(bag_set)
4818                                         + sizeof(bag_entry)*newAvail);
4819                 if (set == NULL) {
4820                     free(oldSet);
4821                     return NO_MEMORY;
4822                 }
4823                 set->availAttrs = newAvail;
4824                 entries = (bag_entry*)(set+1);
4825                 if (kDebugTableNoisy) {
4826                     ALOGI("Reallocated set %p, entries=%p, avail=%zu\n",
4827                             set, entries, set->availAttrs);
4828                 }
4829             }
4830             if (isInside) {
4831                 // Going in the middle, need to make space.
4832                 memmove(entries+curEntry+1, entries+curEntry,
4833                         sizeof(bag_entry)*(set->numAttrs-curEntry));
4834                 set->numAttrs++;
4835             }
4836             if (kDebugTableNoisy) {
4837                 ALOGI("#%zu: Inserting new attribute: 0x%08x\n", curEntry, newName);
4838             }
4839         } else {
4840             if (kDebugTableNoisy) {
4841                 ALOGI("#%zu: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
4842             }
4843         }
4844 
4845         bag_entry* cur = entries+curEntry;
4846 
4847         cur->stringBlock = entry.package->header->index;
4848         cur->map.name.ident = newName;
4849         cur->map.value.copyFrom_dtoh(map->value);
4850         status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value);
4851         if (err != NO_ERROR) {
4852             ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data);
4853             return UNKNOWN_ERROR;
4854         }
4855 
4856         if (kDebugTableNoisy) {
4857             ALOGI("Setting entry #%zu %p: block=%zd, name=0x%08d, type=%d, data=0x%08x\n",
4858                     curEntry, cur, cur->stringBlock, cur->map.name.ident,
4859                     cur->map.value.dataType, cur->map.value.data);
4860         }
4861 
4862         // On to the next!
4863         curEntry++;
4864         pos++;
4865         const size_t size = dtohs(map->value.size);
4866         curOff += size + sizeof(*map)-sizeof(map->value);
4867     }
4868 
4869     if (curEntry > set->numAttrs) {
4870         set->numAttrs = curEntry;
4871     }
4872 
4873     // And this is it...
4874     typeSet[e] = set;
4875     if (set) {
4876         if (outTypeSpecFlags != NULL) {
4877             *outTypeSpecFlags = set->typeSpecFlags;
4878         }
4879         *outBag = (bag_entry*)(set+1);
4880         if (kDebugTableNoisy) {
4881             ALOGI("Returning %zu attrs\n", set->numAttrs);
4882         }
4883         return set->numAttrs;
4884     }
4885     return BAD_INDEX;
4886 }
4887 
setParameters(const ResTable_config * params)4888 void ResTable::setParameters(const ResTable_config* params)
4889 {
4890     AutoMutex _lock(mLock);
4891     AutoMutex _lock2(mFilteredConfigLock);
4892 
4893     if (kDebugTableGetEntry) {
4894         ALOGI("Setting parameters: %s\n", params->toString().string());
4895     }
4896     mParams = *params;
4897     for (size_t p = 0; p < mPackageGroups.size(); p++) {
4898         PackageGroup* packageGroup = mPackageGroups.editItemAt(p);
4899         if (kDebugTableNoisy) {
4900             ALOGI("CLEARING BAGS FOR GROUP %zu!", p);
4901         }
4902         packageGroup->clearBagCache();
4903 
4904         // Find which configurations match the set of parameters. This allows for a much
4905         // faster lookup in Lookup() if the set of values is narrowed down.
4906         for (size_t t = 0; t < packageGroup->types.size(); t++) {
4907             if (packageGroup->types[t].isEmpty()) {
4908                 continue;
4909             }
4910 
4911             TypeList& typeList = packageGroup->types.editItemAt(t);
4912 
4913             // Retrieve the cache entry for this type.
4914             TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries.editItemAt(t);
4915 
4916             for (size_t ts = 0; ts < typeList.size(); ts++) {
4917                 Type* type = typeList.editItemAt(ts);
4918 
4919                 std::shared_ptr<Vector<const ResTable_type*>> newFilteredConfigs =
4920                         std::make_shared<Vector<const ResTable_type*>>();
4921 
4922                 for (size_t ti = 0; ti < type->configs.size(); ti++) {
4923                     ResTable_config config;
4924                     config.copyFromDtoH(type->configs[ti]->config);
4925 
4926                     if (config.match(mParams)) {
4927                         newFilteredConfigs->add(type->configs[ti]);
4928                     }
4929                 }
4930 
4931                 if (kDebugTableNoisy) {
4932                     ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs",
4933                           p, t, newFilteredConfigs->size());
4934                 }
4935 
4936                 cacheEntry.filteredConfigs.add(newFilteredConfigs);
4937             }
4938         }
4939     }
4940 }
4941 
getParameters(ResTable_config * params) const4942 void ResTable::getParameters(ResTable_config* params) const
4943 {
4944     mLock.lock();
4945     *params = mParams;
4946     mLock.unlock();
4947 }
4948 
4949 struct id_name_map {
4950     uint32_t id;
4951     size_t len;
4952     char16_t name[6];
4953 };
4954 
4955 const static id_name_map ID_NAMES[] = {
4956     { ResTable_map::ATTR_TYPE,  5, { '^', 't', 'y', 'p', 'e' } },
4957     { ResTable_map::ATTR_L10N,  5, { '^', 'l', '1', '0', 'n' } },
4958     { ResTable_map::ATTR_MIN,   4, { '^', 'm', 'i', 'n' } },
4959     { ResTable_map::ATTR_MAX,   4, { '^', 'm', 'a', 'x' } },
4960     { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
4961     { ResTable_map::ATTR_ZERO,  5, { '^', 'z', 'e', 'r', 'o' } },
4962     { ResTable_map::ATTR_ONE,   4, { '^', 'o', 'n', 'e' } },
4963     { ResTable_map::ATTR_TWO,   4, { '^', 't', 'w', 'o' } },
4964     { ResTable_map::ATTR_FEW,   4, { '^', 'f', 'e', 'w' } },
4965     { ResTable_map::ATTR_MANY,  5, { '^', 'm', 'a', 'n', 'y' } },
4966 };
4967 
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) const4968 uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
4969                                      const char16_t* type, size_t typeLen,
4970                                      const char16_t* package,
4971                                      size_t packageLen,
4972                                      uint32_t* outTypeSpecFlags) const
4973 {
4974     if (kDebugTableSuperNoisy) {
4975         printf("Identifier for name: error=%d\n", mError);
4976     }
4977 
4978     // Check for internal resource identifier as the very first thing, so
4979     // that we will always find them even when there are no resources.
4980     if (name[0] == '^') {
4981         const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
4982         size_t len;
4983         for (int i=0; i<N; i++) {
4984             const id_name_map* m = ID_NAMES + i;
4985             len = m->len;
4986             if (len != nameLen) {
4987                 continue;
4988             }
4989             for (size_t j=1; j<len; j++) {
4990                 if (m->name[j] != name[j]) {
4991                     goto nope;
4992                 }
4993             }
4994             if (outTypeSpecFlags) {
4995                 *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
4996             }
4997             return m->id;
4998 nope:
4999             ;
5000         }
5001         if (nameLen > 7) {
5002             if (name[1] == 'i' && name[2] == 'n'
5003                 && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
5004                 && name[6] == '_') {
5005                 int index = atoi(String8(name + 7, nameLen - 7).string());
5006                 if (Res_CHECKID(index)) {
5007                     ALOGW("Array resource index: %d is too large.",
5008                          index);
5009                     return 0;
5010                 }
5011                 if (outTypeSpecFlags) {
5012                     *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
5013                 }
5014                 return  Res_MAKEARRAY(index);
5015             }
5016         }
5017         return 0;
5018     }
5019 
5020     if (mError != NO_ERROR) {
5021         return 0;
5022     }
5023 
5024     bool fakePublic = false;
5025 
5026     // Figure out the package and type we are looking in...
5027 
5028     const char16_t* packageEnd = NULL;
5029     const char16_t* typeEnd = NULL;
5030     const char16_t* const nameEnd = name+nameLen;
5031     const char16_t* p = name;
5032     while (p < nameEnd) {
5033         if (*p == ':') packageEnd = p;
5034         else if (*p == '/') typeEnd = p;
5035         p++;
5036     }
5037     if (*name == '@') {
5038         name++;
5039         if (*name == '*') {
5040             fakePublic = true;
5041             name++;
5042         }
5043     }
5044     if (name >= nameEnd) {
5045         return 0;
5046     }
5047 
5048     if (packageEnd) {
5049         package = name;
5050         packageLen = packageEnd-name;
5051         name = packageEnd+1;
5052     } else if (!package) {
5053         return 0;
5054     }
5055 
5056     if (typeEnd) {
5057         type = name;
5058         typeLen = typeEnd-name;
5059         name = typeEnd+1;
5060     } else if (!type) {
5061         return 0;
5062     }
5063 
5064     if (name >= nameEnd) {
5065         return 0;
5066     }
5067     nameLen = nameEnd-name;
5068 
5069     if (kDebugTableNoisy) {
5070         printf("Looking for identifier: type=%s, name=%s, package=%s\n",
5071                 String8(type, typeLen).string(),
5072                 String8(name, nameLen).string(),
5073                 String8(package, packageLen).string());
5074     }
5075 
5076     const String16 attr("attr");
5077     const String16 attrPrivate("^attr-private");
5078 
5079     const size_t NG = mPackageGroups.size();
5080     for (size_t ig=0; ig<NG; ig++) {
5081         const PackageGroup* group = mPackageGroups[ig];
5082 
5083         if (strzcmp16(package, packageLen,
5084                       group->name.string(), group->name.size())) {
5085             if (kDebugTableNoisy) {
5086                 printf("Skipping package group: %s\n", String8(group->name).string());
5087             }
5088             continue;
5089         }
5090 
5091         const size_t packageCount = group->packages.size();
5092         for (size_t pi = 0; pi < packageCount; pi++) {
5093             const char16_t* targetType = type;
5094             size_t targetTypeLen = typeLen;
5095 
5096             do {
5097                 auto ti = group->packages[pi]->typeStrings.indexOfString(targetType, targetTypeLen);
5098                 if (!ti.has_value()) {
5099                     continue;
5100                 }
5101 
5102                 *ti += group->packages[pi]->typeIdOffset;
5103                 const uint32_t identifier = findEntry(group, *ti, name, nameLen,
5104                         outTypeSpecFlags);
5105                 if (identifier != 0) {
5106                     if (fakePublic && outTypeSpecFlags) {
5107                         *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
5108                     }
5109                     return identifier;
5110                 }
5111             } while (strzcmp16(attr.string(), attr.size(), targetType, targetTypeLen) == 0
5112                     && (targetType = attrPrivate.string())
5113                     && (targetTypeLen = attrPrivate.size())
5114             );
5115         }
5116     }
5117     return 0;
5118 }
5119 
findEntry(const PackageGroup * group,ssize_t typeIndex,const char16_t * name,size_t nameLen,uint32_t * outTypeSpecFlags) const5120 uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name,
5121         size_t nameLen, uint32_t* outTypeSpecFlags) const {
5122     const TypeList& typeList = group->types[typeIndex];
5123     const size_t typeCount = typeList.size();
5124     for (size_t i = 0; i < typeCount; i++) {
5125         const Type* t = typeList[i];
5126         const base::expected<size_t, NullOrIOError> ei =
5127             t->package->keyStrings.indexOfString(name, nameLen);
5128         if (!ei.has_value()) {
5129             continue;
5130         }
5131 
5132         const size_t configCount = t->configs.size();
5133         for (size_t j = 0; j < configCount; j++) {
5134             const TypeVariant tv(t->configs[j]);
5135             for (TypeVariant::iterator iter = tv.beginEntries();
5136                  iter != tv.endEntries();
5137                  iter++) {
5138                 const ResTable_entry* entry = *iter;
5139                 if (entry == NULL) {
5140                     continue;
5141                 }
5142 
5143                 if (dtohl(entry->key.index) == (size_t) *ei) {
5144                     uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index());
5145                     if (outTypeSpecFlags) {
5146                         Entry result;
5147                         if (getEntry(group, typeIndex, iter.index(), NULL, &result) != NO_ERROR) {
5148                             ALOGW("Failed to find spec flags for 0x%08x", resId);
5149                             return 0;
5150                         }
5151                         *outTypeSpecFlags = result.specFlags;
5152                     }
5153                     return resId;
5154                 }
5155             }
5156         }
5157     }
5158     return 0;
5159 }
5160 
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)5161 bool ResTable::expandResourceRef(const char16_t* refStr, size_t refLen,
5162                                  String16* outPackage,
5163                                  String16* outType,
5164                                  String16* outName,
5165                                  const String16* defType,
5166                                  const String16* defPackage,
5167                                  const char** outErrorMsg,
5168                                  bool* outPublicOnly)
5169 {
5170     const char16_t* packageEnd = NULL;
5171     const char16_t* typeEnd = NULL;
5172     const char16_t* p = refStr;
5173     const char16_t* const end = p + refLen;
5174     while (p < end) {
5175         if (*p == ':') packageEnd = p;
5176         else if (*p == '/') {
5177             typeEnd = p;
5178             break;
5179         }
5180         p++;
5181     }
5182     p = refStr;
5183     if (*p == '@') p++;
5184 
5185     if (outPublicOnly != NULL) {
5186         *outPublicOnly = true;
5187     }
5188     if (*p == '*') {
5189         p++;
5190         if (outPublicOnly != NULL) {
5191             *outPublicOnly = false;
5192         }
5193     }
5194 
5195     if (packageEnd) {
5196         *outPackage = String16(p, packageEnd-p);
5197         p = packageEnd+1;
5198     } else {
5199         if (!defPackage) {
5200             if (outErrorMsg) {
5201                 *outErrorMsg = "No resource package specified";
5202             }
5203             return false;
5204         }
5205         *outPackage = *defPackage;
5206     }
5207     if (typeEnd) {
5208         *outType = String16(p, typeEnd-p);
5209         p = typeEnd+1;
5210     } else {
5211         if (!defType) {
5212             if (outErrorMsg) {
5213                 *outErrorMsg = "No resource type specified";
5214             }
5215             return false;
5216         }
5217         *outType = *defType;
5218     }
5219     *outName = String16(p, end-p);
5220     if(**outPackage == 0) {
5221         if(outErrorMsg) {
5222             *outErrorMsg = "Resource package cannot be an empty string";
5223         }
5224         return false;
5225     }
5226     if(**outType == 0) {
5227         if(outErrorMsg) {
5228             *outErrorMsg = "Resource type cannot be an empty string";
5229         }
5230         return false;
5231     }
5232     if(**outName == 0) {
5233         if(outErrorMsg) {
5234             *outErrorMsg = "Resource id cannot be an empty string";
5235         }
5236         return false;
5237     }
5238     return true;
5239 }
5240 
get_hex(char c,bool * outError)5241 static uint32_t get_hex(char c, bool* outError)
5242 {
5243     if (c >= '0' && c <= '9') {
5244         return c - '0';
5245     } else if (c >= 'a' && c <= 'f') {
5246         return c - 'a' + 0xa;
5247     } else if (c >= 'A' && c <= 'F') {
5248         return c - 'A' + 0xa;
5249     }
5250     *outError = true;
5251     return 0;
5252 }
5253 
5254 struct unit_entry
5255 {
5256     const char* name;
5257     size_t len;
5258     uint8_t type;
5259     uint32_t unit;
5260     float scale;
5261 };
5262 
5263 static const unit_entry unitNames[] = {
5264     { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
5265     { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
5266     { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
5267     { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
5268     { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
5269     { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
5270     { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
5271     { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
5272     { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
5273     { NULL, 0, 0, 0, 0 }
5274 };
5275 
parse_unit(const char * str,Res_value * outValue,float * outScale,const char ** outEnd)5276 static bool parse_unit(const char* str, Res_value* outValue,
5277                        float* outScale, const char** outEnd)
5278 {
5279     const char* end = str;
5280     while (*end != 0 && !isspace((unsigned char)*end)) {
5281         end++;
5282     }
5283     const size_t len = end-str;
5284 
5285     const char* realEnd = end;
5286     while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
5287         realEnd++;
5288     }
5289     if (*realEnd != 0) {
5290         return false;
5291     }
5292 
5293     const unit_entry* cur = unitNames;
5294     while (cur->name) {
5295         if (len == cur->len && strncmp(cur->name, str, len) == 0) {
5296             outValue->dataType = cur->type;
5297             outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
5298             *outScale = cur->scale;
5299             *outEnd = end;
5300             //printf("Found unit %s for %s\n", cur->name, str);
5301             return true;
5302         }
5303         cur++;
5304     }
5305 
5306     return false;
5307 }
5308 
U16StringToInt(const char16_t * s,size_t len,Res_value * outValue)5309 bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue)
5310 {
5311     while (len > 0 && isspace16(*s)) {
5312         s++;
5313         len--;
5314     }
5315 
5316     if (len <= 0) {
5317         return false;
5318     }
5319 
5320     size_t i = 0;
5321     int64_t val = 0;
5322     bool neg = false;
5323 
5324     if (*s == '-') {
5325         neg = true;
5326         i++;
5327     }
5328 
5329     if (s[i] < '0' || s[i] > '9') {
5330         return false;
5331     }
5332 
5333     static_assert(std::is_same<uint32_t, Res_value::data_type>::value,
5334                   "Res_value::data_type has changed. The range checks in this "
5335                   "function are no longer correct.");
5336 
5337     // Decimal or hex?
5338     bool isHex;
5339     if (len > 1 && s[i] == '0' && s[i+1] == 'x') {
5340         isHex = true;
5341         i += 2;
5342 
5343         if (neg) {
5344             return false;
5345         }
5346 
5347         if (i == len) {
5348             // Just u"0x"
5349             return false;
5350         }
5351 
5352         bool error = false;
5353         while (i < len && !error) {
5354             val = (val*16) + get_hex(s[i], &error);
5355             i++;
5356 
5357             if (val > std::numeric_limits<uint32_t>::max()) {
5358                 return false;
5359             }
5360         }
5361         if (error) {
5362             return false;
5363         }
5364     } else {
5365         isHex = false;
5366         while (i < len) {
5367             if (s[i] < '0' || s[i] > '9') {
5368                 return false;
5369             }
5370             val = (val*10) + s[i]-'0';
5371             i++;
5372 
5373             if ((neg && -val < std::numeric_limits<int32_t>::min()) ||
5374                 (!neg && val > std::numeric_limits<int32_t>::max())) {
5375                 return false;
5376             }
5377         }
5378     }
5379 
5380     if (neg) val = -val;
5381 
5382     while (i < len && isspace16(s[i])) {
5383         i++;
5384     }
5385 
5386     if (i != len) {
5387         return false;
5388     }
5389 
5390     if (outValue) {
5391         outValue->dataType =
5392             isHex ? outValue->TYPE_INT_HEX : outValue->TYPE_INT_DEC;
5393         outValue->data = static_cast<Res_value::data_type>(val);
5394     }
5395     return true;
5396 }
5397 
stringToInt(const char16_t * s,size_t len,Res_value * outValue)5398 bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
5399 {
5400     return U16StringToInt(s, len, outValue);
5401 }
5402 
stringToFloat(const char16_t * s,size_t len,Res_value * outValue)5403 bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
5404 {
5405     while (len > 0 && isspace16(*s)) {
5406         s++;
5407         len--;
5408     }
5409 
5410     if (len <= 0) {
5411         return false;
5412     }
5413 
5414     char buf[128];
5415     int i=0;
5416     while (len > 0 && *s != 0 && i < 126) {
5417         if (*s > 255) {
5418             return false;
5419         }
5420         buf[i++] = *s++;
5421         len--;
5422     }
5423 
5424     if (len > 0) {
5425         return false;
5426     }
5427     if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
5428         return false;
5429     }
5430 
5431     buf[i] = 0;
5432     const char* end;
5433     float f = strtof(buf, (char**)&end);
5434 
5435     if (*end != 0 && !isspace((unsigned char)*end)) {
5436         // Might be a unit...
5437         float scale;
5438         if (parse_unit(end, outValue, &scale, &end)) {
5439             f *= scale;
5440             const bool neg = f < 0;
5441             if (neg) f = -f;
5442             uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
5443             uint32_t radix;
5444             uint32_t shift;
5445             if ((bits&0x7fffff) == 0) {
5446                 // Always use 23p0 if there is no fraction, just to make
5447                 // things easier to read.
5448                 radix = Res_value::COMPLEX_RADIX_23p0;
5449                 shift = 23;
5450             } else if ((bits&0xffffffffff800000LL) == 0) {
5451                 // Magnitude is zero -- can fit in 0 bits of precision.
5452                 radix = Res_value::COMPLEX_RADIX_0p23;
5453                 shift = 0;
5454             } else if ((bits&0xffffffff80000000LL) == 0) {
5455                 // Magnitude can fit in 8 bits of precision.
5456                 radix = Res_value::COMPLEX_RADIX_8p15;
5457                 shift = 8;
5458             } else if ((bits&0xffffff8000000000LL) == 0) {
5459                 // Magnitude can fit in 16 bits of precision.
5460                 radix = Res_value::COMPLEX_RADIX_16p7;
5461                 shift = 16;
5462             } else {
5463                 // Magnitude needs entire range, so no fractional part.
5464                 radix = Res_value::COMPLEX_RADIX_23p0;
5465                 shift = 23;
5466             }
5467             int32_t mantissa = (int32_t)(
5468                 (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
5469             if (neg) {
5470                 mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
5471             }
5472             outValue->data |=
5473                 (radix<<Res_value::COMPLEX_RADIX_SHIFT)
5474                 | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
5475             //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
5476             //       f * (neg ? -1 : 1), bits, f*(1<<23),
5477             //       radix, shift, outValue->data);
5478             return true;
5479         }
5480         return false;
5481     }
5482 
5483     while (*end != 0 && isspace((unsigned char)*end)) {
5484         end++;
5485     }
5486 
5487     if (*end == 0) {
5488         if (outValue) {
5489             outValue->dataType = outValue->TYPE_FLOAT;
5490             *(float*)(&outValue->data) = f;
5491             return true;
5492         }
5493     }
5494 
5495     return false;
5496 }
5497 
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) const5498 bool ResTable::stringToValue(Res_value* outValue, String16* outString,
5499                              const char16_t* s, size_t len,
5500                              bool preserveSpaces, bool coerceType,
5501                              uint32_t attrID,
5502                              const String16* defType,
5503                              const String16* defPackage,
5504                              Accessor* accessor,
5505                              void* accessorCookie,
5506                              uint32_t attrType,
5507                              bool enforcePrivate) const
5508 {
5509     bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
5510     const char* errorMsg = NULL;
5511 
5512     outValue->size = sizeof(Res_value);
5513     outValue->res0 = 0;
5514 
5515     // First strip leading/trailing whitespace.  Do this before handling
5516     // escapes, so they can be used to force whitespace into the string.
5517     if (!preserveSpaces) {
5518         while (len > 0 && isspace16(*s)) {
5519             s++;
5520             len--;
5521         }
5522         while (len > 0 && isspace16(s[len-1])) {
5523             len--;
5524         }
5525         // If the string ends with '\', then we keep the space after it.
5526         if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
5527             len++;
5528         }
5529     }
5530 
5531     //printf("Value for: %s\n", String8(s, len).string());
5532 
5533     uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
5534     uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
5535     bool fromAccessor = false;
5536     if (attrID != 0 && !Res_INTERNALID(attrID)) {
5537         const ssize_t p = getResourcePackageIndex(attrID);
5538         const bag_entry* bag;
5539         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
5540         //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
5541         if (cnt >= 0) {
5542             while (cnt > 0) {
5543                 //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
5544                 switch (bag->map.name.ident) {
5545                 case ResTable_map::ATTR_TYPE:
5546                     attrType = bag->map.value.data;
5547                     break;
5548                 case ResTable_map::ATTR_MIN:
5549                     attrMin = bag->map.value.data;
5550                     break;
5551                 case ResTable_map::ATTR_MAX:
5552                     attrMax = bag->map.value.data;
5553                     break;
5554                 case ResTable_map::ATTR_L10N:
5555                     l10nReq = bag->map.value.data;
5556                     break;
5557                 }
5558                 bag++;
5559                 cnt--;
5560             }
5561             unlockBag(bag);
5562         } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
5563             fromAccessor = true;
5564             if (attrType == ResTable_map::TYPE_ENUM
5565                     || attrType == ResTable_map::TYPE_FLAGS
5566                     || attrType == ResTable_map::TYPE_INTEGER) {
5567                 accessor->getAttributeMin(attrID, &attrMin);
5568                 accessor->getAttributeMax(attrID, &attrMax);
5569             }
5570             if (localizationSetting) {
5571                 l10nReq = accessor->getAttributeL10N(attrID);
5572             }
5573         }
5574     }
5575 
5576     const bool canStringCoerce =
5577         coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
5578 
5579     if (*s == '@') {
5580         outValue->dataType = outValue->TYPE_REFERENCE;
5581 
5582         // Note: we don't check attrType here because the reference can
5583         // be to any other type; we just need to count on the client making
5584         // sure the referenced type is correct.
5585 
5586         //printf("Looking up ref: %s\n", String8(s, len).string());
5587 
5588         // It's a reference!
5589         if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
5590             // Special case @null as undefined. This will be converted by
5591             // AssetManager to TYPE_NULL with data DATA_NULL_UNDEFINED.
5592             outValue->data = 0;
5593             return true;
5594         } else if (len == 6 && s[1]=='e' && s[2]=='m' && s[3]=='p' && s[4]=='t' && s[5]=='y') {
5595             // Special case @empty as explicitly defined empty value.
5596             outValue->dataType = Res_value::TYPE_NULL;
5597             outValue->data = Res_value::DATA_NULL_EMPTY;
5598             return true;
5599         } else {
5600             bool createIfNotFound = false;
5601             const char16_t* resourceRefName;
5602             int resourceNameLen;
5603             if (len > 2 && s[1] == '+') {
5604                 createIfNotFound = true;
5605                 resourceRefName = s + 2;
5606                 resourceNameLen = len - 2;
5607             } else if (len > 2 && s[1] == '*') {
5608                 enforcePrivate = false;
5609                 resourceRefName = s + 2;
5610                 resourceNameLen = len - 2;
5611             } else {
5612                 createIfNotFound = false;
5613                 resourceRefName = s + 1;
5614                 resourceNameLen = len - 1;
5615             }
5616             String16 package, type, name;
5617             if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
5618                                    defType, defPackage, &errorMsg)) {
5619                 if (accessor != NULL) {
5620                     accessor->reportError(accessorCookie, errorMsg);
5621                 }
5622                 return false;
5623             }
5624 
5625             uint32_t specFlags = 0;
5626             uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
5627                     type.size(), package.string(), package.size(), &specFlags);
5628             if (rid != 0) {
5629                 if (enforcePrivate) {
5630                     if (accessor == NULL || accessor->getAssetsPackage() != package) {
5631                         if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
5632                             if (accessor != NULL) {
5633                                 accessor->reportError(accessorCookie, "Resource is not public.");
5634                             }
5635                             return false;
5636                         }
5637                     }
5638                 }
5639 
5640                 if (accessor) {
5641                     rid = Res_MAKEID(
5642                         accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
5643                         Res_GETTYPE(rid), Res_GETENTRY(rid));
5644                     if (kDebugTableNoisy) {
5645                         ALOGI("Incl %s:%s/%s: 0x%08x\n",
5646                                 String8(package).string(), String8(type).string(),
5647                                 String8(name).string(), rid);
5648                     }
5649                 }
5650 
5651                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5652                 if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
5653                     outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
5654                 }
5655                 outValue->data = rid;
5656                 return true;
5657             }
5658 
5659             if (accessor) {
5660                 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
5661                                                                        createIfNotFound);
5662                 if (rid != 0) {
5663                     if (kDebugTableNoisy) {
5664                         ALOGI("Pckg %s:%s/%s: 0x%08x\n",
5665                                 String8(package).string(), String8(type).string(),
5666                                 String8(name).string(), rid);
5667                     }
5668                     uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5669                     if (packageId == 0x00) {
5670                         outValue->data = rid;
5671                         outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
5672                         return true;
5673                     } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
5674                         // We accept packageId's generated as 0x01 in order to support
5675                         // building the android system resources
5676                         outValue->data = rid;
5677                         return true;
5678                     }
5679                 }
5680             }
5681         }
5682 
5683         if (accessor != NULL) {
5684             accessor->reportError(accessorCookie, "No resource found that matches the given name");
5685         }
5686         return false;
5687     }
5688 
5689     // if we got to here, and localization is required and it's not a reference,
5690     // complain and bail.
5691     if (l10nReq == ResTable_map::L10N_SUGGESTED) {
5692         if (localizationSetting) {
5693             if (accessor != NULL) {
5694                 accessor->reportError(accessorCookie, "This attribute must be localized.");
5695             }
5696         }
5697     }
5698 
5699     if (*s == '#') {
5700         // It's a color!  Convert to an integer of the form 0xaarrggbb.
5701         uint32_t color = 0;
5702         bool error = false;
5703         if (len == 4) {
5704             outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
5705             color |= 0xFF000000;
5706             color |= get_hex(s[1], &error) << 20;
5707             color |= get_hex(s[1], &error) << 16;
5708             color |= get_hex(s[2], &error) << 12;
5709             color |= get_hex(s[2], &error) << 8;
5710             color |= get_hex(s[3], &error) << 4;
5711             color |= get_hex(s[3], &error);
5712         } else if (len == 5) {
5713             outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
5714             color |= get_hex(s[1], &error) << 28;
5715             color |= get_hex(s[1], &error) << 24;
5716             color |= get_hex(s[2], &error) << 20;
5717             color |= get_hex(s[2], &error) << 16;
5718             color |= get_hex(s[3], &error) << 12;
5719             color |= get_hex(s[3], &error) << 8;
5720             color |= get_hex(s[4], &error) << 4;
5721             color |= get_hex(s[4], &error);
5722         } else if (len == 7) {
5723             outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
5724             color |= 0xFF000000;
5725             color |= get_hex(s[1], &error) << 20;
5726             color |= get_hex(s[2], &error) << 16;
5727             color |= get_hex(s[3], &error) << 12;
5728             color |= get_hex(s[4], &error) << 8;
5729             color |= get_hex(s[5], &error) << 4;
5730             color |= get_hex(s[6], &error);
5731         } else if (len == 9) {
5732             outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
5733             color |= get_hex(s[1], &error) << 28;
5734             color |= get_hex(s[2], &error) << 24;
5735             color |= get_hex(s[3], &error) << 20;
5736             color |= get_hex(s[4], &error) << 16;
5737             color |= get_hex(s[5], &error) << 12;
5738             color |= get_hex(s[6], &error) << 8;
5739             color |= get_hex(s[7], &error) << 4;
5740             color |= get_hex(s[8], &error);
5741         } else {
5742             error = true;
5743         }
5744         if (!error) {
5745             if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
5746                 if (!canStringCoerce) {
5747                     if (accessor != NULL) {
5748                         accessor->reportError(accessorCookie,
5749                                 "Color types not allowed");
5750                     }
5751                     return false;
5752                 }
5753             } else {
5754                 outValue->data = color;
5755                 //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
5756                 return true;
5757             }
5758         } else {
5759             if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
5760                 if (accessor != NULL) {
5761                     accessor->reportError(accessorCookie, "Color value not valid --"
5762                             " must be #rgb, #argb, #rrggbb, or #aarrggbb");
5763                 }
5764                 #if 0
5765                 fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
5766                         "Resource File", //(const char*)in->getPrintableSource(),
5767                         String8(*curTag).string(),
5768                         String8(s, len).string());
5769                 #endif
5770                 return false;
5771             }
5772         }
5773     }
5774 
5775     if (*s == '?') {
5776         outValue->dataType = outValue->TYPE_ATTRIBUTE;
5777 
5778         // Note: we don't check attrType here because the reference can
5779         // be to any other type; we just need to count on the client making
5780         // sure the referenced type is correct.
5781 
5782         //printf("Looking up attr: %s\n", String8(s, len).string());
5783 
5784         static const String16 attr16("attr");
5785         String16 package, type, name;
5786         if (!expandResourceRef(s+1, len-1, &package, &type, &name,
5787                                &attr16, defPackage, &errorMsg)) {
5788             if (accessor != NULL) {
5789                 accessor->reportError(accessorCookie, errorMsg);
5790             }
5791             return false;
5792         }
5793 
5794         //printf("Pkg: %s, Type: %s, Name: %s\n",
5795         //       String8(package).string(), String8(type).string(),
5796         //       String8(name).string());
5797         uint32_t specFlags = 0;
5798         uint32_t rid =
5799             identifierForName(name.string(), name.size(),
5800                               type.string(), type.size(),
5801                               package.string(), package.size(), &specFlags);
5802         if (rid != 0) {
5803             if (enforcePrivate) {
5804                 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
5805                     if (accessor != NULL) {
5806                         accessor->reportError(accessorCookie, "Attribute is not public.");
5807                     }
5808                     return false;
5809                 }
5810             }
5811 
5812             if (accessor) {
5813                 rid = Res_MAKEID(
5814                     accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
5815                     Res_GETTYPE(rid), Res_GETENTRY(rid));
5816             }
5817 
5818             uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5819             if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
5820                 outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
5821             }
5822             outValue->data = rid;
5823             return true;
5824         }
5825 
5826         if (accessor) {
5827             uint32_t rid = accessor->getCustomResource(package, type, name);
5828             if (rid != 0) {
5829                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5830                 if (packageId == 0x00) {
5831                     outValue->data = rid;
5832                     outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
5833                     return true;
5834                 } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
5835                     // We accept packageId's generated as 0x01 in order to support
5836                     // building the android system resources
5837                     outValue->data = rid;
5838                     return true;
5839                 }
5840             }
5841         }
5842 
5843         if (accessor != NULL) {
5844             accessor->reportError(accessorCookie, "No resource found that matches the given name");
5845         }
5846         return false;
5847     }
5848 
5849     if (stringToInt(s, len, outValue)) {
5850         if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
5851             // If this type does not allow integers, but does allow floats,
5852             // fall through on this error case because the float type should
5853             // be able to accept any integer value.
5854             if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
5855                 if (accessor != NULL) {
5856                     accessor->reportError(accessorCookie, "Integer types not allowed");
5857                 }
5858                 return false;
5859             }
5860         } else {
5861             if (((int32_t)outValue->data) < ((int32_t)attrMin)
5862                     || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
5863                 if (accessor != NULL) {
5864                     accessor->reportError(accessorCookie, "Integer value out of range");
5865                 }
5866                 return false;
5867             }
5868             return true;
5869         }
5870     }
5871 
5872     if (stringToFloat(s, len, outValue)) {
5873         if (outValue->dataType == Res_value::TYPE_DIMENSION) {
5874             if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
5875                 return true;
5876             }
5877             if (!canStringCoerce) {
5878                 if (accessor != NULL) {
5879                     accessor->reportError(accessorCookie, "Dimension types not allowed");
5880                 }
5881                 return false;
5882             }
5883         } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
5884             if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
5885                 return true;
5886             }
5887             if (!canStringCoerce) {
5888                 if (accessor != NULL) {
5889                     accessor->reportError(accessorCookie, "Fraction types not allowed");
5890                 }
5891                 return false;
5892             }
5893         } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
5894             if (!canStringCoerce) {
5895                 if (accessor != NULL) {
5896                     accessor->reportError(accessorCookie, "Float types not allowed");
5897                 }
5898                 return false;
5899             }
5900         } else {
5901             return true;
5902         }
5903     }
5904 
5905     if (len == 4) {
5906         if ((s[0] == 't' || s[0] == 'T') &&
5907             (s[1] == 'r' || s[1] == 'R') &&
5908             (s[2] == 'u' || s[2] == 'U') &&
5909             (s[3] == 'e' || s[3] == 'E')) {
5910             if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
5911                 if (!canStringCoerce) {
5912                     if (accessor != NULL) {
5913                         accessor->reportError(accessorCookie, "Boolean types not allowed");
5914                     }
5915                     return false;
5916                 }
5917             } else {
5918                 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
5919                 outValue->data = (uint32_t)-1;
5920                 return true;
5921             }
5922         }
5923     }
5924 
5925     if (len == 5) {
5926         if ((s[0] == 'f' || s[0] == 'F') &&
5927             (s[1] == 'a' || s[1] == 'A') &&
5928             (s[2] == 'l' || s[2] == 'L') &&
5929             (s[3] == 's' || s[3] == 'S') &&
5930             (s[4] == 'e' || s[4] == 'E')) {
5931             if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
5932                 if (!canStringCoerce) {
5933                     if (accessor != NULL) {
5934                         accessor->reportError(accessorCookie, "Boolean types not allowed");
5935                     }
5936                     return false;
5937                 }
5938             } else {
5939                 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
5940                 outValue->data = 0;
5941                 return true;
5942             }
5943         }
5944     }
5945 
5946     if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
5947         const ssize_t p = getResourcePackageIndex(attrID);
5948         const bag_entry* bag;
5949         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
5950         //printf("Got %d for enum\n", cnt);
5951         if (cnt >= 0) {
5952             resource_name rname;
5953             while (cnt > 0) {
5954                 if (!Res_INTERNALID(bag->map.name.ident)) {
5955                     //printf("Trying attr #%08x\n", bag->map.name.ident);
5956                     if (getResourceName(bag->map.name.ident, false, &rname)) {
5957                         #if 0
5958                         printf("Matching %s against %s (0x%08x)\n",
5959                                String8(s, len).string(),
5960                                String8(rname.name, rname.nameLen).string(),
5961                                bag->map.name.ident);
5962                         #endif
5963                         if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
5964                             outValue->dataType = bag->map.value.dataType;
5965                             outValue->data = bag->map.value.data;
5966                             unlockBag(bag);
5967                             return true;
5968                         }
5969                     }
5970 
5971                 }
5972                 bag++;
5973                 cnt--;
5974             }
5975             unlockBag(bag);
5976         }
5977 
5978         if (fromAccessor) {
5979             if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
5980                 return true;
5981             }
5982         }
5983     }
5984 
5985     if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
5986         const ssize_t p = getResourcePackageIndex(attrID);
5987         const bag_entry* bag;
5988         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
5989         //printf("Got %d for flags\n", cnt);
5990         if (cnt >= 0) {
5991             bool failed = false;
5992             resource_name rname;
5993             outValue->dataType = Res_value::TYPE_INT_HEX;
5994             outValue->data = 0;
5995             const char16_t* end = s + len;
5996             const char16_t* pos = s;
5997             while (pos < end && !failed) {
5998                 const char16_t* start = pos;
5999                 pos++;
6000                 while (pos < end && *pos != '|') {
6001                     pos++;
6002                 }
6003                 //printf("Looking for: %s\n", String8(start, pos-start).string());
6004                 const bag_entry* bagi = bag;
6005                 ssize_t i;
6006                 for (i=0; i<cnt; i++, bagi++) {
6007                     if (!Res_INTERNALID(bagi->map.name.ident)) {
6008                         //printf("Trying attr #%08x\n", bagi->map.name.ident);
6009                         if (getResourceName(bagi->map.name.ident, false, &rname)) {
6010                             #if 0
6011                             printf("Matching %s against %s (0x%08x)\n",
6012                                    String8(start,pos-start).string(),
6013                                    String8(rname.name, rname.nameLen).string(),
6014                                    bagi->map.name.ident);
6015                             #endif
6016                             if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
6017                                 outValue->data |= bagi->map.value.data;
6018                                 break;
6019                             }
6020                         }
6021                     }
6022                 }
6023                 if (i >= cnt) {
6024                     // Didn't find this flag identifier.
6025                     failed = true;
6026                 }
6027                 if (pos < end) {
6028                     pos++;
6029                 }
6030             }
6031             unlockBag(bag);
6032             if (!failed) {
6033                 //printf("Final flag value: 0x%lx\n", outValue->data);
6034                 return true;
6035             }
6036         }
6037 
6038 
6039         if (fromAccessor) {
6040             if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
6041                 //printf("Final flag value: 0x%lx\n", outValue->data);
6042                 return true;
6043             }
6044         }
6045     }
6046 
6047     if ((attrType&ResTable_map::TYPE_STRING) == 0) {
6048         if (accessor != NULL) {
6049             accessor->reportError(accessorCookie, "String types not allowed");
6050         }
6051         return false;
6052     }
6053 
6054     // Generic string handling...
6055     outValue->dataType = outValue->TYPE_STRING;
6056     if (outString) {
6057         bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
6058         if (accessor != NULL) {
6059             accessor->reportError(accessorCookie, errorMsg);
6060         }
6061         return failed;
6062     }
6063 
6064     return true;
6065 }
6066 
collectString(String16 * outString,const char16_t * s,size_t len,bool preserveSpaces,const char ** outErrorMsg,bool append)6067 bool ResTable::collectString(String16* outString,
6068                              const char16_t* s, size_t len,
6069                              bool preserveSpaces,
6070                              const char** outErrorMsg,
6071                              bool append)
6072 {
6073     String16 tmp;
6074 
6075     char quoted = 0;
6076     const char16_t* p = s;
6077     while (p < (s+len)) {
6078         while (p < (s+len)) {
6079             const char16_t c = *p;
6080             if (c == '\\') {
6081                 break;
6082             }
6083             if (!preserveSpaces) {
6084                 if (quoted == 0 && isspace16(c)
6085                     && (c != ' ' || isspace16(*(p+1)))) {
6086                     break;
6087                 }
6088                 if (c == '"' && (quoted == 0 || quoted == '"')) {
6089                     break;
6090                 }
6091                 if (c == '\'' && (quoted == 0 || quoted == '\'')) {
6092                     /*
6093                      * In practice, when people write ' instead of \'
6094                      * in a string, they are doing it by accident
6095                      * instead of really meaning to use ' as a quoting
6096                      * character.  Warn them so they don't lose it.
6097                      */
6098                     if (outErrorMsg) {
6099                         *outErrorMsg = "Apostrophe not preceded by \\";
6100                     }
6101                     return false;
6102                 }
6103             }
6104             p++;
6105         }
6106         if (p < (s+len)) {
6107             if (p > s) {
6108                 tmp.append(String16(s, p-s));
6109             }
6110             if (!preserveSpaces && (*p == '"' || *p == '\'')) {
6111                 if (quoted == 0) {
6112                     quoted = *p;
6113                 } else {
6114                     quoted = 0;
6115                 }
6116                 p++;
6117             } else if (!preserveSpaces && isspace16(*p)) {
6118                 // Space outside of a quote -- consume all spaces and
6119                 // leave a single plain space char.
6120                 tmp.append(String16(" "));
6121                 p++;
6122                 while (p < (s+len) && isspace16(*p)) {
6123                     p++;
6124                 }
6125             } else if (*p == '\\') {
6126                 p++;
6127                 if (p < (s+len)) {
6128                     switch (*p) {
6129                     case 't':
6130                         tmp.append(String16("\t"));
6131                         break;
6132                     case 'n':
6133                         tmp.append(String16("\n"));
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 '\\':
6151                         tmp.append(String16("\\"));
6152                         break;
6153                     case 'u':
6154                     {
6155                         char16_t chr = 0;
6156                         int i = 0;
6157                         while (i < 4 && p[1] != 0) {
6158                             p++;
6159                             i++;
6160                             int c;
6161                             if (*p >= '0' && *p <= '9') {
6162                                 c = *p - '0';
6163                             } else if (*p >= 'a' && *p <= 'f') {
6164                                 c = *p - 'a' + 10;
6165                             } else if (*p >= 'A' && *p <= 'F') {
6166                                 c = *p - 'A' + 10;
6167                             } else {
6168                                 if (outErrorMsg) {
6169                                     *outErrorMsg = "Bad character in \\u unicode escape sequence";
6170                                 }
6171                                 return false;
6172                             }
6173                             chr = (chr<<4) | c;
6174                         }
6175                         tmp.append(String16(&chr, 1));
6176                     } break;
6177                     default:
6178                         // ignore unknown escape chars.
6179                         break;
6180                     }
6181                     p++;
6182                 }
6183             }
6184             len -= (p-s);
6185             s = p;
6186         }
6187     }
6188 
6189     if (tmp.size() != 0) {
6190         if (len > 0) {
6191             tmp.append(String16(s, len));
6192         }
6193         if (append) {
6194             outString->append(tmp);
6195         } else {
6196             outString->setTo(tmp);
6197         }
6198     } else {
6199         if (append) {
6200             outString->append(String16(s, len));
6201         } else {
6202             outString->setTo(s, len);
6203         }
6204     }
6205 
6206     return true;
6207 }
6208 
getBasePackageCount() const6209 size_t ResTable::getBasePackageCount() const
6210 {
6211     if (mError != NO_ERROR) {
6212         return 0;
6213     }
6214     return mPackageGroups.size();
6215 }
6216 
getBasePackageName(size_t idx) const6217 const String16 ResTable::getBasePackageName(size_t idx) const
6218 {
6219     if (mError != NO_ERROR) {
6220         return String16();
6221     }
6222     LOG_FATAL_IF(idx >= mPackageGroups.size(),
6223                  "Requested package index %d past package count %d",
6224                  (int)idx, (int)mPackageGroups.size());
6225     return mPackageGroups[idx]->name;
6226 }
6227 
getBasePackageId(size_t idx) const6228 uint32_t ResTable::getBasePackageId(size_t idx) const
6229 {
6230     if (mError != NO_ERROR) {
6231         return 0;
6232     }
6233     LOG_FATAL_IF(idx >= mPackageGroups.size(),
6234                  "Requested package index %d past package count %d",
6235                  (int)idx, (int)mPackageGroups.size());
6236     return mPackageGroups[idx]->id;
6237 }
6238 
getLastTypeIdForPackage(size_t idx) const6239 uint32_t ResTable::getLastTypeIdForPackage(size_t idx) const
6240 {
6241     if (mError != NO_ERROR) {
6242         return 0;
6243     }
6244     LOG_FATAL_IF(idx >= mPackageGroups.size(),
6245             "Requested package index %d past package count %d",
6246             (int)idx, (int)mPackageGroups.size());
6247     const PackageGroup* const group = mPackageGroups[idx];
6248     return group->largestTypeId;
6249 }
6250 
getTableCount() const6251 size_t ResTable::getTableCount() const
6252 {
6253     return mHeaders.size();
6254 }
6255 
getTableStringBlock(size_t index) const6256 const ResStringPool* ResTable::getTableStringBlock(size_t index) const
6257 {
6258     return &mHeaders[index]->values;
6259 }
6260 
getTableCookie(size_t index) const6261 int32_t ResTable::getTableCookie(size_t index) const
6262 {
6263     return mHeaders[index]->cookie;
6264 }
6265 
getDynamicRefTableForCookie(int32_t cookie) const6266 const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) const
6267 {
6268     const size_t N = mPackageGroups.size();
6269     for (size_t i = 0; i < N; i++) {
6270         const PackageGroup* pg = mPackageGroups[i];
6271         size_t M = pg->packages.size();
6272         for (size_t j = 0; j < M; j++) {
6273             if (pg->packages[j]->header->cookie == cookie) {
6274                 return &pg->dynamicRefTable;
6275             }
6276         }
6277     }
6278     return NULL;
6279 }
6280 
compareResTableConfig(const ResTable_config & a,const ResTable_config & b)6281 static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
6282     return a.compare(b) < 0;
6283 }
6284 
6285 template <typename Func>
forEachConfiguration(bool ignoreMipmap,bool ignoreAndroidPackage,bool includeSystemConfigs,const Func & f) const6286 void ResTable::forEachConfiguration(bool ignoreMipmap, bool ignoreAndroidPackage,
6287                                     bool includeSystemConfigs, const Func& f) const {
6288     const size_t packageCount = mPackageGroups.size();
6289     const String16 android("android");
6290     for (size_t i = 0; i < packageCount; i++) {
6291         const PackageGroup* packageGroup = mPackageGroups[i];
6292         if (ignoreAndroidPackage && android == packageGroup->name) {
6293             continue;
6294         }
6295         if (!includeSystemConfigs && packageGroup->isSystemAsset) {
6296             continue;
6297         }
6298         const size_t typeCount = packageGroup->types.size();
6299         for (size_t j = 0; j < typeCount; j++) {
6300             const TypeList& typeList = packageGroup->types[j];
6301             const size_t numTypes = typeList.size();
6302             for (size_t k = 0; k < numTypes; k++) {
6303                 const Type* type = typeList[k];
6304                 const ResStringPool& typeStrings = type->package->typeStrings;
6305                 const base::expected<String8, NullOrIOError> typeStr = typeStrings.string8ObjectAt(
6306                     type->typeSpec->id - 1);
6307                 if (ignoreMipmap && typeStr.has_value() && *typeStr == "mipmap") {
6308                     continue;
6309                 }
6310 
6311                 const size_t numConfigs = type->configs.size();
6312                 for (size_t m = 0; m < numConfigs; m++) {
6313                     const ResTable_type* config = type->configs[m];
6314                     ResTable_config cfg;
6315                     memset(&cfg, 0, sizeof(ResTable_config));
6316                     cfg.copyFromDtoH(config->config);
6317 
6318                     f(cfg);
6319                 }
6320             }
6321         }
6322     }
6323 }
6324 
getConfigurations(Vector<ResTable_config> * configs,bool ignoreMipmap,bool ignoreAndroidPackage,bool includeSystemConfigs) const6325 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
6326                                  bool ignoreAndroidPackage, bool includeSystemConfigs) const {
6327     auto func = [&](const ResTable_config& cfg) {
6328         const auto beginIter = configs->begin();
6329         const auto endIter = configs->end();
6330 
6331         auto iter = std::lower_bound(beginIter, endIter, cfg, compareResTableConfig);
6332         if (iter == endIter || iter->compare(cfg) != 0) {
6333             configs->insertAt(cfg, std::distance(beginIter, iter));
6334         }
6335     };
6336     forEachConfiguration(ignoreMipmap, ignoreAndroidPackage, includeSystemConfigs, func);
6337 }
6338 
compareString8AndCString(const String8 & str,const char * cStr)6339 static bool compareString8AndCString(const String8& str, const char* cStr) {
6340     return strcmp(str.string(), cStr) < 0;
6341 }
6342 
getLocales(Vector<String8> * locales,bool includeSystemLocales,bool mergeEquivalentLangs) const6343 void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales,
6344                           bool mergeEquivalentLangs) const {
6345     char locale[RESTABLE_MAX_LOCALE_LEN];
6346 
6347     forEachConfiguration(false, false, includeSystemLocales, [&](const ResTable_config& cfg) {
6348         cfg.getBcp47Locale(locale, mergeEquivalentLangs /* canonicalize if merging */);
6349 
6350         const auto beginIter = locales->begin();
6351         const auto endIter = locales->end();
6352 
6353         auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
6354         if (iter == endIter || strcmp(iter->string(), locale) != 0) {
6355             locales->insertAt(String8(locale), std::distance(beginIter, iter));
6356         }
6357     });
6358 }
6359 
StringPoolRef(const ResStringPool * pool,uint32_t index)6360 StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
6361     : mPool(pool), mIndex(index) {}
6362 
string8() const6363 base::expected<StringPiece, NullOrIOError> StringPoolRef::string8() const {
6364     if (LIKELY(mPool != NULL)) {
6365         return mPool->string8At(mIndex);
6366     }
6367     return base::unexpected(std::nullopt);
6368 }
6369 
string16() const6370 base::expected<StringPiece16, NullOrIOError> StringPoolRef::string16() const {
6371     if (LIKELY(mPool != NULL)) {
6372         return mPool->stringAt(mIndex);
6373     }
6374     return base::unexpected(std::nullopt);
6375 }
6376 
getResourceFlags(uint32_t resID,uint32_t * outFlags) const6377 bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
6378     if (mError != NO_ERROR) {
6379         return false;
6380     }
6381 
6382     const ssize_t p = getResourcePackageIndex(resID);
6383     const int t = Res_GETTYPE(resID);
6384     const int e = Res_GETENTRY(resID);
6385 
6386     if (p < 0) {
6387         if (Res_GETPACKAGE(resID)+1 == 0) {
6388             ALOGW("No package identifier when getting flags for resource number 0x%08x", resID);
6389         } else {
6390             ALOGW("No known package when getting flags for resource number 0x%08x", resID);
6391         }
6392         return false;
6393     }
6394     if (t < 0) {
6395         ALOGW("No type identifier when getting flags for resource number 0x%08x", resID);
6396         return false;
6397     }
6398 
6399     const PackageGroup* const grp = mPackageGroups[p];
6400     if (grp == NULL) {
6401         ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID);
6402         return false;
6403     }
6404 
6405     Entry entry;
6406     status_t err = getEntry(grp, t, e, NULL, &entry);
6407     if (err != NO_ERROR) {
6408         return false;
6409     }
6410 
6411     *outFlags = entry.specFlags;
6412     return true;
6413 }
6414 
isPackageDynamic(uint8_t packageID) const6415 bool ResTable::isPackageDynamic(uint8_t packageID) const {
6416   if (mError != NO_ERROR) {
6417       return false;
6418   }
6419   if (packageID == 0) {
6420       ALOGW("Invalid package number 0x%08x", packageID);
6421       return false;
6422   }
6423 
6424   const ssize_t p = getResourcePackageIndexFromPackage(packageID);
6425 
6426   if (p < 0) {
6427       ALOGW("Unknown package number 0x%08x", packageID);
6428       return false;
6429   }
6430 
6431   const PackageGroup* const grp = mPackageGroups[p];
6432   if (grp == NULL) {
6433       ALOGW("Bad identifier for package number 0x%08x", packageID);
6434       return false;
6435   }
6436 
6437   return grp->isDynamic;
6438 }
6439 
isResourceDynamic(uint32_t resID) const6440 bool ResTable::isResourceDynamic(uint32_t resID) const {
6441     if (mError != NO_ERROR) {
6442         return false;
6443     }
6444 
6445     const ssize_t p = getResourcePackageIndex(resID);
6446     const int t = Res_GETTYPE(resID);
6447     const int e = Res_GETENTRY(resID);
6448 
6449     if (p < 0) {
6450         if (Res_GETPACKAGE(resID)+1 == 0) {
6451             ALOGW("No package identifier for resource number 0x%08x", resID);
6452         } else {
6453             ALOGW("No known package for resource number 0x%08x", resID);
6454         }
6455         return false;
6456     }
6457     if (t < 0) {
6458         ALOGW("No type identifier for resource number 0x%08x", resID);
6459         return false;
6460     }
6461 
6462     const PackageGroup* const grp = mPackageGroups[p];
6463     if (grp == NULL) {
6464         ALOGW("Bad identifier for resource number 0x%08x", resID);
6465         return false;
6466     }
6467 
6468     Entry entry;
6469     status_t err = getEntry(grp, t, e, NULL, &entry);
6470     if (err != NO_ERROR) {
6471         return false;
6472     }
6473 
6474     return grp->isDynamic;
6475 }
6476 
keyCompare(const ResTable_sparseTypeEntry & entry,uint16_t entryIdx)6477 static bool keyCompare(const ResTable_sparseTypeEntry& entry , uint16_t entryIdx) {
6478   return dtohs(entry.idx) < entryIdx;
6479 }
6480 
getEntry(const PackageGroup * packageGroup,int typeIndex,int entryIndex,const ResTable_config * config,Entry * outEntry) const6481 status_t ResTable::getEntry(
6482         const PackageGroup* packageGroup, int typeIndex, int entryIndex,
6483         const ResTable_config* config,
6484         Entry* outEntry) const
6485 {
6486     const TypeList& typeList = packageGroup->types[typeIndex];
6487     if (typeList.isEmpty()) {
6488         ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
6489         return BAD_TYPE;
6490     }
6491 
6492     const ResTable_type* bestType = NULL;
6493     uint32_t bestOffset = ResTable_type::NO_ENTRY;
6494     const Package* bestPackage = NULL;
6495     uint32_t specFlags = 0;
6496     uint8_t actualTypeIndex = typeIndex;
6497     ResTable_config bestConfig;
6498     memset(&bestConfig, 0, sizeof(bestConfig));
6499 
6500     // Iterate over the Types of each package.
6501     const size_t typeCount = typeList.size();
6502     for (size_t i = 0; i < typeCount; i++) {
6503         const Type* const typeSpec = typeList[i];
6504 
6505         int realEntryIndex = entryIndex;
6506         int realTypeIndex = typeIndex;
6507         bool currentTypeIsOverlay = false;
6508 
6509         // Runtime overlay packages provide a mapping of app resource
6510         // ID to package resource ID.
6511         if (typeSpec->idmapEntries.hasEntries()) {
6512             uint16_t overlayEntryIndex;
6513             if (typeSpec->idmapEntries.lookup(entryIndex, &overlayEntryIndex) != NO_ERROR) {
6514                 // No such mapping exists
6515                 continue;
6516             }
6517             realEntryIndex = overlayEntryIndex;
6518             realTypeIndex = typeSpec->idmapEntries.overlayTypeId() - 1;
6519             currentTypeIsOverlay = true;
6520         }
6521 
6522         // Check that the entry idx is within range of the declared entry count (ResTable_typeSpec).
6523         // Particular types (ResTable_type) may be encoded with sparse entries, and so their
6524         // entryCount do not need to match.
6525         if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) {
6526             ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
6527                     Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex),
6528                     entryIndex, static_cast<int>(typeSpec->entryCount));
6529             // We should normally abort here, but some legacy apps declare
6530             // resources in the 'android' package (old bug in AAPT).
6531             continue;
6532         }
6533 
6534         // Aggregate all the flags for each package that defines this entry.
6535         if (typeSpec->typeSpecFlags != NULL) {
6536             specFlags |= dtohl(typeSpec->typeSpecFlags[realEntryIndex]);
6537         } else {
6538             specFlags = -1;
6539         }
6540 
6541         const Vector<const ResTable_type*>* candidateConfigs = &typeSpec->configs;
6542 
6543         std::shared_ptr<Vector<const ResTable_type*>> filteredConfigs;
6544         if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) {
6545             // Grab the lock first so we can safely get the current filtered list.
6546             AutoMutex _lock(mFilteredConfigLock);
6547 
6548             // This configuration is equal to the one we have previously cached for,
6549             // so use the filtered configs.
6550 
6551             const TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries[typeIndex];
6552             if (i < cacheEntry.filteredConfigs.size()) {
6553                 if (cacheEntry.filteredConfigs[i]) {
6554                     // Grab a reference to the shared_ptr so it doesn't get destroyed while
6555                     // going through this list.
6556                     filteredConfigs = cacheEntry.filteredConfigs[i];
6557 
6558                     // Use this filtered list.
6559                     candidateConfigs = filteredConfigs.get();
6560                 }
6561             }
6562         }
6563 
6564         const size_t numConfigs = candidateConfigs->size();
6565         for (size_t c = 0; c < numConfigs; c++) {
6566             const ResTable_type* const thisType = candidateConfigs->itemAt(c);
6567             if (thisType == NULL) {
6568                 continue;
6569             }
6570 
6571             ResTable_config thisConfig;
6572             thisConfig.copyFromDtoH(thisType->config);
6573 
6574             // Check to make sure this one is valid for the current parameters.
6575             if (config != NULL && !thisConfig.match(*config)) {
6576                 continue;
6577             }
6578 
6579             const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
6580                     reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
6581 
6582             uint32_t thisOffset;
6583 
6584             // Check if there is the desired entry in this type.
6585             if (thisType->flags & ResTable_type::FLAG_SPARSE) {
6586                 // This is encoded as a sparse map, so perform a binary search.
6587                 const ResTable_sparseTypeEntry* sparseIndices =
6588                         reinterpret_cast<const ResTable_sparseTypeEntry*>(eindex);
6589                 const ResTable_sparseTypeEntry* result = std::lower_bound(
6590                         sparseIndices, sparseIndices + dtohl(thisType->entryCount), realEntryIndex,
6591                         keyCompare);
6592                 if (result == sparseIndices + dtohl(thisType->entryCount)
6593                         || dtohs(result->idx) != realEntryIndex) {
6594                     // No entry found.
6595                     continue;
6596                 }
6597 
6598                 // Extract the offset from the entry. Each offset must be a multiple of 4
6599                 // so we store it as the real offset divided by 4.
6600                 thisOffset = dtohs(result->offset) * 4u;
6601             } else {
6602                 if (static_cast<uint32_t>(realEntryIndex) >= dtohl(thisType->entryCount)) {
6603                     // Entry does not exist.
6604                     continue;
6605                 }
6606 
6607                 thisOffset = dtohl(eindex[realEntryIndex]);
6608             }
6609 
6610             if (thisOffset == ResTable_type::NO_ENTRY) {
6611                 // There is no entry for this index and configuration.
6612                 continue;
6613             }
6614 
6615             if (bestType != NULL) {
6616                 // Check if this one is less specific than the last found.  If so,
6617                 // we will skip it.  We check starting with things we most care
6618                 // about to those we least care about.
6619                 if (!thisConfig.isBetterThan(bestConfig, config)) {
6620                     if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
6621                         continue;
6622                     }
6623                 }
6624             }
6625 
6626             bestType = thisType;
6627             bestOffset = thisOffset;
6628             bestConfig = thisConfig;
6629             bestPackage = typeSpec->package;
6630             actualTypeIndex = realTypeIndex;
6631 
6632             // If no config was specified, any type will do, so skip
6633             if (config == NULL) {
6634                 break;
6635             }
6636         }
6637     }
6638 
6639     if (bestType == NULL) {
6640         return BAD_INDEX;
6641     }
6642 
6643     bestOffset += dtohl(bestType->entriesStart);
6644 
6645     if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) {
6646         ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
6647                 bestOffset, dtohl(bestType->header.size));
6648         return BAD_TYPE;
6649     }
6650     if ((bestOffset & 0x3) != 0) {
6651         ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset);
6652         return BAD_TYPE;
6653     }
6654 
6655     const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>(
6656             reinterpret_cast<const uint8_t*>(bestType) + bestOffset);
6657     if (dtohs(entry->size) < sizeof(*entry)) {
6658         ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
6659         return BAD_TYPE;
6660     }
6661 
6662     if (outEntry != NULL) {
6663         outEntry->entry = entry;
6664         outEntry->config = bestConfig;
6665         outEntry->type = bestType;
6666         outEntry->specFlags = specFlags;
6667         outEntry->package = bestPackage;
6668         outEntry->typeStr = StringPoolRef(&bestPackage->typeStrings, actualTypeIndex - bestPackage->typeIdOffset);
6669         outEntry->keyStr = StringPoolRef(&bestPackage->keyStrings, dtohl(entry->key.index));
6670     }
6671     return NO_ERROR;
6672 }
6673 
parsePackage(const ResTable_package * const pkg,const Header * const header,bool appAsLib,bool isSystemAsset)6674 status_t ResTable::parsePackage(const ResTable_package* const pkg,
6675                                 const Header* const header, bool appAsLib, bool isSystemAsset)
6676 {
6677     const uint8_t* base = (const uint8_t*)pkg;
6678     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
6679                                   header->dataEnd, "ResTable_package");
6680     if (err != NO_ERROR) {
6681         return (mError=err);
6682     }
6683 
6684     const uint32_t pkgSize = dtohl(pkg->header.size);
6685 
6686     if (dtohl(pkg->typeStrings) >= pkgSize) {
6687         ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
6688              dtohl(pkg->typeStrings), pkgSize);
6689         return (mError=BAD_TYPE);
6690     }
6691     if ((dtohl(pkg->typeStrings)&0x3) != 0) {
6692         ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
6693              dtohl(pkg->typeStrings));
6694         return (mError=BAD_TYPE);
6695     }
6696     if (dtohl(pkg->keyStrings) >= pkgSize) {
6697         ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
6698              dtohl(pkg->keyStrings), pkgSize);
6699         return (mError=BAD_TYPE);
6700     }
6701     if ((dtohl(pkg->keyStrings)&0x3) != 0) {
6702         ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
6703              dtohl(pkg->keyStrings));
6704         return (mError=BAD_TYPE);
6705     }
6706 
6707     uint32_t id = dtohl(pkg->id);
6708     KeyedVector<uint8_t, IdmapEntries> idmapEntries;
6709 
6710     if (header->resourceIDMap != NULL) {
6711         uint8_t targetPackageId = 0;
6712         status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries);
6713         if (err != NO_ERROR) {
6714             ALOGW("Overlay is broken");
6715             return (mError=err);
6716         }
6717         id = targetPackageId;
6718     }
6719 
6720     bool isDynamic = false;
6721     if (id >= 256) {
6722         LOG_ALWAYS_FATAL("Package id out of range");
6723         return NO_ERROR;
6724     } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
6725         // This is a library or a system asset, so assign an ID
6726         id = mNextPackageId++;
6727         isDynamic = true;
6728     }
6729 
6730     PackageGroup* group = NULL;
6731     Package* package = new Package(this, header, pkg);
6732     if (package == NULL) {
6733         return (mError=NO_MEMORY);
6734     }
6735 
6736     err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
6737                                    header->dataEnd-(base+dtohl(pkg->typeStrings)));
6738     if (err != NO_ERROR) {
6739         delete group;
6740         delete package;
6741         return (mError=err);
6742     }
6743 
6744     err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
6745                                   header->dataEnd-(base+dtohl(pkg->keyStrings)));
6746     if (err != NO_ERROR) {
6747         delete group;
6748         delete package;
6749         return (mError=err);
6750     }
6751 
6752     size_t idx = mPackageMap[id];
6753     if (idx == 0) {
6754         idx = mPackageGroups.size() + 1;
6755         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
6756         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
6757         group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset, isDynamic);
6758         if (group == NULL) {
6759             delete package;
6760             return (mError=NO_MEMORY);
6761         }
6762 
6763         err = mPackageGroups.add(group);
6764         if (err < NO_ERROR) {
6765             return (mError=err);
6766         }
6767 
6768         mPackageMap[id] = static_cast<uint8_t>(idx);
6769 
6770         // Find all packages that reference this package
6771         size_t N = mPackageGroups.size();
6772         for (size_t i = 0; i < N; i++) {
6773             mPackageGroups[i]->dynamicRefTable.addMapping(
6774                     group->name, static_cast<uint8_t>(group->id));
6775         }
6776     } else {
6777         group = mPackageGroups.itemAt(idx - 1);
6778         if (group == NULL) {
6779             return (mError=UNKNOWN_ERROR);
6780         }
6781     }
6782 
6783     err = group->packages.add(package);
6784     if (err < NO_ERROR) {
6785         return (mError=err);
6786     }
6787 
6788     // Iterate through all chunks.
6789     const ResChunk_header* chunk =
6790         (const ResChunk_header*)(((const uint8_t*)pkg)
6791                                  + dtohs(pkg->header.headerSize));
6792     const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
6793     while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
6794            ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
6795         if (kDebugTableNoisy) {
6796             ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
6797                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
6798                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
6799         }
6800         const size_t csize = dtohl(chunk->size);
6801         const uint16_t ctype = dtohs(chunk->type);
6802         if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
6803             const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
6804             err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
6805                                  endPos, "ResTable_typeSpec");
6806             if (err != NO_ERROR) {
6807                 return (mError=err);
6808             }
6809 
6810             const size_t typeSpecSize = dtohl(typeSpec->header.size);
6811             const size_t newEntryCount = dtohl(typeSpec->entryCount);
6812 
6813             if (kDebugLoadTableNoisy) {
6814                 ALOGI("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
6815                         (void*)(base-(const uint8_t*)chunk),
6816                         dtohs(typeSpec->header.type),
6817                         dtohs(typeSpec->header.headerSize),
6818                         (void*)typeSpecSize);
6819             }
6820             // look for block overrun or int overflow when multiplying by 4
6821             if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
6822                     || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
6823                     > typeSpecSize)) {
6824                 ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
6825                         (void*)(dtohs(typeSpec->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
6826                         (void*)typeSpecSize);
6827                 return (mError=BAD_TYPE);
6828             }
6829 
6830             if (typeSpec->id == 0) {
6831                 ALOGW("ResTable_type has an id of 0.");
6832                 return (mError=BAD_TYPE);
6833             }
6834 
6835             if (newEntryCount > 0) {
6836                 bool addToType = true;
6837                 uint8_t typeIndex = typeSpec->id - 1;
6838                 ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
6839                 if (idmapIndex >= 0) {
6840                     typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
6841                 } else if (header->resourceIDMap != NULL) {
6842                     // This is an overlay, but the types in this overlay are not
6843                     // overlaying anything according to the idmap. We can skip these
6844                     // as they will otherwise conflict with the other resources in the package
6845                     // without a mapping.
6846                     addToType = false;
6847                 }
6848 
6849                 if (addToType) {
6850                     TypeList& typeList = group->types.editItemAt(typeIndex);
6851                     if (!typeList.isEmpty()) {
6852                         const Type* existingType = typeList[0];
6853                         if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
6854                             ALOGW("ResTable_typeSpec entry count inconsistent: "
6855                                   "given %d, previously %d",
6856                                   (int) newEntryCount, (int) existingType->entryCount);
6857                             // We should normally abort here, but some legacy apps declare
6858                             // resources in the 'android' package (old bug in AAPT).
6859                         }
6860                     }
6861 
6862                     Type* t = new Type(header, package, newEntryCount);
6863                     t->typeSpec = typeSpec;
6864                     t->typeSpecFlags = (const uint32_t*)(
6865                             ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
6866                     if (idmapIndex >= 0) {
6867                         t->idmapEntries = idmapEntries[idmapIndex];
6868                     }
6869                     typeList.add(t);
6870                     group->largestTypeId = max(group->largestTypeId, typeSpec->id);
6871                 }
6872             } else {
6873                 ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
6874             }
6875 
6876         } else if (ctype == RES_TABLE_TYPE_TYPE) {
6877             const ResTable_type* type = (const ResTable_type*)(chunk);
6878             err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
6879                                  endPos, "ResTable_type");
6880             if (err != NO_ERROR) {
6881                 return (mError=err);
6882             }
6883 
6884             const uint32_t typeSize = dtohl(type->header.size);
6885             const size_t newEntryCount = dtohl(type->entryCount);
6886 
6887             if (kDebugLoadTableNoisy) {
6888                 printf("Type off %p: type=0x%x, headerSize=0x%x, size=%u\n",
6889                         (void*)(base-(const uint8_t*)chunk),
6890                         dtohs(type->header.type),
6891                         dtohs(type->header.headerSize),
6892                         typeSize);
6893             }
6894             if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount) > typeSize) {
6895                 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
6896                         (void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
6897                         typeSize);
6898                 return (mError=BAD_TYPE);
6899             }
6900 
6901             if (newEntryCount != 0
6902                 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
6903                 ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
6904                      dtohl(type->entriesStart), typeSize);
6905                 return (mError=BAD_TYPE);
6906             }
6907 
6908             if (type->id == 0) {
6909                 ALOGW("ResTable_type has an id of 0.");
6910                 return (mError=BAD_TYPE);
6911             }
6912 
6913             if (newEntryCount > 0) {
6914                 bool addToType = true;
6915                 uint8_t typeIndex = type->id - 1;
6916                 ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
6917                 if (idmapIndex >= 0) {
6918                     typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
6919                 } else if (header->resourceIDMap != NULL) {
6920                     // This is an overlay, but the types in this overlay are not
6921                     // overlaying anything according to the idmap. We can skip these
6922                     // as they will otherwise conflict with the other resources in the package
6923                     // without a mapping.
6924                     addToType = false;
6925                 }
6926 
6927                 if (addToType) {
6928                     TypeList& typeList = group->types.editItemAt(typeIndex);
6929                     if (typeList.isEmpty()) {
6930                         ALOGE("No TypeSpec for type %d", type->id);
6931                         return (mError=BAD_TYPE);
6932                     }
6933 
6934                     Type* t = typeList.editItemAt(typeList.size() - 1);
6935                     if (t->package != package) {
6936                         ALOGE("No TypeSpec for type %d", type->id);
6937                         return (mError=BAD_TYPE);
6938                     }
6939 
6940                     t->configs.add(type);
6941 
6942                     if (kDebugTableGetEntry) {
6943                         ResTable_config thisConfig;
6944                         thisConfig.copyFromDtoH(type->config);
6945                         ALOGI("Adding config to type %d: %s\n", type->id,
6946                                 thisConfig.toString().string());
6947                     }
6948                 }
6949             } else {
6950                 ALOGV("Skipping empty ResTable_type for type %d", type->id);
6951             }
6952 
6953         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
6954 
6955             if (group->dynamicRefTable.entries().size() == 0) {
6956                 const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
6957                 status_t err = validate_chunk(&lib->header, sizeof(*lib),
6958                                               endPos, "ResTable_lib_header");
6959                 if (err != NO_ERROR) {
6960                     return (mError=err);
6961                 }
6962 
6963                 err = group->dynamicRefTable.load(lib);
6964                 if (err != NO_ERROR) {
6965                     return (mError=err);
6966                 }
6967 
6968                 // Fill in the reference table with the entries we already know about.
6969                 size_t N = mPackageGroups.size();
6970                 for (size_t i = 0; i < N; i++) {
6971                     group->dynamicRefTable.addMapping(mPackageGroups[i]->name, mPackageGroups[i]->id);
6972                 }
6973             } else {
6974                 ALOGW("Found multiple library tables, ignoring...");
6975             }
6976         } else {
6977             if (ctype == RES_TABLE_OVERLAYABLE_TYPE) {
6978                 package->definesOverlayable = true;
6979             }
6980 
6981             status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
6982                                           endPos, "ResTable_package:unknown");
6983             if (err != NO_ERROR) {
6984                 return (mError=err);
6985             }
6986         }
6987         chunk = (const ResChunk_header*)
6988             (((const uint8_t*)chunk) + csize);
6989     }
6990 
6991     return NO_ERROR;
6992 }
6993 
DynamicRefTable()6994 DynamicRefTable::DynamicRefTable() : DynamicRefTable(0, false) {}
6995 
DynamicRefTable(uint8_t packageId,bool appAsLib)6996 DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib)
6997     : mAssignedPackageId(packageId)
6998     , mAppAsLib(appAsLib)
6999 {
7000     memset(mLookupTable, 0, sizeof(mLookupTable));
7001 
7002     // Reserved package ids
7003     mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
7004     mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
7005 }
7006 
load(const ResTable_lib_header * const header)7007 status_t DynamicRefTable::load(const ResTable_lib_header* const header)
7008 {
7009     const uint32_t entryCount = dtohl(header->count);
7010     const uint32_t expectedSize = dtohl(header->header.size) - dtohl(header->header.headerSize);
7011     if (entryCount > (expectedSize / sizeof(ResTable_lib_entry))) {
7012         ALOGE("ResTable_lib_header size %u is too small to fit %u entries (x %u).",
7013                 expectedSize, entryCount, (uint32_t)sizeof(ResTable_lib_entry));
7014         return UNKNOWN_ERROR;
7015     }
7016 
7017     const ResTable_lib_entry* entry = (const ResTable_lib_entry*)(((uint8_t*) header) +
7018             dtohl(header->header.headerSize));
7019     for (uint32_t entryIndex = 0; entryIndex < entryCount; entryIndex++) {
7020         uint32_t packageId = dtohl(entry->packageId);
7021         char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
7022         strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
7023         if (kDebugLibNoisy) {
7024             ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
7025                     dtohl(entry->packageId));
7026         }
7027         if (packageId >= 256) {
7028             ALOGE("Bad package id 0x%08x", packageId);
7029             return UNKNOWN_ERROR;
7030         }
7031         mEntries.replaceValueFor(String16(tmpName), (uint8_t) packageId);
7032         entry = entry + 1;
7033     }
7034     return NO_ERROR;
7035 }
7036 
addMappings(const DynamicRefTable & other)7037 status_t DynamicRefTable::addMappings(const DynamicRefTable& other) {
7038     if (mAssignedPackageId != other.mAssignedPackageId) {
7039         return UNKNOWN_ERROR;
7040     }
7041 
7042     const size_t entryCount = other.mEntries.size();
7043     for (size_t i = 0; i < entryCount; i++) {
7044         ssize_t index = mEntries.indexOfKey(other.mEntries.keyAt(i));
7045         if (index < 0) {
7046             mEntries.add(String16(other.mEntries.keyAt(i)), other.mEntries[i]);
7047         } else {
7048             if (other.mEntries[i] != mEntries[index]) {
7049                 return UNKNOWN_ERROR;
7050             }
7051         }
7052     }
7053 
7054     // Merge the lookup table. No entry can conflict
7055     // (value of 0 means not set).
7056     for (size_t i = 0; i < 256; i++) {
7057         if (mLookupTable[i] != other.mLookupTable[i]) {
7058             if (mLookupTable[i] == 0) {
7059                 mLookupTable[i] = other.mLookupTable[i];
7060             } else if (other.mLookupTable[i] != 0) {
7061                 return UNKNOWN_ERROR;
7062             }
7063         }
7064     }
7065     return NO_ERROR;
7066 }
7067 
addMapping(const String16 & packageName,uint8_t packageId)7068 status_t DynamicRefTable::addMapping(const String16& packageName, uint8_t packageId)
7069 {
7070     ssize_t index = mEntries.indexOfKey(packageName);
7071     if (index < 0) {
7072         return UNKNOWN_ERROR;
7073     }
7074     mLookupTable[mEntries.valueAt(index)] = packageId;
7075     return NO_ERROR;
7076 }
7077 
addMapping(uint8_t buildPackageId,uint8_t runtimePackageId)7078 void DynamicRefTable::addMapping(uint8_t buildPackageId, uint8_t runtimePackageId) {
7079     mLookupTable[buildPackageId] = runtimePackageId;
7080 }
7081 
addAlias(uint32_t stagedId,uint32_t finalizedId)7082 void DynamicRefTable::addAlias(uint32_t stagedId, uint32_t finalizedId) {
7083   mAliasId[stagedId] = finalizedId;
7084 }
7085 
lookupResourceId(uint32_t * resId) const7086 status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
7087     uint32_t res = *resId;
7088     size_t packageId = Res_GETPACKAGE(res) + 1;
7089 
7090     if (!Res_VALIDID(res)) {
7091         // Cannot look up a null or invalid id, so no lookup needs to be done.
7092         return NO_ERROR;
7093     }
7094 
7095     auto alias_id = mAliasId.find(res);
7096     if (alias_id != mAliasId.end()) {
7097       // Rewrite the resource id to its alias resource id. Since the alias resource id is a
7098       // compile-time id, it still needs to be resolved further.
7099       res = alias_id->second;
7100     }
7101 
7102     if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) {
7103         // No lookup needs to be done, app and framework package IDs are absolute.
7104         *resId = res;
7105         return NO_ERROR;
7106     }
7107 
7108     if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) {
7109         // The package ID is 0x00. That means that a shared library is accessing
7110         // its own local resource.
7111         // Or if app resource is loaded as shared library, the resource which has
7112         // app package Id is local resources.
7113         // so we fix up those resources with the calling package ID.
7114         *resId = (0xFFFFFF & (*resId)) | (((uint32_t) mAssignedPackageId) << 24);
7115         return NO_ERROR;
7116     }
7117 
7118     // Do a proper lookup.
7119     uint8_t translatedId = mLookupTable[packageId];
7120     if (translatedId == 0) {
7121         ALOGW("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
7122                 (uint8_t)mAssignedPackageId, (uint8_t)packageId);
7123         for (size_t i = 0; i < 256; i++) {
7124             if (mLookupTable[i] != 0) {
7125                 ALOGW("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
7126             }
7127         }
7128         return UNKNOWN_ERROR;
7129     }
7130 
7131     *resId = (res & 0x00ffffff) | (((uint32_t) translatedId) << 24);
7132     return NO_ERROR;
7133 }
7134 
requiresLookup(const Res_value * value) const7135 bool DynamicRefTable::requiresLookup(const Res_value* value) const {
7136     // Only resolve non-dynamic references and attributes if the package is loaded as a
7137     // library or if a shared library is attempting to retrieve its own resource
7138     if ((value->dataType == Res_value::TYPE_REFERENCE ||
7139          value->dataType == Res_value::TYPE_ATTRIBUTE) &&
7140         (mAppAsLib || (Res_GETPACKAGE(value->data) + 1) == 0)) {
7141         return true;
7142     }
7143     return value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE ||
7144            value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE;
7145 }
7146 
lookupResourceValue(Res_value * value) const7147 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
7148     if (!requiresLookup(value)) {
7149       return NO_ERROR;
7150     }
7151 
7152     uint8_t resolvedType = Res_value::TYPE_REFERENCE;
7153     switch (value->dataType) {
7154         case Res_value::TYPE_ATTRIBUTE:
7155             resolvedType = Res_value::TYPE_ATTRIBUTE;
7156             FALLTHROUGH_INTENDED;
7157         case Res_value::TYPE_REFERENCE:
7158         break;
7159         case Res_value::TYPE_DYNAMIC_ATTRIBUTE:
7160             resolvedType = Res_value::TYPE_ATTRIBUTE;
7161             FALLTHROUGH_INTENDED;
7162         case Res_value::TYPE_DYNAMIC_REFERENCE:
7163             break;
7164         default:
7165             return NO_ERROR;
7166     }
7167 
7168     status_t err = lookupResourceId(&value->data);
7169     if (err != NO_ERROR) {
7170         return err;
7171     }
7172 
7173     value->dataType = resolvedType;
7174     return NO_ERROR;
7175 }
7176 
7177 class IdmapMatchingResources;
7178 
7179 class IdmapTypeMapping {
7180 public:
add(uint32_t targetResId,uint32_t overlayResId)7181     void add(uint32_t targetResId, uint32_t overlayResId) {
7182         uint8_t targetTypeId = Res_GETTYPE(targetResId);
7183         if (mData.find(targetTypeId) == mData.end()) {
7184             mData.emplace(targetTypeId, std::set<std::pair<uint32_t, uint32_t>>());
7185         }
7186         auto& entries = mData[targetTypeId];
7187         entries.insert(std::make_pair(targetResId, overlayResId));
7188     }
7189 
empty() const7190     bool empty() const {
7191         return mData.empty();
7192     }
7193 
7194 private:
7195     // resource type ID in context of target -> set of resource entries mapping target -> overlay
7196     std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> mData;
7197 
7198     friend IdmapMatchingResources;
7199 };
7200 
7201 class IdmapMatchingResources {
7202 public:
IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm)7203     IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm) : mTypeMapping(std::move(tm)) {
7204         assert(mTypeMapping);
7205         for (auto ti = mTypeMapping->mData.cbegin(); ti != mTypeMapping->mData.cend(); ++ti) {
7206             uint32_t lastSeen = 0xffffffff;
7207             size_t totalEntries = 0;
7208             for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) {
7209                 assert(lastSeen == 0xffffffff || lastSeen < ei->first);
7210                 mEntryPadding[ei->first] = (lastSeen == 0xffffffff) ? 0 : ei->first - lastSeen - 1;
7211                 lastSeen = ei->first;
7212                 totalEntries += 1 + mEntryPadding[ei->first];
7213             }
7214             mNumberOfEntriesIncludingPadding[ti->first] = totalEntries;
7215         }
7216     }
7217 
getTypeMapping() const7218     const std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>>& getTypeMapping() const {
7219         return mTypeMapping->mData;
7220     }
7221 
getNumberOfEntriesIncludingPadding(uint8_t type) const7222     size_t getNumberOfEntriesIncludingPadding(uint8_t type) const {
7223         return mNumberOfEntriesIncludingPadding.at(type);
7224     }
7225 
getPadding(uint32_t resid) const7226     size_t getPadding(uint32_t resid) const {
7227         return mEntryPadding.at(resid);
7228     }
7229 
7230 private:
7231     // resource type ID in context of target -> set of resource entries mapping target -> overlay
7232     const std::unique_ptr<IdmapTypeMapping> mTypeMapping;
7233 
7234     // resource ID in context of target -> trailing padding for that resource (call FixPadding
7235     // before use)
7236     std::map<uint32_t, size_t> mEntryPadding;
7237 
7238     // resource type ID in context of target -> total number of entries, including padding entries,
7239     // for that type (call FixPadding before use)
7240     std::map<uint8_t, size_t> mNumberOfEntriesIncludingPadding;
7241 };
7242 
createIdmap(const ResTable & targetResTable,uint32_t targetCrc,uint32_t overlayCrc,const char * targetPath,const char * overlayPath,void ** outData,size_t * outSize) const7243 status_t ResTable::createIdmap(const ResTable& targetResTable,
7244         uint32_t targetCrc, uint32_t overlayCrc,
7245         const char* targetPath, const char* overlayPath,
7246         void** outData, size_t* outSize) const
7247 {
7248     if (targetPath == NULL || overlayPath == NULL || outData == NULL || outSize == NULL) {
7249         ALOGE("idmap: unexpected NULL parameter");
7250         return UNKNOWN_ERROR;
7251     }
7252     if (strlen(targetPath) > 255) {
7253         ALOGE("idmap: target path exceeds idmap file format limit of 255 chars");
7254         return UNKNOWN_ERROR;
7255     }
7256     if (strlen(overlayPath) > 255) {
7257         ALOGE("idmap: overlay path exceeds idmap file format limit of 255 chars");
7258         return UNKNOWN_ERROR;
7259     }
7260     if (mPackageGroups.size() == 0 || mPackageGroups[0]->packages.size() == 0) {
7261         ALOGE("idmap: invalid overlay package");
7262         return UNKNOWN_ERROR;
7263     }
7264     if (targetResTable.mPackageGroups.size() == 0 ||
7265             targetResTable.mPackageGroups[0]->packages.size() == 0) {
7266         ALOGE("idmap: invalid target package");
7267         return UNKNOWN_ERROR;
7268     }
7269 
7270     // Idmap is not aware of overlayable, exit since policy checks can't be done
7271     if (targetResTable.mPackageGroups[0]->packages[0]->definesOverlayable) {
7272         return UNKNOWN_ERROR;
7273     }
7274 
7275     const ResTable_package* targetPackageStruct =
7276         targetResTable.mPackageGroups[0]->packages[0]->package;
7277     const size_t tmpNameSize = arraysize(targetPackageStruct->name);
7278     char16_t tmpName[tmpNameSize];
7279     strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize);
7280     const String16 targetPackageName(tmpName);
7281 
7282     const PackageGroup* packageGroup = mPackageGroups[0];
7283 
7284     // find the resources that exist in both packages
7285     auto typeMapping = std::make_unique<IdmapTypeMapping>();
7286     for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) {
7287         const TypeList& typeList = packageGroup->types[typeIndex];
7288         if (typeList.isEmpty()) {
7289             continue;
7290         }
7291         const Type* typeConfigs = typeList[0];
7292 
7293         for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
7294             uint32_t overlay_resid = Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex);
7295             resource_name current_res;
7296             if (!getResourceName(overlay_resid, false, &current_res)) {
7297                 continue;
7298             }
7299 
7300             uint32_t typeSpecFlags = 0u;
7301             const uint32_t target_resid = targetResTable.identifierForName(
7302                     current_res.name,
7303                     current_res.nameLen,
7304                     current_res.type,
7305                     current_res.typeLen,
7306                     targetPackageName.string(),
7307                     targetPackageName.size(),
7308                     &typeSpecFlags);
7309 
7310             if (target_resid == 0) {
7311                 continue;
7312             }
7313 
7314             typeMapping->add(target_resid, overlay_resid);
7315         }
7316     }
7317 
7318     if (typeMapping->empty()) {
7319         ALOGE("idmap: no matching resources");
7320         return UNKNOWN_ERROR;
7321     }
7322 
7323     const IdmapMatchingResources matchingResources(std::move(typeMapping));
7324 
7325     // write idmap
7326     *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc
7327     *outSize += 2 * sizeof(uint16_t); // target package id, type count
7328     auto fixedTypeMapping = matchingResources.getTypeMapping();
7329     const auto typesEnd = fixedTypeMapping.cend();
7330     for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) {
7331         *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset
7332         *outSize += matchingResources.getNumberOfEntriesIncludingPadding(ti->first) *
7333             sizeof(uint32_t); // entries
7334     }
7335     if ((*outData = malloc(*outSize)) == NULL) {
7336         return NO_MEMORY;
7337     }
7338 
7339     // write idmap header
7340     uint32_t* data = reinterpret_cast<uint32_t*>(*outData);
7341     *data++ = htodl(IDMAP_MAGIC); // write: magic
7342     *data++ = htodl(ResTable::IDMAP_CURRENT_VERSION); // write: version
7343     *data++ = htodl(targetCrc); // write: target crc
7344     *data++ = htodl(overlayCrc); // write: overlay crc
7345 
7346     char* charData = reinterpret_cast<char*>(data);
7347     size_t pathLen = strlen(targetPath);
7348     for (size_t i = 0; i < 256; ++i) {
7349         *charData++ = i < pathLen ? targetPath[i] : '\0'; // write: target path
7350     }
7351     pathLen = strlen(overlayPath);
7352     for (size_t i = 0; i < 256; ++i) {
7353         *charData++ = i < pathLen ? overlayPath[i] : '\0'; // write: overlay path
7354     }
7355     data += (2 * 256) / sizeof(uint32_t);
7356 
7357     // write idmap data header
7358     uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
7359     *typeData++ = htods(targetPackageStruct->id); // write: target package id
7360     *typeData++ =
7361         htods(static_cast<uint16_t>(fixedTypeMapping.size())); // write: type count
7362 
7363     // write idmap data
7364     for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) {
7365         const size_t entryCount = matchingResources.getNumberOfEntriesIncludingPadding(ti->first);
7366         auto ei = ti->second.cbegin();
7367         *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id
7368         *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id
7369         *typeData++ = htods(entryCount); // write: entry count
7370         *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset
7371         uint32_t *entryData = reinterpret_cast<uint32_t*>(typeData);
7372         for (; ei != ti->second.cend(); ++ei) {
7373             const size_t padding = matchingResources.getPadding(ei->first);
7374             for (size_t i = 0; i < padding; ++i) {
7375                 *entryData++ = htodl(0xffffffff); // write: padding
7376             }
7377             *entryData++ = htodl(Res_GETENTRY(ei->second)); // write: (overlay) entry
7378         }
7379         typeData += entryCount * 2;
7380     }
7381 
7382     return NO_ERROR;
7383 }
7384 
getIdmapInfo(const void * idmap,size_t sizeBytes,uint32_t * pVersion,uint32_t * pTargetCrc,uint32_t * pOverlayCrc,String8 * pTargetPath,String8 * pOverlayPath)7385 bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
7386                             uint32_t* pVersion,
7387                             uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
7388                             String8* pTargetPath, String8* pOverlayPath)
7389 {
7390     const uint32_t* map = (const uint32_t*)idmap;
7391     if (!assertIdmapHeader(map, sizeBytes)) {
7392         return false;
7393     }
7394     if (pVersion) {
7395         *pVersion = dtohl(map[1]);
7396     }
7397     if (pTargetCrc) {
7398         *pTargetCrc = dtohl(map[2]);
7399     }
7400     if (pOverlayCrc) {
7401         *pOverlayCrc = dtohl(map[3]);
7402     }
7403     if (pTargetPath) {
7404         pTargetPath->setTo(reinterpret_cast<const char*>(map + 4));
7405     }
7406     if (pOverlayPath) {
7407         pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t)));
7408     }
7409     return true;
7410 }
7411 
7412 
7413 #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
7414 
7415 #define CHAR16_ARRAY_EQ(constant, var, len) \
7416         (((len) == (sizeof(constant)/sizeof((constant)[0]))) && (0 == memcmp((var), (constant), (len))))
7417 
print_complex(uint32_t complex,bool isFraction)7418 static void print_complex(uint32_t complex, bool isFraction)
7419 {
7420     const float MANTISSA_MULT =
7421         1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
7422     const float RADIX_MULTS[] = {
7423         1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
7424         1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
7425     };
7426 
7427     float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
7428                    <<Res_value::COMPLEX_MANTISSA_SHIFT))
7429             * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
7430                             & Res_value::COMPLEX_RADIX_MASK];
7431     printf("%f", value);
7432 
7433     if (!isFraction) {
7434         switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
7435             case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
7436             case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
7437             case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
7438             case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
7439             case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
7440             case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
7441             default: printf(" (unknown unit)"); break;
7442         }
7443     } else {
7444         switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
7445             case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
7446             case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
7447             default: printf(" (unknown unit)"); break;
7448         }
7449     }
7450 }
7451 
7452 // Normalize a string for output
normalizeForOutput(const char * input)7453 String8 ResTable::normalizeForOutput( const char *input )
7454 {
7455     String8 ret;
7456     char buff[2];
7457     buff[1] = '\0';
7458 
7459     while (*input != '\0') {
7460         switch (*input) {
7461             // All interesting characters are in the ASCII zone, so we are making our own lives
7462             // easier by scanning the string one byte at a time.
7463         case '\\':
7464             ret += "\\\\";
7465             break;
7466         case '\n':
7467             ret += "\\n";
7468             break;
7469         case '"':
7470             ret += "\\\"";
7471             break;
7472         default:
7473             buff[0] = *input;
7474             ret += buff;
7475             break;
7476         }
7477 
7478         input++;
7479     }
7480 
7481     return ret;
7482 }
7483 
print_value(const Package * pkg,const Res_value & value) const7484 void ResTable::print_value(const Package* pkg, const Res_value& value) const
7485 {
7486     if (value.dataType == Res_value::TYPE_NULL) {
7487         if (value.data == Res_value::DATA_NULL_UNDEFINED) {
7488             printf("(null)\n");
7489         } else if (value.data == Res_value::DATA_NULL_EMPTY) {
7490             printf("(null empty)\n");
7491         } else {
7492             // This should never happen.
7493             printf("(null) 0x%08x\n", value.data);
7494         }
7495     } else if (value.dataType == Res_value::TYPE_REFERENCE) {
7496         printf("(reference) 0x%08x\n", value.data);
7497     } else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
7498         printf("(dynamic reference) 0x%08x\n", value.data);
7499     } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
7500         printf("(attribute) 0x%08x\n", value.data);
7501     } else if (value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
7502         printf("(dynamic attribute) 0x%08x\n", value.data);
7503     } else if (value.dataType == Res_value::TYPE_STRING) {
7504         size_t len;
7505         const char* str8 = UnpackOptionalString(pkg->header->values.string8At(
7506                 value.data), &len);
7507         if (str8 != NULL) {
7508             printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
7509         } else {
7510             const char16_t* str16 = UnpackOptionalString(pkg->header->values.stringAt(
7511                     value.data), &len);
7512             if (str16 != NULL) {
7513                 printf("(string16) \"%s\"\n",
7514                     normalizeForOutput(String8(str16, len).string()).string());
7515             } else {
7516                 printf("(string) null\n");
7517             }
7518         }
7519     } else if (value.dataType == Res_value::TYPE_FLOAT) {
7520         printf("(float) %g\n", *(const float*)&value.data);
7521     } else if (value.dataType == Res_value::TYPE_DIMENSION) {
7522         printf("(dimension) ");
7523         print_complex(value.data, false);
7524         printf("\n");
7525     } else if (value.dataType == Res_value::TYPE_FRACTION) {
7526         printf("(fraction) ");
7527         print_complex(value.data, true);
7528         printf("\n");
7529     } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
7530             && value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
7531         printf("(color) #%08x\n", value.data);
7532     } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
7533         printf("(boolean) %s\n", value.data ? "true" : "false");
7534     } else if (value.dataType >= Res_value::TYPE_FIRST_INT
7535             && value.dataType <= Res_value::TYPE_LAST_INT) {
7536         printf("(int) 0x%08x or %d\n", value.data, value.data);
7537     } else {
7538         printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
7539                (int)value.dataType, (int)value.data,
7540                (int)value.size, (int)value.res0);
7541     }
7542 }
7543 
print(bool inclValues) const7544 void ResTable::print(bool inclValues) const
7545 {
7546     if (mError != 0) {
7547         printf("mError=0x%x (%s)\n", mError, strerror(mError));
7548     }
7549     size_t pgCount = mPackageGroups.size();
7550     printf("Package Groups (%d)\n", (int)pgCount);
7551     for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
7552         const PackageGroup* pg = mPackageGroups[pgIndex];
7553         printf("Package Group %d id=0x%02x packageCount=%d name=%s\n",
7554                 (int)pgIndex, pg->id, (int)pg->packages.size(),
7555                 String8(pg->name).string());
7556 
7557         const KeyedVector<String16, uint8_t>& refEntries = pg->dynamicRefTable.entries();
7558         const size_t refEntryCount = refEntries.size();
7559         if (refEntryCount > 0) {
7560             printf("  DynamicRefTable entryCount=%d:\n", (int) refEntryCount);
7561             for (size_t refIndex = 0; refIndex < refEntryCount; refIndex++) {
7562                 printf("    0x%02x -> %s\n",
7563                         refEntries.valueAt(refIndex),
7564                         String8(refEntries.keyAt(refIndex)).string());
7565             }
7566             printf("\n");
7567         }
7568 
7569         // Determine the number of resource splits for the resource types in this package.
7570         // It needs to be done outside of the loop below so all of the information for a
7571         // is displayed in a single block. Otherwise, a resource split's resource types
7572         // would be interleaved with other splits.
7573         size_t splitCount = 0;
7574         for (size_t typeIndex = 0; typeIndex < pg->types.size(); typeIndex++) {
7575             splitCount = max(splitCount, pg->types[typeIndex].size());
7576         }
7577 
7578         int packageId = pg->id;
7579         for (size_t splitIndex = 0; splitIndex < splitCount; splitIndex++) {
7580             size_t pkgCount = pg->packages.size();
7581             for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
7582                 const Package* pkg = pg->packages[pkgIndex];
7583                 // Use a package's real ID, since the ID may have been assigned
7584                 // if this package is a shared library.
7585                 packageId = pkg->package->id;
7586                 char16_t tmpName[sizeof(pkg->package->name)/sizeof(pkg->package->name[0])];
7587                 strcpy16_dtoh(tmpName, pkg->package->name,
7588                               sizeof(pkg->package->name)/sizeof(pkg->package->name[0]));
7589                 printf("  Package %d id=0x%02x name=%s\n", (int)pkgIndex,
7590                         pkg->package->id, String8(tmpName).string());
7591             }
7592 
7593             for (size_t typeIndex = 0; typeIndex < pg->types.size(); typeIndex++) {
7594                 const TypeList& typeList = pg->types[typeIndex];
7595                 if (splitIndex >= typeList.size() || typeList.isEmpty()) {
7596                     // Only dump if the split exists and contains entries for this type
7597                     continue;
7598                 }
7599                 const Type* typeConfigs = typeList[splitIndex];
7600                 const size_t NTC = typeConfigs->configs.size();
7601                 printf("    type %d configCount=%d entryCount=%d\n",
7602                        (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
7603                 if (typeConfigs->typeSpecFlags != NULL) {
7604                     for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
7605                         uint32_t resID = (0xff000000 & ((packageId)<<24))
7606                                     | (0x00ff0000 & ((typeIndex+1)<<16))
7607                                     | (0x0000ffff & (entryIndex));
7608                         // Since we are creating resID without actually
7609                         // iterating over them, we have no idea which is a
7610                         // dynamic reference. We must check.
7611                         if (packageId == 0) {
7612                             pg->dynamicRefTable.lookupResourceId(&resID);
7613                         }
7614 
7615                         resource_name resName;
7616                         if (this->getResourceName(resID, true, &resName)) {
7617                             String8 type8;
7618                             String8 name8;
7619                             if (resName.type8 != NULL) {
7620                                 type8 = String8(resName.type8, resName.typeLen);
7621                             } else {
7622                                 type8 = String8(resName.type, resName.typeLen);
7623                             }
7624                             if (resName.name8 != NULL) {
7625                                 name8 = String8(resName.name8, resName.nameLen);
7626                             } else {
7627                                 name8 = String8(resName.name, resName.nameLen);
7628                             }
7629                             printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
7630                                 resID,
7631                                 CHAR16_TO_CSTR(resName.package, resName.packageLen),
7632                                 type8.string(), name8.string(),
7633                                 dtohl(typeConfigs->typeSpecFlags[entryIndex]));
7634                         } else {
7635                             printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
7636                         }
7637                     }
7638                 }
7639                 for (size_t configIndex=0; configIndex<NTC; configIndex++) {
7640                     const ResTable_type* type = typeConfigs->configs[configIndex];
7641                     if ((((uint64_t)type)&0x3) != 0) {
7642                         printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
7643                         continue;
7644                     }
7645 
7646                     // Always copy the config, as fields get added and we need to
7647                     // set the defaults.
7648                     ResTable_config thisConfig;
7649                     thisConfig.copyFromDtoH(type->config);
7650 
7651                     String8 configStr = thisConfig.toString();
7652                     printf("      config %s", configStr.size() > 0
7653                             ? configStr.string() : "(default)");
7654                     if (type->flags != 0u) {
7655                         printf(" flags=0x%02x", type->flags);
7656                         if (type->flags & ResTable_type::FLAG_SPARSE) {
7657                             printf(" [sparse]");
7658                         }
7659                     }
7660 
7661                     printf(":\n");
7662 
7663                     size_t entryCount = dtohl(type->entryCount);
7664                     uint32_t entriesStart = dtohl(type->entriesStart);
7665                     if ((entriesStart&0x3) != 0) {
7666                         printf("      NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n",
7667                                entriesStart);
7668                         continue;
7669                     }
7670                     uint32_t typeSize = dtohl(type->header.size);
7671                     if ((typeSize&0x3) != 0) {
7672                         printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
7673                         continue;
7674                     }
7675 
7676                     const uint32_t* const eindex = (const uint32_t*)
7677                             (((const uint8_t*)type) + dtohs(type->header.headerSize));
7678                     for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
7679                         size_t entryId;
7680                         uint32_t thisOffset;
7681                         if (type->flags & ResTable_type::FLAG_SPARSE) {
7682                             const ResTable_sparseTypeEntry* entry =
7683                                     reinterpret_cast<const ResTable_sparseTypeEntry*>(
7684                                             eindex + entryIndex);
7685                             entryId = dtohs(entry->idx);
7686                             // Offsets are encoded as divided by 4.
7687                             thisOffset = static_cast<uint32_t>(dtohs(entry->offset)) * 4u;
7688                         } else {
7689                             entryId = entryIndex;
7690                             thisOffset = dtohl(eindex[entryIndex]);
7691                             if (thisOffset == ResTable_type::NO_ENTRY) {
7692                                 continue;
7693                             }
7694                         }
7695 
7696                         uint32_t resID = (0xff000000 & ((packageId)<<24))
7697                                     | (0x00ff0000 & ((typeIndex+1)<<16))
7698                                     | (0x0000ffff & (entryId));
7699                         if (packageId == 0) {
7700                             pg->dynamicRefTable.lookupResourceId(&resID);
7701                         }
7702                         resource_name resName;
7703                         if (this->getResourceName(resID, true, &resName)) {
7704                             String8 type8;
7705                             String8 name8;
7706                             if (resName.type8 != NULL) {
7707                                 type8 = String8(resName.type8, resName.typeLen);
7708                             } else {
7709                                 type8 = String8(resName.type, resName.typeLen);
7710                             }
7711                             if (resName.name8 != NULL) {
7712                                 name8 = String8(resName.name8, resName.nameLen);
7713                             } else {
7714                                 name8 = String8(resName.name, resName.nameLen);
7715                             }
7716                             printf("        resource 0x%08x %s:%s/%s: ", resID,
7717                                     CHAR16_TO_CSTR(resName.package, resName.packageLen),
7718                                     type8.string(), name8.string());
7719                         } else {
7720                             printf("        INVALID RESOURCE 0x%08x: ", resID);
7721                         }
7722                         if ((thisOffset&0x3) != 0) {
7723                             printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
7724                             continue;
7725                         }
7726                         if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
7727                             printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
7728                                    entriesStart, thisOffset, typeSize);
7729                             continue;
7730                         }
7731 
7732                         const ResTable_entry* ent = (const ResTable_entry*)
7733                             (((const uint8_t*)type) + entriesStart + thisOffset);
7734                         if (((entriesStart + thisOffset)&0x3) != 0) {
7735                             printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
7736                                  (entriesStart + thisOffset));
7737                             continue;
7738                         }
7739 
7740                         uintptr_t esize = dtohs(ent->size);
7741                         if ((esize&0x3) != 0) {
7742                             printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize);
7743                             continue;
7744                         }
7745                         if ((thisOffset+esize) > typeSize) {
7746                             printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n",
7747                                    entriesStart, thisOffset, (void *)esize, typeSize);
7748                             continue;
7749                         }
7750 
7751                         const Res_value* valuePtr = NULL;
7752                         const ResTable_map_entry* bagPtr = NULL;
7753                         Res_value value;
7754                         if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
7755                             printf("<bag>");
7756                             bagPtr = (const ResTable_map_entry*)ent;
7757                         } else {
7758                             valuePtr = (const Res_value*)
7759                                 (((const uint8_t*)ent) + esize);
7760                             value.copyFrom_dtoh(*valuePtr);
7761                             printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
7762                                    (int)value.dataType, (int)value.data,
7763                                    (int)value.size, (int)value.res0);
7764                         }
7765 
7766                         if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
7767                             printf(" (PUBLIC)");
7768                         }
7769                         printf("\n");
7770 
7771                         if (inclValues) {
7772                             if (valuePtr != NULL) {
7773                                 printf("          ");
7774                                 print_value(typeConfigs->package, value);
7775                             } else if (bagPtr != NULL) {
7776                                 const int N = dtohl(bagPtr->count);
7777                                 const uint8_t* baseMapPtr = (const uint8_t*)ent;
7778                                 size_t mapOffset = esize;
7779                                 const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
7780                                 const uint32_t parent = dtohl(bagPtr->parent.ident);
7781                                 uint32_t resolvedParent = parent;
7782                                 if (Res_GETPACKAGE(resolvedParent) + 1 == 0) {
7783                                     status_t err =
7784                                         pg->dynamicRefTable.lookupResourceId(&resolvedParent);
7785                                     if (err != NO_ERROR) {
7786                                         resolvedParent = 0;
7787                                     }
7788                                 }
7789                                 printf("          Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
7790                                         parent, resolvedParent, N);
7791                                 for (int i=0;
7792                                      i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
7793                                     printf("          #%i (Key=0x%08x): ",
7794                                         i, dtohl(mapPtr->name.ident));
7795                                     value.copyFrom_dtoh(mapPtr->value);
7796                                     print_value(typeConfigs->package, value);
7797                                     const size_t size = dtohs(mapPtr->value.size);
7798                                     mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
7799                                     mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
7800                                 }
7801                             }
7802                         }
7803                     }
7804                 }
7805             }
7806         }
7807     }
7808 }
7809 
7810 }   // namespace android
7811