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 <utils/Atomic.h>
21 #include <utils/ByteOrder.h>
22 #include <utils/Debug.h>
23 #include <utils/ResourceTypes.h>
24 #include <utils/String16.h>
25 #include <utils/String8.h>
26 #include <utils/TextOutput.h>
27 #include <utils/Log.h>
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <memory.h>
32 #include <ctype.h>
33 #include <stdint.h>
34
35 #ifndef INT32_MAX
36 #define INT32_MAX ((int32_t)(2147483647))
37 #endif
38
39 #define POOL_NOISY(x) //x
40 #define XML_NOISY(x) //x
41 #define TABLE_NOISY(x) //x
42 #define TABLE_GETENTRY(x) //x
43 #define TABLE_SUPER_NOISY(x) //x
44 #define LOAD_TABLE_NOISY(x) //x
45
46 namespace android {
47
48 #ifdef HAVE_WINSOCK
49 #undef nhtol
50 #undef htonl
51
52 #ifdef HAVE_LITTLE_ENDIAN
53 #define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
54 #define htonl(x) ntohl(x)
55 #define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
56 #define htons(x) ntohs(x)
57 #else
58 #define ntohl(x) (x)
59 #define htonl(x) (x)
60 #define ntohs(x) (x)
61 #define htons(x) (x)
62 #endif
63 #endif
64
printToLogFunc(void * cookie,const char * txt)65 static void printToLogFunc(void* cookie, const char* txt)
66 {
67 LOGV("%s", txt);
68 }
69
70 // Standard C isspace() is only required to look at the low byte of its input, so
71 // produces incorrect results for UTF-16 characters. For safety's sake, assume that
72 // any high-byte UTF-16 code point is not whitespace.
isspace16(char16_t c)73 inline int isspace16(char16_t c) {
74 return (c < 0x0080 && isspace(c));
75 }
76
77 // range checked; guaranteed to NUL-terminate within the stated number of available slots
78 // NOTE: if this truncates the dst string due to running out of space, no attempt is
79 // made to avoid splitting surrogate pairs.
strcpy16_dtoh(uint16_t * dst,const uint16_t * src,size_t avail)80 static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail)
81 {
82 uint16_t* last = dst + avail - 1;
83 while (*src && (dst < last)) {
84 char16_t s = dtohs(*src);
85 *dst++ = s;
86 src++;
87 }
88 *dst = 0;
89 }
90
validate_chunk(const ResChunk_header * chunk,size_t minSize,const uint8_t * dataEnd,const char * name)91 static status_t validate_chunk(const ResChunk_header* chunk,
92 size_t minSize,
93 const uint8_t* dataEnd,
94 const char* name)
95 {
96 const uint16_t headerSize = dtohs(chunk->headerSize);
97 const uint32_t size = dtohl(chunk->size);
98
99 if (headerSize >= minSize) {
100 if (headerSize <= size) {
101 if (((headerSize|size)&0x3) == 0) {
102 if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
103 return NO_ERROR;
104 }
105 LOGW("%s data size %p extends beyond resource end %p.",
106 name, (void*)size,
107 (void*)(dataEnd-((const uint8_t*)chunk)));
108 return BAD_TYPE;
109 }
110 LOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
111 name, (int)size, (int)headerSize);
112 return BAD_TYPE;
113 }
114 LOGW("%s size %p is smaller than header size %p.",
115 name, (void*)size, (void*)(int)headerSize);
116 return BAD_TYPE;
117 }
118 LOGW("%s header size %p is too small.",
119 name, (void*)(int)headerSize);
120 return BAD_TYPE;
121 }
122
copyFrom_dtoh(const Res_value & src)123 inline void Res_value::copyFrom_dtoh(const Res_value& src)
124 {
125 size = dtohs(src.size);
126 res0 = src.res0;
127 dataType = src.dataType;
128 data = dtohl(src.data);
129 }
130
deviceToFile()131 void Res_png_9patch::deviceToFile()
132 {
133 for (int i = 0; i < numXDivs; i++) {
134 xDivs[i] = htonl(xDivs[i]);
135 }
136 for (int i = 0; i < numYDivs; i++) {
137 yDivs[i] = htonl(yDivs[i]);
138 }
139 paddingLeft = htonl(paddingLeft);
140 paddingRight = htonl(paddingRight);
141 paddingTop = htonl(paddingTop);
142 paddingBottom = htonl(paddingBottom);
143 for (int i=0; i<numColors; i++) {
144 colors[i] = htonl(colors[i]);
145 }
146 }
147
fileToDevice()148 void Res_png_9patch::fileToDevice()
149 {
150 for (int i = 0; i < numXDivs; i++) {
151 xDivs[i] = ntohl(xDivs[i]);
152 }
153 for (int i = 0; i < numYDivs; i++) {
154 yDivs[i] = ntohl(yDivs[i]);
155 }
156 paddingLeft = ntohl(paddingLeft);
157 paddingRight = ntohl(paddingRight);
158 paddingTop = ntohl(paddingTop);
159 paddingBottom = ntohl(paddingBottom);
160 for (int i=0; i<numColors; i++) {
161 colors[i] = ntohl(colors[i]);
162 }
163 }
164
serializedSize()165 size_t Res_png_9patch::serializedSize()
166 {
167 // The size of this struct is 32 bytes on the 32-bit target system
168 // 4 * int8_t
169 // 4 * int32_t
170 // 3 * pointer
171 return 32
172 + numXDivs * sizeof(int32_t)
173 + numYDivs * sizeof(int32_t)
174 + numColors * sizeof(uint32_t);
175 }
176
serialize()177 void* Res_png_9patch::serialize()
178 {
179 // Use calloc since we're going to leave a few holes in the data
180 // and want this to run cleanly under valgrind
181 void* newData = calloc(1, serializedSize());
182 serialize(newData);
183 return newData;
184 }
185
serialize(void * outData)186 void Res_png_9patch::serialize(void * outData)
187 {
188 char* data = (char*) outData;
189 memmove(data, &wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
190 memmove(data + 12, &paddingLeft, 16); // copy paddingXXXX
191 data += 32;
192
193 memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
194 data += numXDivs * sizeof(int32_t);
195 memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
196 data += numYDivs * sizeof(int32_t);
197 memmove(data, this->colors, numColors * sizeof(uint32_t));
198 }
199
deserializeInternal(const void * inData,Res_png_9patch * outData)200 static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
201 char* patch = (char*) inData;
202 if (inData != outData) {
203 memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
204 memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
205 }
206 outData->wasDeserialized = true;
207 char* data = (char*)outData;
208 data += sizeof(Res_png_9patch);
209 outData->xDivs = (int32_t*) data;
210 data += outData->numXDivs * sizeof(int32_t);
211 outData->yDivs = (int32_t*) data;
212 data += outData->numYDivs * sizeof(int32_t);
213 outData->colors = (uint32_t*) data;
214 }
215
deserialize(const void * inData)216 Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
217 {
218 if (sizeof(void*) != sizeof(int32_t)) {
219 LOGE("Cannot deserialize on non 32-bit system\n");
220 return NULL;
221 }
222 deserializeInternal(inData, (Res_png_9patch*) inData);
223 return (Res_png_9patch*) inData;
224 }
225
226 // --------------------------------------------------------------------
227 // --------------------------------------------------------------------
228 // --------------------------------------------------------------------
229
ResStringPool()230 ResStringPool::ResStringPool()
231 : mError(NO_INIT), mOwnedData(NULL)
232 {
233 }
234
ResStringPool(const void * data,size_t size,bool copyData)235 ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
236 : mError(NO_INIT), mOwnedData(NULL)
237 {
238 setTo(data, size, copyData);
239 }
240
~ResStringPool()241 ResStringPool::~ResStringPool()
242 {
243 uninit();
244 }
245
setTo(const void * data,size_t size,bool copyData)246 status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
247 {
248 if (!data || !size) {
249 return (mError=BAD_TYPE);
250 }
251
252 uninit();
253
254 const bool notDeviceEndian = htods(0xf0) != 0xf0;
255
256 if (copyData || notDeviceEndian) {
257 mOwnedData = malloc(size);
258 if (mOwnedData == NULL) {
259 return (mError=NO_MEMORY);
260 }
261 memcpy(mOwnedData, data, size);
262 data = mOwnedData;
263 }
264
265 mHeader = (const ResStringPool_header*)data;
266
267 if (notDeviceEndian) {
268 ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
269 h->header.headerSize = dtohs(mHeader->header.headerSize);
270 h->header.type = dtohs(mHeader->header.type);
271 h->header.size = dtohl(mHeader->header.size);
272 h->stringCount = dtohl(mHeader->stringCount);
273 h->styleCount = dtohl(mHeader->styleCount);
274 h->flags = dtohl(mHeader->flags);
275 h->stringsStart = dtohl(mHeader->stringsStart);
276 h->stylesStart = dtohl(mHeader->stylesStart);
277 }
278
279 if (mHeader->header.headerSize > mHeader->header.size
280 || mHeader->header.size > size) {
281 LOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
282 (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
283 return (mError=BAD_TYPE);
284 }
285 mSize = mHeader->header.size;
286 mEntries = (const uint32_t*)
287 (((const uint8_t*)data)+mHeader->header.headerSize);
288
289 if (mHeader->stringCount > 0) {
290 if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow?
291 || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
292 > size) {
293 LOGW("Bad string block: entry of %d items extends past data size %d\n",
294 (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
295 (int)size);
296 return (mError=BAD_TYPE);
297 }
298 mStrings = (const char16_t*)
299 (((const uint8_t*)data)+mHeader->stringsStart);
300 if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
301 LOGW("Bad string block: string pool starts at %d, after total size %d\n",
302 (int)mHeader->stringsStart, (int)mHeader->header.size);
303 return (mError=BAD_TYPE);
304 }
305 if (mHeader->styleCount == 0) {
306 mStringPoolSize =
307 (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t);
308 } else {
309 // check invariant: styles follow the strings
310 if (mHeader->stylesStart <= mHeader->stringsStart) {
311 LOGW("Bad style block: style block starts at %d, before strings at %d\n",
312 (int)mHeader->stylesStart, (int)mHeader->stringsStart);
313 return (mError=BAD_TYPE);
314 }
315 mStringPoolSize =
316 (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t);
317 }
318
319 // check invariant: stringCount > 0 requires a string pool to exist
320 if (mStringPoolSize == 0) {
321 LOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
322 return (mError=BAD_TYPE);
323 }
324
325 if (notDeviceEndian) {
326 size_t i;
327 uint32_t* e = const_cast<uint32_t*>(mEntries);
328 for (i=0; i<mHeader->stringCount; i++) {
329 e[i] = dtohl(mEntries[i]);
330 }
331 char16_t* s = const_cast<char16_t*>(mStrings);
332 for (i=0; i<mStringPoolSize; i++) {
333 s[i] = dtohs(mStrings[i]);
334 }
335 }
336
337 if (mStrings[mStringPoolSize-1] != 0) {
338 LOGW("Bad string block: last string is not 0-terminated\n");
339 return (mError=BAD_TYPE);
340 }
341 } else {
342 mStrings = NULL;
343 mStringPoolSize = 0;
344 }
345
346 if (mHeader->styleCount > 0) {
347 mEntryStyles = mEntries + mHeader->stringCount;
348 // invariant: integer overflow in calculating mEntryStyles
349 if (mEntryStyles < mEntries) {
350 LOGW("Bad string block: integer overflow finding styles\n");
351 return (mError=BAD_TYPE);
352 }
353
354 if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
355 LOGW("Bad string block: entry of %d styles extends past data size %d\n",
356 (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
357 (int)size);
358 return (mError=BAD_TYPE);
359 }
360 mStyles = (const uint32_t*)
361 (((const uint8_t*)data)+mHeader->stylesStart);
362 if (mHeader->stylesStart >= mHeader->header.size) {
363 LOGW("Bad string block: style pool starts %d, after total size %d\n",
364 (int)mHeader->stylesStart, (int)mHeader->header.size);
365 return (mError=BAD_TYPE);
366 }
367 mStylePoolSize =
368 (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
369
370 if (notDeviceEndian) {
371 size_t i;
372 uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
373 for (i=0; i<mHeader->styleCount; i++) {
374 e[i] = dtohl(mEntryStyles[i]);
375 }
376 uint32_t* s = const_cast<uint32_t*>(mStyles);
377 for (i=0; i<mStylePoolSize; i++) {
378 s[i] = dtohl(mStyles[i]);
379 }
380 }
381
382 const ResStringPool_span endSpan = {
383 { htodl(ResStringPool_span::END) },
384 htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
385 };
386 if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
387 &endSpan, sizeof(endSpan)) != 0) {
388 LOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
389 return (mError=BAD_TYPE);
390 }
391 } else {
392 mEntryStyles = NULL;
393 mStyles = NULL;
394 mStylePoolSize = 0;
395 }
396
397 return (mError=NO_ERROR);
398 }
399
getError() const400 status_t ResStringPool::getError() const
401 {
402 return mError;
403 }
404
uninit()405 void ResStringPool::uninit()
406 {
407 mError = NO_INIT;
408 if (mOwnedData) {
409 free(mOwnedData);
410 mOwnedData = NULL;
411 }
412 }
413
stringAt(size_t idx,size_t * outLen) const414 const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
415 {
416 if (mError == NO_ERROR && idx < mHeader->stringCount) {
417 const uint32_t off = (mEntries[idx]/sizeof(uint16_t));
418 if (off < (mStringPoolSize-1)) {
419 const char16_t* str = mStrings+off;
420 *outLen = *str;
421 if ((*str)&0x8000) {
422 str++;
423 *outLen = (((*outLen)&0x7fff)<<16) + *str;
424 }
425 if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) {
426 return str+1;
427 } else {
428 LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
429 (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize);
430 }
431 } else {
432 LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
433 (int)idx, (int)(off*sizeof(uint16_t)),
434 (int)(mStringPoolSize*sizeof(uint16_t)));
435 }
436 }
437 return NULL;
438 }
439
styleAt(const ResStringPool_ref & ref) const440 const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
441 {
442 return styleAt(ref.index);
443 }
444
styleAt(size_t idx) const445 const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
446 {
447 if (mError == NO_ERROR && idx < mHeader->styleCount) {
448 const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
449 if (off < mStylePoolSize) {
450 return (const ResStringPool_span*)(mStyles+off);
451 } else {
452 LOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
453 (int)idx, (int)(off*sizeof(uint32_t)),
454 (int)(mStylePoolSize*sizeof(uint32_t)));
455 }
456 }
457 return NULL;
458 }
459
indexOfString(const char16_t * str,size_t strLen) const460 ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
461 {
462 if (mError != NO_ERROR) {
463 return mError;
464 }
465
466 size_t len;
467
468 if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
469 // Do a binary search for the string...
470 ssize_t l = 0;
471 ssize_t h = mHeader->stringCount-1;
472
473 ssize_t mid;
474 while (l <= h) {
475 mid = l + (h - l)/2;
476 const char16_t* s = stringAt(mid, &len);
477 int c = s ? strzcmp16(s, len, str, strLen) : -1;
478 POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
479 String8(str).string(),
480 String8(s).string(),
481 c, (int)l, (int)mid, (int)h));
482 if (c == 0) {
483 return mid;
484 } else if (c < 0) {
485 l = mid + 1;
486 } else {
487 h = mid - 1;
488 }
489 }
490 } else {
491 // It is unusual to get the ID from an unsorted string block...
492 // most often this happens because we want to get IDs for style
493 // span tags; since those always appear at the end of the string
494 // block, start searching at the back.
495 for (int i=mHeader->stringCount-1; i>=0; i--) {
496 const char16_t* s = stringAt(i, &len);
497 POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
498 String8(str, strLen).string(),
499 String8(s).string(),
500 i));
501 if (s && strzcmp16(s, len, str, strLen) == 0) {
502 return i;
503 }
504 }
505 }
506
507 return NAME_NOT_FOUND;
508 }
509
size() const510 size_t ResStringPool::size() const
511 {
512 return (mError == NO_ERROR) ? mHeader->stringCount : 0;
513 }
514
515 // --------------------------------------------------------------------
516 // --------------------------------------------------------------------
517 // --------------------------------------------------------------------
518
ResXMLParser(const ResXMLTree & tree)519 ResXMLParser::ResXMLParser(const ResXMLTree& tree)
520 : mTree(tree), mEventCode(BAD_DOCUMENT)
521 {
522 }
523
restart()524 void ResXMLParser::restart()
525 {
526 mCurNode = NULL;
527 mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
528 }
529
getEventType() const530 ResXMLParser::event_code_t ResXMLParser::getEventType() const
531 {
532 return mEventCode;
533 }
534
next()535 ResXMLParser::event_code_t ResXMLParser::next()
536 {
537 if (mEventCode == START_DOCUMENT) {
538 mCurNode = mTree.mRootNode;
539 mCurExt = mTree.mRootExt;
540 return (mEventCode=mTree.mRootCode);
541 } else if (mEventCode >= FIRST_CHUNK_CODE) {
542 return nextNode();
543 }
544 return mEventCode;
545 }
546
getCommentID() const547 int32_t ResXMLParser::getCommentID() const
548 {
549 return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
550 }
551
getComment(size_t * outLen) const552 const uint16_t* ResXMLParser::getComment(size_t* outLen) const
553 {
554 int32_t id = getCommentID();
555 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
556 }
557
getLineNumber() const558 uint32_t ResXMLParser::getLineNumber() const
559 {
560 return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
561 }
562
getTextID() const563 int32_t ResXMLParser::getTextID() const
564 {
565 if (mEventCode == TEXT) {
566 return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
567 }
568 return -1;
569 }
570
getText(size_t * outLen) const571 const uint16_t* ResXMLParser::getText(size_t* outLen) const
572 {
573 int32_t id = getTextID();
574 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
575 }
576
getTextValue(Res_value * outValue) const577 ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
578 {
579 if (mEventCode == TEXT) {
580 outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
581 return sizeof(Res_value);
582 }
583 return BAD_TYPE;
584 }
585
getNamespacePrefixID() const586 int32_t ResXMLParser::getNamespacePrefixID() const
587 {
588 if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
589 return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
590 }
591 return -1;
592 }
593
getNamespacePrefix(size_t * outLen) const594 const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
595 {
596 int32_t id = getNamespacePrefixID();
597 //printf("prefix=%d event=%p\n", id, mEventCode);
598 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
599 }
600
getNamespaceUriID() const601 int32_t ResXMLParser::getNamespaceUriID() const
602 {
603 if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
604 return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
605 }
606 return -1;
607 }
608
getNamespaceUri(size_t * outLen) const609 const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
610 {
611 int32_t id = getNamespaceUriID();
612 //printf("uri=%d event=%p\n", id, mEventCode);
613 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
614 }
615
getElementNamespaceID() const616 int32_t ResXMLParser::getElementNamespaceID() const
617 {
618 if (mEventCode == START_TAG) {
619 return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
620 }
621 if (mEventCode == END_TAG) {
622 return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
623 }
624 return -1;
625 }
626
getElementNamespace(size_t * outLen) const627 const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
628 {
629 int32_t id = getElementNamespaceID();
630 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
631 }
632
getElementNameID() const633 int32_t ResXMLParser::getElementNameID() const
634 {
635 if (mEventCode == START_TAG) {
636 return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
637 }
638 if (mEventCode == END_TAG) {
639 return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
640 }
641 return -1;
642 }
643
getElementName(size_t * outLen) const644 const uint16_t* ResXMLParser::getElementName(size_t* outLen) const
645 {
646 int32_t id = getElementNameID();
647 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
648 }
649
getAttributeCount() const650 size_t ResXMLParser::getAttributeCount() const
651 {
652 if (mEventCode == START_TAG) {
653 return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
654 }
655 return 0;
656 }
657
getAttributeNamespaceID(size_t idx) const658 int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
659 {
660 if (mEventCode == START_TAG) {
661 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
662 if (idx < dtohs(tag->attributeCount)) {
663 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
664 (((const uint8_t*)tag)
665 + dtohs(tag->attributeStart)
666 + (dtohs(tag->attributeSize)*idx));
667 return dtohl(attr->ns.index);
668 }
669 }
670 return -2;
671 }
672
getAttributeNamespace(size_t idx,size_t * outLen) const673 const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
674 {
675 int32_t id = getAttributeNamespaceID(idx);
676 //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode);
677 //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
678 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
679 }
680
getAttributeNameID(size_t idx) const681 int32_t ResXMLParser::getAttributeNameID(size_t idx) const
682 {
683 if (mEventCode == START_TAG) {
684 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
685 if (idx < dtohs(tag->attributeCount)) {
686 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
687 (((const uint8_t*)tag)
688 + dtohs(tag->attributeStart)
689 + (dtohs(tag->attributeSize)*idx));
690 return dtohl(attr->name.index);
691 }
692 }
693 return -1;
694 }
695
getAttributeName(size_t idx,size_t * outLen) const696 const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
697 {
698 int32_t id = getAttributeNameID(idx);
699 //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode);
700 //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
701 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
702 }
703
getAttributeNameResID(size_t idx) const704 uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
705 {
706 int32_t id = getAttributeNameID(idx);
707 if (id >= 0 && (size_t)id < mTree.mNumResIds) {
708 return dtohl(mTree.mResIds[id]);
709 }
710 return 0;
711 }
712
getAttributeValueStringID(size_t idx) const713 int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
714 {
715 if (mEventCode == START_TAG) {
716 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
717 if (idx < dtohs(tag->attributeCount)) {
718 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
719 (((const uint8_t*)tag)
720 + dtohs(tag->attributeStart)
721 + (dtohs(tag->attributeSize)*idx));
722 return dtohl(attr->rawValue.index);
723 }
724 }
725 return -1;
726 }
727
getAttributeStringValue(size_t idx,size_t * outLen) const728 const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
729 {
730 int32_t id = getAttributeValueStringID(idx);
731 //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
732 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
733 }
734
getAttributeDataType(size_t idx) const735 int32_t ResXMLParser::getAttributeDataType(size_t idx) const
736 {
737 if (mEventCode == START_TAG) {
738 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
739 if (idx < dtohs(tag->attributeCount)) {
740 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
741 (((const uint8_t*)tag)
742 + dtohs(tag->attributeStart)
743 + (dtohs(tag->attributeSize)*idx));
744 return attr->typedValue.dataType;
745 }
746 }
747 return Res_value::TYPE_NULL;
748 }
749
getAttributeData(size_t idx) const750 int32_t ResXMLParser::getAttributeData(size_t idx) const
751 {
752 if (mEventCode == START_TAG) {
753 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
754 if (idx < dtohs(tag->attributeCount)) {
755 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
756 (((const uint8_t*)tag)
757 + dtohs(tag->attributeStart)
758 + (dtohs(tag->attributeSize)*idx));
759 return dtohl(attr->typedValue.data);
760 }
761 }
762 return 0;
763 }
764
getAttributeValue(size_t idx,Res_value * outValue) const765 ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
766 {
767 if (mEventCode == START_TAG) {
768 const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
769 if (idx < dtohs(tag->attributeCount)) {
770 const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
771 (((const uint8_t*)tag)
772 + dtohs(tag->attributeStart)
773 + (dtohs(tag->attributeSize)*idx));
774 outValue->copyFrom_dtoh(attr->typedValue);
775 return sizeof(Res_value);
776 }
777 }
778 return BAD_TYPE;
779 }
780
indexOfAttribute(const char * ns,const char * attr) const781 ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
782 {
783 String16 nsStr(ns != NULL ? ns : "");
784 String16 attrStr(attr);
785 return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
786 attrStr.string(), attrStr.size());
787 }
788
indexOfAttribute(const char16_t * ns,size_t nsLen,const char16_t * attr,size_t attrLen) const789 ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
790 const char16_t* attr, size_t attrLen) const
791 {
792 if (mEventCode == START_TAG) {
793 const size_t N = getAttributeCount();
794 for (size_t i=0; i<N; i++) {
795 size_t curNsLen, curAttrLen;
796 const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
797 const char16_t* curAttr = getAttributeName(i, &curAttrLen);
798 //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
799 // i, ns, attr, curNs, curAttr);
800 //printf(" --> attr=%s, curAttr=%s\n",
801 // String8(attr).string(), String8(curAttr).string());
802 if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
803 if (ns == NULL) {
804 if (curNs == NULL) return i;
805 } else if (curNs != NULL) {
806 //printf(" --> ns=%s, curNs=%s\n",
807 // String8(ns).string(), String8(curNs).string());
808 if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
809 }
810 }
811 }
812 }
813
814 return NAME_NOT_FOUND;
815 }
816
indexOfID() const817 ssize_t ResXMLParser::indexOfID() const
818 {
819 if (mEventCode == START_TAG) {
820 const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
821 if (idx > 0) return (idx-1);
822 }
823 return NAME_NOT_FOUND;
824 }
825
indexOfClass() const826 ssize_t ResXMLParser::indexOfClass() const
827 {
828 if (mEventCode == START_TAG) {
829 const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
830 if (idx > 0) return (idx-1);
831 }
832 return NAME_NOT_FOUND;
833 }
834
indexOfStyle() const835 ssize_t ResXMLParser::indexOfStyle() const
836 {
837 if (mEventCode == START_TAG) {
838 const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
839 if (idx > 0) return (idx-1);
840 }
841 return NAME_NOT_FOUND;
842 }
843
nextNode()844 ResXMLParser::event_code_t ResXMLParser::nextNode()
845 {
846 if (mEventCode < 0) {
847 return mEventCode;
848 }
849
850 do {
851 const ResXMLTree_node* next = (const ResXMLTree_node*)
852 (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
853 //LOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
854
855 if (((const uint8_t*)next) >= mTree.mDataEnd) {
856 mCurNode = NULL;
857 return (mEventCode=END_DOCUMENT);
858 }
859
860 if (mTree.validateNode(next) != NO_ERROR) {
861 mCurNode = NULL;
862 return (mEventCode=BAD_DOCUMENT);
863 }
864
865 mCurNode = next;
866 const uint16_t headerSize = dtohs(next->header.headerSize);
867 const uint32_t totalSize = dtohl(next->header.size);
868 mCurExt = ((const uint8_t*)next) + headerSize;
869 size_t minExtSize = 0;
870 event_code_t eventCode = (event_code_t)dtohs(next->header.type);
871 switch ((mEventCode=eventCode)) {
872 case RES_XML_START_NAMESPACE_TYPE:
873 case RES_XML_END_NAMESPACE_TYPE:
874 minExtSize = sizeof(ResXMLTree_namespaceExt);
875 break;
876 case RES_XML_START_ELEMENT_TYPE:
877 minExtSize = sizeof(ResXMLTree_attrExt);
878 break;
879 case RES_XML_END_ELEMENT_TYPE:
880 minExtSize = sizeof(ResXMLTree_endElementExt);
881 break;
882 case RES_XML_CDATA_TYPE:
883 minExtSize = sizeof(ResXMLTree_cdataExt);
884 break;
885 default:
886 LOGW("Unknown XML block: header type %d in node at %d\n",
887 (int)dtohs(next->header.type),
888 (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
889 continue;
890 }
891
892 if ((totalSize-headerSize) < minExtSize) {
893 LOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
894 (int)dtohs(next->header.type),
895 (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
896 (int)(totalSize-headerSize), (int)minExtSize);
897 return (mEventCode=BAD_DOCUMENT);
898 }
899
900 //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
901 // mCurNode, mCurExt, headerSize, minExtSize);
902
903 return eventCode;
904 } while (true);
905 }
906
getPosition(ResXMLParser::ResXMLPosition * pos) const907 void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
908 {
909 pos->eventCode = mEventCode;
910 pos->curNode = mCurNode;
911 pos->curExt = mCurExt;
912 }
913
setPosition(const ResXMLParser::ResXMLPosition & pos)914 void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
915 {
916 mEventCode = pos.eventCode;
917 mCurNode = pos.curNode;
918 mCurExt = pos.curExt;
919 }
920
921
922 // --------------------------------------------------------------------
923
924 static volatile int32_t gCount = 0;
925
ResXMLTree()926 ResXMLTree::ResXMLTree()
927 : ResXMLParser(*this)
928 , mError(NO_INIT), mOwnedData(NULL)
929 {
930 //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
931 restart();
932 }
933
ResXMLTree(const void * data,size_t size,bool copyData)934 ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData)
935 : ResXMLParser(*this)
936 , mError(NO_INIT), mOwnedData(NULL)
937 {
938 //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
939 setTo(data, size, copyData);
940 }
941
~ResXMLTree()942 ResXMLTree::~ResXMLTree()
943 {
944 //LOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
945 uninit();
946 }
947
setTo(const void * data,size_t size,bool copyData)948 status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
949 {
950 uninit();
951 mEventCode = START_DOCUMENT;
952
953 if (copyData) {
954 mOwnedData = malloc(size);
955 if (mOwnedData == NULL) {
956 return (mError=NO_MEMORY);
957 }
958 memcpy(mOwnedData, data, size);
959 data = mOwnedData;
960 }
961
962 mHeader = (const ResXMLTree_header*)data;
963 mSize = dtohl(mHeader->header.size);
964 if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
965 LOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n",
966 (int)dtohs(mHeader->header.headerSize),
967 (int)dtohl(mHeader->header.size), (int)size);
968 mError = BAD_TYPE;
969 restart();
970 return mError;
971 }
972 mDataEnd = ((const uint8_t*)mHeader) + mSize;
973
974 mStrings.uninit();
975 mRootNode = NULL;
976 mResIds = NULL;
977 mNumResIds = 0;
978
979 // First look for a couple interesting chunks: the string block
980 // and first XML node.
981 const ResChunk_header* chunk =
982 (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
983 const ResChunk_header* lastChunk = chunk;
984 while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
985 ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
986 status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
987 if (err != NO_ERROR) {
988 mError = err;
989 goto done;
990 }
991 const uint16_t type = dtohs(chunk->type);
992 const size_t size = dtohl(chunk->size);
993 XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
994 (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
995 if (type == RES_STRING_POOL_TYPE) {
996 mStrings.setTo(chunk, size);
997 } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
998 mResIds = (const uint32_t*)
999 (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
1000 mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
1001 } else if (type >= RES_XML_FIRST_CHUNK_TYPE
1002 && type <= RES_XML_LAST_CHUNK_TYPE) {
1003 if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
1004 mError = BAD_TYPE;
1005 goto done;
1006 }
1007 mCurNode = (const ResXMLTree_node*)lastChunk;
1008 if (nextNode() == BAD_DOCUMENT) {
1009 mError = BAD_TYPE;
1010 goto done;
1011 }
1012 mRootNode = mCurNode;
1013 mRootExt = mCurExt;
1014 mRootCode = mEventCode;
1015 break;
1016 } else {
1017 XML_NOISY(printf("Skipping unknown chunk!\n"));
1018 }
1019 lastChunk = chunk;
1020 chunk = (const ResChunk_header*)
1021 (((const uint8_t*)chunk) + size);
1022 }
1023
1024 if (mRootNode == NULL) {
1025 LOGW("Bad XML block: no root element node found\n");
1026 mError = BAD_TYPE;
1027 goto done;
1028 }
1029
1030 mError = mStrings.getError();
1031
1032 done:
1033 restart();
1034 return mError;
1035 }
1036
getError() const1037 status_t ResXMLTree::getError() const
1038 {
1039 return mError;
1040 }
1041
uninit()1042 void ResXMLTree::uninit()
1043 {
1044 mError = NO_INIT;
1045 if (mOwnedData) {
1046 free(mOwnedData);
1047 mOwnedData = NULL;
1048 }
1049 restart();
1050 }
1051
getStrings() const1052 const ResStringPool& ResXMLTree::getStrings() const
1053 {
1054 return mStrings;
1055 }
1056
validateNode(const ResXMLTree_node * node) const1057 status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
1058 {
1059 const uint16_t eventCode = dtohs(node->header.type);
1060
1061 status_t err = validate_chunk(
1062 &node->header, sizeof(ResXMLTree_node),
1063 mDataEnd, "ResXMLTree_node");
1064
1065 if (err >= NO_ERROR) {
1066 // Only perform additional validation on START nodes
1067 if (eventCode != RES_XML_START_ELEMENT_TYPE) {
1068 return NO_ERROR;
1069 }
1070
1071 const uint16_t headerSize = dtohs(node->header.headerSize);
1072 const uint32_t size = dtohl(node->header.size);
1073 const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
1074 (((const uint8_t*)node) + headerSize);
1075 // check for sensical values pulled out of the stream so far...
1076 if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
1077 && ((void*)attrExt > (void*)node)) {
1078 const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
1079 * dtohs(attrExt->attributeCount);
1080 if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
1081 return NO_ERROR;
1082 }
1083 LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
1084 (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
1085 (unsigned int)(size-headerSize));
1086 }
1087 else {
1088 LOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
1089 (unsigned int)headerSize, (unsigned int)size);
1090 }
1091 return BAD_TYPE;
1092 }
1093
1094 return err;
1095
1096 #if 0
1097 const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
1098
1099 const uint16_t headerSize = dtohs(node->header.headerSize);
1100 const uint32_t size = dtohl(node->header.size);
1101
1102 if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
1103 if (size >= headerSize) {
1104 if (((const uint8_t*)node) <= (mDataEnd-size)) {
1105 if (!isStart) {
1106 return NO_ERROR;
1107 }
1108 if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
1109 <= (size-headerSize)) {
1110 return NO_ERROR;
1111 }
1112 LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
1113 ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
1114 (int)(size-headerSize));
1115 return BAD_TYPE;
1116 }
1117 LOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
1118 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
1119 return BAD_TYPE;
1120 }
1121 LOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
1122 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
1123 (int)headerSize, (int)size);
1124 return BAD_TYPE;
1125 }
1126 LOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
1127 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
1128 (int)headerSize);
1129 return BAD_TYPE;
1130 #endif
1131 }
1132
1133 // --------------------------------------------------------------------
1134 // --------------------------------------------------------------------
1135 // --------------------------------------------------------------------
1136
1137 struct ResTable::Header
1138 {
Headerandroid::ResTable::Header1139 Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
1140
1141 ResTable* const owner;
1142 void* ownedData;
1143 const ResTable_header* header;
1144 size_t size;
1145 const uint8_t* dataEnd;
1146 size_t index;
1147 void* cookie;
1148
1149 ResStringPool values;
1150 };
1151
1152 struct ResTable::Type
1153 {
Typeandroid::ResTable::Type1154 Type(const Header* _header, const Package* _package, size_t count)
1155 : header(_header), package(_package), entryCount(count),
1156 typeSpec(NULL), typeSpecFlags(NULL) { }
1157 const Header* const header;
1158 const Package* const package;
1159 const size_t entryCount;
1160 const ResTable_typeSpec* typeSpec;
1161 const uint32_t* typeSpecFlags;
1162 Vector<const ResTable_type*> configs;
1163 };
1164
1165 struct ResTable::Package
1166 {
Packageandroid::ResTable::Package1167 Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
1168 : owner(_owner), header(_header), package(_package) { }
~Packageandroid::ResTable::Package1169 ~Package()
1170 {
1171 size_t i = types.size();
1172 while (i > 0) {
1173 i--;
1174 delete types[i];
1175 }
1176 }
1177
1178 ResTable* const owner;
1179 const Header* const header;
1180 const ResTable_package* const package;
1181 Vector<Type*> types;
1182
1183 ResStringPool typeStrings;
1184 ResStringPool keyStrings;
1185
getTypeandroid::ResTable::Package1186 const Type* getType(size_t idx) const {
1187 return idx < types.size() ? types[idx] : NULL;
1188 }
1189 };
1190
1191 // A group of objects describing a particular resource package.
1192 // The first in 'package' is always the root object (from the resource
1193 // table that defined the package); the ones after are skins on top of it.
1194 struct ResTable::PackageGroup
1195 {
PackageGroupandroid::ResTable::PackageGroup1196 PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
1197 : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
~PackageGroupandroid::ResTable::PackageGroup1198 ~PackageGroup() {
1199 clearBagCache();
1200 const size_t N = packages.size();
1201 for (size_t i=0; i<N; i++) {
1202 Package* pkg = packages[i];
1203 if (pkg->owner == owner) {
1204 delete pkg;
1205 }
1206 }
1207 }
1208
clearBagCacheandroid::ResTable::PackageGroup1209 void clearBagCache() {
1210 if (bags) {
1211 TABLE_NOISY(printf("bags=%p\n", bags));
1212 Package* pkg = packages[0];
1213 TABLE_NOISY(printf("typeCount=%x\n", typeCount));
1214 for (size_t i=0; i<typeCount; i++) {
1215 TABLE_NOISY(printf("type=%d\n", i));
1216 const Type* type = pkg->getType(i);
1217 if (type != NULL) {
1218 bag_set** typeBags = bags[i];
1219 TABLE_NOISY(printf("typeBags=%p\n", typeBags));
1220 if (typeBags) {
1221 TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
1222 const size_t N = type->entryCount;
1223 for (size_t j=0; j<N; j++) {
1224 if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
1225 free(typeBags[j]);
1226 }
1227 free(typeBags);
1228 }
1229 }
1230 }
1231 free(bags);
1232 bags = NULL;
1233 }
1234 }
1235
1236 ResTable* const owner;
1237 String16 const name;
1238 uint32_t const id;
1239 Vector<Package*> packages;
1240
1241 // This is for finding typeStrings and other common package stuff.
1242 Package* basePackage;
1243
1244 // For quick access.
1245 size_t typeCount;
1246
1247 // Computed attribute bags, first indexed by the type and second
1248 // by the entry in that type.
1249 bag_set*** bags;
1250 };
1251
1252 struct ResTable::bag_set
1253 {
1254 size_t numAttrs; // number in array
1255 size_t availAttrs; // total space in array
1256 uint32_t typeSpecFlags;
1257 // Followed by 'numAttr' bag_entry structures.
1258 };
1259
Theme(const ResTable & table)1260 ResTable::Theme::Theme(const ResTable& table)
1261 : mTable(table)
1262 {
1263 memset(mPackages, 0, sizeof(mPackages));
1264 }
1265
~Theme()1266 ResTable::Theme::~Theme()
1267 {
1268 for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1269 package_info* pi = mPackages[i];
1270 if (pi != NULL) {
1271 free_package(pi);
1272 }
1273 }
1274 }
1275
free_package(package_info * pi)1276 void ResTable::Theme::free_package(package_info* pi)
1277 {
1278 for (size_t j=0; j<pi->numTypes; j++) {
1279 theme_entry* te = pi->types[j].entries;
1280 if (te != NULL) {
1281 free(te);
1282 }
1283 }
1284 free(pi);
1285 }
1286
copy_package(package_info * pi)1287 ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
1288 {
1289 package_info* newpi = (package_info*)malloc(
1290 sizeof(package_info) + (pi->numTypes*sizeof(type_info)));
1291 newpi->numTypes = pi->numTypes;
1292 for (size_t j=0; j<newpi->numTypes; j++) {
1293 size_t cnt = pi->types[j].numEntries;
1294 newpi->types[j].numEntries = cnt;
1295 theme_entry* te = pi->types[j].entries;
1296 if (te != NULL) {
1297 theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
1298 newpi->types[j].entries = newte;
1299 memcpy(newte, te, cnt*sizeof(theme_entry));
1300 } else {
1301 newpi->types[j].entries = NULL;
1302 }
1303 }
1304 return newpi;
1305 }
1306
applyStyle(uint32_t resID,bool force)1307 status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
1308 {
1309 const bag_entry* bag;
1310 uint32_t bagTypeSpecFlags = 0;
1311 mTable.lock();
1312 const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
1313 TABLE_NOISY(LOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
1314 if (N < 0) {
1315 mTable.unlock();
1316 return N;
1317 }
1318
1319 uint32_t curPackage = 0xffffffff;
1320 ssize_t curPackageIndex = 0;
1321 package_info* curPI = NULL;
1322 uint32_t curType = 0xffffffff;
1323 size_t numEntries = 0;
1324 theme_entry* curEntries = NULL;
1325
1326 const bag_entry* end = bag + N;
1327 while (bag < end) {
1328 const uint32_t attrRes = bag->map.name.ident;
1329 const uint32_t p = Res_GETPACKAGE(attrRes);
1330 const uint32_t t = Res_GETTYPE(attrRes);
1331 const uint32_t e = Res_GETENTRY(attrRes);
1332
1333 if (curPackage != p) {
1334 const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
1335 if (pidx < 0) {
1336 LOGE("Style contains key with bad package: 0x%08x\n", attrRes);
1337 bag++;
1338 continue;
1339 }
1340 curPackage = p;
1341 curPackageIndex = pidx;
1342 curPI = mPackages[pidx];
1343 if (curPI == NULL) {
1344 PackageGroup* const grp = mTable.mPackageGroups[pidx];
1345 int cnt = grp->typeCount;
1346 curPI = (package_info*)malloc(
1347 sizeof(package_info) + (cnt*sizeof(type_info)));
1348 curPI->numTypes = cnt;
1349 memset(curPI->types, 0, cnt*sizeof(type_info));
1350 mPackages[pidx] = curPI;
1351 }
1352 curType = 0xffffffff;
1353 }
1354 if (curType != t) {
1355 if (t >= curPI->numTypes) {
1356 LOGE("Style contains key with bad type: 0x%08x\n", attrRes);
1357 bag++;
1358 continue;
1359 }
1360 curType = t;
1361 curEntries = curPI->types[t].entries;
1362 if (curEntries == NULL) {
1363 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
1364 const Type* type = grp->packages[0]->getType(t);
1365 int cnt = type != NULL ? type->entryCount : 0;
1366 curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
1367 memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
1368 curPI->types[t].numEntries = cnt;
1369 curPI->types[t].entries = curEntries;
1370 }
1371 numEntries = curPI->types[t].numEntries;
1372 }
1373 if (e >= numEntries) {
1374 LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
1375 bag++;
1376 continue;
1377 }
1378 theme_entry* curEntry = curEntries + e;
1379 TABLE_NOISY(LOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
1380 attrRes, bag->map.value.dataType, bag->map.value.data,
1381 curEntry->value.dataType));
1382 if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
1383 curEntry->stringBlock = bag->stringBlock;
1384 curEntry->typeSpecFlags |= bagTypeSpecFlags;
1385 curEntry->value = bag->map.value;
1386 }
1387
1388 bag++;
1389 }
1390
1391 mTable.unlock();
1392
1393 //LOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this);
1394 //dumpToLog();
1395
1396 return NO_ERROR;
1397 }
1398
setTo(const Theme & other)1399 status_t ResTable::Theme::setTo(const Theme& other)
1400 {
1401 //LOGI("Setting theme %p from theme %p...\n", this, &other);
1402 //dumpToLog();
1403 //other.dumpToLog();
1404
1405 if (&mTable == &other.mTable) {
1406 for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1407 if (mPackages[i] != NULL) {
1408 free_package(mPackages[i]);
1409 }
1410 if (other.mPackages[i] != NULL) {
1411 mPackages[i] = copy_package(other.mPackages[i]);
1412 } else {
1413 mPackages[i] = NULL;
1414 }
1415 }
1416 } else {
1417 // @todo: need to really implement this, not just copy
1418 // the system package (which is still wrong because it isn't
1419 // fixing up resource references).
1420 for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1421 if (mPackages[i] != NULL) {
1422 free_package(mPackages[i]);
1423 }
1424 if (i == 0 && other.mPackages[i] != NULL) {
1425 mPackages[i] = copy_package(other.mPackages[i]);
1426 } else {
1427 mPackages[i] = NULL;
1428 }
1429 }
1430 }
1431
1432 //LOGI("Final theme:");
1433 //dumpToLog();
1434
1435 return NO_ERROR;
1436 }
1437
getAttribute(uint32_t resID,Res_value * outValue,uint32_t * outTypeSpecFlags) const1438 ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
1439 uint32_t* outTypeSpecFlags) const
1440 {
1441 int cnt = 20;
1442
1443 if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
1444
1445 do {
1446 const ssize_t p = mTable.getResourcePackageIndex(resID);
1447 const uint32_t t = Res_GETTYPE(resID);
1448 const uint32_t e = Res_GETENTRY(resID);
1449
1450 TABLE_NOISY(LOGV("Looking up attr 0x%08x in theme %p", resID, this));
1451
1452 if (p >= 0) {
1453 const package_info* const pi = mPackages[p];
1454 if (pi != NULL) {
1455 if (t < pi->numTypes) {
1456 const type_info& ti = pi->types[t];
1457 if (e < ti.numEntries) {
1458 const theme_entry& te = ti.entries[e];
1459 if (outTypeSpecFlags != NULL) {
1460 *outTypeSpecFlags |= te.typeSpecFlags;
1461 }
1462 const uint8_t type = te.value.dataType;
1463 if (type == Res_value::TYPE_ATTRIBUTE) {
1464 if (cnt > 0) {
1465 cnt--;
1466 resID = te.value.data;
1467 continue;
1468 }
1469 LOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
1470 return BAD_INDEX;
1471 } else if (type != Res_value::TYPE_NULL) {
1472 *outValue = te.value;
1473 return te.stringBlock;
1474 }
1475 return BAD_INDEX;
1476 }
1477 }
1478 }
1479 }
1480 break;
1481
1482 } while (true);
1483
1484 return BAD_INDEX;
1485 }
1486
resolveAttributeReference(Res_value * inOutValue,ssize_t blockIndex,uint32_t * outLastRef,uint32_t * inoutTypeSpecFlags,ResTable_config * inoutConfig) const1487 ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
1488 ssize_t blockIndex, uint32_t* outLastRef,
1489 uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
1490 {
1491 //printf("Resolving type=0x%x\n", inOutValue->dataType);
1492 if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
1493 uint32_t newTypeSpecFlags;
1494 blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
1495 if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
1496 //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
1497 if (blockIndex < 0) {
1498 return blockIndex;
1499 }
1500 }
1501 return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
1502 inoutTypeSpecFlags, inoutConfig);
1503 }
1504
dumpToLog() const1505 void ResTable::Theme::dumpToLog() const
1506 {
1507 LOGI("Theme %p:\n", this);
1508 for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1509 package_info* pi = mPackages[i];
1510 if (pi == NULL) continue;
1511
1512 LOGI(" Package #0x%02x:\n", (int)(i+1));
1513 for (size_t j=0; j<pi->numTypes; j++) {
1514 type_info& ti = pi->types[j];
1515 if (ti.numEntries == 0) continue;
1516
1517 LOGI(" Type #0x%02x:\n", (int)(j+1));
1518 for (size_t k=0; k<ti.numEntries; k++) {
1519 theme_entry& te = ti.entries[k];
1520 if (te.value.dataType == Res_value::TYPE_NULL) continue;
1521 LOGI(" 0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
1522 (int)Res_MAKEID(i, j, k),
1523 te.value.dataType, (int)te.value.data, (int)te.stringBlock);
1524 }
1525 }
1526 }
1527 }
1528
ResTable()1529 ResTable::ResTable()
1530 : mError(NO_INIT)
1531 {
1532 memset(&mParams, 0, sizeof(mParams));
1533 memset(mPackageMap, 0, sizeof(mPackageMap));
1534 //LOGI("Creating ResTable %p\n", this);
1535 }
1536
ResTable(const void * data,size_t size,void * cookie,bool copyData)1537 ResTable::ResTable(const void* data, size_t size, void* cookie, bool copyData)
1538 : mError(NO_INIT)
1539 {
1540 memset(&mParams, 0, sizeof(mParams));
1541 memset(mPackageMap, 0, sizeof(mPackageMap));
1542 add(data, size, cookie, copyData);
1543 LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
1544 //LOGI("Creating ResTable %p\n", this);
1545 }
1546
~ResTable()1547 ResTable::~ResTable()
1548 {
1549 //LOGI("Destroying ResTable in %p\n", this);
1550 uninit();
1551 }
1552
getResourcePackageIndex(uint32_t resID) const1553 inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
1554 {
1555 return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
1556 }
1557
add(const void * data,size_t size,void * cookie,bool copyData)1558 status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
1559 {
1560 return add(data, size, cookie, NULL, copyData);
1561 }
1562
add(Asset * asset,void * cookie,bool copyData)1563 status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
1564 {
1565 const void* data = asset->getBuffer(true);
1566 if (data == NULL) {
1567 LOGW("Unable to get buffer of resource asset file");
1568 return UNKNOWN_ERROR;
1569 }
1570 size_t size = (size_t)asset->getLength();
1571 return add(data, size, cookie, asset, copyData);
1572 }
1573
add(ResTable * src)1574 status_t ResTable::add(ResTable* src)
1575 {
1576 mError = src->mError;
1577
1578 for (size_t i=0; i<src->mHeaders.size(); i++) {
1579 mHeaders.add(src->mHeaders[i]);
1580 }
1581
1582 for (size_t i=0; i<src->mPackageGroups.size(); i++) {
1583 PackageGroup* srcPg = src->mPackageGroups[i];
1584 PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
1585 for (size_t j=0; j<srcPg->packages.size(); j++) {
1586 pg->packages.add(srcPg->packages[j]);
1587 }
1588 pg->basePackage = srcPg->basePackage;
1589 pg->typeCount = srcPg->typeCount;
1590 mPackageGroups.add(pg);
1591 }
1592
1593 memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
1594
1595 return mError;
1596 }
1597
add(const void * data,size_t size,void * cookie,Asset * asset,bool copyData)1598 status_t ResTable::add(const void* data, size_t size, void* cookie,
1599 Asset* asset, bool copyData)
1600 {
1601 if (!data) return NO_ERROR;
1602 Header* header = new Header(this);
1603 header->index = mHeaders.size();
1604 header->cookie = cookie;
1605 mHeaders.add(header);
1606
1607 const bool notDeviceEndian = htods(0xf0) != 0xf0;
1608
1609 LOAD_TABLE_NOISY(
1610 LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
1611 data, size, cookie, asset, copyData));
1612
1613 if (copyData || notDeviceEndian) {
1614 header->ownedData = malloc(size);
1615 if (header->ownedData == NULL) {
1616 return (mError=NO_MEMORY);
1617 }
1618 memcpy(header->ownedData, data, size);
1619 data = header->ownedData;
1620 }
1621
1622 header->header = (const ResTable_header*)data;
1623 header->size = dtohl(header->header->header.size);
1624 //LOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
1625 // dtohl(header->header->header.size), header->header->header.size);
1626 LOAD_TABLE_NOISY(LOGV("Loading ResTable @%p:\n", header->header));
1627 LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256,
1628 16, 16, 0, false, printToLogFunc));
1629 if (dtohs(header->header->header.headerSize) > header->size
1630 || header->size > size) {
1631 LOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
1632 (int)dtohs(header->header->header.headerSize),
1633 (int)header->size, (int)size);
1634 return (mError=BAD_TYPE);
1635 }
1636 if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
1637 LOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
1638 (int)dtohs(header->header->header.headerSize),
1639 (int)header->size);
1640 return (mError=BAD_TYPE);
1641 }
1642 header->dataEnd = ((const uint8_t*)header->header) + header->size;
1643
1644 // Iterate through all chunks.
1645 size_t curPackage = 0;
1646
1647 const ResChunk_header* chunk =
1648 (const ResChunk_header*)(((const uint8_t*)header->header)
1649 + dtohs(header->header->header.headerSize));
1650 while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
1651 ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
1652 status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
1653 if (err != NO_ERROR) {
1654 return (mError=err);
1655 }
1656 TABLE_NOISY(LOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
1657 dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
1658 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
1659 const size_t csize = dtohl(chunk->size);
1660 const uint16_t ctype = dtohs(chunk->type);
1661 if (ctype == RES_STRING_POOL_TYPE) {
1662 if (header->values.getError() != NO_ERROR) {
1663 // Only use the first string chunk; ignore any others that
1664 // may appear.
1665 status_t err = header->values.setTo(chunk, csize);
1666 if (err != NO_ERROR) {
1667 return (mError=err);
1668 }
1669 } else {
1670 LOGW("Multiple string chunks found in resource table.");
1671 }
1672 } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
1673 if (curPackage >= dtohl(header->header->packageCount)) {
1674 LOGW("More package chunks were found than the %d declared in the header.",
1675 dtohl(header->header->packageCount));
1676 return (mError=BAD_TYPE);
1677 }
1678 if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
1679 return mError;
1680 }
1681 curPackage++;
1682 } else {
1683 LOGW("Unknown chunk type %p in table at %p.\n",
1684 (void*)(int)(ctype),
1685 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
1686 }
1687 chunk = (const ResChunk_header*)
1688 (((const uint8_t*)chunk) + csize);
1689 }
1690
1691 if (curPackage < dtohl(header->header->packageCount)) {
1692 LOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
1693 (int)curPackage, dtohl(header->header->packageCount));
1694 return (mError=BAD_TYPE);
1695 }
1696 mError = header->values.getError();
1697 if (mError != NO_ERROR) {
1698 LOGW("No string values found in resource table!");
1699 }
1700 TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
1701 return mError;
1702 }
1703
getError() const1704 status_t ResTable::getError() const
1705 {
1706 return mError;
1707 }
1708
uninit()1709 void ResTable::uninit()
1710 {
1711 mError = NO_INIT;
1712 size_t N = mPackageGroups.size();
1713 for (size_t i=0; i<N; i++) {
1714 PackageGroup* g = mPackageGroups[i];
1715 delete g;
1716 }
1717 N = mHeaders.size();
1718 for (size_t i=0; i<N; i++) {
1719 Header* header = mHeaders[i];
1720 if (header->owner == this) {
1721 if (header->ownedData) {
1722 free(header->ownedData);
1723 }
1724 delete header;
1725 }
1726 }
1727
1728 mPackageGroups.clear();
1729 mHeaders.clear();
1730 }
1731
getResourceName(uint32_t resID,resource_name * outName) const1732 bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
1733 {
1734 if (mError != NO_ERROR) {
1735 return false;
1736 }
1737
1738 const ssize_t p = getResourcePackageIndex(resID);
1739 const int t = Res_GETTYPE(resID);
1740 const int e = Res_GETENTRY(resID);
1741
1742 if (p < 0) {
1743 if (Res_GETPACKAGE(resID)+1 == 0) {
1744 LOGW("No package identifier when getting name for resource number 0x%08x", resID);
1745 } else {
1746 LOGW("Resources don't contain package for resource number 0x%08x", resID);
1747 }
1748 return false;
1749 }
1750 if (t < 0) {
1751 LOGW("No type identifier when getting name for resource number 0x%08x", resID);
1752 return false;
1753 }
1754
1755 const PackageGroup* const grp = mPackageGroups[p];
1756 if (grp == NULL) {
1757 LOGW("Bad identifier when getting name for resource number 0x%08x", resID);
1758 return false;
1759 }
1760 if (grp->packages.size() > 0) {
1761 const Package* const package = grp->packages[0];
1762
1763 const ResTable_type* type;
1764 const ResTable_entry* entry;
1765 ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL);
1766 if (offset <= 0) {
1767 return false;
1768 }
1769
1770 outName->package = grp->name.string();
1771 outName->packageLen = grp->name.size();
1772 outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
1773 outName->name = grp->basePackage->keyStrings.stringAt(
1774 dtohl(entry->key.index), &outName->nameLen);
1775 return true;
1776 }
1777
1778 return false;
1779 }
1780
getResource(uint32_t resID,Res_value * outValue,bool mayBeBag,uint32_t * outSpecFlags,ResTable_config * outConfig) const1781 ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
1782 uint32_t* outSpecFlags, ResTable_config* outConfig) const
1783 {
1784 if (mError != NO_ERROR) {
1785 return mError;
1786 }
1787
1788 const ssize_t p = getResourcePackageIndex(resID);
1789 const int t = Res_GETTYPE(resID);
1790 const int e = Res_GETENTRY(resID);
1791
1792 if (p < 0) {
1793 if (Res_GETPACKAGE(resID)+1 == 0) {
1794 LOGW("No package identifier when getting name for resource number 0x%08x", resID);
1795 } else {
1796 LOGW("Resources don't contain package for resource number 0x%08x", resID);
1797 }
1798 return BAD_INDEX;
1799 }
1800 if (t < 0) {
1801 LOGW("No type identifier when getting value for resource number 0x%08x", resID);
1802 return BAD_INDEX;
1803 }
1804
1805 const Res_value* bestValue = NULL;
1806 const Package* bestPackage = NULL;
1807 ResTable_config bestItem;
1808 memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
1809
1810 if (outSpecFlags != NULL) *outSpecFlags = 0;
1811
1812 // Look through all resource packages, starting with the most
1813 // recently added.
1814 const PackageGroup* const grp = mPackageGroups[p];
1815 if (grp == NULL) {
1816 LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
1817 return false;
1818 }
1819 size_t ip = grp->packages.size();
1820 while (ip > 0) {
1821 ip--;
1822
1823 const Package* const package = grp->packages[ip];
1824
1825 const ResTable_type* type;
1826 const ResTable_entry* entry;
1827 const Type* typeClass;
1828 ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
1829 if (offset <= 0) {
1830 if (offset < 0) {
1831 LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %d: 0x%08x\n",
1832 resID, t, e, (int)ip, (int)offset);
1833 return offset;
1834 }
1835 continue;
1836 }
1837
1838 if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
1839 if (!mayBeBag) {
1840 LOGW("Requesting resource %p failed because it is complex\n",
1841 (void*)resID);
1842 }
1843 continue;
1844 }
1845
1846 TABLE_NOISY(aout << "Resource type data: "
1847 << HexDump(type, dtohl(type->header.size)) << endl);
1848
1849 if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
1850 LOGW("ResTable_item at %d is beyond type chunk data %d",
1851 (int)offset, dtohl(type->header.size));
1852 return BAD_TYPE;
1853 }
1854
1855 const Res_value* item =
1856 (const Res_value*)(((const uint8_t*)type) + offset);
1857 ResTable_config thisConfig;
1858 thisConfig.copyFromDtoH(type->config);
1859
1860 if (outSpecFlags != NULL) {
1861 if (typeClass->typeSpecFlags != NULL) {
1862 *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
1863 } else {
1864 *outSpecFlags = -1;
1865 }
1866 }
1867
1868 if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
1869 continue;
1870 }
1871
1872 bestItem = thisConfig;
1873 bestValue = item;
1874 bestPackage = package;
1875 }
1876
1877 TABLE_NOISY(printf("Found result: package %p\n", bestPackage));
1878
1879 if (bestValue) {
1880 outValue->size = dtohs(bestValue->size);
1881 outValue->res0 = bestValue->res0;
1882 outValue->dataType = bestValue->dataType;
1883 outValue->data = dtohl(bestValue->data);
1884 if (outConfig != NULL) {
1885 *outConfig = bestItem;
1886 }
1887 TABLE_NOISY(size_t len;
1888 printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
1889 bestPackage->header->index,
1890 outValue->dataType,
1891 outValue->dataType == bestValue->TYPE_STRING
1892 ? String8(bestPackage->header->values.stringAt(
1893 outValue->data, &len)).string()
1894 : "",
1895 outValue->data));
1896 return bestPackage->header->index;
1897 }
1898
1899 return BAD_INDEX;
1900 }
1901
resolveReference(Res_value * value,ssize_t blockIndex,uint32_t * outLastRef,uint32_t * inoutTypeSpecFlags,ResTable_config * outConfig) const1902 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
1903 uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
1904 ResTable_config* outConfig) const
1905 {
1906 int count=0;
1907 while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
1908 && value->data != 0 && count < 20) {
1909 if (outLastRef) *outLastRef = value->data;
1910 uint32_t lastRef = value->data;
1911 uint32_t newFlags = 0;
1912 const ssize_t newIndex = getResource(value->data, value, true, &newFlags,
1913 outConfig);
1914 //LOGI("Resolving reference d=%p: newIndex=%d, t=0x%02x, d=%p\n",
1915 // (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data);
1916 //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
1917 if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
1918 if (newIndex < 0) {
1919 // This can fail if the resource being referenced is a style...
1920 // in this case, just return the reference, and expect the
1921 // caller to deal with.
1922 return blockIndex;
1923 }
1924 blockIndex = newIndex;
1925 count++;
1926 }
1927 return blockIndex;
1928 }
1929
valueToString(const Res_value * value,size_t stringBlock,char16_t tmpBuffer[TMP_BUFFER_SIZE],size_t * outLen)1930 const char16_t* ResTable::valueToString(
1931 const Res_value* value, size_t stringBlock,
1932 char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen)
1933 {
1934 if (!value) {
1935 return NULL;
1936 }
1937 if (value->dataType == value->TYPE_STRING) {
1938 return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
1939 }
1940 // XXX do int to string conversions.
1941 return NULL;
1942 }
1943
lockBag(uint32_t resID,const bag_entry ** outBag) const1944 ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
1945 {
1946 mLock.lock();
1947 ssize_t err = getBagLocked(resID, outBag);
1948 if (err < NO_ERROR) {
1949 //printf("*** get failed! unlocking\n");
1950 mLock.unlock();
1951 }
1952 return err;
1953 }
1954
unlockBag(const bag_entry * bag) const1955 void ResTable::unlockBag(const bag_entry* bag) const
1956 {
1957 //printf("<<< unlockBag %p\n", this);
1958 mLock.unlock();
1959 }
1960
lock() const1961 void ResTable::lock() const
1962 {
1963 mLock.lock();
1964 }
1965
unlock() const1966 void ResTable::unlock() const
1967 {
1968 mLock.unlock();
1969 }
1970
getBagLocked(uint32_t resID,const bag_entry ** outBag,uint32_t * outTypeSpecFlags) const1971 ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
1972 uint32_t* outTypeSpecFlags) const
1973 {
1974 if (mError != NO_ERROR) {
1975 return mError;
1976 }
1977
1978 const ssize_t p = getResourcePackageIndex(resID);
1979 const int t = Res_GETTYPE(resID);
1980 const int e = Res_GETENTRY(resID);
1981
1982 if (p < 0) {
1983 LOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
1984 return BAD_INDEX;
1985 }
1986 if (t < 0) {
1987 LOGW("No type identifier when getting bag for resource number 0x%08x", resID);
1988 return BAD_INDEX;
1989 }
1990
1991 //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
1992 PackageGroup* const grp = mPackageGroups[p];
1993 if (grp == NULL) {
1994 LOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
1995 return false;
1996 }
1997
1998 if (t >= (int)grp->typeCount) {
1999 LOGW("Type identifier 0x%x is larger than type count 0x%x",
2000 t+1, (int)grp->typeCount);
2001 return BAD_INDEX;
2002 }
2003
2004 const Package* const basePackage = grp->packages[0];
2005
2006 const Type* const typeConfigs = basePackage->getType(t);
2007
2008 const size_t NENTRY = typeConfigs->entryCount;
2009 if (e >= (int)NENTRY) {
2010 LOGW("Entry identifier 0x%x is larger than entry count 0x%x",
2011 e, (int)typeConfigs->entryCount);
2012 return BAD_INDEX;
2013 }
2014
2015 // First see if we've already computed this bag...
2016 if (grp->bags) {
2017 bag_set** typeSet = grp->bags[t];
2018 if (typeSet) {
2019 bag_set* set = typeSet[e];
2020 if (set) {
2021 if (set != (bag_set*)0xFFFFFFFF) {
2022 if (outTypeSpecFlags != NULL) {
2023 *outTypeSpecFlags = set->typeSpecFlags;
2024 }
2025 *outBag = (bag_entry*)(set+1);
2026 //LOGI("Found existing bag for: %p\n", (void*)resID);
2027 return set->numAttrs;
2028 }
2029 LOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
2030 resID);
2031 return BAD_INDEX;
2032 }
2033 }
2034 }
2035
2036 // Bag not found, we need to compute it!
2037 if (!grp->bags) {
2038 grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount);
2039 if (!grp->bags) return NO_MEMORY;
2040 memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount);
2041 }
2042
2043 bag_set** typeSet = grp->bags[t];
2044 if (!typeSet) {
2045 typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY);
2046 if (!typeSet) return NO_MEMORY;
2047 memset(typeSet, 0, sizeof(bag_set*)*NENTRY);
2048 grp->bags[t] = typeSet;
2049 }
2050
2051 // Mark that we are currently working on this one.
2052 typeSet[e] = (bag_set*)0xFFFFFFFF;
2053
2054 // This is what we are building.
2055 bag_set* set = NULL;
2056
2057 TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
2058
2059 // Now collect all bag attributes from all packages.
2060 size_t ip = grp->packages.size();
2061 while (ip > 0) {
2062 ip--;
2063
2064 const Package* const package = grp->packages[ip];
2065
2066 const ResTable_type* type;
2067 const ResTable_entry* entry;
2068 const Type* typeClass;
2069 LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
2070 ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
2071 LOGV("Resulting offset=%d\n", offset);
2072 if (offset <= 0) {
2073 if (offset < 0) {
2074 if (set) free(set);
2075 return offset;
2076 }
2077 continue;
2078 }
2079
2080 if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
2081 LOGW("Skipping entry %p in package table %d because it is not complex!\n",
2082 (void*)resID, (int)ip);
2083 continue;
2084 }
2085
2086 const uint16_t entrySize = dtohs(entry->size);
2087 const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
2088 ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
2089 const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
2090 ? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
2091
2092 size_t N = count;
2093
2094 TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
2095 entrySize, parent, count));
2096
2097 if (set == NULL) {
2098 // If this map inherits from another, we need to start
2099 // with its parent's values. Otherwise start out empty.
2100 TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
2101 entrySize, parent));
2102 if (parent) {
2103 const bag_entry* parentBag;
2104 uint32_t parentTypeSpecFlags = 0;
2105 const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
2106 const size_t NT = ((NP >= 0) ? NP : 0) + N;
2107 set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
2108 if (set == NULL) {
2109 return NO_MEMORY;
2110 }
2111 if (NP > 0) {
2112 memcpy(set+1, parentBag, NP*sizeof(bag_entry));
2113 set->numAttrs = NP;
2114 TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
2115 } else {
2116 TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
2117 set->numAttrs = 0;
2118 }
2119 set->availAttrs = NT;
2120 set->typeSpecFlags = parentTypeSpecFlags;
2121 } else {
2122 set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
2123 if (set == NULL) {
2124 return NO_MEMORY;
2125 }
2126 set->numAttrs = 0;
2127 set->availAttrs = N;
2128 set->typeSpecFlags = 0;
2129 }
2130 }
2131
2132 if (typeClass->typeSpecFlags != NULL) {
2133 set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
2134 } else {
2135 set->typeSpecFlags = -1;
2136 }
2137
2138 // Now merge in the new attributes...
2139 ssize_t curOff = offset;
2140 const ResTable_map* map;
2141 bag_entry* entries = (bag_entry*)(set+1);
2142 size_t curEntry = 0;
2143 uint32_t pos = 0;
2144 TABLE_NOISY(LOGI("Starting with set %p, entries=%p, avail=%d\n",
2145 set, entries, set->availAttrs));
2146 while (pos < count) {
2147 TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
2148
2149 if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) {
2150 LOGW("ResTable_map at %d is beyond type chunk data %d",
2151 (int)curOff, dtohl(type->header.size));
2152 return BAD_TYPE;
2153 }
2154 map = (const ResTable_map*)(((const uint8_t*)type) + curOff);
2155 N++;
2156
2157 const uint32_t newName = htodl(map->name.ident);
2158 bool isInside;
2159 uint32_t oldName = 0;
2160 while ((isInside=(curEntry < set->numAttrs))
2161 && (oldName=entries[curEntry].map.name.ident) < newName) {
2162 TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
2163 curEntry, entries[curEntry].map.name.ident));
2164 curEntry++;
2165 }
2166
2167 if ((!isInside) || oldName != newName) {
2168 // This is a new attribute... figure out what to do with it.
2169 if (set->numAttrs >= set->availAttrs) {
2170 // Need to alloc more memory...
2171 const size_t newAvail = set->availAttrs+N;
2172 set = (bag_set*)realloc(set,
2173 sizeof(bag_set)
2174 + sizeof(bag_entry)*newAvail);
2175 if (set == NULL) {
2176 return NO_MEMORY;
2177 }
2178 set->availAttrs = newAvail;
2179 entries = (bag_entry*)(set+1);
2180 TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
2181 set, entries, set->availAttrs));
2182 }
2183 if (isInside) {
2184 // Going in the middle, need to make space.
2185 memmove(entries+curEntry+1, entries+curEntry,
2186 sizeof(bag_entry)*(set->numAttrs-curEntry));
2187 set->numAttrs++;
2188 }
2189 TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
2190 curEntry, newName));
2191 } else {
2192 TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
2193 curEntry, oldName));
2194 }
2195
2196 bag_entry* cur = entries+curEntry;
2197
2198 cur->stringBlock = package->header->index;
2199 cur->map.name.ident = newName;
2200 cur->map.value.copyFrom_dtoh(map->value);
2201 TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
2202 curEntry, cur, cur->stringBlock, cur->map.name.ident,
2203 cur->map.value.dataType, cur->map.value.data));
2204
2205 // On to the next!
2206 curEntry++;
2207 pos++;
2208 const size_t size = dtohs(map->value.size);
2209 curOff += size + sizeof(*map)-sizeof(map->value);
2210 };
2211 if (curEntry > set->numAttrs) {
2212 set->numAttrs = curEntry;
2213 }
2214 }
2215
2216 // And this is it...
2217 typeSet[e] = set;
2218 if (set) {
2219 if (outTypeSpecFlags != NULL) {
2220 *outTypeSpecFlags = set->typeSpecFlags;
2221 }
2222 *outBag = (bag_entry*)(set+1);
2223 TABLE_NOISY(LOGI("Returning %d attrs\n", set->numAttrs));
2224 return set->numAttrs;
2225 }
2226 return BAD_INDEX;
2227 }
2228
setParameters(const ResTable_config * params)2229 void ResTable::setParameters(const ResTable_config* params)
2230 {
2231 mLock.lock();
2232 TABLE_GETENTRY(LOGI("Setting parameters: imsi:%d/%d lang:%c%c cnt:%c%c "
2233 "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
2234 params->mcc, params->mnc,
2235 params->language[0] ? params->language[0] : '-',
2236 params->language[1] ? params->language[1] : '-',
2237 params->country[0] ? params->country[0] : '-',
2238 params->country[1] ? params->country[1] : '-',
2239 params->orientation,
2240 params->touchscreen,
2241 params->density,
2242 params->keyboard,
2243 params->inputFlags,
2244 params->navigation,
2245 params->screenWidth,
2246 params->screenHeight));
2247 mParams = *params;
2248 for (size_t i=0; i<mPackageGroups.size(); i++) {
2249 TABLE_NOISY(LOGI("CLEARING BAGS FOR GROUP %d!", i));
2250 mPackageGroups[i]->clearBagCache();
2251 }
2252 mLock.unlock();
2253 }
2254
getParameters(ResTable_config * params) const2255 void ResTable::getParameters(ResTable_config* params) const
2256 {
2257 mLock.lock();
2258 *params = mParams;
2259 mLock.unlock();
2260 }
2261
2262 struct id_name_map {
2263 uint32_t id;
2264 size_t len;
2265 char16_t name[6];
2266 };
2267
2268 const static id_name_map ID_NAMES[] = {
2269 { ResTable_map::ATTR_TYPE, 5, { '^', 't', 'y', 'p', 'e' } },
2270 { ResTable_map::ATTR_L10N, 5, { '^', 'l', '1', '0', 'n' } },
2271 { ResTable_map::ATTR_MIN, 4, { '^', 'm', 'i', 'n' } },
2272 { ResTable_map::ATTR_MAX, 4, { '^', 'm', 'a', 'x' } },
2273 { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
2274 { ResTable_map::ATTR_ZERO, 5, { '^', 'z', 'e', 'r', 'o' } },
2275 { ResTable_map::ATTR_ONE, 4, { '^', 'o', 'n', 'e' } },
2276 { ResTable_map::ATTR_TWO, 4, { '^', 't', 'w', 'o' } },
2277 { ResTable_map::ATTR_FEW, 4, { '^', 'f', 'e', 'w' } },
2278 { ResTable_map::ATTR_MANY, 5, { '^', 'm', 'a', 'n', 'y' } },
2279 };
2280
identifierForName(const char16_t * name,size_t nameLen,const char16_t * type,size_t typeLen,const char16_t * package,size_t packageLen,uint32_t * outTypeSpecFlags) const2281 uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
2282 const char16_t* type, size_t typeLen,
2283 const char16_t* package,
2284 size_t packageLen,
2285 uint32_t* outTypeSpecFlags) const
2286 {
2287 TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
2288
2289 // Check for internal resource identifier as the very first thing, so
2290 // that we will always find them even when there are no resources.
2291 if (name[0] == '^') {
2292 const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
2293 size_t len;
2294 for (int i=0; i<N; i++) {
2295 const id_name_map* m = ID_NAMES + i;
2296 len = m->len;
2297 if (len != nameLen) {
2298 continue;
2299 }
2300 for (size_t j=1; j<len; j++) {
2301 if (m->name[j] != name[j]) {
2302 goto nope;
2303 }
2304 }
2305 return m->id;
2306 nope:
2307 ;
2308 }
2309 if (nameLen > 7) {
2310 if (name[1] == 'i' && name[2] == 'n'
2311 && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
2312 && name[6] == '_') {
2313 int index = atoi(String8(name + 7, nameLen - 7).string());
2314 if (Res_CHECKID(index)) {
2315 LOGW("Array resource index: %d is too large.",
2316 index);
2317 return 0;
2318 }
2319 return Res_MAKEARRAY(index);
2320 }
2321 }
2322 return 0;
2323 }
2324
2325 if (mError != NO_ERROR) {
2326 return 0;
2327 }
2328
2329 // Figure out the package and type we are looking in...
2330
2331 const char16_t* packageEnd = NULL;
2332 const char16_t* typeEnd = NULL;
2333 const char16_t* const nameEnd = name+nameLen;
2334 const char16_t* p = name;
2335 while (p < nameEnd) {
2336 if (*p == ':') packageEnd = p;
2337 else if (*p == '/') typeEnd = p;
2338 p++;
2339 }
2340 if (*name == '@') name++;
2341 if (name >= nameEnd) {
2342 return 0;
2343 }
2344
2345 if (packageEnd) {
2346 package = name;
2347 packageLen = packageEnd-name;
2348 name = packageEnd+1;
2349 } else if (!package) {
2350 return 0;
2351 }
2352
2353 if (typeEnd) {
2354 type = name;
2355 typeLen = typeEnd-name;
2356 name = typeEnd+1;
2357 } else if (!type) {
2358 return 0;
2359 }
2360
2361 if (name >= nameEnd) {
2362 return 0;
2363 }
2364 nameLen = nameEnd-name;
2365
2366 TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
2367 String8(type, typeLen).string(),
2368 String8(name, nameLen).string(),
2369 String8(package, packageLen).string()));
2370
2371 const size_t NG = mPackageGroups.size();
2372 for (size_t ig=0; ig<NG; ig++) {
2373 const PackageGroup* group = mPackageGroups[ig];
2374
2375 if (strzcmp16(package, packageLen,
2376 group->name.string(), group->name.size())) {
2377 TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
2378 continue;
2379 }
2380
2381 const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
2382 if (ti < 0) {
2383 TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
2384 continue;
2385 }
2386
2387 const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
2388 if (ei < 0) {
2389 TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
2390 continue;
2391 }
2392
2393 TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei));
2394
2395 const Type* const typeConfigs = group->packages[0]->getType(ti);
2396 if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) {
2397 TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
2398 String8(group->name).string(), ti));
2399 }
2400
2401 size_t NTC = typeConfigs->configs.size();
2402 for (size_t tci=0; tci<NTC; tci++) {
2403 const ResTable_type* const ty = typeConfigs->configs[tci];
2404 const uint32_t typeOffset = dtohl(ty->entriesStart);
2405
2406 const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size);
2407 const uint32_t* const eindex = (const uint32_t*)
2408 (((const uint8_t*)ty) + dtohs(ty->header.headerSize));
2409
2410 const size_t NE = dtohl(ty->entryCount);
2411 for (size_t i=0; i<NE; i++) {
2412 uint32_t offset = dtohl(eindex[i]);
2413 if (offset == ResTable_type::NO_ENTRY) {
2414 continue;
2415 }
2416
2417 offset += typeOffset;
2418
2419 if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
2420 LOGW("ResTable_entry at %d is beyond type chunk data %d",
2421 offset, dtohl(ty->header.size));
2422 return 0;
2423 }
2424 if ((offset&0x3) != 0) {
2425 LOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s",
2426 (int)offset, (int)group->id, (int)ti+1, (int)i,
2427 String8(package, packageLen).string(),
2428 String8(type, typeLen).string(),
2429 String8(name, nameLen).string());
2430 return 0;
2431 }
2432
2433 const ResTable_entry* const entry = (const ResTable_entry*)
2434 (((const uint8_t*)ty) + offset);
2435 if (dtohs(entry->size) < sizeof(*entry)) {
2436 LOGW("ResTable_entry size %d is too small", dtohs(entry->size));
2437 return BAD_TYPE;
2438 }
2439
2440 TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n",
2441 i, ei, dtohl(entry->key.index)));
2442 if (dtohl(entry->key.index) == (size_t)ei) {
2443 if (outTypeSpecFlags) {
2444 *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
2445 }
2446 return Res_MAKEID(group->id-1, ti, i);
2447 }
2448 }
2449 }
2450 }
2451
2452 return 0;
2453 }
2454
expandResourceRef(const uint16_t * refStr,size_t refLen,String16 * outPackage,String16 * outType,String16 * outName,const String16 * defType,const String16 * defPackage,const char ** outErrorMsg)2455 bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen,
2456 String16* outPackage,
2457 String16* outType,
2458 String16* outName,
2459 const String16* defType,
2460 const String16* defPackage,
2461 const char** outErrorMsg)
2462 {
2463 const char16_t* packageEnd = NULL;
2464 const char16_t* typeEnd = NULL;
2465 const char16_t* p = refStr;
2466 const char16_t* const end = p + refLen;
2467 while (p < end) {
2468 if (*p == ':') packageEnd = p;
2469 else if (*p == '/') {
2470 typeEnd = p;
2471 break;
2472 }
2473 p++;
2474 }
2475 p = refStr;
2476 if (*p == '@') p++;
2477
2478 if (packageEnd) {
2479 *outPackage = String16(p, packageEnd-p);
2480 p = packageEnd+1;
2481 } else {
2482 if (!defPackage) {
2483 if (outErrorMsg) {
2484 *outErrorMsg = "No resource package specified";
2485 }
2486 return false;
2487 }
2488 *outPackage = *defPackage;
2489 }
2490 if (typeEnd) {
2491 *outType = String16(p, typeEnd-p);
2492 p = typeEnd+1;
2493 } else {
2494 if (!defType) {
2495 if (outErrorMsg) {
2496 *outErrorMsg = "No resource type specified";
2497 }
2498 return false;
2499 }
2500 *outType = *defType;
2501 }
2502 *outName = String16(p, end-p);
2503 return true;
2504 }
2505
get_hex(char c,bool * outError)2506 static uint32_t get_hex(char c, bool* outError)
2507 {
2508 if (c >= '0' && c <= '9') {
2509 return c - '0';
2510 } else if (c >= 'a' && c <= 'f') {
2511 return c - 'a' + 0xa;
2512 } else if (c >= 'A' && c <= 'F') {
2513 return c - 'A' + 0xa;
2514 }
2515 *outError = true;
2516 return 0;
2517 }
2518
2519 struct unit_entry
2520 {
2521 const char* name;
2522 size_t len;
2523 uint8_t type;
2524 uint32_t unit;
2525 float scale;
2526 };
2527
2528 static const unit_entry unitNames[] = {
2529 { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
2530 { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
2531 { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
2532 { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
2533 { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
2534 { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
2535 { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
2536 { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
2537 { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
2538 { NULL, 0, 0, 0, 0 }
2539 };
2540
parse_unit(const char * str,Res_value * outValue,float * outScale,const char ** outEnd)2541 static bool parse_unit(const char* str, Res_value* outValue,
2542 float* outScale, const char** outEnd)
2543 {
2544 const char* end = str;
2545 while (*end != 0 && !isspace((unsigned char)*end)) {
2546 end++;
2547 }
2548 const size_t len = end-str;
2549
2550 const char* realEnd = end;
2551 while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
2552 realEnd++;
2553 }
2554 if (*realEnd != 0) {
2555 return false;
2556 }
2557
2558 const unit_entry* cur = unitNames;
2559 while (cur->name) {
2560 if (len == cur->len && strncmp(cur->name, str, len) == 0) {
2561 outValue->dataType = cur->type;
2562 outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
2563 *outScale = cur->scale;
2564 *outEnd = end;
2565 //printf("Found unit %s for %s\n", cur->name, str);
2566 return true;
2567 }
2568 cur++;
2569 }
2570
2571 return false;
2572 }
2573
2574
stringToInt(const char16_t * s,size_t len,Res_value * outValue)2575 bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
2576 {
2577 while (len > 0 && isspace16(*s)) {
2578 s++;
2579 len--;
2580 }
2581
2582 if (len <= 0) {
2583 return false;
2584 }
2585
2586 size_t i = 0;
2587 int32_t val = 0;
2588 bool neg = false;
2589
2590 if (*s == '-') {
2591 neg = true;
2592 i++;
2593 }
2594
2595 if (s[i] < '0' || s[i] > '9') {
2596 return false;
2597 }
2598
2599 // Decimal or hex?
2600 if (s[i] == '0' && s[i+1] == 'x') {
2601 if (outValue)
2602 outValue->dataType = outValue->TYPE_INT_HEX;
2603 i += 2;
2604 bool error = false;
2605 while (i < len && !error) {
2606 val = (val*16) + get_hex(s[i], &error);
2607 i++;
2608 }
2609 if (error) {
2610 return false;
2611 }
2612 } else {
2613 if (outValue)
2614 outValue->dataType = outValue->TYPE_INT_DEC;
2615 while (i < len) {
2616 if (s[i] < '0' || s[i] > '9') {
2617 return false;
2618 }
2619 val = (val*10) + s[i]-'0';
2620 i++;
2621 }
2622 }
2623
2624 if (neg) val = -val;
2625
2626 while (i < len && isspace16(s[i])) {
2627 i++;
2628 }
2629
2630 if (i == len) {
2631 if (outValue)
2632 outValue->data = val;
2633 return true;
2634 }
2635
2636 return false;
2637 }
2638
stringToFloat(const char16_t * s,size_t len,Res_value * outValue)2639 bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
2640 {
2641 while (len > 0 && isspace16(*s)) {
2642 s++;
2643 len--;
2644 }
2645
2646 if (len <= 0) {
2647 return false;
2648 }
2649
2650 char buf[128];
2651 int i=0;
2652 while (len > 0 && *s != 0 && i < 126) {
2653 if (*s > 255) {
2654 return false;
2655 }
2656 buf[i++] = *s++;
2657 len--;
2658 }
2659
2660 if (len > 0) {
2661 return false;
2662 }
2663 if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
2664 return false;
2665 }
2666
2667 buf[i] = 0;
2668 const char* end;
2669 float f = strtof(buf, (char**)&end);
2670
2671 if (*end != 0 && !isspace((unsigned char)*end)) {
2672 // Might be a unit...
2673 float scale;
2674 if (parse_unit(end, outValue, &scale, &end)) {
2675 f *= scale;
2676 const bool neg = f < 0;
2677 if (neg) f = -f;
2678 uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
2679 uint32_t radix;
2680 uint32_t shift;
2681 if ((bits&0x7fffff) == 0) {
2682 // Always use 23p0 if there is no fraction, just to make
2683 // things easier to read.
2684 radix = Res_value::COMPLEX_RADIX_23p0;
2685 shift = 23;
2686 } else if ((bits&0xffffffffff800000LL) == 0) {
2687 // Magnitude is zero -- can fit in 0 bits of precision.
2688 radix = Res_value::COMPLEX_RADIX_0p23;
2689 shift = 0;
2690 } else if ((bits&0xffffffff80000000LL) == 0) {
2691 // Magnitude can fit in 8 bits of precision.
2692 radix = Res_value::COMPLEX_RADIX_8p15;
2693 shift = 8;
2694 } else if ((bits&0xffffff8000000000LL) == 0) {
2695 // Magnitude can fit in 16 bits of precision.
2696 radix = Res_value::COMPLEX_RADIX_16p7;
2697 shift = 16;
2698 } else {
2699 // Magnitude needs entire range, so no fractional part.
2700 radix = Res_value::COMPLEX_RADIX_23p0;
2701 shift = 23;
2702 }
2703 int32_t mantissa = (int32_t)(
2704 (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
2705 if (neg) {
2706 mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
2707 }
2708 outValue->data |=
2709 (radix<<Res_value::COMPLEX_RADIX_SHIFT)
2710 | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
2711 //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
2712 // f * (neg ? -1 : 1), bits, f*(1<<23),
2713 // radix, shift, outValue->data);
2714 return true;
2715 }
2716 return false;
2717 }
2718
2719 while (*end != 0 && isspace((unsigned char)*end)) {
2720 end++;
2721 }
2722
2723 if (*end == 0) {
2724 if (outValue) {
2725 outValue->dataType = outValue->TYPE_FLOAT;
2726 *(float*)(&outValue->data) = f;
2727 return true;
2728 }
2729 }
2730
2731 return false;
2732 }
2733
stringToValue(Res_value * outValue,String16 * outString,const char16_t * s,size_t len,bool preserveSpaces,bool coerceType,uint32_t attrID,const String16 * defType,const String16 * defPackage,Accessor * accessor,void * accessorCookie,uint32_t attrType,bool enforcePrivate) const2734 bool ResTable::stringToValue(Res_value* outValue, String16* outString,
2735 const char16_t* s, size_t len,
2736 bool preserveSpaces, bool coerceType,
2737 uint32_t attrID,
2738 const String16* defType,
2739 const String16* defPackage,
2740 Accessor* accessor,
2741 void* accessorCookie,
2742 uint32_t attrType,
2743 bool enforcePrivate) const
2744 {
2745 bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
2746 const char* errorMsg = NULL;
2747
2748 outValue->size = sizeof(Res_value);
2749 outValue->res0 = 0;
2750
2751 // First strip leading/trailing whitespace. Do this before handling
2752 // escapes, so they can be used to force whitespace into the string.
2753 if (!preserveSpaces) {
2754 while (len > 0 && isspace16(*s)) {
2755 s++;
2756 len--;
2757 }
2758 while (len > 0 && isspace16(s[len-1])) {
2759 len--;
2760 }
2761 // If the string ends with '\', then we keep the space after it.
2762 if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
2763 len++;
2764 }
2765 }
2766
2767 //printf("Value for: %s\n", String8(s, len).string());
2768
2769 uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
2770 uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
2771 bool fromAccessor = false;
2772 if (attrID != 0 && !Res_INTERNALID(attrID)) {
2773 const ssize_t p = getResourcePackageIndex(attrID);
2774 const bag_entry* bag;
2775 ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
2776 //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
2777 if (cnt >= 0) {
2778 while (cnt > 0) {
2779 //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
2780 switch (bag->map.name.ident) {
2781 case ResTable_map::ATTR_TYPE:
2782 attrType = bag->map.value.data;
2783 break;
2784 case ResTable_map::ATTR_MIN:
2785 attrMin = bag->map.value.data;
2786 break;
2787 case ResTable_map::ATTR_MAX:
2788 attrMax = bag->map.value.data;
2789 break;
2790 case ResTable_map::ATTR_L10N:
2791 l10nReq = bag->map.value.data;
2792 break;
2793 }
2794 bag++;
2795 cnt--;
2796 }
2797 unlockBag(bag);
2798 } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
2799 fromAccessor = true;
2800 if (attrType == ResTable_map::TYPE_ENUM
2801 || attrType == ResTable_map::TYPE_FLAGS
2802 || attrType == ResTable_map::TYPE_INTEGER) {
2803 accessor->getAttributeMin(attrID, &attrMin);
2804 accessor->getAttributeMax(attrID, &attrMax);
2805 }
2806 if (localizationSetting) {
2807 l10nReq = accessor->getAttributeL10N(attrID);
2808 }
2809 }
2810 }
2811
2812 const bool canStringCoerce =
2813 coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
2814
2815 if (*s == '@') {
2816 outValue->dataType = outValue->TYPE_REFERENCE;
2817
2818 // Note: we don't check attrType here because the reference can
2819 // be to any other type; we just need to count on the client making
2820 // sure the referenced type is correct.
2821
2822 //printf("Looking up ref: %s\n", String8(s, len).string());
2823
2824 // It's a reference!
2825 if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
2826 outValue->data = 0;
2827 return true;
2828 } else {
2829 bool createIfNotFound = false;
2830 const char16_t* resourceRefName;
2831 int resourceNameLen;
2832 if (len > 2 && s[1] == '+') {
2833 createIfNotFound = true;
2834 resourceRefName = s + 2;
2835 resourceNameLen = len - 2;
2836 } else if (len > 2 && s[1] == '*') {
2837 enforcePrivate = false;
2838 resourceRefName = s + 2;
2839 resourceNameLen = len - 2;
2840 } else {
2841 createIfNotFound = false;
2842 resourceRefName = s + 1;
2843 resourceNameLen = len - 1;
2844 }
2845 String16 package, type, name;
2846 if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
2847 defType, defPackage, &errorMsg)) {
2848 if (accessor != NULL) {
2849 accessor->reportError(accessorCookie, errorMsg);
2850 }
2851 return false;
2852 }
2853
2854 uint32_t specFlags = 0;
2855 uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
2856 type.size(), package.string(), package.size(), &specFlags);
2857 if (rid != 0) {
2858 if (enforcePrivate) {
2859 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
2860 if (accessor != NULL) {
2861 accessor->reportError(accessorCookie, "Resource is not public.");
2862 }
2863 return false;
2864 }
2865 }
2866 if (!accessor) {
2867 outValue->data = rid;
2868 return true;
2869 }
2870 rid = Res_MAKEID(
2871 accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
2872 Res_GETTYPE(rid), Res_GETENTRY(rid));
2873 TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
2874 String8(package).string(), String8(type).string(),
2875 String8(name).string(), rid));
2876 outValue->data = rid;
2877 return true;
2878 }
2879
2880 if (accessor) {
2881 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
2882 createIfNotFound);
2883 if (rid != 0) {
2884 TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
2885 String8(package).string(), String8(type).string(),
2886 String8(name).string(), rid));
2887 outValue->data = rid;
2888 return true;
2889 }
2890 }
2891 }
2892
2893 if (accessor != NULL) {
2894 accessor->reportError(accessorCookie, "No resource found that matches the given name");
2895 }
2896 return false;
2897 }
2898
2899 // if we got to here, and localization is required and it's not a reference,
2900 // complain and bail.
2901 if (l10nReq == ResTable_map::L10N_SUGGESTED) {
2902 if (localizationSetting) {
2903 if (accessor != NULL) {
2904 accessor->reportError(accessorCookie, "This attribute must be localized.");
2905 }
2906 }
2907 }
2908
2909 if (*s == '#') {
2910 // It's a color! Convert to an integer of the form 0xaarrggbb.
2911 uint32_t color = 0;
2912 bool error = false;
2913 if (len == 4) {
2914 outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
2915 color |= 0xFF000000;
2916 color |= get_hex(s[1], &error) << 20;
2917 color |= get_hex(s[1], &error) << 16;
2918 color |= get_hex(s[2], &error) << 12;
2919 color |= get_hex(s[2], &error) << 8;
2920 color |= get_hex(s[3], &error) << 4;
2921 color |= get_hex(s[3], &error);
2922 } else if (len == 5) {
2923 outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
2924 color |= get_hex(s[1], &error) << 28;
2925 color |= get_hex(s[1], &error) << 24;
2926 color |= get_hex(s[2], &error) << 20;
2927 color |= get_hex(s[2], &error) << 16;
2928 color |= get_hex(s[3], &error) << 12;
2929 color |= get_hex(s[3], &error) << 8;
2930 color |= get_hex(s[4], &error) << 4;
2931 color |= get_hex(s[4], &error);
2932 } else if (len == 7) {
2933 outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
2934 color |= 0xFF000000;
2935 color |= get_hex(s[1], &error) << 20;
2936 color |= get_hex(s[2], &error) << 16;
2937 color |= get_hex(s[3], &error) << 12;
2938 color |= get_hex(s[4], &error) << 8;
2939 color |= get_hex(s[5], &error) << 4;
2940 color |= get_hex(s[6], &error);
2941 } else if (len == 9) {
2942 outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
2943 color |= get_hex(s[1], &error) << 28;
2944 color |= get_hex(s[2], &error) << 24;
2945 color |= get_hex(s[3], &error) << 20;
2946 color |= get_hex(s[4], &error) << 16;
2947 color |= get_hex(s[5], &error) << 12;
2948 color |= get_hex(s[6], &error) << 8;
2949 color |= get_hex(s[7], &error) << 4;
2950 color |= get_hex(s[8], &error);
2951 } else {
2952 error = true;
2953 }
2954 if (!error) {
2955 if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
2956 if (!canStringCoerce) {
2957 if (accessor != NULL) {
2958 accessor->reportError(accessorCookie,
2959 "Color types not allowed");
2960 }
2961 return false;
2962 }
2963 } else {
2964 outValue->data = color;
2965 //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
2966 return true;
2967 }
2968 } else {
2969 if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
2970 if (accessor != NULL) {
2971 accessor->reportError(accessorCookie, "Color value not valid --"
2972 " must be #rgb, #argb, #rrggbb, or #aarrggbb");
2973 }
2974 #if 0
2975 fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
2976 "Resource File", //(const char*)in->getPrintableSource(),
2977 String8(*curTag).string(),
2978 String8(s, len).string());
2979 #endif
2980 return false;
2981 }
2982 }
2983 }
2984
2985 if (*s == '?') {
2986 outValue->dataType = outValue->TYPE_ATTRIBUTE;
2987
2988 // Note: we don't check attrType here because the reference can
2989 // be to any other type; we just need to count on the client making
2990 // sure the referenced type is correct.
2991
2992 //printf("Looking up attr: %s\n", String8(s, len).string());
2993
2994 static const String16 attr16("attr");
2995 String16 package, type, name;
2996 if (!expandResourceRef(s+1, len-1, &package, &type, &name,
2997 &attr16, defPackage, &errorMsg)) {
2998 if (accessor != NULL) {
2999 accessor->reportError(accessorCookie, errorMsg);
3000 }
3001 return false;
3002 }
3003
3004 //printf("Pkg: %s, Type: %s, Name: %s\n",
3005 // String8(package).string(), String8(type).string(),
3006 // String8(name).string());
3007 uint32_t specFlags = 0;
3008 uint32_t rid =
3009 identifierForName(name.string(), name.size(),
3010 type.string(), type.size(),
3011 package.string(), package.size(), &specFlags);
3012 if (rid != 0) {
3013 if (enforcePrivate) {
3014 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
3015 if (accessor != NULL) {
3016 accessor->reportError(accessorCookie, "Attribute is not public.");
3017 }
3018 return false;
3019 }
3020 }
3021 if (!accessor) {
3022 outValue->data = rid;
3023 return true;
3024 }
3025 rid = Res_MAKEID(
3026 accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
3027 Res_GETTYPE(rid), Res_GETENTRY(rid));
3028 //printf("Incl %s:%s/%s: 0x%08x\n",
3029 // String8(package).string(), String8(type).string(),
3030 // String8(name).string(), rid);
3031 outValue->data = rid;
3032 return true;
3033 }
3034
3035 if (accessor) {
3036 uint32_t rid = accessor->getCustomResource(package, type, name);
3037 if (rid != 0) {
3038 //printf("Mine %s:%s/%s: 0x%08x\n",
3039 // String8(package).string(), String8(type).string(),
3040 // String8(name).string(), rid);
3041 outValue->data = rid;
3042 return true;
3043 }
3044 }
3045
3046 if (accessor != NULL) {
3047 accessor->reportError(accessorCookie, "No resource found that matches the given name");
3048 }
3049 return false;
3050 }
3051
3052 if (stringToInt(s, len, outValue)) {
3053 if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
3054 // If this type does not allow integers, but does allow floats,
3055 // fall through on this error case because the float type should
3056 // be able to accept any integer value.
3057 if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
3058 if (accessor != NULL) {
3059 accessor->reportError(accessorCookie, "Integer types not allowed");
3060 }
3061 return false;
3062 }
3063 } else {
3064 if (((int32_t)outValue->data) < ((int32_t)attrMin)
3065 || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
3066 if (accessor != NULL) {
3067 accessor->reportError(accessorCookie, "Integer value out of range");
3068 }
3069 return false;
3070 }
3071 return true;
3072 }
3073 }
3074
3075 if (stringToFloat(s, len, outValue)) {
3076 if (outValue->dataType == Res_value::TYPE_DIMENSION) {
3077 if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
3078 return true;
3079 }
3080 if (!canStringCoerce) {
3081 if (accessor != NULL) {
3082 accessor->reportError(accessorCookie, "Dimension types not allowed");
3083 }
3084 return false;
3085 }
3086 } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
3087 if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
3088 return true;
3089 }
3090 if (!canStringCoerce) {
3091 if (accessor != NULL) {
3092 accessor->reportError(accessorCookie, "Fraction types not allowed");
3093 }
3094 return false;
3095 }
3096 } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
3097 if (!canStringCoerce) {
3098 if (accessor != NULL) {
3099 accessor->reportError(accessorCookie, "Float types not allowed");
3100 }
3101 return false;
3102 }
3103 } else {
3104 return true;
3105 }
3106 }
3107
3108 if (len == 4) {
3109 if ((s[0] == 't' || s[0] == 'T') &&
3110 (s[1] == 'r' || s[1] == 'R') &&
3111 (s[2] == 'u' || s[2] == 'U') &&
3112 (s[3] == 'e' || s[3] == 'E')) {
3113 if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
3114 if (!canStringCoerce) {
3115 if (accessor != NULL) {
3116 accessor->reportError(accessorCookie, "Boolean types not allowed");
3117 }
3118 return false;
3119 }
3120 } else {
3121 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
3122 outValue->data = (uint32_t)-1;
3123 return true;
3124 }
3125 }
3126 }
3127
3128 if (len == 5) {
3129 if ((s[0] == 'f' || s[0] == 'F') &&
3130 (s[1] == 'a' || s[1] == 'A') &&
3131 (s[2] == 'l' || s[2] == 'L') &&
3132 (s[3] == 's' || s[3] == 'S') &&
3133 (s[4] == 'e' || s[4] == 'E')) {
3134 if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
3135 if (!canStringCoerce) {
3136 if (accessor != NULL) {
3137 accessor->reportError(accessorCookie, "Boolean types not allowed");
3138 }
3139 return false;
3140 }
3141 } else {
3142 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
3143 outValue->data = 0;
3144 return true;
3145 }
3146 }
3147 }
3148
3149 if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
3150 const ssize_t p = getResourcePackageIndex(attrID);
3151 const bag_entry* bag;
3152 ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
3153 //printf("Got %d for enum\n", cnt);
3154 if (cnt >= 0) {
3155 resource_name rname;
3156 while (cnt > 0) {
3157 if (!Res_INTERNALID(bag->map.name.ident)) {
3158 //printf("Trying attr #%08x\n", bag->map.name.ident);
3159 if (getResourceName(bag->map.name.ident, &rname)) {
3160 #if 0
3161 printf("Matching %s against %s (0x%08x)\n",
3162 String8(s, len).string(),
3163 String8(rname.name, rname.nameLen).string(),
3164 bag->map.name.ident);
3165 #endif
3166 if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
3167 outValue->dataType = bag->map.value.dataType;
3168 outValue->data = bag->map.value.data;
3169 unlockBag(bag);
3170 return true;
3171 }
3172 }
3173
3174 }
3175 bag++;
3176 cnt--;
3177 }
3178 unlockBag(bag);
3179 }
3180
3181 if (fromAccessor) {
3182 if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
3183 return true;
3184 }
3185 }
3186 }
3187
3188 if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
3189 const ssize_t p = getResourcePackageIndex(attrID);
3190 const bag_entry* bag;
3191 ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
3192 //printf("Got %d for flags\n", cnt);
3193 if (cnt >= 0) {
3194 bool failed = false;
3195 resource_name rname;
3196 outValue->dataType = Res_value::TYPE_INT_HEX;
3197 outValue->data = 0;
3198 const char16_t* end = s + len;
3199 const char16_t* pos = s;
3200 while (pos < end && !failed) {
3201 const char16_t* start = pos;
3202 pos++;
3203 while (pos < end && *pos != '|') {
3204 pos++;
3205 }
3206 //printf("Looking for: %s\n", String8(start, pos-start).string());
3207 const bag_entry* bagi = bag;
3208 ssize_t i;
3209 for (i=0; i<cnt; i++, bagi++) {
3210 if (!Res_INTERNALID(bagi->map.name.ident)) {
3211 //printf("Trying attr #%08x\n", bagi->map.name.ident);
3212 if (getResourceName(bagi->map.name.ident, &rname)) {
3213 #if 0
3214 printf("Matching %s against %s (0x%08x)\n",
3215 String8(start,pos-start).string(),
3216 String8(rname.name, rname.nameLen).string(),
3217 bagi->map.name.ident);
3218 #endif
3219 if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
3220 outValue->data |= bagi->map.value.data;
3221 break;
3222 }
3223 }
3224 }
3225 }
3226 if (i >= cnt) {
3227 // Didn't find this flag identifier.
3228 failed = true;
3229 }
3230 if (pos < end) {
3231 pos++;
3232 }
3233 }
3234 unlockBag(bag);
3235 if (!failed) {
3236 //printf("Final flag value: 0x%lx\n", outValue->data);
3237 return true;
3238 }
3239 }
3240
3241
3242 if (fromAccessor) {
3243 if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
3244 //printf("Final flag value: 0x%lx\n", outValue->data);
3245 return true;
3246 }
3247 }
3248 }
3249
3250 if ((attrType&ResTable_map::TYPE_STRING) == 0) {
3251 if (accessor != NULL) {
3252 accessor->reportError(accessorCookie, "String types not allowed");
3253 }
3254 return false;
3255 }
3256
3257 // Generic string handling...
3258 outValue->dataType = outValue->TYPE_STRING;
3259 if (outString) {
3260 bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
3261 if (accessor != NULL) {
3262 accessor->reportError(accessorCookie, errorMsg);
3263 }
3264 return failed;
3265 }
3266
3267 return true;
3268 }
3269
collectString(String16 * outString,const char16_t * s,size_t len,bool preserveSpaces,const char ** outErrorMsg,bool append)3270 bool ResTable::collectString(String16* outString,
3271 const char16_t* s, size_t len,
3272 bool preserveSpaces,
3273 const char** outErrorMsg,
3274 bool append)
3275 {
3276 String16 tmp;
3277
3278 char quoted = 0;
3279 const char16_t* p = s;
3280 while (p < (s+len)) {
3281 while (p < (s+len)) {
3282 const char16_t c = *p;
3283 if (c == '\\') {
3284 break;
3285 }
3286 if (!preserveSpaces) {
3287 if (quoted == 0 && isspace16(c)
3288 && (c != ' ' || isspace16(*(p+1)))) {
3289 break;
3290 }
3291 if (c == '"' && (quoted == 0 || quoted == '"')) {
3292 break;
3293 }
3294 if (c == '\'' && (quoted == 0 || quoted == '\'')) {
3295 /*
3296 * In practice, when people write ' instead of \'
3297 * in a string, they are doing it by accident
3298 * instead of really meaning to use ' as a quoting
3299 * character. Warn them so they don't lose it.
3300 */
3301 if (outErrorMsg) {
3302 *outErrorMsg = "Apostrophe not preceded by \\";
3303 }
3304 return false;
3305 }
3306 }
3307 p++;
3308 }
3309 if (p < (s+len)) {
3310 if (p > s) {
3311 tmp.append(String16(s, p-s));
3312 }
3313 if (!preserveSpaces && (*p == '"' || *p == '\'')) {
3314 if (quoted == 0) {
3315 quoted = *p;
3316 } else {
3317 quoted = 0;
3318 }
3319 p++;
3320 } else if (!preserveSpaces && isspace16(*p)) {
3321 // Space outside of a quote -- consume all spaces and
3322 // leave a single plain space char.
3323 tmp.append(String16(" "));
3324 p++;
3325 while (p < (s+len) && isspace16(*p)) {
3326 p++;
3327 }
3328 } else if (*p == '\\') {
3329 p++;
3330 if (p < (s+len)) {
3331 switch (*p) {
3332 case 't':
3333 tmp.append(String16("\t"));
3334 break;
3335 case 'n':
3336 tmp.append(String16("\n"));
3337 break;
3338 case '#':
3339 tmp.append(String16("#"));
3340 break;
3341 case '@':
3342 tmp.append(String16("@"));
3343 break;
3344 case '?':
3345 tmp.append(String16("?"));
3346 break;
3347 case '"':
3348 tmp.append(String16("\""));
3349 break;
3350 case '\'':
3351 tmp.append(String16("'"));
3352 break;
3353 case '\\':
3354 tmp.append(String16("\\"));
3355 break;
3356 case 'u':
3357 {
3358 char16_t chr = 0;
3359 int i = 0;
3360 while (i < 4 && p[1] != 0) {
3361 p++;
3362 i++;
3363 int c;
3364 if (*p >= '0' && *p <= '9') {
3365 c = *p - '0';
3366 } else if (*p >= 'a' && *p <= 'f') {
3367 c = *p - 'a' + 10;
3368 } else if (*p >= 'A' && *p <= 'F') {
3369 c = *p - 'A' + 10;
3370 } else {
3371 if (outErrorMsg) {
3372 *outErrorMsg = "Bad character in \\u unicode escape sequence";
3373 }
3374 return false;
3375 }
3376 chr = (chr<<4) | c;
3377 }
3378 tmp.append(String16(&chr, 1));
3379 } break;
3380 default:
3381 // ignore unknown escape chars.
3382 break;
3383 }
3384 p++;
3385 }
3386 }
3387 len -= (p-s);
3388 s = p;
3389 }
3390 }
3391
3392 if (tmp.size() != 0) {
3393 if (len > 0) {
3394 tmp.append(String16(s, len));
3395 }
3396 if (append) {
3397 outString->append(tmp);
3398 } else {
3399 outString->setTo(tmp);
3400 }
3401 } else {
3402 if (append) {
3403 outString->append(String16(s, len));
3404 } else {
3405 outString->setTo(s, len);
3406 }
3407 }
3408
3409 return true;
3410 }
3411
getBasePackageCount() const3412 size_t ResTable::getBasePackageCount() const
3413 {
3414 if (mError != NO_ERROR) {
3415 return 0;
3416 }
3417 return mPackageGroups.size();
3418 }
3419
getBasePackageName(size_t idx) const3420 const char16_t* ResTable::getBasePackageName(size_t idx) const
3421 {
3422 if (mError != NO_ERROR) {
3423 return 0;
3424 }
3425 LOG_FATAL_IF(idx >= mPackageGroups.size(),
3426 "Requested package index %d past package count %d",
3427 (int)idx, (int)mPackageGroups.size());
3428 return mPackageGroups[idx]->name.string();
3429 }
3430
getBasePackageId(size_t idx) const3431 uint32_t ResTable::getBasePackageId(size_t idx) const
3432 {
3433 if (mError != NO_ERROR) {
3434 return 0;
3435 }
3436 LOG_FATAL_IF(idx >= mPackageGroups.size(),
3437 "Requested package index %d past package count %d",
3438 (int)idx, (int)mPackageGroups.size());
3439 return mPackageGroups[idx]->id;
3440 }
3441
getTableCount() const3442 size_t ResTable::getTableCount() const
3443 {
3444 return mHeaders.size();
3445 }
3446
getTableStringBlock(size_t index) const3447 const ResStringPool* ResTable::getTableStringBlock(size_t index) const
3448 {
3449 return &mHeaders[index]->values;
3450 }
3451
getTableCookie(size_t index) const3452 void* ResTable::getTableCookie(size_t index) const
3453 {
3454 return mHeaders[index]->cookie;
3455 }
3456
getConfigurations(Vector<ResTable_config> * configs) const3457 void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
3458 {
3459 const size_t I = mPackageGroups.size();
3460 for (size_t i=0; i<I; i++) {
3461 const PackageGroup* packageGroup = mPackageGroups[i];
3462 const size_t J = packageGroup->packages.size();
3463 for (size_t j=0; j<J; j++) {
3464 const Package* package = packageGroup->packages[j];
3465 const size_t K = package->types.size();
3466 for (size_t k=0; k<K; k++) {
3467 const Type* type = package->types[k];
3468 if (type == NULL) continue;
3469 const size_t L = type->configs.size();
3470 for (size_t l=0; l<L; l++) {
3471 const ResTable_type* config = type->configs[l];
3472 const ResTable_config* cfg = &config->config;
3473 // only insert unique
3474 const size_t M = configs->size();
3475 size_t m;
3476 for (m=0; m<M; m++) {
3477 if (0 == (*configs)[m].compare(*cfg)) {
3478 break;
3479 }
3480 }
3481 // if we didn't find it
3482 if (m == M) {
3483 configs->add(*cfg);
3484 }
3485 }
3486 }
3487 }
3488 }
3489 }
3490
getLocales(Vector<String8> * locales) const3491 void ResTable::getLocales(Vector<String8>* locales) const
3492 {
3493 Vector<ResTable_config> configs;
3494 LOGD("calling getConfigurations");
3495 getConfigurations(&configs);
3496 LOGD("called getConfigurations size=%d", (int)configs.size());
3497 const size_t I = configs.size();
3498 for (size_t i=0; i<I; i++) {
3499 char locale[6];
3500 configs[i].getLocale(locale);
3501 const size_t J = locales->size();
3502 size_t j;
3503 for (j=0; j<J; j++) {
3504 if (0 == strcmp(locale, (*locales)[j].string())) {
3505 break;
3506 }
3507 }
3508 if (j == J) {
3509 locales->add(String8(locale));
3510 }
3511 }
3512 }
3513
getEntry(const Package * package,int typeIndex,int entryIndex,const ResTable_config * config,const ResTable_type ** outType,const ResTable_entry ** outEntry,const Type ** outTypeClass) const3514 ssize_t ResTable::getEntry(
3515 const Package* package, int typeIndex, int entryIndex,
3516 const ResTable_config* config,
3517 const ResTable_type** outType, const ResTable_entry** outEntry,
3518 const Type** outTypeClass) const
3519 {
3520 LOGV("Getting entry from package %p\n", package);
3521 const ResTable_package* const pkg = package->package;
3522
3523 const Type* allTypes = package->getType(typeIndex);
3524 LOGV("allTypes=%p\n", allTypes);
3525 if (allTypes == NULL) {
3526 LOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
3527 return 0;
3528 }
3529
3530 if ((size_t)entryIndex >= allTypes->entryCount) {
3531 LOGW("getEntry failing because entryIndex %d is beyond type entryCount %d",
3532 entryIndex, (int)allTypes->entryCount);
3533 return BAD_TYPE;
3534 }
3535
3536 const ResTable_type* type = NULL;
3537 uint32_t offset = ResTable_type::NO_ENTRY;
3538 ResTable_config bestConfig;
3539 memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
3540
3541 const size_t NT = allTypes->configs.size();
3542 for (size_t i=0; i<NT; i++) {
3543 const ResTable_type* const thisType = allTypes->configs[i];
3544 if (thisType == NULL) continue;
3545
3546 ResTable_config thisConfig;
3547 thisConfig.copyFromDtoH(thisType->config);
3548
3549 TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
3550 "orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
3551 entryIndex, typeIndex+1, dtohl(thisType->config.size),
3552 thisConfig.mcc, thisConfig.mnc,
3553 config ? config->mcc : 0, config ? config->mnc : 0,
3554 thisConfig.language[0] ? thisConfig.language[0] : '-',
3555 thisConfig.language[1] ? thisConfig.language[1] : '-',
3556 config && config->language[0] ? config->language[0] : '-',
3557 config && config->language[1] ? config->language[1] : '-',
3558 thisConfig.country[0] ? thisConfig.country[0] : '-',
3559 thisConfig.country[1] ? thisConfig.country[1] : '-',
3560 config && config->country[0] ? config->country[0] : '-',
3561 config && config->country[1] ? config->country[1] : '-',
3562 thisConfig.orientation,
3563 config ? config->orientation : 0,
3564 thisConfig.touchscreen,
3565 config ? config->touchscreen : 0,
3566 thisConfig.density,
3567 config ? config->density : 0,
3568 thisConfig.keyboard,
3569 config ? config->keyboard : 0,
3570 thisConfig.inputFlags,
3571 config ? config->inputFlags : 0,
3572 thisConfig.navigation,
3573 config ? config->navigation : 0,
3574 thisConfig.screenWidth,
3575 config ? config->screenWidth : 0,
3576 thisConfig.screenHeight,
3577 config ? config->screenHeight : 0));
3578
3579 // Check to make sure this one is valid for the current parameters.
3580 if (config && !thisConfig.match(*config)) {
3581 TABLE_GETENTRY(LOGI("Does not match config!\n"));
3582 continue;
3583 }
3584
3585 // Check if there is the desired entry in this type.
3586
3587 const uint8_t* const end = ((const uint8_t*)thisType)
3588 + dtohl(thisType->header.size);
3589 const uint32_t* const eindex = (const uint32_t*)
3590 (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
3591
3592 uint32_t thisOffset = dtohl(eindex[entryIndex]);
3593 if (thisOffset == ResTable_type::NO_ENTRY) {
3594 TABLE_GETENTRY(LOGI("Skipping because it is not defined!\n"));
3595 continue;
3596 }
3597
3598 if (type != NULL) {
3599 // Check if this one is less specific than the last found. If so,
3600 // we will skip it. We check starting with things we most care
3601 // about to those we least care about.
3602 if (!thisConfig.isBetterThan(bestConfig, config)) {
3603 TABLE_GETENTRY(LOGI("This config is worse than last!\n"));
3604 continue;
3605 }
3606 }
3607
3608 type = thisType;
3609 offset = thisOffset;
3610 bestConfig = thisConfig;
3611 TABLE_GETENTRY(LOGI("Best entry so far -- using it!\n"));
3612 if (!config) break;
3613 }
3614
3615 if (type == NULL) {
3616 TABLE_GETENTRY(LOGI("No value found for requested entry!\n"));
3617 return BAD_INDEX;
3618 }
3619
3620 offset += dtohl(type->entriesStart);
3621 TABLE_NOISY(aout << "Looking in resource table " << package->header->header
3622 << ", typeOff="
3623 << (void*)(((const char*)type)-((const char*)package->header->header))
3624 << ", offset=" << (void*)offset << endl);
3625
3626 if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
3627 LOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
3628 offset, dtohl(type->header.size));
3629 return BAD_TYPE;
3630 }
3631 if ((offset&0x3) != 0) {
3632 LOGW("ResTable_entry at 0x%x is not on an integer boundary",
3633 offset);
3634 return BAD_TYPE;
3635 }
3636
3637 const ResTable_entry* const entry = (const ResTable_entry*)
3638 (((const uint8_t*)type) + offset);
3639 if (dtohs(entry->size) < sizeof(*entry)) {
3640 LOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
3641 return BAD_TYPE;
3642 }
3643
3644 *outType = type;
3645 *outEntry = entry;
3646 if (outTypeClass != NULL) {
3647 *outTypeClass = allTypes;
3648 }
3649 return offset + dtohs(entry->size);
3650 }
3651
parsePackage(const ResTable_package * const pkg,const Header * const header)3652 status_t ResTable::parsePackage(const ResTable_package* const pkg,
3653 const Header* const header)
3654 {
3655 const uint8_t* base = (const uint8_t*)pkg;
3656 status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
3657 header->dataEnd, "ResTable_package");
3658 if (err != NO_ERROR) {
3659 return (mError=err);
3660 }
3661
3662 const size_t pkgSize = dtohl(pkg->header.size);
3663
3664 if (dtohl(pkg->typeStrings) >= pkgSize) {
3665 LOGW("ResTable_package type strings at %p are past chunk size %p.",
3666 (void*)dtohl(pkg->typeStrings), (void*)pkgSize);
3667 return (mError=BAD_TYPE);
3668 }
3669 if ((dtohl(pkg->typeStrings)&0x3) != 0) {
3670 LOGW("ResTable_package type strings at %p is not on an integer boundary.",
3671 (void*)dtohl(pkg->typeStrings));
3672 return (mError=BAD_TYPE);
3673 }
3674 if (dtohl(pkg->keyStrings) >= pkgSize) {
3675 LOGW("ResTable_package key strings at %p are past chunk size %p.",
3676 (void*)dtohl(pkg->keyStrings), (void*)pkgSize);
3677 return (mError=BAD_TYPE);
3678 }
3679 if ((dtohl(pkg->keyStrings)&0x3) != 0) {
3680 LOGW("ResTable_package key strings at %p is not on an integer boundary.",
3681 (void*)dtohl(pkg->keyStrings));
3682 return (mError=BAD_TYPE);
3683 }
3684
3685 Package* package = NULL;
3686 PackageGroup* group = NULL;
3687 uint32_t id = dtohl(pkg->id);
3688 if (id != 0 && id < 256) {
3689
3690 package = new Package(this, header, pkg);
3691 if (package == NULL) {
3692 return (mError=NO_MEMORY);
3693 }
3694
3695 size_t idx = mPackageMap[id];
3696 if (idx == 0) {
3697 idx = mPackageGroups.size()+1;
3698
3699 char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
3700 strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
3701 group = new PackageGroup(this, String16(tmpName), id);
3702 if (group == NULL) {
3703 delete package;
3704 return (mError=NO_MEMORY);
3705 }
3706
3707 err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
3708 header->dataEnd-(base+dtohl(pkg->typeStrings)));
3709 if (err != NO_ERROR) {
3710 delete group;
3711 delete package;
3712 return (mError=err);
3713 }
3714 err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
3715 header->dataEnd-(base+dtohl(pkg->keyStrings)));
3716 if (err != NO_ERROR) {
3717 delete group;
3718 delete package;
3719 return (mError=err);
3720 }
3721
3722 //printf("Adding new package id %d at index %d\n", id, idx);
3723 err = mPackageGroups.add(group);
3724 if (err < NO_ERROR) {
3725 return (mError=err);
3726 }
3727 group->basePackage = package;
3728
3729 mPackageMap[id] = (uint8_t)idx;
3730 } else {
3731 group = mPackageGroups.itemAt(idx-1);
3732 if (group == NULL) {
3733 return (mError=UNKNOWN_ERROR);
3734 }
3735 }
3736 err = group->packages.add(package);
3737 if (err < NO_ERROR) {
3738 return (mError=err);
3739 }
3740 } else {
3741 LOG_ALWAYS_FATAL("Skins not supported!");
3742 return NO_ERROR;
3743 }
3744
3745
3746 // Iterate through all chunks.
3747 size_t curPackage = 0;
3748
3749 const ResChunk_header* chunk =
3750 (const ResChunk_header*)(((const uint8_t*)pkg)
3751 + dtohs(pkg->header.headerSize));
3752 const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
3753 while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
3754 ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
3755 TABLE_NOISY(LOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
3756 dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
3757 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
3758 const size_t csize = dtohl(chunk->size);
3759 const uint16_t ctype = dtohs(chunk->type);
3760 if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
3761 const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
3762 err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
3763 endPos, "ResTable_typeSpec");
3764 if (err != NO_ERROR) {
3765 return (mError=err);
3766 }
3767
3768 const size_t typeSpecSize = dtohl(typeSpec->header.size);
3769
3770 LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
3771 (void*)(base-(const uint8_t*)chunk),
3772 dtohs(typeSpec->header.type),
3773 dtohs(typeSpec->header.headerSize),
3774 (void*)typeSize));
3775 // look for block overrun or int overflow when multiplying by 4
3776 if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
3777 || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
3778 > typeSpecSize)) {
3779 LOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
3780 (void*)(dtohs(typeSpec->header.headerSize)
3781 +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))),
3782 (void*)typeSpecSize);
3783 return (mError=BAD_TYPE);
3784 }
3785
3786 if (typeSpec->id == 0) {
3787 LOGW("ResTable_type has an id of 0.");
3788 return (mError=BAD_TYPE);
3789 }
3790
3791 while (package->types.size() < typeSpec->id) {
3792 package->types.add(NULL);
3793 }
3794 Type* t = package->types[typeSpec->id-1];
3795 if (t == NULL) {
3796 t = new Type(header, package, dtohl(typeSpec->entryCount));
3797 package->types.editItemAt(typeSpec->id-1) = t;
3798 } else if (dtohl(typeSpec->entryCount) != t->entryCount) {
3799 LOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
3800 (int)dtohl(typeSpec->entryCount), (int)t->entryCount);
3801 return (mError=BAD_TYPE);
3802 }
3803 t->typeSpecFlags = (const uint32_t*)(
3804 ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
3805 t->typeSpec = typeSpec;
3806
3807 } else if (ctype == RES_TABLE_TYPE_TYPE) {
3808 const ResTable_type* type = (const ResTable_type*)(chunk);
3809 err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
3810 endPos, "ResTable_type");
3811 if (err != NO_ERROR) {
3812 return (mError=err);
3813 }
3814
3815 const size_t typeSize = dtohl(type->header.size);
3816
3817 LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
3818 (void*)(base-(const uint8_t*)chunk),
3819 dtohs(type->header.type),
3820 dtohs(type->header.headerSize),
3821 (void*)typeSize));
3822 if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
3823 > typeSize) {
3824 LOGW("ResTable_type entry index to %p extends beyond chunk end %p.",
3825 (void*)(dtohs(type->header.headerSize)
3826 +(sizeof(uint32_t)*dtohl(type->entryCount))),
3827 (void*)typeSize);
3828 return (mError=BAD_TYPE);
3829 }
3830 if (dtohl(type->entryCount) != 0
3831 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
3832 LOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.",
3833 (void*)dtohl(type->entriesStart), (void*)typeSize);
3834 return (mError=BAD_TYPE);
3835 }
3836 if (type->id == 0) {
3837 LOGW("ResTable_type has an id of 0.");
3838 return (mError=BAD_TYPE);
3839 }
3840
3841 while (package->types.size() < type->id) {
3842 package->types.add(NULL);
3843 }
3844 Type* t = package->types[type->id-1];
3845 if (t == NULL) {
3846 t = new Type(header, package, dtohl(type->entryCount));
3847 package->types.editItemAt(type->id-1) = t;
3848 } else if (dtohl(type->entryCount) != t->entryCount) {
3849 LOGW("ResTable_type entry count inconsistent: given %d, previously %d",
3850 (int)dtohl(type->entryCount), (int)t->entryCount);
3851 return (mError=BAD_TYPE);
3852 }
3853
3854 TABLE_GETENTRY(
3855 ResTable_config thisConfig;
3856 thisConfig.copyFromDtoH(type->config);
3857 LOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
3858 "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
3859 type->id,
3860 thisConfig.mcc, thisConfig.mnc,
3861 thisConfig.language[0] ? thisConfig.language[0] : '-',
3862 thisConfig.language[1] ? thisConfig.language[1] : '-',
3863 thisConfig.country[0] ? thisConfig.country[0] : '-',
3864 thisConfig.country[1] ? thisConfig.country[1] : '-',
3865 thisConfig.orientation,
3866 thisConfig.touchscreen,
3867 thisConfig.density,
3868 thisConfig.keyboard,
3869 thisConfig.inputFlags,
3870 thisConfig.navigation,
3871 thisConfig.screenWidth,
3872 thisConfig.screenHeight));
3873 t->configs.add(type);
3874 } else {
3875 status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
3876 endPos, "ResTable_package:unknown");
3877 if (err != NO_ERROR) {
3878 return (mError=err);
3879 }
3880 }
3881 chunk = (const ResChunk_header*)
3882 (((const uint8_t*)chunk) + csize);
3883 }
3884
3885 if (group->typeCount == 0) {
3886 group->typeCount = package->types.size();
3887 }
3888
3889 return NO_ERROR;
3890 }
3891
3892 #ifndef HAVE_ANDROID_OS
3893 #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
3894
3895 #define CHAR16_ARRAY_EQ(constant, var, len) \
3896 ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
3897
print_complex(uint32_t complex,bool isFraction)3898 void print_complex(uint32_t complex, bool isFraction)
3899 {
3900 const float MANTISSA_MULT =
3901 1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
3902 const float RADIX_MULTS[] = {
3903 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
3904 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
3905 };
3906
3907 float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
3908 <<Res_value::COMPLEX_MANTISSA_SHIFT))
3909 * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
3910 & Res_value::COMPLEX_RADIX_MASK];
3911 printf("%f", value);
3912
3913 if (!isFraction) {
3914 switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
3915 case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
3916 case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
3917 case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
3918 case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
3919 case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
3920 case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
3921 default: printf(" (unknown unit)"); break;
3922 }
3923 } else {
3924 switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
3925 case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
3926 case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
3927 default: printf(" (unknown unit)"); break;
3928 }
3929 }
3930 }
3931
print_value(const Package * pkg,const Res_value & value) const3932 void ResTable::print_value(const Package* pkg, const Res_value& value) const
3933 {
3934 if (value.dataType == Res_value::TYPE_NULL) {
3935 printf("(null)\n");
3936 } else if (value.dataType == Res_value::TYPE_REFERENCE) {
3937 printf("(reference) 0x%08x\n", value.data);
3938 } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
3939 printf("(attribute) 0x%08x\n", value.data);
3940 } else if (value.dataType == Res_value::TYPE_STRING) {
3941 size_t len;
3942 const char16_t* str = pkg->header->values.stringAt(
3943 value.data, &len);
3944 if (str == NULL) {
3945 printf("(string) null\n");
3946 } else {
3947 printf("(string) \"%s\"\n",
3948 String8(str, len).string());
3949 }
3950 } else if (value.dataType == Res_value::TYPE_FLOAT) {
3951 printf("(float) %g\n", *(const float*)&value.data);
3952 } else if (value.dataType == Res_value::TYPE_DIMENSION) {
3953 printf("(dimension) ");
3954 print_complex(value.data, false);
3955 printf("\n");
3956 } else if (value.dataType == Res_value::TYPE_FRACTION) {
3957 printf("(fraction) ");
3958 print_complex(value.data, true);
3959 printf("\n");
3960 } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
3961 || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
3962 printf("(color) #%08x\n", value.data);
3963 } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
3964 printf("(boolean) %s\n", value.data ? "true" : "false");
3965 } else if (value.dataType >= Res_value::TYPE_FIRST_INT
3966 || value.dataType <= Res_value::TYPE_LAST_INT) {
3967 printf("(int) 0x%08x or %d\n", value.data, value.data);
3968 } else {
3969 printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
3970 (int)value.dataType, (int)value.data,
3971 (int)value.size, (int)value.res0);
3972 }
3973 }
3974
print(bool inclValues) const3975 void ResTable::print(bool inclValues) const
3976 {
3977 if (mError != 0) {
3978 printf("mError=0x%x (%s)\n", mError, strerror(mError));
3979 }
3980 #if 0
3981 printf("mParams=%c%c-%c%c,\n",
3982 mParams.language[0], mParams.language[1],
3983 mParams.country[0], mParams.country[1]);
3984 #endif
3985 size_t pgCount = mPackageGroups.size();
3986 printf("Package Groups (%d)\n", (int)pgCount);
3987 for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
3988 const PackageGroup* pg = mPackageGroups[pgIndex];
3989 printf("Package Group %d id=%d packageCount=%d name=%s\n",
3990 (int)pgIndex, pg->id, (int)pg->packages.size(),
3991 String8(pg->name).string());
3992
3993 size_t pkgCount = pg->packages.size();
3994 for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
3995 const Package* pkg = pg->packages[pkgIndex];
3996 size_t typeCount = pkg->types.size();
3997 printf(" Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
3998 pkg->package->id, String8(String16(pkg->package->name)).string(),
3999 (int)typeCount);
4000 for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) {
4001 const Type* typeConfigs = pkg->getType(typeIndex);
4002 if (typeConfigs == NULL) {
4003 printf(" type %d NULL\n", (int)typeIndex);
4004 continue;
4005 }
4006 const size_t NTC = typeConfigs->configs.size();
4007 printf(" type %d configCount=%d entryCount=%d\n",
4008 (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
4009 if (typeConfigs->typeSpecFlags != NULL) {
4010 for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
4011 uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
4012 | (0x00ff0000 & ((typeIndex+1)<<16))
4013 | (0x0000ffff & (entryIndex));
4014 resource_name resName;
4015 this->getResourceName(resID, &resName);
4016 printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
4017 resID,
4018 CHAR16_TO_CSTR(resName.package, resName.packageLen),
4019 CHAR16_TO_CSTR(resName.type, resName.typeLen),
4020 CHAR16_TO_CSTR(resName.name, resName.nameLen),
4021 dtohl(typeConfigs->typeSpecFlags[entryIndex]));
4022 }
4023 }
4024 for (size_t configIndex=0; configIndex<NTC; configIndex++) {
4025 const ResTable_type* type = typeConfigs->configs[configIndex];
4026 if ((((uint64_t)type)&0x3) != 0) {
4027 printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
4028 continue;
4029 }
4030 char density[16];
4031 uint16_t dval = dtohs(type->config.density);
4032 if (dval == ResTable_config::DENSITY_DEFAULT) {
4033 strcpy(density, "def");
4034 } else if (dval == ResTable_config::DENSITY_NONE) {
4035 strcpy(density, "no");
4036 } else {
4037 sprintf(density, "%d", (int)dval);
4038 }
4039 printf(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%s key=%d infl=%d nav=%d w=%d h=%d sz=%d lng=%d\n",
4040 (int)configIndex,
4041 type->config.language[0] ? type->config.language[0] : '-',
4042 type->config.language[1] ? type->config.language[1] : '-',
4043 type->config.country[0] ? type->config.country[0] : '-',
4044 type->config.country[1] ? type->config.country[1] : '-',
4045 type->config.orientation,
4046 type->config.touchscreen,
4047 density,
4048 type->config.keyboard,
4049 type->config.inputFlags,
4050 type->config.navigation,
4051 dtohs(type->config.screenWidth),
4052 dtohs(type->config.screenHeight),
4053 type->config.screenLayout&ResTable_config::MASK_SCREENSIZE,
4054 type->config.screenLayout&ResTable_config::MASK_SCREENLONG);
4055 size_t entryCount = dtohl(type->entryCount);
4056 uint32_t entriesStart = dtohl(type->entriesStart);
4057 if ((entriesStart&0x3) != 0) {
4058 printf(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart);
4059 continue;
4060 }
4061 uint32_t typeSize = dtohl(type->header.size);
4062 if ((typeSize&0x3) != 0) {
4063 printf(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize);
4064 continue;
4065 }
4066 for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
4067
4068 const uint8_t* const end = ((const uint8_t*)type)
4069 + dtohl(type->header.size);
4070 const uint32_t* const eindex = (const uint32_t*)
4071 (((const uint8_t*)type) + dtohs(type->header.headerSize));
4072
4073 uint32_t thisOffset = dtohl(eindex[entryIndex]);
4074 if (thisOffset == ResTable_type::NO_ENTRY) {
4075 continue;
4076 }
4077
4078 uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
4079 | (0x00ff0000 & ((typeIndex+1)<<16))
4080 | (0x0000ffff & (entryIndex));
4081 resource_name resName;
4082 this->getResourceName(resID, &resName);
4083 printf(" resource 0x%08x %s:%s/%s: ", resID,
4084 CHAR16_TO_CSTR(resName.package, resName.packageLen),
4085 CHAR16_TO_CSTR(resName.type, resName.typeLen),
4086 CHAR16_TO_CSTR(resName.name, resName.nameLen));
4087 if ((thisOffset&0x3) != 0) {
4088 printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
4089 continue;
4090 }
4091 if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
4092 printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n",
4093 (void*)entriesStart, (void*)thisOffset,
4094 (void*)typeSize);
4095 continue;
4096 }
4097
4098 const ResTable_entry* ent = (const ResTable_entry*)
4099 (((const uint8_t*)type) + entriesStart + thisOffset);
4100 if (((entriesStart + thisOffset)&0x3) != 0) {
4101 printf("NON-INTEGER ResTable_entry OFFSET: %p\n",
4102 (void*)(entriesStart + thisOffset));
4103 continue;
4104 }
4105
4106 uint16_t esize = dtohs(ent->size);
4107 if ((esize&0x3) != 0) {
4108 printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
4109 continue;
4110 }
4111 if ((thisOffset+esize) > typeSize) {
4112 printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
4113 (void*)entriesStart, (void*)thisOffset,
4114 (void*)esize, (void*)typeSize);
4115 continue;
4116 }
4117
4118 const Res_value* valuePtr = NULL;
4119 const ResTable_map_entry* bagPtr = NULL;
4120 Res_value value;
4121 if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
4122 printf("<bag>");
4123 bagPtr = (const ResTable_map_entry*)ent;
4124 } else {
4125 valuePtr = (const Res_value*)
4126 (((const uint8_t*)ent) + esize);
4127 value.copyFrom_dtoh(*valuePtr);
4128 printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
4129 (int)value.dataType, (int)value.data,
4130 (int)value.size, (int)value.res0);
4131 }
4132
4133 if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
4134 printf(" (PUBLIC)");
4135 }
4136 printf("\n");
4137
4138 if (inclValues) {
4139 if (valuePtr != NULL) {
4140 printf(" ");
4141 print_value(pkg, value);
4142 } else if (bagPtr != NULL) {
4143 const int N = dtohl(bagPtr->count);
4144 const ResTable_map* mapPtr = (const ResTable_map*)
4145 (((const uint8_t*)ent) + esize);
4146 printf(" Parent=0x%08x, Count=%d\n",
4147 dtohl(bagPtr->parent.ident), N);
4148 for (int i=0; i<N; i++) {
4149 printf(" #%i (Key=0x%08x): ",
4150 i, dtohl(mapPtr->name.ident));
4151 value.copyFrom_dtoh(mapPtr->value);
4152 print_value(pkg, value);
4153 const size_t size = dtohs(mapPtr->value.size);
4154 mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
4155 + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
4156 }
4157 }
4158 }
4159 }
4160 }
4161 }
4162 }
4163 }
4164 }
4165
4166 #endif // HAVE_ANDROID_OS
4167
4168 } // namespace android
4169