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