2 // Copyright 2006 The Android Open Source Project 
   4 // Build resource files from raw assets. 
   7 #include "ResourceTable.h" 
  11 #include <utils/ByteOrder.h> 
  12 #include <utils/ResourceTypes.h> 
  17 status_t 
compileXmlFile(const sp
<AaptAssets
>& assets
, 
  18                         const sp
<AaptFile
>& target
, 
  22     sp
<XMLNode
> root 
= XMLNode::parse(target
); 
  26     if ((options
&XML_COMPILE_STRIP_WHITESPACE
) != 0) { 
  27         root
->removeWhitespace(true, NULL
); 
  28     } else  if ((options
&XML_COMPILE_COMPACT_WHITESPACE
) != 0) { 
  29         root
->removeWhitespace(false, NULL
); 
  32     bool hasErrors 
= false; 
  34     if ((options
&XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
) != 0) { 
  35         status_t err 
= root
->assignResourceIds(assets
, table
); 
  36         if (err 
!= NO_ERROR
) { 
  41     status_t err 
= root
->parseValues(assets
, table
); 
  42     if (err 
!= NO_ERROR
) { 
  50     NOISY(printf("Input XML Resource:\n")); 
  52     err 
= root
->flatten(target
, 
  53             (options
&XML_COMPILE_STRIP_COMMENTS
) != 0, 
  54             (options
&XML_COMPILE_STRIP_RAW_VALUES
) != 0); 
  55     if (err 
!= NO_ERROR
) { 
  59     NOISY(printf("Output XML Resource:\n")); 
  60     NOISY(ResXMLTree tree
; 
  61         tree
.setTo(target
->getData(), target
->getSize()); 
  62         printXMLBlock(&tree
)); 
  64     target
->setCompressionMethod(ZipEntry::kCompressDeflated
); 
  77     const char* description
; 
  80 static const char16_t referenceArray
[] = 
  81     { 'r', 'e', 'f', 'e', 'r', 'e', 'n', 'c', 'e' }; 
  82 static const char16_t stringArray
[] = 
  83     { 's', 't', 'r', 'i', 'n', 'g' }; 
  84 static const char16_t integerArray
[] = 
  85     { 'i', 'n', 't', 'e', 'g', 'e', 'r' }; 
  86 static const char16_t booleanArray
[] = 
  87     { 'b', 'o', 'o', 'l', 'e', 'a', 'n' }; 
  88 static const char16_t colorArray
[] = 
  89     { 'c', 'o', 'l', 'o', 'r' }; 
  90 static const char16_t floatArray
[] = 
  91     { 'f', 'l', 'o', 'a', 't' }; 
  92 static const char16_t dimensionArray
[] = 
  93     { 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n' }; 
  94 static const char16_t fractionArray
[] = 
  95     { 'f', 'r', 'a', 'c', 't', 'i', 'o', 'n' }; 
  96 static const char16_t enumArray
[] = 
  97     { 'e', 'n', 'u', 'm' }; 
  98 static const char16_t flagsArray
[] = 
  99     { 'f', 'l', 'a', 'g', 's' }; 
 101 static const flag_entry gFormatFlags
[] = { 
 102     { referenceArray
, sizeof(referenceArray
)/2, ResTable_map::TYPE_REFERENCE
, 
 103       "a reference to another resource, in the form \"<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>\"\n" 
 104       "or to a theme attribute in the form \"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\"."}, 
 105     { stringArray
, sizeof(stringArray
)/2, ResTable_map::TYPE_STRING
, 
 106       "a string value, using '\\\\;' to escape characters such as '\\\\n' or '\\\\uxxxx' for a unicode character." }, 
 107     { integerArray
, sizeof(integerArray
)/2, ResTable_map::TYPE_INTEGER
, 
 108       "an integer value, such as \"<code>100</code>\"." }, 
 109     { booleanArray
, sizeof(booleanArray
)/2, ResTable_map::TYPE_BOOLEAN
, 
 110       "a boolean value, either \"<code>true</code>\" or \"<code>false</code>\"." }, 
 111     { colorArray
, sizeof(colorArray
)/2, ResTable_map::TYPE_COLOR
, 
 112       "a color value, in the form of \"<code>#<i>rgb</i></code>\", \"<code>#<i>argb</i></code>\",\n" 
 113       "\"<code>#<i>rrggbb</i></code>\", or \"<code>#<i>aarrggbb</i></code>\"." }, 
 114     { floatArray
, sizeof(floatArray
)/2, ResTable_map::TYPE_FLOAT
, 
 115       "a floating point value, such as \"<code>1.2</code>\"."}, 
 116     { dimensionArray
, sizeof(dimensionArray
)/2, ResTable_map::TYPE_DIMENSION
, 
 117       "a dimension value, which is a floating point number appended with a unit such as \"<code>14.5sp</code>\".\n" 
 118       "Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\n" 
 119       "in (inches), mm (millimeters)." }, 
 120     { fractionArray
, sizeof(fractionArray
)/2, ResTable_map::TYPE_FRACTION
, 
 121       "a fractional value, which is a floating point number appended with either % or %p, such as \"<code>14.5%</code>\".\n" 
 122       "The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to\n" 
 123       "some parent container." }, 
 124     { enumArray
, sizeof(enumArray
)/2, ResTable_map::TYPE_ENUM
, NULL 
}, 
 125     { flagsArray
, sizeof(flagsArray
)/2, ResTable_map::TYPE_FLAGS
, NULL 
}, 
 129 static const char16_t suggestedArray
[] = { 's', 'u', 'g', 'g', 'e', 's', 't', 'e', 'd' }; 
 131 static const flag_entry l10nRequiredFlags
[] = { 
 132     { suggestedArray
, sizeof(suggestedArray
)/2, ResTable_map::L10N_SUGGESTED
, NULL 
}, 
 136 static const char16_t nulStr
[] = { 0 }; 
 138 static uint32_t parse_flags(const char16_t* str
, size_t len
, 
 139                              const flag_entry
* flags
, bool* outError 
= NULL
) 
 141     while (len 
> 0 && isspace(*str
)) { 
 145     while (len 
> 0 && isspace(str
[len
-1])) { 
 149     const char16_t* const end 
= str 
+ len
; 
 153         const char16_t* div 
= str
; 
 154         while (div 
< end 
&& *div 
!= '|') { 
 158         const flag_entry
* cur 
= flags
; 
 160             if (strzcmp16(cur
->name
, cur
->nameLen
, str
, div
-str
) == 0) { 
 168             if (outError
) *outError 
= true; 
 172         str 
= div 
< end 
? div
+1 : div
; 
 175     if (outError
) *outError 
= false; 
 179 static String16 
mayOrMust(int type
, int flags
) 
 181     if ((type
&(~flags
)) == 0) { 
 182         return String16("<p>Must"); 
 185     return String16("<p>May"); 
 188 static void appendTypeInfo(ResourceTable
* outTable
, const String16
& pkg
, 
 189         const String16
& typeName
, const String16
& ident
, int type
, 
 190         const flag_entry
* flags
) 
 192     bool hadType 
= false; 
 193     while (flags
->name
) { 
 194         if ((type
&flags
->value
) != 0 && flags
->description 
!= NULL
) { 
 195             String16 
fullMsg(mayOrMust(type
, flags
->value
)); 
 196             fullMsg
.append(String16(" be ")); 
 197             fullMsg
.append(String16(flags
->description
)); 
 198             outTable
->appendTypeComment(pkg
, typeName
, ident
, fullMsg
); 
 203     if (hadType 
&& (type
&ResTable_map::TYPE_REFERENCE
) == 0) { 
 204         outTable
->appendTypeComment(pkg
, typeName
, ident
, 
 205                 String16("<p>This may also be a reference to a resource (in the form\n" 
 206                          "\"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>\") or\n" 
 207                          "theme attribute (in the form\n" 
 208                          "\"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\")\n" 
 209                          "containing a value of this type.")); 
 213 struct PendingAttribute
 
 215     const String16 myPackage
; 
 216     const SourcePos sourcePos
; 
 217     const bool appendComment
; 
 224     PendingAttribute(String16 _package
, const sp
<AaptFile
>& in
, 
 225             ResXMLTree
& block
, bool _appendComment
) 
 226         : myPackage(_package
) 
 227         , sourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 228         , appendComment(_appendComment
) 
 229         , type(ResTable_map::TYPE_ANY
) 
 235     status_t 
createIfNeeded(ResourceTable
* outTable
) 
 237         if (added 
|| hasErrors
) { 
 242         String16 
attr16("attr"); 
 244         if (outTable
->hasBagOrEntry(myPackage
, attr16
, ident
)) { 
 245             sourcePos
.error("Attribute \"%s\" has already been defined\n", 
 246                     String8(ident
).string()); 
 248             return UNKNOWN_ERROR
; 
 252         sprintf(numberStr
, "%d", type
); 
 253         status_t err 
= outTable
->addBag(sourcePos
, myPackage
, 
 254                 attr16
, ident
, String16(""), 
 256                 String16(numberStr
), NULL
, NULL
); 
 257         if (err 
!= NO_ERROR
) { 
 261         outTable
->appendComment(myPackage
, attr16
, ident
, comment
, appendComment
); 
 262         //printf("Attribute %s comment: %s\n", String8(ident).string(), 
 263         //     String8(comment).string()); 
 268 static status_t 
compileAttribute(const sp
<AaptFile
>& in
, 
 270                                  const String16
& myPackage
, 
 271                                  ResourceTable
* outTable
, 
 272                                  String16
* outIdent 
= NULL
, 
 273                                  bool inStyleable 
= false) 
 275     PendingAttribute 
attr(myPackage
, in
, block
, inStyleable
); 
 277     const String16 
attr16("attr"); 
 278     const String16 
id16("id"); 
 280     // Attribute type constants. 
 281     const String16 
enum16("enum"); 
 282     const String16 
flag16("flag"); 
 284     ResXMLTree::event_code_t code
; 
 288     ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "name"); 
 290         attr
.ident 
= String16(block
.getAttributeStringValue(identIdx
, &len
)); 
 292             *outIdent 
= attr
.ident
; 
 295         attr
.sourcePos
.error("A 'name' attribute is required for <attr>\n"); 
 296         attr
.hasErrors 
= true; 
 299     attr
.comment 
= String16( 
 300             block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 302     ssize_t typeIdx 
= block
.indexOfAttribute(NULL
, "format"); 
 304         String16 typeStr 
= String16(block
.getAttributeStringValue(typeIdx
, &len
)); 
 305         attr
.type 
= parse_flags(typeStr
.string(), typeStr
.size(), gFormatFlags
); 
 306         if (attr
.type 
== 0) { 
 307             attr
.sourcePos
.error("Tag <attr> 'format' attribute value \"%s\" not valid\n", 
 308                     String8(typeStr
).string()); 
 309             attr
.hasErrors 
= true; 
 311         attr
.createIfNeeded(outTable
); 
 312     } else if (!inStyleable
) { 
 313         // Attribute definitions outside of styleables always define the 
 314         // attribute as a generic value. 
 315         attr
.createIfNeeded(outTable
); 
 318     //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).string(), attr.type); 
 320     ssize_t minIdx 
= block
.indexOfAttribute(NULL
, "min"); 
 322         String16 val 
= String16(block
.getAttributeStringValue(minIdx
, &len
)); 
 323         if (!ResTable::stringToInt(val
.string(), val
.size(), NULL
)) { 
 324             attr
.sourcePos
.error("Tag <attr> 'min' attribute must be a number, not \"%s\"\n", 
 325                     String8(val
).string()); 
 326             attr
.hasErrors 
= true; 
 328         attr
.createIfNeeded(outTable
); 
 329         if (!attr
.hasErrors
) { 
 330             err 
= outTable
->addBag(attr
.sourcePos
, myPackage
, attr16
, attr
.ident
, 
 331                     String16(""), String16("^min"), String16(val
), NULL
, NULL
); 
 332             if (err 
!= NO_ERROR
) { 
 333                 attr
.hasErrors 
= true; 
 338     ssize_t maxIdx 
= block
.indexOfAttribute(NULL
, "max"); 
 340         String16 val 
= String16(block
.getAttributeStringValue(maxIdx
, &len
)); 
 341         if (!ResTable::stringToInt(val
.string(), val
.size(), NULL
)) { 
 342             attr
.sourcePos
.error("Tag <attr> 'max' attribute must be a number, not \"%s\"\n", 
 343                     String8(val
).string()); 
 344             attr
.hasErrors 
= true; 
 346         attr
.createIfNeeded(outTable
); 
 347         if (!attr
.hasErrors
) { 
 348             err 
= outTable
->addBag(attr
.sourcePos
, myPackage
, attr16
, attr
.ident
, 
 349                     String16(""), String16("^max"), String16(val
), NULL
, NULL
); 
 350             attr
.hasErrors 
= true; 
 354     if ((minIdx 
>= 0 || maxIdx 
>= 0) && (attr
.type
&ResTable_map::TYPE_INTEGER
) == 0) { 
 355         attr
.sourcePos
.error("Tag <attr> must have format=integer attribute if using max or min\n"); 
 356         attr
.hasErrors 
= true; 
 359     ssize_t l10nIdx 
= block
.indexOfAttribute(NULL
, "localization"); 
 361         const uint16_t* str 
= block
.getAttributeStringValue(l10nIdx
, &len
); 
 363         uint32_t l10n_required 
= parse_flags(str
, len
, l10nRequiredFlags
, &error
); 
 365             attr
.sourcePos
.error("Tag <attr> 'localization' attribute value \"%s\" not valid\n", 
 366                     String8(str
).string()); 
 367             attr
.hasErrors 
= true; 
 369         attr
.createIfNeeded(outTable
); 
 370         if (!attr
.hasErrors
) { 
 372             sprintf(buf
, "%d", l10n_required
); 
 373             err 
= outTable
->addBag(attr
.sourcePos
, myPackage
, attr16
, attr
.ident
, 
 374                     String16(""), String16("^l10n"), String16(buf
), NULL
, NULL
); 
 375             if (err 
!= NO_ERROR
) { 
 376                 attr
.hasErrors 
= true; 
 381     String16 enumOrFlagsComment
; 
 383     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 384         if (code 
== ResXMLTree::START_TAG
) { 
 385             uint32_t localType 
= 0; 
 386             if (strcmp16(block
.getElementName(&len
), enum16
.string()) == 0) { 
 387                 localType 
= ResTable_map::TYPE_ENUM
; 
 388             } else if (strcmp16(block
.getElementName(&len
), flag16
.string()) == 0) { 
 389                 localType 
= ResTable_map::TYPE_FLAGS
; 
 391                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 392                         .error("Tag <%s> can not appear inside <attr>, only <enum> or <flag>\n", 
 393                         String8(block
.getElementName(&len
)).string()); 
 394                 return UNKNOWN_ERROR
; 
 397             attr
.createIfNeeded(outTable
); 
 399             if (attr
.type 
== ResTable_map::TYPE_ANY
) { 
 400                 // No type was explicitly stated, so supplying enum tags 
 401                 // implicitly creates an enum or flag. 
 405             if ((attr
.type
&(ResTable_map::TYPE_ENUM
|ResTable_map::TYPE_FLAGS
)) == 0) { 
 406                 // Wasn't originally specified as an enum, so update its type. 
 407                 attr
.type 
|= localType
; 
 408                 if (!attr
.hasErrors
) { 
 410                     sprintf(numberStr
, "%d", attr
.type
); 
 411                     err 
= outTable
->addBag(SourcePos(in
->getPrintableSource(), block
.getLineNumber()), 
 412                             myPackage
, attr16
, attr
.ident
, String16(""), 
 413                             String16("^type"), String16(numberStr
), NULL
, NULL
, true); 
 414                     if (err 
!= NO_ERROR
) { 
 415                         attr
.hasErrors 
= true; 
 418             } else if ((uint32_t)(attr
.type
&(ResTable_map::TYPE_ENUM
|ResTable_map::TYPE_FLAGS
)) != localType
) { 
 419                 if (localType 
== ResTable_map::TYPE_ENUM
) { 
 420                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 421                             .error("<enum> attribute can not be used inside a flags format\n"); 
 422                     attr
.hasErrors 
= true; 
 424                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 425                             .error("<flag> attribute can not be used inside a enum format\n"); 
 426                     attr
.hasErrors 
= true; 
 431             ssize_t itemIdentIdx 
= block
.indexOfAttribute(NULL
, "name"); 
 432             if (itemIdentIdx 
>= 0) { 
 433                 itemIdent 
= String16(block
.getAttributeStringValue(itemIdentIdx
, &len
)); 
 435                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 436                         .error("A 'name' attribute is required for <enum> or <flag>\n"); 
 437                 attr
.hasErrors 
= true; 
 441             ssize_t valueIdx 
= block
.indexOfAttribute(NULL
, "value"); 
 443                 value 
= String16(block
.getAttributeStringValue(valueIdx
, &len
)); 
 445                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 446                         .error("A 'value' attribute is required for <enum> or <flag>\n"); 
 447                 attr
.hasErrors 
= true; 
 449             if (!attr
.hasErrors 
&& !ResTable::stringToInt(value
.string(), value
.size(), NULL
)) { 
 450                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 451                         .error("Tag <enum> or <flag> 'value' attribute must be a number," 
 453                         String8(value
).string()); 
 454                 attr
.hasErrors 
= true; 
 457             // Make sure an id is defined for this enum/flag identifier... 
 458             if (!attr
.hasErrors 
&& !outTable
->hasBagOrEntry(itemIdent
, &id16
, &myPackage
)) { 
 459                 err 
= outTable
->startBag(SourcePos(in
->getPrintableSource(), block
.getLineNumber()), 
 460                                          myPackage
, id16
, itemIdent
, String16(), NULL
); 
 461                 if (err 
!= NO_ERROR
) { 
 462                     attr
.hasErrors 
= true; 
 466             if (!attr
.hasErrors
) { 
 467                 if (enumOrFlagsComment
.size() == 0) { 
 468                     enumOrFlagsComment
.append(mayOrMust(attr
.type
, 
 469                             ResTable_map::TYPE_ENUM
|ResTable_map::TYPE_FLAGS
)); 
 470                     enumOrFlagsComment
.append((attr
.type
&ResTable_map::TYPE_ENUM
) 
 471                                        ? String16(" be one of the following constant values.") 
 472                                        : String16(" be one or more (separated by '|') of the following constant values.")); 
 473                     enumOrFlagsComment
.append(String16("</p>\n<table border=\"2\" width=\"85%\" align=\"center\" frame=\"hsides\" rules=\"all\" cellpadding=\"5\">\n" 
 474                                                 "<colgroup align=\"left\" />\n" 
 475                                                 "<colgroup align=\"left\" />\n" 
 476                                                 "<colgroup align=\"left\" />\n" 
 477                                                 "<tr><th>Constant<th>Value<th>Description</tr>")); 
 480                 enumOrFlagsComment
.append(String16("\n<tr><th><code>")); 
 481                 enumOrFlagsComment
.append(itemIdent
); 
 482                 enumOrFlagsComment
.append(String16("</code><td>")); 
 483                 enumOrFlagsComment
.append(value
); 
 484                 enumOrFlagsComment
.append(String16("<td>")); 
 485                 if (block
.getComment(&len
)) { 
 486                     enumOrFlagsComment
.append(String16(block
.getComment(&len
))); 
 488                 enumOrFlagsComment
.append(String16("</tr>")); 
 490                 err 
= outTable
->addBag(SourcePos(in
->getPrintableSource(), block
.getLineNumber()), 
 492                                        attr16
, attr
.ident
, String16(""), 
 493                                        itemIdent
, value
, NULL
, NULL
, false, true); 
 494                 if (err 
!= NO_ERROR
) { 
 495                     attr
.hasErrors 
= true; 
 498         } else if (code 
== ResXMLTree::END_TAG
) { 
 499             if (strcmp16(block
.getElementName(&len
), attr16
.string()) == 0) { 
 502             if ((attr
.type
&ResTable_map::TYPE_ENUM
) != 0) { 
 503                 if (strcmp16(block
.getElementName(&len
), enum16
.string()) != 0) { 
 504                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 505                             .error("Found tag </%s> where </enum> is expected\n", 
 506                             String8(block
.getElementName(&len
)).string()); 
 507                     return UNKNOWN_ERROR
; 
 510                 if (strcmp16(block
.getElementName(&len
), flag16
.string()) != 0) { 
 511                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()) 
 512                             .error("Found tag </%s> where </flag> is expected\n", 
 513                             String8(block
.getElementName(&len
)).string()); 
 514                     return UNKNOWN_ERROR
; 
 520     if (!attr
.hasErrors 
&& attr
.added
) { 
 521         appendTypeInfo(outTable
, myPackage
, attr16
, attr
.ident
, attr
.type
, gFormatFlags
); 
 524     if (!attr
.hasErrors 
&& enumOrFlagsComment
.size() > 0) { 
 525         enumOrFlagsComment
.append(String16("\n</table>")); 
 526         outTable
->appendTypeComment(myPackage
, attr16
, attr
.ident
, enumOrFlagsComment
); 
 533 bool localeIsDefined(const ResTable_config
& config
) 
 535     return config
.locale 
== 0; 
 538 status_t 
parseAndAddBag(Bundle
* bundle
, 
 539                         const sp
<AaptFile
>& in
, 
 541                         const ResTable_config
& config
, 
 542                         const String16
& myPackage
, 
 543                         const String16
& curType
, 
 544                         const String16
& ident
, 
 545                         const String16
& parentIdent
, 
 546                         const String16
& itemIdent
, 
 549                         const bool overwrite
, 
 550                         ResourceTable
* outTable
) 
 553     const String16 
item16("item"); 
 556     Vector
<StringPool::entry_style_span
> spans
; 
 557     err 
= parseStyledString(bundle
, in
->getPrintableSource().string(), 
 558                             block
, item16
, &str
, &spans
, 
 560     if (err 
!= NO_ERROR
) { 
 564     NOISY(printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d " 
 565                  " pid=%s, bag=%s, id=%s: %s\n", 
 566                  config
.language
[0], config
.language
[1], 
 567                  config
.country
[0], config
.country
[1], 
 568                  config
.orientation
, config
.density
, 
 569                  String8(parentIdent
).string(), 
 570                  String8(ident
).string(), 
 571                  String8(itemIdent
).string(), 
 572                  String8(str
).string())); 
 574     err 
= outTable
->addBag(SourcePos(in
->getPrintableSource(), block
->getLineNumber()), 
 575                            myPackage
, curType
, ident
, parentIdent
, itemIdent
, str
, 
 576                            &spans
, &config
, overwrite
, false, curFormat
); 
 581 status_t 
parseAndAddEntry(Bundle
* bundle
, 
 582                         const sp
<AaptFile
>& in
, 
 584                         const ResTable_config
& config
, 
 585                         const String16
& myPackage
, 
 586                         const String16
& curType
, 
 587                         const String16
& ident
, 
 588                         const String16
& curTag
, 
 592                         const bool overwrite
, 
 593                         ResourceTable
* outTable
) 
 598     Vector
<StringPool::entry_style_span
> spans
; 
 599     err 
= parseStyledString(bundle
, in
->getPrintableSource().string(), block
, 
 600                             curTag
, &str
, curIsStyled 
? &spans 
: NULL
, 
 603     if (err 
< NO_ERROR
) {  
 607     NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n", 
 608                  config
.language
[0], config
.language
[1], 
 609                  config
.country
[0], config
.country
[1], 
 610                  config
.orientation
, config
.density
, 
 611                  String8(ident
).string(), String8(str
).string())); 
 613     err 
= outTable
->addEntry(SourcePos(in
->getPrintableSource(), block
->getLineNumber()), 
 614                              myPackage
, curType
, ident
, str
, &spans
, &config
, 
 615                              false, curFormat
, overwrite
); 
 620 status_t 
compileResourceFile(Bundle
* bundle
, 
 621                              const sp
<AaptAssets
>& assets
, 
 622                              const sp
<AaptFile
>& in
, 
 623                              const ResTable_config
& defParams
, 
 624                              const bool overwrite
, 
 625                              ResourceTable
* outTable
) 
 628     status_t err 
= parseXMLResource(in
, &block
, false, true); 
 629     if (err 
!= NO_ERROR
) { 
 634     const String16 
resources16("resources"); 
 636     // Identifier declaration tags. 
 637     const String16 
declare_styleable16("declare-styleable"); 
 638     const String16 
attr16("attr"); 
 640     // Data creation organizational tags. 
 641     const String16 
string16("string"); 
 642     const String16 
drawable16("drawable"); 
 643     const String16 
color16("color"); 
 644     const String16 
bool16("bool"); 
 645     const String16 
integer16("integer"); 
 646     const String16 
dimen16("dimen"); 
 647     const String16 
style16("style"); 
 648     const String16 
plurals16("plurals"); 
 649     const String16 
array16("array"); 
 650     const String16 
string_array16("string-array"); 
 651     const String16 
integer_array16("integer-array"); 
 652     const String16 
public16("public"); 
 653     const String16 
private_symbols16("private-symbols"); 
 654     const String16 
skip16("skip"); 
 655     const String16 
eat_comment16("eat-comment"); 
 657     // Data creation tags. 
 658     const String16 
bag16("bag"); 
 659     const String16 
item16("item"); 
 661     // Attribute type constants. 
 662     const String16 
enum16("enum"); 
 665     const String16 
other16("other"); 
 666     const String16 
quantityOther16("^other"); 
 667     const String16 
zero16("zero"); 
 668     const String16 
quantityZero16("^zero"); 
 669     const String16 
one16("one"); 
 670     const String16 
quantityOne16("^one"); 
 671     const String16 
two16("two"); 
 672     const String16 
quantityTwo16("^two"); 
 673     const String16 
few16("few"); 
 674     const String16 
quantityFew16("^few"); 
 675     const String16 
many16("many"); 
 676     const String16 
quantityMany16("^many"); 
 678     // useful attribute names and special values 
 679     const String16 
name16("name"); 
 680     const String16 
translatable16("translatable"); 
 681     const String16 
false16("false"); 
 683     const String16 
myPackage(assets
->getPackage()); 
 685     bool hasErrors 
= false; 
 687     uint32_t nextPublicId 
= 0; 
 689     ResXMLTree::event_code_t code
; 
 692     } while (code 
== ResXMLTree::START_NAMESPACE
); 
 695     if (code 
!= ResXMLTree::START_TAG
) { 
 696         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 697                 "No start tag found\n"); 
 698         return UNKNOWN_ERROR
; 
 700     if (strcmp16(block
.getElementName(&len
), resources16
.string()) != 0) { 
 701         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 702                 "Invalid start tag %s\n", String8(block
.getElementName(&len
)).string()); 
 703         return UNKNOWN_ERROR
; 
 706     ResTable_config 
curParams(defParams
); 
 708     ResTable_config 
pseudoParams(curParams
); 
 709         pseudoParams
.language
[0] = 'z'; 
 710         pseudoParams
.language
[1] = 'z'; 
 711         pseudoParams
.country
[0] = 'Z'; 
 712         pseudoParams
.country
[1] = 'Z'; 
 714     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 715         if (code 
== ResXMLTree::START_TAG
) { 
 716             const String16
* curTag 
= NULL
; 
 718             int32_t curFormat 
= ResTable_map::TYPE_ANY
; 
 719             bool curIsBag 
= false; 
 720             bool curIsStyled 
= false; 
 721             bool curIsPseudolocalizable 
= false; 
 722             bool localHasErrors 
= false; 
 724             if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 725                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 726                         && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 727                     if (code 
== ResXMLTree::END_TAG
) { 
 728                         if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 735             } else if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 736                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 737                         && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 738                     if (code 
== ResXMLTree::END_TAG
) { 
 739                         if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 746             } else if (strcmp16(block
.getElementName(&len
), public16
.string()) == 0) { 
 747                 SourcePos 
srcPos(in
->getPrintableSource(), block
.getLineNumber()); 
 750                 ssize_t typeIdx 
= block
.indexOfAttribute(NULL
, "type"); 
 752                     srcPos
.error("A 'type' attribute is required for <public>\n"); 
 753                     hasErrors 
= localHasErrors 
= true; 
 755                 type 
= String16(block
.getAttributeStringValue(typeIdx
, &len
)); 
 758                 ssize_t nameIdx 
= block
.indexOfAttribute(NULL
, "name"); 
 760                     srcPos
.error("A 'name' attribute is required for <public>\n"); 
 761                     hasErrors 
= localHasErrors 
= true; 
 763                 name 
= String16(block
.getAttributeStringValue(nameIdx
, &len
)); 
 766                 ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "id"); 
 768                     const char16_t* identStr 
= block
.getAttributeStringValue(identIdx
, &len
); 
 769                     Res_value identValue
; 
 770                     if (!ResTable::stringToInt(identStr
, len
, &identValue
)) { 
 771                         srcPos
.error("Given 'id' attribute is not an integer: %s\n", 
 772                                 String8(block
.getAttributeStringValue(identIdx
, &len
)).string()); 
 773                         hasErrors 
= localHasErrors 
= true; 
 775                         ident 
= identValue
.data
; 
 776                         nextPublicId 
= ident
+1; 
 778                 } else if (nextPublicId 
== 0) { 
 779                     srcPos
.error("No 'id' attribute supplied <public>," 
 780                             " and no previous id defined in this file.\n"); 
 781                     hasErrors 
= localHasErrors 
= true; 
 782                 } else if (!localHasErrors
) { 
 783                     ident 
= nextPublicId
; 
 787                 if (!localHasErrors
) { 
 788                     err 
= outTable
->addPublic(srcPos
, myPackage
, type
, name
, ident
); 
 789                     if (err 
< NO_ERROR
) { 
 790                         hasErrors 
= localHasErrors 
= true; 
 793                 if (!localHasErrors
) { 
 794                     sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
 795                     if (symbols 
!= NULL
) { 
 796                         symbols 
= symbols
->addNestedSymbol(String8(type
), srcPos
); 
 798                     if (symbols 
!= NULL
) { 
 799                         symbols
->makeSymbolPublic(String8(name
), srcPos
); 
 801                             block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 802                         symbols
->appendComment(String8(name
), comment
, srcPos
); 
 804                         srcPos
.error("Unable to create symbols!\n"); 
 805                         hasErrors 
= localHasErrors 
= true; 
 809                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 810                     if (code 
== ResXMLTree::END_TAG
) { 
 811                         if (strcmp16(block
.getElementName(&len
), public16
.string()) == 0) { 
 818             } else if (strcmp16(block
.getElementName(&len
), private_symbols16
.string()) == 0) { 
 820                 ssize_t pkgIdx 
= block
.indexOfAttribute(NULL
, "package"); 
 822                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 823                             "A 'package' attribute is required for <private-symbols>\n"); 
 824                     hasErrors 
= localHasErrors 
= true; 
 826                 pkg 
= String16(block
.getAttributeStringValue(pkgIdx
, &len
)); 
 827                 if (!localHasErrors
) { 
 828                     assets
->setSymbolsPrivatePackage(String8(pkg
)); 
 831                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 832                     if (code 
== ResXMLTree::END_TAG
) { 
 833                         if (strcmp16(block
.getElementName(&len
), private_symbols16
.string()) == 0) { 
 840             } else if (strcmp16(block
.getElementName(&len
), declare_styleable16
.string()) == 0) { 
 841                 SourcePos 
srcPos(in
->getPrintableSource(), block
.getLineNumber()); 
 844                 ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "name"); 
 846                     srcPos
.error("A 'name' attribute is required for <declare-styleable>\n"); 
 847                     hasErrors 
= localHasErrors 
= true; 
 849                 ident 
= String16(block
.getAttributeStringValue(identIdx
, &len
)); 
 851                 sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
 852                 if (!localHasErrors
) { 
 853                     if (symbols 
!= NULL
) { 
 854                         symbols 
= symbols
->addNestedSymbol(String8("styleable"), srcPos
); 
 856                     sp
<AaptSymbols
> styleSymbols 
= symbols
; 
 857                     if (symbols 
!= NULL
) { 
 858                         symbols 
= symbols
->addNestedSymbol(String8(ident
), srcPos
); 
 860                     if (symbols 
== NULL
) { 
 861                         srcPos
.error("Unable to create symbols!\n"); 
 862                         return UNKNOWN_ERROR
; 
 866                         block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 867                     styleSymbols
->appendComment(String8(ident
), comment
, srcPos
); 
 872                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 873                     if (code 
== ResXMLTree::START_TAG
) { 
 874                         if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 875                             while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 876                                    && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 877                                 if (code 
== ResXMLTree::END_TAG
) { 
 878                                     if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 884                         } else if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 885                             while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 886                                    && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 887                                 if (code 
== ResXMLTree::END_TAG
) { 
 888                                     if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 894                         } else if (strcmp16(block
.getElementName(&len
), attr16
.string()) != 0) { 
 895                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 896                                     "Tag <%s> can not appear inside <declare-styleable>, only <attr>\n", 
 897                                     String8(block
.getElementName(&len
)).string()); 
 898                             return UNKNOWN_ERROR
; 
 902                             block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 904                         err 
= compileAttribute(in
, block
, myPackage
, outTable
, &itemIdent
, true); 
 905                         if (err 
!= NO_ERROR
) { 
 906                             hasErrors 
= localHasErrors 
= true; 
 909                         if (symbols 
!= NULL
) { 
 910                             SourcePos 
srcPos(String8(in
->getPrintableSource()), block
.getLineNumber()); 
 911                             symbols
->addSymbol(String8(itemIdent
), 0, srcPos
); 
 912                             symbols
->appendComment(String8(itemIdent
), comment
, srcPos
); 
 913                             //printf("Attribute %s comment: %s\n", String8(itemIdent).string(), 
 914                             //     String8(comment).string()); 
 916                     } else if (code 
== ResXMLTree::END_TAG
) { 
 917                         if (strcmp16(block
.getElementName(&len
), declare_styleable16
.string()) == 0) { 
 921                         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 922                                 "Found tag </%s> where </attr> is expected\n", 
 923                                 String8(block
.getElementName(&len
)).string()); 
 924                         return UNKNOWN_ERROR
; 
 929             } else if (strcmp16(block
.getElementName(&len
), attr16
.string()) == 0) { 
 930                 err 
= compileAttribute(in
, block
, myPackage
, outTable
, NULL
); 
 931                 if (err 
!= NO_ERROR
) { 
 936             } else if (strcmp16(block
.getElementName(&len
), item16
.string()) == 0) { 
 938                 ssize_t attri 
= block
.indexOfAttribute(NULL
, "type"); 
 940                     curType 
= String16(block
.getAttributeStringValue(attri
, &len
)); 
 941                     ssize_t formatIdx 
= block
.indexOfAttribute(NULL
, "format"); 
 942                     if (formatIdx 
>= 0) { 
 943                         String16 formatStr 
= String16(block
.getAttributeStringValue( 
 945                         curFormat 
= parse_flags(formatStr
.string(), formatStr
.size(), 
 947                         if (curFormat 
== 0) { 
 948                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 949                                     "Tag <item> 'format' attribute value \"%s\" not valid\n", 
 950                                     String8(formatStr
).string()); 
 951                             hasErrors 
= localHasErrors 
= true; 
 955                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 956                             "A 'type' attribute is required for <item>\n"); 
 957                     hasErrors 
= localHasErrors 
= true; 
 960             } else if (strcmp16(block
.getElementName(&len
), string16
.string()) == 0) { 
 961                 // Note the existence and locale of every string we process 
 963                 curParams
.getLocale(rawLocale
); 
 964                 String8 
locale(rawLocale
); 
 966                 String16 translatable
; 
 968                 size_t n 
= block
.getAttributeCount(); 
 969                 for (size_t i 
= 0; i 
< n
; i
++) { 
 971                     const uint16_t* attr 
= block
.getAttributeName(i
, &length
); 
 972                     if (strcmp16(attr
, name16
.string()) == 0) { 
 973                         name
.setTo(block
.getAttributeStringValue(i
, &length
)); 
 974                     } else if (strcmp16(attr
, translatable16
.string()) == 0) { 
 975                         translatable
.setTo(block
.getAttributeStringValue(i
, &length
)); 
 979                 if (name
.size() > 0) { 
 980                     if (translatable 
== false16
) { 
 981                         // Untranslatable strings must only exist in the default [empty] locale 
 982                         if (locale
.size() > 0) { 
 983                             fprintf(stderr
, "aapt: warning: string '%s' in %s marked untranslatable but exists" 
 984                                     " in locale '%s'\n", String8(name
).string(), 
 985                                     bundle
->getResourceSourceDirs()[0], 
 987                             // hasErrors = localHasErrors = true; 
 989                             // Intentionally empty block: 
 991                             // Don't add untranslatable strings to the localization table; that 
 992                             // way if we later see localizations of them, they'll be flagged as 
 993                             // having no default translation. 
 996                         outTable
->addLocalization(name
, locale
); 
1002                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_STRING
; 
1004                 curIsPseudolocalizable 
= true; 
1005             } else if (strcmp16(block
.getElementName(&len
), drawable16
.string()) == 0) { 
1006                 curTag 
= &drawable16
; 
1007                 curType 
= drawable16
; 
1008                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_COLOR
; 
1009             } else if (strcmp16(block
.getElementName(&len
), color16
.string()) == 0) { 
1012                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_COLOR
; 
1013             } else if (strcmp16(block
.getElementName(&len
), bool16
.string()) == 0) { 
1016                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_BOOLEAN
; 
1017             } else if (strcmp16(block
.getElementName(&len
), integer16
.string()) == 0) { 
1018                 curTag 
= &integer16
; 
1019                 curType 
= integer16
; 
1020                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_INTEGER
; 
1021             } else if (strcmp16(block
.getElementName(&len
), dimen16
.string()) == 0) { 
1024                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_DIMENSION
; 
1025             } else if (strcmp16(block
.getElementName(&len
), bag16
.string()) == 0) { 
1028                 ssize_t attri 
= block
.indexOfAttribute(NULL
, "type"); 
1030                     curType 
= String16(block
.getAttributeStringValue(attri
, &len
)); 
1032                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1033                             "A 'type' attribute is required for <bag>\n"); 
1034                     hasErrors 
= localHasErrors 
= true; 
1036             } else if (strcmp16(block
.getElementName(&len
), style16
.string()) == 0) { 
1040             } else if (strcmp16(block
.getElementName(&len
), plurals16
.string()) == 0) { 
1041                 curTag 
= &plurals16
; 
1042                 curType 
= plurals16
; 
1044             } else if (strcmp16(block
.getElementName(&len
), array16
.string()) == 0) { 
1048                 ssize_t formatIdx 
= block
.indexOfAttribute(NULL
, "format"); 
1049                 if (formatIdx 
>= 0) { 
1050                     String16 formatStr 
= String16(block
.getAttributeStringValue( 
1052                     curFormat 
= parse_flags(formatStr
.string(), formatStr
.size(), 
1054                     if (curFormat 
== 0) { 
1055                         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1056                                 "Tag <array> 'format' attribute value \"%s\" not valid\n", 
1057                                 String8(formatStr
).string()); 
1058                         hasErrors 
= localHasErrors 
= true; 
1061             } else if (strcmp16(block
.getElementName(&len
), string_array16
.string()) == 0) { 
1062                 curTag 
= &string_array16
; 
1064                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_STRING
; 
1066                 curIsPseudolocalizable 
= true; 
1067             } else if (strcmp16(block
.getElementName(&len
), integer_array16
.string()) == 0) { 
1068                 curTag 
= &integer_array16
; 
1070                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_INTEGER
; 
1073                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1074                         "Found tag %s where item is expected\n", 
1075                         String8(block
.getElementName(&len
)).string()); 
1076                 return UNKNOWN_ERROR
; 
1080             ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "name"); 
1081             if (identIdx 
>= 0) { 
1082                 ident 
= String16(block
.getAttributeStringValue(identIdx
, &len
)); 
1084                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1085                         "A 'name' attribute is required for <%s>\n", 
1086                         String8(*curTag
).string()); 
1087                 hasErrors 
= localHasErrors 
= true; 
1090             String16 
comment(block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
1093                 // Figure out the parent of this bag... 
1094                 String16 parentIdent
; 
1095                 ssize_t parentIdentIdx 
= block
.indexOfAttribute(NULL
, "parent"); 
1096                 if (parentIdentIdx 
>= 0) { 
1097                     parentIdent 
= String16(block
.getAttributeStringValue(parentIdentIdx
, &len
)); 
1099                     ssize_t sep 
= ident
.findLast('.'); 
1101                         parentIdent
.setTo(ident
, sep
); 
1105                 if (!localHasErrors
) { 
1106                     err 
= outTable
->startBag(SourcePos(in
->getPrintableSource(), block
.getLineNumber()), 
1107                                              myPackage
, curType
, ident
, parentIdent
, &curParams
); 
1108                     if (err 
!= NO_ERROR
) { 
1109                         hasErrors 
= localHasErrors 
= true; 
1113                 ssize_t elmIndex 
= 0; 
1114                 char elmIndexStr
[14]; 
1115                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
1116                         && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
1118                     if (code 
== ResXMLTree::START_TAG
) { 
1119                         if (strcmp16(block
.getElementName(&len
), item16
.string()) != 0) { 
1120                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1121                                     "Tag <%s> can not appear inside <%s>, only <item>\n", 
1122                                     String8(block
.getElementName(&len
)).string(), 
1123                                     String8(*curTag
).string()); 
1124                             return UNKNOWN_ERROR
; 
1128                         if (curType 
== array16
) { 
1129                             sprintf(elmIndexStr
, "^index_%d", (int)elmIndex
++); 
1130                             itemIdent 
= String16(elmIndexStr
); 
1131                         } else if (curType 
== plurals16
) { 
1132                             ssize_t itemIdentIdx 
= block
.indexOfAttribute(NULL
, "quantity"); 
1133                             if (itemIdentIdx 
>= 0) { 
1134                                 String16 
quantity16(block
.getAttributeStringValue(itemIdentIdx
, &len
)); 
1135                                 if (quantity16 
== other16
) { 
1136                                     itemIdent 
= quantityOther16
; 
1138                                 else if (quantity16 
== zero16
) { 
1139                                     itemIdent 
= quantityZero16
; 
1141                                 else if (quantity16 
== one16
) { 
1142                                     itemIdent 
= quantityOne16
; 
1144                                 else if (quantity16 
== two16
) { 
1145                                     itemIdent 
= quantityTwo16
; 
1147                                 else if (quantity16 
== few16
) { 
1148                                     itemIdent 
= quantityFew16
; 
1150                                 else if (quantity16 
== many16
) { 
1151                                     itemIdent 
= quantityMany16
; 
1154                                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1155                                             "Illegal 'quantity' attribute is <item> inside <plurals>\n"); 
1156                                     hasErrors 
= localHasErrors 
= true; 
1159                                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1160                                         "A 'quantity' attribute is required for <item> inside <plurals>\n"); 
1161                                 hasErrors 
= localHasErrors 
= true; 
1164                             ssize_t itemIdentIdx 
= block
.indexOfAttribute(NULL
, "name"); 
1165                             if (itemIdentIdx 
>= 0) { 
1166                                 itemIdent 
= String16(block
.getAttributeStringValue(itemIdentIdx
, &len
)); 
1168                                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1169                                         "A 'name' attribute is required for <item>\n"); 
1170                                 hasErrors 
= localHasErrors 
= true; 
1174                         ResXMLParser::ResXMLPosition parserPosition
; 
1175                         block
.getPosition(&parserPosition
); 
1177                         err 
= parseAndAddBag(bundle
, in
, &block
, curParams
, myPackage
, curType
, 
1178                                 ident
, parentIdent
, itemIdent
, curFormat
,  
1179                                 false, overwrite
, outTable
); 
1180                         if (err 
== NO_ERROR
) { 
1181                             if (curIsPseudolocalizable 
&& localeIsDefined(curParams
) 
1182                                     && bundle
->getPseudolocalize()) { 
1183                                 // pseudolocalize here 
1185                                 block
.setPosition(parserPosition
); 
1186                                 err 
= parseAndAddBag(bundle
, in
, &block
, pseudoParams
, myPackage
, 
1187                                         curType
, ident
, parentIdent
, itemIdent
, curFormat
, true, 
1188                                         overwrite
, outTable
); 
1192                         if (err 
!= NO_ERROR
) { 
1193                             hasErrors 
= localHasErrors 
= true; 
1195                     } else if (code 
== ResXMLTree::END_TAG
) { 
1196                         if (strcmp16(block
.getElementName(&len
), curTag
->string()) != 0) { 
1197                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1198                                     "Found tag </%s> where </%s> is expected\n", 
1199                                     String8(block
.getElementName(&len
)).string(), 
1200                                     String8(*curTag
).string()); 
1201                             return UNKNOWN_ERROR
; 
1207                 ResXMLParser::ResXMLPosition parserPosition
; 
1208                 block
.getPosition(&parserPosition
); 
1210                 err 
= parseAndAddEntry(bundle
, in
, &block
, curParams
, myPackage
, curType
, ident
, 
1211                         *curTag
, curIsStyled
, curFormat
, false, overwrite
, outTable
); 
1213                 if (err 
< NO_ERROR
) { // Why err < NO_ERROR instead of err != NO_ERROR? 
1214                     hasErrors 
= localHasErrors 
= true; 
1216                 else if (err 
== NO_ERROR
) { 
1217                     if (curIsPseudolocalizable 
&& localeIsDefined(curParams
) 
1218                             && bundle
->getPseudolocalize()) { 
1219                         // pseudolocalize here 
1220                         block
.setPosition(parserPosition
); 
1221                         err 
= parseAndAddEntry(bundle
, in
, &block
, pseudoParams
, myPackage
, curType
, 
1222                                 ident
, *curTag
, curIsStyled
, curFormat
, true, false, outTable
); 
1223                         if (err 
!= NO_ERROR
) { 
1224                             hasErrors 
= localHasErrors 
= true; 
1231             if (comment
.size() > 0) { 
1232                 printf("Comment for @%s:%s/%s: %s\n", String8(myPackage
).string(), 
1233                        String8(curType
).string(), String8(ident
).string(), 
1234                        String8(comment
).string()); 
1237             if (!localHasErrors
) { 
1238                 outTable
->appendComment(myPackage
, curType
, ident
, comment
, false); 
1241         else if (code 
== ResXMLTree::END_TAG
) { 
1242             if (strcmp16(block
.getElementName(&len
), resources16
.string()) != 0) { 
1243                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1244                         "Unexpected end tag %s\n", String8(block
.getElementName(&len
)).string()); 
1245                 return UNKNOWN_ERROR
; 
1248         else if (code 
== ResXMLTree::START_NAMESPACE 
|| code 
== ResXMLTree::END_NAMESPACE
) { 
1250         else if (code 
== ResXMLTree::TEXT
) { 
1251             if (isWhitespace(block
.getText(&len
))) { 
1254             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1255                     "Found text \"%s\" where item tag is expected\n", 
1256                     String8(block
.getText(&len
)).string()); 
1257             return UNKNOWN_ERROR
; 
1261     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
1264 ResourceTable::ResourceTable(Bundle
* bundle
, const String16
& assetsPackage
) 
1265     : mAssetsPackage(assetsPackage
), mNextPackageId(1), mHaveAppPackage(false), 
1266       mIsAppPackage(!bundle
->getExtending()), 
1272 status_t 
ResourceTable::addIncludedResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
1274     status_t err 
= assets
->buildIncludedResources(bundle
); 
1275     if (err 
!= NO_ERROR
) { 
1279     // For future reference to included resources. 
1282     const ResTable
& incl 
= assets
->getIncludedResources(); 
1284     // Retrieve all the packages. 
1285     const size_t N 
= incl
.getBasePackageCount(); 
1286     for (size_t phase
=0; phase
<2; phase
++) { 
1287         for (size_t i
=0; i
<N
; i
++) { 
1288             String16 
name(incl
.getBasePackageName(i
)); 
1289             uint32_t id 
= incl
.getBasePackageId(i
); 
1290             // First time through: only add base packages (id 
1291             // is not 0); second time through add the other 
1295                     // Skip base packages -- already one. 
1298                     // Assign a dynamic id. 
1299                     id 
= mNextPackageId
; 
1301             } else if (id 
!= 0) { 
1303                     if (mHaveAppPackage
) { 
1304                         fprintf(stderr
, "Included resource have two application packages!\n"); 
1305                         return UNKNOWN_ERROR
; 
1307                     mHaveAppPackage 
= true; 
1309                 if (mNextPackageId 
> id
) { 
1310                     fprintf(stderr
, "Included base package ID %d already in use!\n", id
); 
1311                     return UNKNOWN_ERROR
; 
1315                 NOISY(printf("Including package %s with ID=%d\n", 
1316                              String8(name
).string(), id
)); 
1317                 sp
<Package
> p 
= new Package(name
, id
); 
1318                 mPackages
.add(name
, p
); 
1319                 mOrderedPackages
.add(p
); 
1321                 if (id 
>= mNextPackageId
) { 
1322                     mNextPackageId 
= id
+1; 
1328     // Every resource table always has one first entry, the bag attributes. 
1329     const SourcePos 
unknown(String8("????"), 0); 
1330     sp
<Type
> attr 
= getType(mAssetsPackage
, String16("attr"), unknown
); 
1335 status_t 
ResourceTable::addPublic(const SourcePos
& sourcePos
, 
1336                                   const String16
& package
, 
1337                                   const String16
& type
, 
1338                                   const String16
& name
, 
1339                                   const uint32_t ident
) 
1341     uint32_t rid 
= mAssets
->getIncludedResources() 
1342         .identifierForName(name
.string(), name
.size(), 
1343                            type
.string(), type
.size(), 
1344                            package
.string(), package
.size()); 
1346         sourcePos
.error("Error declaring public resource %s/%s for included package %s\n", 
1347                 String8(type
).string(), String8(name
).string(), 
1348                 String8(package
).string()); 
1349         return UNKNOWN_ERROR
; 
1352     sp
<Type
> t 
= getType(package
, type
, sourcePos
); 
1354         return UNKNOWN_ERROR
; 
1356     return t
->addPublic(sourcePos
, name
, ident
); 
1359 status_t 
ResourceTable::addEntry(const SourcePos
& sourcePos
, 
1360                                  const String16
& package
, 
1361                                  const String16
& type
, 
1362                                  const String16
& name
, 
1363                                  const String16
& value
, 
1364                                  const Vector
<StringPool::entry_style_span
>* style
, 
1365                                  const ResTable_config
* params
, 
1366                                  const bool doSetIndex
, 
1367                                  const int32_t format
, 
1368                                  const bool overwrite
) 
1370     // Check for adding entries in other packages...  for now we do 
1371     // nothing.  We need to do the right thing here to support skinning. 
1372     uint32_t rid 
= mAssets
->getIncludedResources() 
1373         .identifierForName(name
.string(), name
.size(), 
1374                            type
.string(), type
.size(), 
1375                            package
.string(), package
.size()); 
1381     if (name 
== String16("left")) { 
1382         printf("Adding entry left: file=%s, line=%d, type=%s, value=%s\n", 
1383                sourcePos
.file
.string(), sourcePos
.line
, String8(type
).string(), 
1384                String8(value
).string()); 
1388     sp
<Entry
> e 
= getEntry(package
, type
, name
, sourcePos
, params
, doSetIndex
); 
1390         return UNKNOWN_ERROR
; 
1392     status_t err 
= e
->setItem(sourcePos
, value
, style
, format
, overwrite
); 
1393     if (err 
== NO_ERROR
) { 
1399 status_t 
ResourceTable::startBag(const SourcePos
& sourcePos
, 
1400                                  const String16
& package
, 
1401                                  const String16
& type
, 
1402                                  const String16
& name
, 
1403                                  const String16
& bagParent
, 
1404                                  const ResTable_config
* params
, 
1405                                  bool replace
, bool isId
) 
1407     // Check for adding entries in other packages...  for now we do 
1408     // nothing.  We need to do the right thing here to support skinning. 
1409     uint32_t rid 
= mAssets
->getIncludedResources() 
1410     .identifierForName(name
.string(), name
.size(), 
1411                        type
.string(), type
.size(), 
1412                        package
.string(), package
.size()); 
1418     if (name 
== String16("left")) { 
1419         printf("Adding bag left: file=%s, line=%d, type=%s\n", 
1420                sourcePos
.file
.striing(), sourcePos
.line
, String8(type
).string()); 
1424     sp
<Entry
> e 
= getEntry(package
, type
, name
, sourcePos
, params
); 
1426         return UNKNOWN_ERROR
; 
1429     // If a parent is explicitly specified, set it. 
1430     if (bagParent
.size() > 0) { 
1431         String16 curPar 
= e
->getParent(); 
1432         if (curPar
.size() > 0 && curPar 
!= bagParent
) { 
1433             sourcePos
.error("Conflicting parents specified, was '%s', now '%s'\n", 
1434                             String8(e
->getParent()).string(), 
1435                             String8(bagParent
).string()); 
1436             return UNKNOWN_ERROR
; 
1438         e
->setParent(bagParent
); 
1441     return e
->makeItABag(sourcePos
); 
1444 status_t 
ResourceTable::addBag(const SourcePos
& sourcePos
, 
1445                                const String16
& package
, 
1446                                const String16
& type
, 
1447                                const String16
& name
, 
1448                                const String16
& bagParent
, 
1449                                const String16
& bagKey
, 
1450                                const String16
& value
, 
1451                                const Vector
<StringPool::entry_style_span
>* style
, 
1452                                const ResTable_config
* params
, 
1453                                bool replace
, bool isId
, const int32_t format
) 
1455     // Check for adding entries in other packages...  for now we do 
1456     // nothing.  We need to do the right thing here to support skinning. 
1457     uint32_t rid 
= mAssets
->getIncludedResources() 
1458         .identifierForName(name
.string(), name
.size(), 
1459                            type
.string(), type
.size(), 
1460                            package
.string(), package
.size()); 
1466     if (name 
== String16("left")) { 
1467         printf("Adding bag left: file=%s, line=%d, type=%s\n", 
1468                sourcePos
.file
.striing(), sourcePos
.line
, String8(type
).string()); 
1472     sp
<Entry
> e 
= getEntry(package
, type
, name
, sourcePos
, params
); 
1474         return UNKNOWN_ERROR
; 
1477     // If a parent is explicitly specified, set it. 
1478     if (bagParent
.size() > 0) { 
1479         String16 curPar 
= e
->getParent(); 
1480         if (curPar
.size() > 0 && curPar 
!= bagParent
) { 
1481             sourcePos
.error("Conflicting parents specified, was '%s', now '%s'\n", 
1482                     String8(e
->getParent()).string(), 
1483                     String8(bagParent
).string()); 
1484             return UNKNOWN_ERROR
; 
1486         e
->setParent(bagParent
); 
1489     const bool first 
= e
->getBag().indexOfKey(bagKey
) < 0; 
1490     status_t err 
= e
->addToBag(sourcePos
, bagKey
, value
, style
, replace
, isId
, format
); 
1491     if (err 
== NO_ERROR 
&& first
) { 
1497 bool ResourceTable::hasBagOrEntry(const String16
& package
, 
1498                                   const String16
& type
, 
1499                                   const String16
& name
) const 
1501     // First look for this in the included resources... 
1502     uint32_t rid 
= mAssets
->getIncludedResources() 
1503         .identifierForName(name
.string(), name
.size(), 
1504                            type
.string(), type
.size(), 
1505                            package
.string(), package
.size()); 
1510     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1512         sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1514             sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1515             if (c 
!= NULL
) return true; 
1522 bool ResourceTable::hasBagOrEntry(const String16
& ref
, 
1523                                   const String16
* defType
, 
1524                                   const String16
* defPackage
) 
1526     String16 package
, type
, name
; 
1527     if (!ResTable::expandResourceRef(ref
.string(), ref
.size(), &package
, &type
, &name
, 
1528                 defType
, defPackage 
? defPackage
:&mAssetsPackage
, NULL
)) { 
1531     return hasBagOrEntry(package
, type
, name
); 
1534 bool ResourceTable::appendComment(const String16
& package
, 
1535                                   const String16
& type
, 
1536                                   const String16
& name
, 
1537                                   const String16
& comment
, 
1540     if (comment
.size() <= 0) { 
1544     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1546         sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1548             sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1550                 c
->appendComment(comment
, onlyIfEmpty
); 
1558 bool ResourceTable::appendTypeComment(const String16
& package
, 
1559                                       const String16
& type
, 
1560                                       const String16
& name
, 
1561                                       const String16
& comment
) 
1563     if (comment
.size() <= 0) { 
1567     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1569         sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1571             sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1573                 c
->appendTypeComment(comment
); 
1581 size_t ResourceTable::size() const { 
1582     return mPackages
.size(); 
1585 size_t ResourceTable::numLocalResources() const { 
1589 bool ResourceTable::hasResources() const { 
1590     return mNumLocal 
> 0; 
1593 sp
<AaptFile
> ResourceTable::flatten(Bundle
* bundle
) 
1595     sp
<AaptFile
> data 
= new AaptFile(String8(), AaptGroupEntry(), String8()); 
1596     status_t err 
= flatten(bundle
, data
); 
1597     return err 
== NO_ERROR 
? data 
: NULL
; 
1600 inline uint32_t ResourceTable::getResId(const sp
<Package
>& p
, 
1604     return makeResId(p
->getAssignedId(), t
->getIndex(), nameId
); 
1607 uint32_t ResourceTable::getResId(const String16
& package
, 
1608                                  const String16
& type
, 
1609                                  const String16
& name
, 
1610                                  bool onlyPublic
) const 
1612     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1613     if (p 
== NULL
) return 0; 
1615     // First look for this in the included resources... 
1616     uint32_t specFlags 
= 0; 
1617     uint32_t rid 
= mAssets
->getIncludedResources() 
1618         .identifierForName(name
.string(), name
.size(), 
1619                            type
.string(), type
.size(), 
1620                            package
.string(), package
.size(), 
1624             if ((specFlags 
& ResTable_typeSpec::SPEC_PUBLIC
) == 0) { 
1629         if (Res_INTERNALID(rid
)) { 
1632         return Res_MAKEID(p
->getAssignedId()-1, 
1637     sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1638     if (t 
== NULL
) return 0; 
1639     sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1640     if (c 
== NULL
) return 0; 
1641     int32_t ei 
= c
->getEntryIndex(); 
1642     if (ei 
< 0) return 0; 
1643     return getResId(p
, t
, ei
); 
1646 uint32_t ResourceTable::getResId(const String16
& ref
, 
1647                                  const String16
* defType
, 
1648                                  const String16
* defPackage
, 
1649                                  const char** outErrorMsg
, 
1650                                  bool onlyPublic
) const 
1652     String16 package
, type
, name
; 
1653     if (!ResTable::expandResourceRef( 
1654         ref
.string(), ref
.size(), &package
, &type
, &name
, 
1655         defType
, defPackage 
? defPackage
:&mAssetsPackage
, 
1657         NOISY(printf("Expanding resource: ref=%s\n", 
1658                      String8(ref
).string())); 
1659         NOISY(printf("Expanding resource: defType=%s\n", 
1660                      defType 
? String8(*defType
).string() : "NULL")); 
1661         NOISY(printf("Expanding resource: defPackage=%s\n", 
1662                      defPackage 
? String8(*defPackage
).string() : "NULL")); 
1663         NOISY(printf("Expanding resource: ref=%s\n", String8(ref
).string())); 
1664         NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n", 
1665                      String8(package
).string(), String8(type
).string(), 
1666                      String8(name
).string())); 
1669     uint32_t res 
= getResId(package
, type
, name
, onlyPublic
); 
1670     NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n", 
1671                  String8(package
).string(), String8(type
).string(), 
1672                  String8(name
).string(), res
)); 
1675             *outErrorMsg 
= "No resource found that matches the given name"; 
1680 bool ResourceTable::isValidResourceName(const String16
& s
) 
1682     const char16_t* p 
= s
.string(); 
1685         if ((*p 
>= 'a' && *p 
<= 'z') 
1686             || (*p 
>= 'A' && *p 
<= 'Z') 
1688             || (!first 
&& *p 
>= '0' && *p 
<= '9')) { 
1698 bool ResourceTable::stringToValue(Res_value
* outValue
, StringPool
* pool
, 
1699                                   const String16
& str
, 
1700                                   bool preserveSpaces
, bool coerceType
, 
1702                                   const Vector
<StringPool::entry_style_span
>* style
, 
1703                                   String16
* outStr
, void* accessorCookie
, 
1709     if (style 
== NULL 
|| style
->size() == 0) { 
1710         // Text is not styled so it can be any type...  let's figure it out. 
1711         res 
= mAssets
->getIncludedResources() 
1712             .stringToValue(outValue
, &finalStr
, str
.string(), str
.size(), preserveSpaces
, 
1713                             coerceType
, attrID
, NULL
, &mAssetsPackage
, this, 
1714                            accessorCookie
, attrType
); 
1716         // Styled text can only be a string, and while collecting the style 
1717         // information we have already processed that string! 
1718         outValue
->size 
= sizeof(Res_value
); 
1720         outValue
->dataType 
= outValue
->TYPE_STRING
; 
1729     if (outValue
->dataType 
== outValue
->TYPE_STRING
) { 
1730         // Should do better merging styles. 
1732             if (style 
!= NULL 
&& style
->size() > 0) { 
1733                 outValue
->data 
= pool
->add(finalStr
, *style
); 
1735                 outValue
->data 
= pool
->add(finalStr
, true); 
1738             // Caller will fill this in later. 
1751 uint32_t ResourceTable::getCustomResource( 
1752     const String16
& package
, const String16
& type
, const String16
& name
) const 
1754     //printf("getCustomResource: %s %s %s\n", String8(package).string(), 
1755     //       String8(type).string(), String8(name).string()); 
1756     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1757     if (p 
== NULL
) return 0; 
1758     sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1759     if (t 
== NULL
) return 0; 
1760     sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1761     if (c 
== NULL
) return 0; 
1762     int32_t ei 
= c
->getEntryIndex(); 
1763     if (ei 
< 0) return 0; 
1764     return getResId(p
, t
, ei
); 
1767 uint32_t ResourceTable::getCustomResourceWithCreation( 
1768         const String16
& package
, const String16
& type
, const String16
& name
, 
1769         const bool createIfNotFound
) 
1771     uint32_t resId 
= getCustomResource(package
, type
, name
); 
1772     if (resId 
!= 0 || !createIfNotFound
) { 
1775     String16 
value("false"); 
1777     status_t status 
= addEntry(mCurrentXmlPos
, package
, type
, name
, value
, NULL
, NULL
, true); 
1778     if (status 
== NO_ERROR
) { 
1779         resId 
= getResId(package
, type
, name
); 
1785 uint32_t ResourceTable::getRemappedPackage(uint32_t origPackage
) const 
1790 bool ResourceTable::getAttributeType(uint32_t attrID
, uint32_t* outType
) 
1792     //printf("getAttributeType #%08x\n", attrID); 
1794     if (getItemValue(attrID
, ResTable_map::ATTR_TYPE
, &value
)) { 
1795         //printf("getAttributeType #%08x (%s): #%08x\n", attrID, 
1796         //       String8(getEntry(attrID)->getName()).string(), value.data); 
1797         *outType 
= value
.data
; 
1803 bool ResourceTable::getAttributeMin(uint32_t attrID
, uint32_t* outMin
) 
1805     //printf("getAttributeMin #%08x\n", attrID); 
1807     if (getItemValue(attrID
, ResTable_map::ATTR_MIN
, &value
)) { 
1808         *outMin 
= value
.data
; 
1814 bool ResourceTable::getAttributeMax(uint32_t attrID
, uint32_t* outMax
) 
1816     //printf("getAttributeMax #%08x\n", attrID); 
1818     if (getItemValue(attrID
, ResTable_map::ATTR_MAX
, &value
)) { 
1819         *outMax 
= value
.data
; 
1825 uint32_t ResourceTable::getAttributeL10N(uint32_t attrID
) 
1827     //printf("getAttributeL10N #%08x\n", attrID); 
1829     if (getItemValue(attrID
, ResTable_map::ATTR_L10N
, &value
)) { 
1832     return ResTable_map::L10N_NOT_REQUIRED
; 
1835 bool ResourceTable::getLocalizationSetting() 
1837     return mBundle
->getRequireLocalization(); 
1840 void ResourceTable::reportError(void* accessorCookie
, const char* fmt
, ...) 
1842     if (accessorCookie 
!= NULL 
&& fmt 
!= NULL
) { 
1843         AccessorCookie
* ac 
= (AccessorCookie
*)accessorCookie
; 
1848         retval 
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
); 
1850         ac
->sourcePos
.error("Error: %s (at '%s' with value '%s').\n", 
1851                             buf
, ac
->attr
.string(), ac
->value
.string()); 
1855 bool ResourceTable::getAttributeKeys( 
1856     uint32_t attrID
, Vector
<String16
>* outKeys
) 
1858     sp
<const Entry
> e 
= getEntry(attrID
); 
1860         const size_t N 
= e
->getBag().size(); 
1861         for (size_t i
=0; i
<N
; i
++) { 
1862             const String16
& key 
= e
->getBag().keyAt(i
); 
1863             if (key
.size() > 0 && key
.string()[0] != '^') { 
1872 bool ResourceTable::getAttributeEnum( 
1873     uint32_t attrID
, const char16_t* name
, size_t nameLen
, 
1874     Res_value
* outValue
) 
1876     //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).string()); 
1877     String16 
nameStr(name
, nameLen
); 
1878     sp
<const Entry
> e 
= getEntry(attrID
); 
1880         const size_t N 
= e
->getBag().size(); 
1881         for (size_t i
=0; i
<N
; i
++) { 
1882             //printf("Comparing %s to %s\n", String8(name, nameLen).string(), 
1883             //       String8(e->getBag().keyAt(i)).string()); 
1884             if (e
->getBag().keyAt(i
) == nameStr
) { 
1885                 return getItemValue(attrID
, e
->getBag().valueAt(i
).bagKeyId
, outValue
); 
1892 bool ResourceTable::getAttributeFlags( 
1893     uint32_t attrID
, const char16_t* name
, size_t nameLen
, 
1894     Res_value
* outValue
) 
1896     outValue
->dataType 
= Res_value::TYPE_INT_HEX
; 
1899     //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).string()); 
1900     String16 
nameStr(name
, nameLen
); 
1901     sp
<const Entry
> e 
= getEntry(attrID
); 
1903         const size_t N 
= e
->getBag().size(); 
1905         const char16_t* end 
= name 
+ nameLen
; 
1906         const char16_t* pos 
= name
; 
1907         bool failed 
= false; 
1908         while (pos 
< end 
&& !failed
) { 
1909             const char16_t* start 
= pos
; 
1911             while (pos 
< end 
&& *pos 
!= '|') { 
1915             String16 
nameStr(start
, pos
-start
); 
1917             for (i
=0; i
<N
; i
++) { 
1918                 //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).string(), 
1919                 //       String8(e->getBag().keyAt(i)).string()); 
1920                 if (e
->getBag().keyAt(i
) == nameStr
) { 
1922                     bool got 
= getItemValue(attrID
, e
->getBag().valueAt(i
).bagKeyId
, &val
); 
1926                     //printf("Got value: 0x%08x\n", val.data); 
1927                     outValue
->data 
|= val
.data
; 
1933                 // Didn't find this flag identifier. 
1946 status_t 
ResourceTable::assignResourceIds() 
1948     const size_t N 
= mOrderedPackages
.size(); 
1950     status_t firstError 
= NO_ERROR
; 
1952     // First generate all bag attributes and assign indices. 
1953     for (pi
=0; pi
<N
; pi
++) { 
1954         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
1955         if (p 
== NULL 
|| p
->getTypes().size() == 0) { 
1960         status_t err 
= p
->applyPublicTypeOrder(); 
1961         if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
1965         // Generate attributes... 
1966         const size_t N 
= p
->getOrderedTypes().size(); 
1968         for (ti
=0; ti
<N
; ti
++) { 
1969             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
1973             const size_t N 
= t
->getOrderedConfigs().size(); 
1974             for (size_t ci
=0; ci
<N
; ci
++) { 
1975                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
1979                 const size_t N 
= c
->getEntries().size(); 
1980                 for (size_t ei
=0; ei
<N
; ei
++) { 
1981                     sp
<Entry
> e 
= c
->getEntries().valueAt(ei
); 
1985                     status_t err 
= e
->generateAttributes(this, p
->getName()); 
1986                     if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
1993         const SourcePos 
unknown(String8("????"), 0); 
1994         sp
<Type
> attr 
= p
->getType(String16("attr"), unknown
); 
1996         // Assign indices... 
1997         for (ti
=0; ti
<N
; ti
++) { 
1998             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2002             err 
= t
->applyPublicEntryOrder(); 
2003             if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
2007             const size_t N 
= t
->getOrderedConfigs().size(); 
2010             LOG_ALWAYS_FATAL_IF(ti 
== 0 && attr 
!= t
, 
2011                                 "First type is not attr!"); 
2013             for (size_t ei
=0; ei
<N
; ei
++) { 
2014                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ei
); 
2018                 c
->setEntryIndex(ei
); 
2022         // Assign resource IDs to keys in bags... 
2023         for (ti
=0; ti
<N
; ti
++) { 
2024             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2028             const size_t N 
= t
->getOrderedConfigs().size(); 
2029             for (size_t ci
=0; ci
<N
; ci
++) { 
2030                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
2031                 //printf("Ordered config #%d: %p\n", ci, c.get()); 
2032                 const size_t N 
= c
->getEntries().size(); 
2033                 for (size_t ei
=0; ei
<N
; ei
++) { 
2034                     sp
<Entry
> e 
= c
->getEntries().valueAt(ei
); 
2038                     status_t err 
= e
->assignResourceIds(this, p
->getName()); 
2039                     if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
2049 status_t 
ResourceTable::addSymbols(const sp
<AaptSymbols
>& outSymbols
) { 
2050     const size_t N 
= mOrderedPackages
.size(); 
2053     for (pi
=0; pi
<N
; pi
++) { 
2054         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
2055         if (p
->getTypes().size() == 0) { 
2060         const size_t N 
= p
->getOrderedTypes().size(); 
2063         for (ti
=0; ti
<N
; ti
++) { 
2064             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2068             const size_t N 
= t
->getOrderedConfigs().size(); 
2069             sp
<AaptSymbols
> typeSymbols
; 
2070             typeSymbols 
= outSymbols
->addNestedSymbol(String8(t
->getName()), t
->getPos()); 
2071             for (size_t ci
=0; ci
<N
; ci
++) { 
2072                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
2076                 uint32_t rid 
= getResId(p
, t
, ci
); 
2078                     return UNKNOWN_ERROR
; 
2080                 if (Res_GETPACKAGE(rid
) == (size_t)(p
->getAssignedId()-1)) { 
2081                     typeSymbols
->addSymbol(String8(c
->getName()), rid
, c
->getPos()); 
2083                     String16 
comment(c
->getComment()); 
2084                     typeSymbols
->appendComment(String8(c
->getName()), comment
, c
->getPos()); 
2085                     //printf("Type symbol %s comment: %s\n", String8(e->getName()).string(), 
2086                     //     String8(comment).string()); 
2087                     comment 
= c
->getTypeComment(); 
2088                     typeSymbols
->appendTypeComment(String8(c
->getName()), comment
); 
2091                     printf("**** NO MATCH: 0x%08x vs 0x%08x\n", 
2092                            Res_GETPACKAGE(rid
), p
->getAssignedId()); 
2103 ResourceTable::addLocalization(const String16
& name
, const String8
& locale
) 
2105     mLocalizations
[name
].insert(locale
); 
2110  * Flag various sorts of localization problems.  '+' indicates checks already implemented; 
2111  * '-' indicates checks that will be implemented in the future. 
2113  * + A localized string for which no default-locale version exists => warning 
2114  * + A string for which no version in an explicitly-requested locale exists => warning 
2115  * + A localized translation of an translateable="false" string => warning 
2116  * - A localized string not provided in every locale used by the table 
2119 ResourceTable::validateLocalizations(void) 
2121     status_t err 
= NO_ERROR
; 
2122     const String8 defaultLocale
; 
2124     // For all strings... 
2125     for (map
<String16
, set
<String8
> >::iterator nameIter 
= mLocalizations
.begin(); 
2126          nameIter 
!= mLocalizations
.end(); 
2128         const set
<String8
>& configSet 
= nameIter
->second
;   // naming convenience 
2130         // Look for strings with no default localization 
2131         if (configSet
.count(defaultLocale
) == 0) { 
2132             fprintf(stdout
, "aapt: warning: string '%s' has no default translation in %s; found:", 
2133                     String8(nameIter
->first
).string(), mBundle
->getResourceSourceDirs()[0]); 
2134             for (set
<String8
>::iterator locales 
= configSet
.begin(); 
2135                  locales 
!= configSet
.end(); 
2137                 fprintf(stdout
, " %s", (*locales
).string()); 
2139             fprintf(stdout
, "\n"); 
2140             // !!! TODO: throw an error here in some circumstances 
2143         // Check that all requested localizations are present for this string 
2144         if (mBundle
->getConfigurations() != NULL 
&& mBundle
->getRequireLocalization()) { 
2145             const char* allConfigs 
= mBundle
->getConfigurations(); 
2146             const char* start 
= allConfigs
; 
2151                 comma 
= strchr(start
, ','); 
2152                 if (comma 
!= NULL
) { 
2153                     config
.setTo(start
, comma 
- start
); 
2156                     config
.setTo(start
); 
2159                 // don't bother with the pseudolocale "zz_ZZ" 
2160                 if (config 
!= "zz_ZZ") { 
2161                     if (configSet
.find(config
) == configSet
.end()) { 
2162                         // okay, no specific localization found.  it's possible that we are 
2163                         // requiring a specific regional localization [e.g. de_DE] but there is an 
2164                         // available string in the generic language localization [e.g. de]; 
2165                         // consider that string to have fulfilled the localization requirement. 
2166                         String8 
region(config
.string(), 2); 
2167                         if (configSet
.find(region
) == configSet
.end()) { 
2168                             // TODO: force an error if there is no default to fall back to 
2169                             if (configSet
.count(defaultLocale
) == 0) { 
2170                                 fprintf(stdout
, "aapt: warning: " 
2171                                         "*** string '%s' has no default or required localization " 
2173                                         String8(nameIter
->first
).string(), 
2175                                         mBundle
->getResourceSourceDirs()[0]); 
2176                                 //err = UNKNOWN_ERROR; 
2181            } while (comma 
!= NULL
); 
2190 ResourceFilter::parse(const char* arg
) 
2196     const char* p 
= arg
; 
2205         String8 
part(p
, q
-p
); 
2207         if (part 
== "zz_ZZ") { 
2208             mContainsPseudo 
= true; 
2212         if (AaptGroupEntry::parseNamePart(part
, &axis
, &value
)) { 
2213             fprintf(stderr
, "Invalid configuration: %s\n", arg
); 
2214             fprintf(stderr
, "                       "); 
2215             for (int i
=0; i
<p
-arg
; i
++) { 
2216                 fprintf(stderr
, " "); 
2218             for (int i
=0; i
<q
-p
; i
++) { 
2219                 fprintf(stderr
, "^"); 
2221             fprintf(stderr
, "\n"); 
2225         ssize_t index 
= mData
.indexOfKey(axis
); 
2227             mData
.add(axis
, SortedVector
<uint32_t>()); 
2229         SortedVector
<uint32_t>& sv 
= mData
.editValueFor(axis
); 
2231         // if it's a locale with a region, also match an unmodified locale of the 
2233         if (axis 
== AXIS_LANGUAGE
) { 
2234             if (value 
& 0xffff0000) { 
2235                 sv
.add(value 
& 0x0000ffff); 
2247 ResourceFilter::match(int axis
, uint32_t value
) 
2250         // they didn't specify anything so take everything 
2253     ssize_t index 
= mData
.indexOfKey(axis
); 
2255         // we didn't request anything on this axis so take everything 
2258     const SortedVector
<uint32_t>& sv 
= mData
.valueAt(index
); 
2259     return sv
.indexOf(value
) >= 0; 
2263 ResourceFilter::match(const ResTable_config
& config
) 
2265     if (config
.locale
) { 
2266         uint32_t locale 
= (config
.country
[1] << 24) | (config
.country
[0] << 16) 
2267                 | (config
.language
[1] << 8) | (config
.language
[0]); 
2268         if (!match(AXIS_LANGUAGE
, locale
)) { 
2272     if (!match(AXIS_ORIENTATION
, config
.orientation
)) { 
2275     if (!match(AXIS_DENSITY
, config
.density
)) { 
2278     if (!match(AXIS_TOUCHSCREEN
, config
.touchscreen
)) { 
2281     if (!match(AXIS_KEYSHIDDEN
, config
.inputFlags
)) { 
2284     if (!match(AXIS_KEYBOARD
, config
.keyboard
)) { 
2287     if (!match(AXIS_NAVIGATION
, config
.navigation
)) { 
2290     if (!match(AXIS_SCREENSIZE
, config
.screenSize
)) { 
2293     if (!match(AXIS_VERSION
, config
.version
)) { 
2299 status_t 
ResourceTable::flatten(Bundle
* bundle
, const sp
<AaptFile
>& dest
) 
2301     ResourceFilter filter
; 
2302     status_t err 
= filter
.parse(bundle
->getConfigurations()); 
2303     if (err 
!= NO_ERROR
) { 
2307     const size_t N 
= mOrderedPackages
.size(); 
2310     // Iterate through all data, collecting all values (strings, 
2311     // references, etc). 
2312     StringPool valueStrings
; 
2313     for (pi
=0; pi
<N
; pi
++) { 
2314         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
2315         if (p
->getTypes().size() == 0) { 
2320         StringPool typeStrings
; 
2321         StringPool keyStrings
; 
2323         const size_t N 
= p
->getOrderedTypes().size(); 
2324         for (size_t ti
=0; ti
<N
; ti
++) { 
2325             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2327                 typeStrings
.add(String16("<empty>"), false); 
2330             typeStrings
.add(t
->getName(), false); 
2332             const size_t N 
= t
->getOrderedConfigs().size(); 
2333             for (size_t ci
=0; ci
<N
; ci
++) { 
2334                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
2338                 const size_t N 
= c
->getEntries().size(); 
2339                 for (size_t ei
=0; ei
<N
; ei
++) { 
2340                     ConfigDescription config 
= c
->getEntries().keyAt(ei
); 
2341                     if (!filter
.match(config
)) { 
2344                     sp
<Entry
> e 
= c
->getEntries().valueAt(ei
); 
2348                     e
->setNameIndex(keyStrings
.add(e
->getName(), true)); 
2349                     status_t err 
= e
->prepareFlatten(&valueStrings
, this); 
2350                     if (err 
!= NO_ERROR
) { 
2357         p
->setTypeStrings(typeStrings
.createStringBlock()); 
2358         p
->setKeyStrings(keyStrings
.createStringBlock()); 
2363     // Now build the array of package chunks. 
2364     Vector
<sp
<AaptFile
> > flatPackages
; 
2365     for (pi
=0; pi
<N
; pi
++) { 
2366         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
2367         if (p
->getTypes().size() == 0) { 
2372         const size_t N 
= p
->getTypeStrings().size(); 
2374         const size_t baseSize 
= sizeof(ResTable_package
); 
2376         // Start the package data. 
2377         sp
<AaptFile
> data 
= new AaptFile(String8(), AaptGroupEntry(), String8()); 
2378         ResTable_package
* header 
= (ResTable_package
*)data
->editData(baseSize
); 
2379         if (header 
== NULL
) { 
2380             fprintf(stderr
, "ERROR: out of memory creating ResTable_package\n"); 
2383         memset(header
, 0, sizeof(*header
)); 
2384         header
->header
.type 
= htods(RES_TABLE_PACKAGE_TYPE
); 
2385         header
->header
.headerSize 
= htods(sizeof(*header
)); 
2386         header
->id 
= htodl(p
->getAssignedId()); 
2387         strcpy16_htod(header
->name
, p
->getName().string()); 
2389         // Write the string blocks. 
2390         const size_t typeStringsStart 
= data
->getSize(); 
2391         sp
<AaptFile
> strFile 
= p
->getTypeStringsData(); 
2392         ssize_t amt 
= data
->writeData(strFile
->getData(), strFile
->getSize()); 
2393         #if PRINT_STRING_METRICS 
2394         fprintf(stderr
, "**** type strings: %d\n", amt
); 
2400         const size_t keyStringsStart 
= data
->getSize(); 
2401         strFile 
= p
->getKeyStringsData(); 
2402         amt 
= data
->writeData(strFile
->getData(), strFile
->getSize()); 
2403         #if PRINT_STRING_METRICS 
2404         fprintf(stderr
, "**** key strings: %d\n", amt
); 
2411         // Build the type chunks inside of this package. 
2412         for (size_t ti
=0; ti
<N
; ti
++) { 
2413             // Retrieve them in the same order as the type string block. 
2415             String16 
typeName(p
->getTypeStrings().stringAt(ti
, &len
)); 
2416             sp
<Type
> t 
= p
->getTypes().valueFor(typeName
); 
2417             LOG_ALWAYS_FATAL_IF(t 
== NULL 
&& typeName 
!= String16("<empty>"), 
2418                                 "Type name %s not found", 
2419                                 String8(typeName
).string()); 
2421             const size_t N 
= t 
!= NULL 
? t
->getOrderedConfigs().size() : 0; 
2423             // First write the typeSpec chunk, containing information about 
2424             // each resource entry in this type. 
2426                 const size_t typeSpecSize 
= sizeof(ResTable_typeSpec
) + sizeof(uint32_t)*N
; 
2427                 const size_t typeSpecStart 
= data
->getSize(); 
2428                 ResTable_typeSpec
* tsHeader 
= (ResTable_typeSpec
*) 
2429                     (((uint8_t*)data
->editData(typeSpecStart
+typeSpecSize
)) + typeSpecStart
); 
2430                 if (tsHeader 
== NULL
) { 
2431                     fprintf(stderr
, "ERROR: out of memory creating ResTable_typeSpec\n"); 
2434                 memset(tsHeader
, 0, sizeof(*tsHeader
)); 
2435                 tsHeader
->header
.type 
= htods(RES_TABLE_TYPE_SPEC_TYPE
); 
2436                 tsHeader
->header
.headerSize 
= htods(sizeof(*tsHeader
)); 
2437                 tsHeader
->header
.size 
= htodl(typeSpecSize
); 
2438                 tsHeader
->id 
= ti
+1; 
2439                 tsHeader
->entryCount 
= htodl(N
); 
2441                 uint32_t* typeSpecFlags 
= (uint32_t*) 
2442                     (((uint8_t*)data
->editData()) 
2443                         + typeSpecStart 
+ sizeof(ResTable_typeSpec
)); 
2444                 memset(typeSpecFlags
, 0, sizeof(uint32_t)*N
); 
2446                 for (size_t ei
=0; ei
<N
; ei
++) { 
2447                     sp
<ConfigList
> cl 
= t
->getOrderedConfigs().itemAt(ei
); 
2448                     if (cl
->getPublic()) { 
2449                         typeSpecFlags
[ei
] |= htodl(ResTable_typeSpec::SPEC_PUBLIC
); 
2451                     const size_t CN 
= cl
->getEntries().size(); 
2452                     for (size_t ci
=0; ci
<CN
; ci
++) { 
2453                         if (!filter
.match(cl
->getEntries().keyAt(ci
))) { 
2456                         for (size_t cj
=ci
+1; cj
<CN
; cj
++) { 
2457                             if (!filter
.match(cl
->getEntries().keyAt(cj
))) { 
2460                             typeSpecFlags
[ei
] |= htodl( 
2461                                 cl
->getEntries().keyAt(ci
).diff(cl
->getEntries().keyAt(cj
))); 
2467             // We need to write one type chunk for each configuration for 
2468             // which we have entries in this type. 
2469             const size_t NC 
= t
->getUniqueConfigs().size(); 
2471             const size_t typeSize 
= sizeof(ResTable_type
) + sizeof(uint32_t)*N
; 
2473             for (size_t ci
=0; ci
<NC
; ci
++) { 
2474                 ConfigDescription config 
= t
->getUniqueConfigs().itemAt(ci
); 
2476                 NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c " 
2477                      "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", 
2479                       config
.mcc
, config
.mnc
, 
2480                       config
.language
[0] ? config
.language
[0] : '-', 
2481                       config
.language
[1] ? config
.language
[1] : '-', 
2482                       config
.country
[0] ? config
.country
[0] : '-', 
2483                       config
.country
[1] ? config
.country
[1] : '-', 
2491                       config
.screenHeight
)); 
2493                 if (!filter
.match(config
)) { 
2497                 const size_t typeStart 
= data
->getSize(); 
2499                 ResTable_type
* tHeader 
= (ResTable_type
*) 
2500                     (((uint8_t*)data
->editData(typeStart
+typeSize
)) + typeStart
); 
2501                 if (tHeader 
== NULL
) { 
2502                     fprintf(stderr
, "ERROR: out of memory creating ResTable_type\n"); 
2506                 memset(tHeader
, 0, sizeof(*tHeader
)); 
2507                 tHeader
->header
.type 
= htods(RES_TABLE_TYPE_TYPE
); 
2508                 tHeader
->header
.headerSize 
= htods(sizeof(*tHeader
)); 
2510                 tHeader
->entryCount 
= htodl(N
); 
2511                 tHeader
->entriesStart 
= htodl(typeSize
); 
2512                 tHeader
->config 
= config
; 
2513                 NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c " 
2514                      "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", 
2516                       tHeader
->config
.mcc
, tHeader
->config
.mnc
, 
2517                       tHeader
->config
.language
[0] ? tHeader
->config
.language
[0] : '-', 
2518                       tHeader
->config
.language
[1] ? tHeader
->config
.language
[1] : '-', 
2519                       tHeader
->config
.country
[0] ? tHeader
->config
.country
[0] : '-', 
2520                       tHeader
->config
.country
[1] ? tHeader
->config
.country
[1] : '-', 
2521                       tHeader
->config
.orientation
, 
2522                       tHeader
->config
.touchscreen
, 
2523                       tHeader
->config
.density
, 
2524                       tHeader
->config
.keyboard
, 
2525                       tHeader
->config
.inputFlags
, 
2526                       tHeader
->config
.navigation
, 
2527                       tHeader
->config
.screenWidth
, 
2528                       tHeader
->config
.screenHeight
)); 
2529                 tHeader
->config
.swapHtoD(); 
2531                 // Build the entries inside of this type. 
2532                 for (size_t ei
=0; ei
<N
; ei
++) { 
2533                     sp
<ConfigList
> cl 
= t
->getOrderedConfigs().itemAt(ei
); 
2534                     sp
<Entry
> e 
= cl
->getEntries().valueFor(config
); 
2536                     // Set the offset for this entry in its type. 
2537                     uint32_t* index 
= (uint32_t*) 
2538                         (((uint8_t*)data
->editData()) 
2539                             + typeStart 
+ sizeof(ResTable_type
)); 
2541                         index
[ei
] = htodl(data
->getSize()-typeStart
-typeSize
); 
2543                         // Create the entry. 
2544                         ssize_t amt 
= e
->flatten(bundle
, data
, cl
->getPublic()); 
2549                         index
[ei
] = htodl(ResTable_type::NO_ENTRY
); 
2553                 // Fill in the rest of the type information. 
2554                 tHeader 
= (ResTable_type
*) 
2555                     (((uint8_t*)data
->editData()) + typeStart
); 
2556                 tHeader
->header
.size 
= htodl(data
->getSize()-typeStart
); 
2560         // Fill in the rest of the package information. 
2561         header 
= (ResTable_package
*)data
->editData(); 
2562         header
->header
.size 
= htodl(data
->getSize()); 
2563         header
->typeStrings 
= htodl(typeStringsStart
); 
2564         header
->lastPublicType 
= htodl(p
->getTypeStrings().size()); 
2565         header
->keyStrings 
= htodl(keyStringsStart
); 
2566         header
->lastPublicKey 
= htodl(p
->getKeyStrings().size()); 
2568         flatPackages
.add(data
); 
2571     // And now write out the final chunks. 
2572     const size_t dataStart 
= dest
->getSize(); 
2576         ResTable_header header
; 
2577         memset(&header
, 0, sizeof(header
)); 
2578         header
.header
.type 
= htods(RES_TABLE_TYPE
); 
2579         header
.header
.headerSize 
= htods(sizeof(header
)); 
2580         header
.packageCount 
= htodl(flatPackages
.size()); 
2581         status_t err 
= dest
->writeData(&header
, sizeof(header
)); 
2582         if (err 
!= NO_ERROR
) { 
2583             fprintf(stderr
, "ERROR: out of memory creating ResTable_header\n"); 
2588     ssize_t strStart 
= dest
->getSize(); 
2589     err 
= valueStrings
.writeStringBlock(dest
); 
2590     if (err 
!= NO_ERROR
) { 
2594     ssize_t amt 
= (dest
->getSize()-strStart
); 
2596     #if PRINT_STRING_METRICS 
2597     fprintf(stderr
, "**** value strings: %d\n", amt
); 
2598     fprintf(stderr
, "**** total strings: %d\n", strAmt
); 
2601     for (pi
=0; pi
<flatPackages
.size(); pi
++) { 
2602         err 
= dest
->writeData(flatPackages
[pi
]->getData(), 
2603                               flatPackages
[pi
]->getSize()); 
2604         if (err 
!= NO_ERROR
) { 
2605             fprintf(stderr
, "ERROR: out of memory creating package chunk for ResTable_header\n"); 
2610     ResTable_header
* header 
= (ResTable_header
*) 
2611         (((uint8_t*)dest
->getData()) + dataStart
); 
2612     header
->header
.size 
= htodl(dest
->getSize() - dataStart
); 
2614     NOISY(aout 
<< "Resource table:" 
2615           << HexDump(dest
->getData(), dest
->getSize()) << endl
); 
2617     #if PRINT_STRING_METRICS 
2618     fprintf(stderr
, "**** total resource table size: %d / %d%% strings\n", 
2619         dest
->getSize(), (strAmt
*100)/dest
->getSize()); 
2625 void ResourceTable::writePublicDefinitions(const String16
& package
, FILE* fp
) 
2628     "<!-- This file contains <public> resource definitions for all\n" 
2629     "     resources that were generated from the source data. -->\n" 
2633     writePublicDefinitions(package
, fp
, true); 
2634     writePublicDefinitions(package
, fp
, false); 
2641 void ResourceTable::writePublicDefinitions(const String16
& package
, FILE* fp
, bool pub
) 
2643     bool didHeader 
= false; 
2645     sp
<Package
> pkg 
= mPackages
.valueFor(package
); 
2647         const size_t NT 
= pkg
->getOrderedTypes().size(); 
2648         for (size_t i
=0; i
<NT
; i
++) { 
2649             sp
<Type
> t 
= pkg
->getOrderedTypes().itemAt(i
); 
2654             bool didType 
= false; 
2656             const size_t NC 
= t
->getOrderedConfigs().size(); 
2657             for (size_t j
=0; j
<NC
; j
++) { 
2658                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(j
); 
2663                 if (c
->getPublic() != pub
) { 
2673                         fprintf(fp
,"  <!-- PUBLIC SECTION.  These resources have been declared public.\n"); 
2674                         fprintf(fp
,"       Changes to these definitions will break binary compatibility. -->\n\n"); 
2676                         fprintf(fp
,"  <!-- PRIVATE SECTION.  These resources have not been declared public.\n"); 
2677                         fprintf(fp
,"       You can make them public my moving these lines into a file in res/values. -->\n\n"); 
2682                     const size_t NE 
= c
->getEntries().size(); 
2683                     for (size_t k
=0; k
<NE
; k
++) { 
2684                         const SourcePos
& pos 
= c
->getEntries().valueAt(k
)->getPos(); 
2685                         if (pos
.file 
!= "") { 
2686                             fprintf(fp
,"  <!-- Declared at %s:%d -->\n", 
2687                                     pos
.file
.string(), pos
.line
); 
2691                 fprintf(fp
, "  <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n", 
2692                         String8(t
->getName()).string(), 
2693                         String8(c
->getName()).string(), 
2694                         getResId(pkg
, t
, c
->getEntryIndex())); 
2700 ResourceTable::Item::Item(const SourcePos
& _sourcePos
, 
2702                           const String16
& _value
, 
2703                           const Vector
<StringPool::entry_style_span
>* _style
, 
2705     : sourcePos(_sourcePos
) 
2717 status_t 
ResourceTable::Entry::makeItABag(const SourcePos
& sourcePos
) 
2719     if (mType 
== TYPE_BAG
) { 
2722     if (mType 
== TYPE_UNKNOWN
) { 
2726     sourcePos
.error("Resource entry %s is already defined as a single item.\n" 
2727                     "%s:%d: Originally defined here.\n", 
2728                     String8(mName
).string(), 
2729                     mItem
.sourcePos
.file
.string(), mItem
.sourcePos
.line
); 
2730     return UNKNOWN_ERROR
; 
2733 status_t 
ResourceTable::Entry::setItem(const SourcePos
& sourcePos
, 
2734                                        const String16
& value
, 
2735                                        const Vector
<StringPool::entry_style_span
>* style
, 
2737                                        const bool overwrite
) 
2739     Item 
item(sourcePos
, false, value
, style
); 
2741     if (mType 
== TYPE_BAG
) { 
2742         const Item
& item(mBag
.valueAt(0)); 
2743         sourcePos
.error("Resource entry %s is already defined as a bag.\n" 
2744                         "%s:%d: Originally defined here.\n", 
2745                         String8(mName
).string(), 
2746                         item
.sourcePos
.file
.string(), item
.sourcePos
.line
); 
2747         return UNKNOWN_ERROR
; 
2749     if ( (mType 
!= TYPE_UNKNOWN
) && (overwrite 
== false) ) { 
2750         sourcePos
.error("Resource entry %s is already defined.\n" 
2751                         "%s:%d: Originally defined here.\n", 
2752                         String8(mName
).string(), 
2753                         mItem
.sourcePos
.file
.string(), mItem
.sourcePos
.line
); 
2754         return UNKNOWN_ERROR
; 
2759     mItemFormat 
= format
; 
2763 status_t 
ResourceTable::Entry::addToBag(const SourcePos
& sourcePos
, 
2764                                         const String16
& key
, const String16
& value
, 
2765                                         const Vector
<StringPool::entry_style_span
>* style
, 
2766                                         bool replace
, bool isId
, int32_t format
) 
2768     status_t err 
= makeItABag(sourcePos
); 
2769     if (err 
!= NO_ERROR
) { 
2773     Item 
item(sourcePos
, isId
, value
, style
, format
); 
2775     // XXX NOTE: there is an error if you try to have a bag with two keys, 
2776     // one an attr and one an id, with the same name.  Not something we 
2777     // currently ever have to worry about. 
2778     ssize_t origKey 
= mBag
.indexOfKey(key
); 
2781             const Item
& item(mBag
.valueAt(origKey
)); 
2782             sourcePos
.error("Resource entry %s already has bag item %s.\n" 
2783                     "%s:%d: Originally defined here.\n", 
2784                     String8(mName
).string(), String8(key
).string(), 
2785                     item
.sourcePos
.file
.string(), item
.sourcePos
.line
); 
2786             return UNKNOWN_ERROR
; 
2788         //printf("Replacing %s with %s\n", 
2789         //       String8(mBag.valueFor(key).value).string(), String8(value).string()); 
2790         mBag
.replaceValueFor(key
, item
); 
2793     mBag
.add(key
, item
); 
2797 status_t 
ResourceTable::Entry::generateAttributes(ResourceTable
* table
, 
2798                                                   const String16
& package
) 
2800     const String16 
attr16("attr"); 
2801     const String16 
id16("id"); 
2802     const size_t N 
= mBag
.size(); 
2803     for (size_t i
=0; i
<N
; i
++) { 
2804         const String16
& key 
= mBag
.keyAt(i
); 
2805         const Item
& it 
= mBag
.valueAt(i
); 
2807             if (!table
->hasBagOrEntry(key
, &id16
, &package
)) { 
2808                 String16 
value("false"); 
2809                 status_t err 
= table
->addEntry(SourcePos(String8("<generated>"), 0), package
, 
2811                 if (err 
!= NO_ERROR
) { 
2815         } else if (!table
->hasBagOrEntry(key
, &attr16
, &package
)) { 
2818 //             fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n", 
2819 //                     String8(key).string()); 
2820 //             const Item& item(mBag.valueAt(i)); 
2821 //             fprintf(stderr, "Referenced from file %s line %d\n", 
2822 //                     item.sourcePos.file.string(), item.sourcePos.line); 
2823 //             return UNKNOWN_ERROR; 
2826             sprintf(numberStr
, "%d", ResTable_map::TYPE_ANY
); 
2827             status_t err 
= table
->addBag(SourcePos("<generated>", 0), package
, 
2828                                          attr16
, key
, String16(""), 
2830                                          String16(numberStr
), NULL
, NULL
); 
2831             if (err 
!= NO_ERROR
) { 
2840 status_t 
ResourceTable::Entry::assignResourceIds(ResourceTable
* table
, 
2841                                                  const String16
& package
) 
2843     bool hasErrors 
= false; 
2845     if (mType 
== TYPE_BAG
) { 
2846         const char* errorMsg
; 
2847         const String16 
style16("style"); 
2848         const String16 
attr16("attr"); 
2849         const String16 
id16("id"); 
2851         if (mParent
.size() > 0) { 
2852             mParentId 
= table
->getResId(mParent
, &style16
, NULL
, &errorMsg
); 
2853             if (mParentId 
== 0) { 
2854                 mPos
.error("Error retrieving parent for item: %s '%s'.\n", 
2855                         errorMsg
, String8(mParent
).string()); 
2859         const size_t N 
= mBag
.size(); 
2860         for (size_t i
=0; i
<N
; i
++) { 
2861             const String16
& key 
= mBag
.keyAt(i
); 
2862             Item
& it 
= mBag
.editValueAt(i
); 
2863             it
.bagKeyId 
= table
->getResId(key
, 
2864                     it
.isId 
? &id16 
: &attr16
, NULL
, &errorMsg
); 
2865             //printf("Bag key of %s: #%08x\n", String8(key).string(), it.bagKeyId); 
2866             if (it
.bagKeyId 
== 0) { 
2867                 it
.sourcePos
.error("Error: %s: %s '%s'.\n", errorMsg
, 
2868                         String8(it
.isId 
? id16 
: attr16
).string(), 
2869                         String8(key
).string()); 
2874     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
2877 status_t 
ResourceTable::Entry::prepareFlatten(StringPool
* strings
, ResourceTable
* table
) 
2879     if (mType 
== TYPE_ITEM
) { 
2881         AccessorCookie 
ac(it
.sourcePos
, String8(mName
), String8(it
.value
)); 
2882         if (!table
->stringToValue(&it
.parsedValue
, strings
, 
2883                                   it
.value
, false, true, 0, 
2884                                   &it
.style
, NULL
, &ac
, mItemFormat
)) { 
2885             return UNKNOWN_ERROR
; 
2887     } else if (mType 
== TYPE_BAG
) { 
2888         const size_t N 
= mBag
.size(); 
2889         for (size_t i
=0; i
<N
; i
++) { 
2890             const String16
& key 
= mBag
.keyAt(i
); 
2891             Item
& it 
= mBag
.editValueAt(i
); 
2892             AccessorCookie 
ac(it
.sourcePos
, String8(key
), String8(it
.value
)); 
2893             if (!table
->stringToValue(&it
.parsedValue
, strings
, 
2894                                       it
.value
, false, true, it
.bagKeyId
, 
2895                                       &it
.style
, NULL
, &ac
, it
.format
)) { 
2896                 return UNKNOWN_ERROR
; 
2900         mPos
.error("Error: entry %s is not a single item or a bag.\n", 
2901                    String8(mName
).string()); 
2902         return UNKNOWN_ERROR
; 
2907 ssize_t 
ResourceTable::Entry::flatten(Bundle
* bundle
, const sp
<AaptFile
>& data
, bool isPublic
) 
2910     ResTable_entry header
; 
2911     memset(&header
, 0, sizeof(header
)); 
2912     header
.size 
= htods(sizeof(header
)); 
2913     const type ty 
= this != NULL 
? mType 
: TYPE_ITEM
; 
2915         if (ty 
== TYPE_BAG
) { 
2916             header
.flags 
|= htods(header
.FLAG_COMPLEX
); 
2919             header
.flags 
|= htods(header
.FLAG_PUBLIC
); 
2921         header
.key
.index 
= htodl(mNameIndex
); 
2923     if (ty 
!= TYPE_BAG
) { 
2924         status_t err 
= data
->writeData(&header
, sizeof(header
)); 
2925         if (err 
!= NO_ERROR
) { 
2926             fprintf(stderr
, "ERROR: out of memory creating ResTable_entry\n"); 
2930         const Item
& it 
= mItem
; 
2932         memset(&par
, 0, sizeof(par
)); 
2933         par
.size 
= htods(it
.parsedValue
.size
); 
2934         par
.dataType 
= it
.parsedValue
.dataType
; 
2935         par
.res0 
= it
.parsedValue
.res0
; 
2936         par
.data 
= htodl(it
.parsedValue
.data
); 
2938         printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n", 
2939                String8(mName
).string(), it
.parsedValue
.dataType
, 
2940                it
.parsedValue
.data
, par
.res0
); 
2942         err 
= data
->writeData(&par
, it
.parsedValue
.size
); 
2943         if (err 
!= NO_ERROR
) { 
2944             fprintf(stderr
, "ERROR: out of memory creating Res_value\n"); 
2947         amt 
+= it
.parsedValue
.size
; 
2949         size_t N 
= mBag
.size(); 
2951         // Create correct ordering of items. 
2952         KeyedVector
<uint32_t, const Item
*> items
; 
2953         for (i
=0; i
<N
; i
++) { 
2954             const Item
& it 
= mBag
.valueAt(i
); 
2955             items
.add(it
.bagKeyId
, &it
); 
2959         ResTable_map_entry mapHeader
; 
2960         memcpy(&mapHeader
, &header
, sizeof(header
)); 
2961         mapHeader
.size 
= htods(sizeof(mapHeader
)); 
2962         mapHeader
.parent
.ident 
= htodl(mParentId
); 
2963         mapHeader
.count 
= htodl(N
); 
2964         status_t err 
= data
->writeData(&mapHeader
, sizeof(mapHeader
)); 
2965         if (err 
!= NO_ERROR
) { 
2966             fprintf(stderr
, "ERROR: out of memory creating ResTable_entry\n"); 
2970         for (i
=0; i
<N
; i
++) { 
2971             const Item
& it 
= *items
.valueAt(i
); 
2973             map
.name
.ident 
= htodl(it
.bagKeyId
); 
2974             map
.value
.size 
= htods(it
.parsedValue
.size
); 
2975             map
.value
.dataType 
= it
.parsedValue
.dataType
; 
2976             map
.value
.res0 
= it
.parsedValue
.res0
; 
2977             map
.value
.data 
= htodl(it
.parsedValue
.data
); 
2978             err 
= data
->writeData(&map
, sizeof(map
)); 
2979             if (err 
!= NO_ERROR
) { 
2980                 fprintf(stderr
, "ERROR: out of memory creating Res_value\n"); 
2989 void ResourceTable::ConfigList::appendComment(const String16
& comment
, 
2992     if (comment
.size() <= 0) { 
2995     if (onlyIfEmpty 
&& mComment
.size() > 0) { 
2998     if (mComment
.size() > 0) { 
2999         mComment
.append(String16("\n")); 
3001     mComment
.append(comment
); 
3004 void ResourceTable::ConfigList::appendTypeComment(const String16
& comment
) 
3006     if (comment
.size() <= 0) { 
3009     if (mTypeComment
.size() > 0) { 
3010         mTypeComment
.append(String16("\n")); 
3012     mTypeComment
.append(comment
); 
3015 status_t 
ResourceTable::Type::addPublic(const SourcePos
& sourcePos
, 
3016                                         const String16
& name
, 
3017                                         const uint32_t ident
) 
3020     int32_t entryIdx 
= Res_GETENTRY(ident
); 
3022         sourcePos
.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n", 
3023                 String8(mName
).string(), String8(name
).string(), ident
); 
3024         return UNKNOWN_ERROR
; 
3028     int32_t typeIdx 
= Res_GETTYPE(ident
); 
3031         if (mPublicIndex 
> 0 && mPublicIndex 
!= typeIdx
) { 
3032             sourcePos
.error("Public resource %s/%s has conflicting type codes for its" 
3033                     " public identifiers (0x%x vs 0x%x).\n", 
3034                     String8(mName
).string(), String8(name
).string(), 
3035                     mPublicIndex
, typeIdx
); 
3036             return UNKNOWN_ERROR
; 
3038         mPublicIndex 
= typeIdx
; 
3041     if (mFirstPublicSourcePos 
== NULL
) { 
3042         mFirstPublicSourcePos 
= new SourcePos(sourcePos
); 
3045     if (mPublic
.indexOfKey(name
) < 0) { 
3046         mPublic
.add(name
, Public(sourcePos
, String16(), ident
)); 
3048         Public
& p 
= mPublic
.editValueFor(name
); 
3049         if (p
.ident 
!= ident
) { 
3050             sourcePos
.error("Public resource %s/%s has conflicting public identifiers" 
3051                     " (0x%08x vs 0x%08x).\n" 
3052                     "%s:%d: Originally defined here.\n", 
3053                     String8(mName
).string(), String8(name
).string(), p
.ident
, ident
, 
3054                     p
.sourcePos
.file
.string(), p
.sourcePos
.line
); 
3055             return UNKNOWN_ERROR
; 
3062 sp
<ResourceTable::Entry
> ResourceTable::Type::getEntry(const String16
& entry
, 
3063                                                        const SourcePos
& sourcePos
, 
3064                                                        const ResTable_config
* config
, 
3068     sp
<ConfigList
> c 
= mConfigs
.valueFor(entry
); 
3070         c 
= new ConfigList(entry
, sourcePos
); 
3071         mConfigs
.add(entry
, c
); 
3072         pos 
= (int)mOrderedConfigs
.size(); 
3073         mOrderedConfigs
.add(c
); 
3075             c
->setEntryIndex(pos
); 
3079     ConfigDescription cdesc
; 
3080     if (config
) cdesc 
= *config
; 
3082     sp
<Entry
> e 
= c
->getEntries().valueFor(cdesc
); 
3084         if (config 
!= NULL
) { 
3085             NOISY(printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c " 
3086                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", 
3087                       sourcePos
.file
.string(), sourcePos
.line
, 
3088                       config
->mcc
, config
->mnc
, 
3089                       config
->language
[0] ? config
->language
[0] : '-', 
3090                       config
->language
[1] ? config
->language
[1] : '-', 
3091                       config
->country
[0] ? config
->country
[0] : '-', 
3092                       config
->country
[1] ? config
->country
[1] : '-', 
3093                       config
->orientation
, 
3094                       config
->touchscreen
, 
3099                       config
->screenWidth
, 
3100                       config
->screenHeight
)); 
3102             NOISY(printf("New entry at %s:%d: NULL config\n", 
3103                       sourcePos
.file
.string(), sourcePos
.line
)); 
3105         e 
= new Entry(entry
, sourcePos
); 
3106         c
->addEntry(cdesc
, e
); 
3110                 for (pos=0; pos<(int)mOrderedConfigs.size(); pos++) { 
3111                     if (mOrderedConfigs[pos] == c) { 
3115                 if (pos >= (int)mOrderedConfigs.size()) { 
3116                     sourcePos.error("Internal error: config not found in mOrderedConfigs when adding entry"); 
3120             e->setEntryIndex(pos); 
3125     mUniqueConfigs
.add(cdesc
); 
3130 status_t 
ResourceTable::Type::applyPublicEntryOrder() 
3132     size_t N 
= mOrderedConfigs
.size(); 
3133     Vector
<sp
<ConfigList
> > origOrder(mOrderedConfigs
); 
3134     bool hasError 
= false; 
3137     for (i
=0; i
<N
; i
++) { 
3138         mOrderedConfigs
.replaceAt(NULL
, i
); 
3141     const size_t NP 
= mPublic
.size(); 
3142     //printf("Ordering %d configs from %d public defs\n", N, NP); 
3144     for (j
=0; j
<NP
; j
++) { 
3145         const String16
& name 
= mPublic
.keyAt(j
); 
3146         const Public
& p 
= mPublic
.valueAt(j
); 
3147         int32_t idx 
= Res_GETENTRY(p
.ident
); 
3148         //printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n", 
3149         //       String8(mName).string(), String8(name).string(), p.ident, N); 
3151         for (i
=0; i
<N
; i
++) { 
3152             sp
<ConfigList
> e 
= origOrder
.itemAt(i
); 
3153             //printf("#%d: \"%s\"\n", i, String8(e->getName()).string()); 
3154             if (e
->getName() == name
) { 
3155                 if (idx 
>= (int32_t)mOrderedConfigs
.size()) { 
3156                     p
.sourcePos
.error("Public entry identifier 0x%x entry index " 
3157                             "is larger than available symbols (index %d, total symbols %d).\n", 
3158                             p
.ident
, idx
, mOrderedConfigs
.size()); 
3160                 } else if (mOrderedConfigs
.itemAt(idx
) == NULL
) { 
3162                     e
->setPublicSourcePos(p
.sourcePos
); 
3163                     mOrderedConfigs
.replaceAt(e
, idx
); 
3164                     origOrder
.removeAt(i
); 
3169                     sp
<ConfigList
> oe 
= mOrderedConfigs
.itemAt(idx
); 
3171                     p
.sourcePos
.error("Multiple entry names declared for public entry" 
3172                             " identifier 0x%x in type %s (%s vs %s).\n" 
3173                             "%s:%d: Originally defined here.", 
3174                             idx
+1, String8(mName
).string(), 
3175                             String8(oe
->getName()).string(), 
3176                             String8(name
).string(), 
3177                             oe
->getPublicSourcePos().file
.string(), 
3178                             oe
->getPublicSourcePos().line
); 
3185             p
.sourcePos
.error("Public symbol %s/%s declared here is not defined.", 
3186                     String8(mName
).string(), String8(name
).string()); 
3191     //printf("Copying back in %d non-public configs, have %d\n", N, origOrder.size()); 
3193     if (N 
!= origOrder
.size()) { 
3194         printf("Internal error: remaining private symbol count mismatch\n"); 
3195         N 
= origOrder
.size(); 
3199     for (i
=0; i
<N
; i
++) { 
3200         sp
<ConfigList
> e 
= origOrder
.itemAt(i
); 
3201         // There will always be enough room for the remaining entries. 
3202         while (mOrderedConfigs
.itemAt(j
) != NULL
) { 
3205         mOrderedConfigs
.replaceAt(e
, j
); 
3209     return hasError 
? UNKNOWN_ERROR 
: NO_ERROR
; 
3212 ResourceTable::Package::Package(const String16
& name
, ssize_t includedId
) 
3213     : mName(name
), mIncludedId(includedId
), 
3214       mTypeStringsMapping(0xffffffff), 
3215       mKeyStringsMapping(0xffffffff) 
3219 sp
<ResourceTable::Type
> ResourceTable::Package::getType(const String16
& type
, 
3220                                                         const SourcePos
& sourcePos
, 
3223     sp
<Type
> t 
= mTypes
.valueFor(type
); 
3225         t 
= new Type(type
, sourcePos
); 
3226         mTypes
.add(type
, t
); 
3227         mOrderedTypes
.add(t
); 
3229             // For some reason the type's index is set to one plus the index 
3230             // in the mOrderedTypes list, rather than just the index. 
3231             t
->setIndex(mOrderedTypes
.size()); 
3237 status_t 
ResourceTable::Package::setTypeStrings(const sp
<AaptFile
>& data
) 
3239     mTypeStringsData 
= data
; 
3240     status_t err 
= setStrings(data
, &mTypeStrings
, &mTypeStringsMapping
); 
3241     if (err 
!= NO_ERROR
) { 
3242         fprintf(stderr
, "ERROR: Type string data is corrupt!\n"); 
3247 status_t 
ResourceTable::Package::setKeyStrings(const sp
<AaptFile
>& data
) 
3249     mKeyStringsData 
= data
; 
3250     status_t err 
= setStrings(data
, &mKeyStrings
, &mKeyStringsMapping
); 
3251     if (err 
!= NO_ERROR
) { 
3252         fprintf(stderr
, "ERROR: Key string data is corrupt!\n"); 
3257 status_t 
ResourceTable::Package::setStrings(const sp
<AaptFile
>& data
, 
3258                                             ResStringPool
* strings
, 
3259                                             DefaultKeyedVector
<String16
, uint32_t>* mappings
) 
3261     if (data
->getData() == NULL
) { 
3262         return UNKNOWN_ERROR
; 
3265     NOISY(aout 
<< "Setting restable string pool: " 
3266           << HexDump(data
->getData(), data
->getSize()) << endl
); 
3268     status_t err 
= strings
->setTo(data
->getData(), data
->getSize()); 
3269     if (err 
== NO_ERROR
) { 
3270         const size_t N 
= strings
->size(); 
3271         for (size_t i
=0; i
<N
; i
++) { 
3273             mappings
->add(String16(strings
->stringAt(i
, &len
)), i
); 
3279 status_t 
ResourceTable::Package::applyPublicTypeOrder() 
3281     size_t N 
= mOrderedTypes
.size(); 
3282     Vector
<sp
<Type
> > origOrder(mOrderedTypes
); 
3285     for (i
=0; i
<N
; i
++) { 
3286         mOrderedTypes
.replaceAt(NULL
, i
); 
3289     for (i
=0; i
<N
; i
++) { 
3290         sp
<Type
> t 
= origOrder
.itemAt(i
); 
3291         int32_t idx 
= t
->getPublicIndex(); 
3294             while (idx 
>= (int32_t)mOrderedTypes
.size()) { 
3295                 mOrderedTypes
.add(); 
3297             if (mOrderedTypes
.itemAt(idx
) != NULL
) { 
3298                 sp
<Type
> ot 
= mOrderedTypes
.itemAt(idx
); 
3299                 t
->getFirstPublicSourcePos().error("Multiple type names declared for public type" 
3300                         " identifier 0x%x (%s vs %s).\n" 
3301                         "%s:%d: Originally defined here.", 
3302                         idx
, String8(ot
->getName()).string(), 
3303                         String8(t
->getName()).string(), 
3304                         ot
->getFirstPublicSourcePos().file
.string(), 
3305                         ot
->getFirstPublicSourcePos().line
); 
3306                 return UNKNOWN_ERROR
; 
3308             mOrderedTypes
.replaceAt(t
, idx
); 
3309             origOrder
.removeAt(i
); 
3316     for (i
=0; i
<N
; i
++) { 
3317         sp
<Type
> t 
= origOrder
.itemAt(i
); 
3318         // There will always be enough room for the remaining types. 
3319         while (mOrderedTypes
.itemAt(j
) != NULL
) { 
3322         mOrderedTypes
.replaceAt(t
, j
); 
3328 sp
<ResourceTable::Package
> ResourceTable::getPackage(const String16
& package
) 
3330     sp
<Package
> p 
= mPackages
.valueFor(package
); 
3332         if (mIsAppPackage
) { 
3333             if (mHaveAppPackage
) { 
3334                 fprintf(stderr
, "Adding multiple application package resources; only one is allowed.\n" 
3335                                 "Use -x to create extended resources.\n"); 
3338             mHaveAppPackage 
= true; 
3339             p 
= new Package(package
, 127); 
3341             p 
= new Package(package
, mNextPackageId
); 
3343         //printf("*** NEW PACKAGE: \"%s\" id=%d\n", 
3344         //       String8(package).string(), p->getAssignedId()); 
3345         mPackages
.add(package
, p
); 
3346         mOrderedPackages
.add(p
); 
3352 sp
<ResourceTable::Type
> ResourceTable::getType(const String16
& package
, 
3353                                                const String16
& type
, 
3354                                                const SourcePos
& sourcePos
, 
3357     sp
<Package
> p 
= getPackage(package
); 
3361     return p
->getType(type
, sourcePos
, doSetIndex
); 
3364 sp
<ResourceTable::Entry
> ResourceTable::getEntry(const String16
& package
, 
3365                                                  const String16
& type
, 
3366                                                  const String16
& name
, 
3367                                                  const SourcePos
& sourcePos
, 
3368                                                  const ResTable_config
* config
, 
3371     sp
<Type
> t 
= getType(package
, type
, sourcePos
, doSetIndex
); 
3375     return t
->getEntry(name
, sourcePos
, config
, doSetIndex
); 
3378 sp
<const ResourceTable::Entry
> ResourceTable::getEntry(uint32_t resID
, 
3379                                                        const ResTable_config
* config
) const 
3381     int pid 
= Res_GETPACKAGE(resID
)+1; 
3382     const size_t N 
= mOrderedPackages
.size(); 
3385     for (i
=0; i
<N
; i
++) { 
3386         sp
<Package
> check 
= mOrderedPackages
[i
]; 
3387         if (check
->getAssignedId() == pid
) { 
3394         fprintf(stderr
, "WARNING: Package not found for resource #%08x\n", resID
); 
3398     int tid 
= Res_GETTYPE(resID
); 
3399     if (tid 
< 0 || tid 
>= (int)p
->getOrderedTypes().size()) { 
3400         fprintf(stderr
, "WARNING: Type not found for resource #%08x\n", resID
); 
3403     sp
<Type
> t 
= p
->getOrderedTypes()[tid
]; 
3405     int eid 
= Res_GETENTRY(resID
); 
3406     if (eid 
< 0 || eid 
>= (int)t
->getOrderedConfigs().size()) { 
3407         fprintf(stderr
, "WARNING: Entry not found for resource #%08x\n", resID
); 
3411     sp
<ConfigList
> c 
= t
->getOrderedConfigs()[eid
]; 
3413         fprintf(stderr
, "WARNING: Entry not found for resource #%08x\n", resID
); 
3417     ConfigDescription cdesc
; 
3418     if (config
) cdesc 
= *config
; 
3419     sp
<Entry
> e 
= c
->getEntries().valueFor(cdesc
); 
3421         fprintf(stderr
, "WARNING: Entry configuration not found for resource #%08x\n", resID
); 
3428 const ResourceTable::Item
* ResourceTable::getItem(uint32_t resID
, uint32_t attrID
) const 
3430     sp
<const Entry
> e 
= getEntry(resID
); 
3435     const size_t N 
= e
->getBag().size(); 
3436     for (size_t i
=0; i
<N
; i
++) { 
3437         const Item
& it 
= e
->getBag().valueAt(i
); 
3438         if (it
.bagKeyId 
== 0) { 
3439             fprintf(stderr
, "WARNING: ID not yet assigned to '%s' in bag '%s'\n", 
3440                     String8(e
->getName()).string(), 
3441                     String8(e
->getBag().keyAt(i
)).string()); 
3443         if (it
.bagKeyId 
== attrID
) { 
3451 bool ResourceTable::getItemValue( 
3452     uint32_t resID
, uint32_t attrID
, Res_value
* outValue
) 
3454     const Item
* item 
= getItem(resID
, attrID
); 
3458         if (item
->evaluating
) { 
3459             sp
<const Entry
> e 
= getEntry(resID
); 
3460             const size_t N 
= e
->getBag().size(); 
3462             for (i
=0; i
<N
; i
++) { 
3463                 if (&e
->getBag().valueAt(i
) == item
) { 
3467             fprintf(stderr
, "WARNING: Circular reference detected in key '%s' of bag '%s'\n", 
3468                     String8(e
->getName()).string(), 
3469                     String8(e
->getBag().keyAt(i
)).string()); 
3472         item
->evaluating 
= true; 
3473         res 
= stringToValue(outValue
, NULL
, item
->value
, false, false, item
->bagKeyId
); 
3476                 printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n", 
3477                        resID
, attrID
, String8(getEntry(resID
)->getName()).string(), 
3478                        outValue
->dataType
, outValue
->data
); 
3480                 printf("getItemValue of #%08x[#%08x]: failed\n", 
3484         item
->evaluating 
= false;