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