OSDN Git Service

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