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