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 
fraction16("fraction"); 
 648     const String16 
style16("style"); 
 649     const String16 
plurals16("plurals"); 
 650     const String16 
array16("array"); 
 651     const String16 
string_array16("string-array"); 
 652     const String16 
integer_array16("integer-array"); 
 653     const String16 
public16("public"); 
 654     const String16 
private_symbols16("private-symbols"); 
 655     const String16 
skip16("skip"); 
 656     const String16 
eat_comment16("eat-comment"); 
 658     // Data creation tags. 
 659     const String16 
bag16("bag"); 
 660     const String16 
item16("item"); 
 662     // Attribute type constants. 
 663     const String16 
enum16("enum"); 
 666     const String16 
other16("other"); 
 667     const String16 
quantityOther16("^other"); 
 668     const String16 
zero16("zero"); 
 669     const String16 
quantityZero16("^zero"); 
 670     const String16 
one16("one"); 
 671     const String16 
quantityOne16("^one"); 
 672     const String16 
two16("two"); 
 673     const String16 
quantityTwo16("^two"); 
 674     const String16 
few16("few"); 
 675     const String16 
quantityFew16("^few"); 
 676     const String16 
many16("many"); 
 677     const String16 
quantityMany16("^many"); 
 679     // useful attribute names and special values 
 680     const String16 
name16("name"); 
 681     const String16 
translatable16("translatable"); 
 682     const String16 
false16("false"); 
 684     const String16 
myPackage(assets
->getPackage()); 
 686     bool hasErrors 
= false; 
 688     uint32_t nextPublicId 
= 0; 
 690     ResXMLTree::event_code_t code
; 
 693     } while (code 
== ResXMLTree::START_NAMESPACE
); 
 696     if (code 
!= ResXMLTree::START_TAG
) { 
 697         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 698                 "No start tag found\n"); 
 699         return UNKNOWN_ERROR
; 
 701     if (strcmp16(block
.getElementName(&len
), resources16
.string()) != 0) { 
 702         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 703                 "Invalid start tag %s\n", String8(block
.getElementName(&len
)).string()); 
 704         return UNKNOWN_ERROR
; 
 707     ResTable_config 
curParams(defParams
); 
 709     ResTable_config 
pseudoParams(curParams
); 
 710         pseudoParams
.language
[0] = 'z'; 
 711         pseudoParams
.language
[1] = 'z'; 
 712         pseudoParams
.country
[0] = 'Z'; 
 713         pseudoParams
.country
[1] = 'Z'; 
 715     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 716         if (code 
== ResXMLTree::START_TAG
) { 
 717             const String16
* curTag 
= NULL
; 
 719             int32_t curFormat 
= ResTable_map::TYPE_ANY
; 
 720             bool curIsBag 
= false; 
 721             bool curIsStyled 
= false; 
 722             bool curIsPseudolocalizable 
= false; 
 723             bool localHasErrors 
= false; 
 725             if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 726                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 727                         && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 728                     if (code 
== ResXMLTree::END_TAG
) { 
 729                         if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 736             } else if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 737                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 738                         && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 739                     if (code 
== ResXMLTree::END_TAG
) { 
 740                         if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 747             } else if (strcmp16(block
.getElementName(&len
), public16
.string()) == 0) { 
 748                 SourcePos 
srcPos(in
->getPrintableSource(), block
.getLineNumber()); 
 751                 ssize_t typeIdx 
= block
.indexOfAttribute(NULL
, "type"); 
 753                     srcPos
.error("A 'type' attribute is required for <public>\n"); 
 754                     hasErrors 
= localHasErrors 
= true; 
 756                 type 
= String16(block
.getAttributeStringValue(typeIdx
, &len
)); 
 759                 ssize_t nameIdx 
= block
.indexOfAttribute(NULL
, "name"); 
 761                     srcPos
.error("A 'name' attribute is required for <public>\n"); 
 762                     hasErrors 
= localHasErrors 
= true; 
 764                 name 
= String16(block
.getAttributeStringValue(nameIdx
, &len
)); 
 767                 ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "id"); 
 769                     const char16_t* identStr 
= block
.getAttributeStringValue(identIdx
, &len
); 
 770                     Res_value identValue
; 
 771                     if (!ResTable::stringToInt(identStr
, len
, &identValue
)) { 
 772                         srcPos
.error("Given 'id' attribute is not an integer: %s\n", 
 773                                 String8(block
.getAttributeStringValue(identIdx
, &len
)).string()); 
 774                         hasErrors 
= localHasErrors 
= true; 
 776                         ident 
= identValue
.data
; 
 777                         nextPublicId 
= ident
+1; 
 779                 } else if (nextPublicId 
== 0) { 
 780                     srcPos
.error("No 'id' attribute supplied <public>," 
 781                             " and no previous id defined in this file.\n"); 
 782                     hasErrors 
= localHasErrors 
= true; 
 783                 } else if (!localHasErrors
) { 
 784                     ident 
= nextPublicId
; 
 788                 if (!localHasErrors
) { 
 789                     err 
= outTable
->addPublic(srcPos
, myPackage
, type
, name
, ident
); 
 790                     if (err 
< NO_ERROR
) { 
 791                         hasErrors 
= localHasErrors 
= true; 
 794                 if (!localHasErrors
) { 
 795                     sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
 796                     if (symbols 
!= NULL
) { 
 797                         symbols 
= symbols
->addNestedSymbol(String8(type
), srcPos
); 
 799                     if (symbols 
!= NULL
) { 
 800                         symbols
->makeSymbolPublic(String8(name
), srcPos
); 
 802                             block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 803                         symbols
->appendComment(String8(name
), comment
, srcPos
); 
 805                         srcPos
.error("Unable to create symbols!\n"); 
 806                         hasErrors 
= localHasErrors 
= true; 
 810                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 811                     if (code 
== ResXMLTree::END_TAG
) { 
 812                         if (strcmp16(block
.getElementName(&len
), public16
.string()) == 0) { 
 819             } else if (strcmp16(block
.getElementName(&len
), private_symbols16
.string()) == 0) { 
 821                 ssize_t pkgIdx 
= block
.indexOfAttribute(NULL
, "package"); 
 823                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 824                             "A 'package' attribute is required for <private-symbols>\n"); 
 825                     hasErrors 
= localHasErrors 
= true; 
 827                 pkg 
= String16(block
.getAttributeStringValue(pkgIdx
, &len
)); 
 828                 if (!localHasErrors
) { 
 829                     assets
->setSymbolsPrivatePackage(String8(pkg
)); 
 832                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 833                     if (code 
== ResXMLTree::END_TAG
) { 
 834                         if (strcmp16(block
.getElementName(&len
), private_symbols16
.string()) == 0) { 
 841             } else if (strcmp16(block
.getElementName(&len
), declare_styleable16
.string()) == 0) { 
 842                 SourcePos 
srcPos(in
->getPrintableSource(), block
.getLineNumber()); 
 845                 ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "name"); 
 847                     srcPos
.error("A 'name' attribute is required for <declare-styleable>\n"); 
 848                     hasErrors 
= localHasErrors 
= true; 
 850                 ident 
= String16(block
.getAttributeStringValue(identIdx
, &len
)); 
 852                 sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
 853                 if (!localHasErrors
) { 
 854                     if (symbols 
!= NULL
) { 
 855                         symbols 
= symbols
->addNestedSymbol(String8("styleable"), srcPos
); 
 857                     sp
<AaptSymbols
> styleSymbols 
= symbols
; 
 858                     if (symbols 
!= NULL
) { 
 859                         symbols 
= symbols
->addNestedSymbol(String8(ident
), srcPos
); 
 861                     if (symbols 
== NULL
) { 
 862                         srcPos
.error("Unable to create symbols!\n"); 
 863                         return UNKNOWN_ERROR
; 
 867                         block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 868                     styleSymbols
->appendComment(String8(ident
), comment
, srcPos
); 
 873                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 874                     if (code 
== ResXMLTree::START_TAG
) { 
 875                         if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 876                             while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 877                                    && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 878                                 if (code 
== ResXMLTree::END_TAG
) { 
 879                                     if (strcmp16(block
.getElementName(&len
), skip16
.string()) == 0) { 
 885                         } else if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 886                             while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 887                                    && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 888                                 if (code 
== ResXMLTree::END_TAG
) { 
 889                                     if (strcmp16(block
.getElementName(&len
), eat_comment16
.string()) == 0) { 
 895                         } else if (strcmp16(block
.getElementName(&len
), attr16
.string()) != 0) { 
 896                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 897                                     "Tag <%s> can not appear inside <declare-styleable>, only <attr>\n", 
 898                                     String8(block
.getElementName(&len
)).string()); 
 899                             return UNKNOWN_ERROR
; 
 903                             block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
 905                         err 
= compileAttribute(in
, block
, myPackage
, outTable
, &itemIdent
, true); 
 906                         if (err 
!= NO_ERROR
) { 
 907                             hasErrors 
= localHasErrors 
= true; 
 910                         if (symbols 
!= NULL
) { 
 911                             SourcePos 
srcPos(String8(in
->getPrintableSource()), block
.getLineNumber()); 
 912                             symbols
->addSymbol(String8(itemIdent
), 0, srcPos
); 
 913                             symbols
->appendComment(String8(itemIdent
), comment
, srcPos
); 
 914                             //printf("Attribute %s comment: %s\n", String8(itemIdent).string(), 
 915                             //     String8(comment).string()); 
 917                     } else if (code 
== ResXMLTree::END_TAG
) { 
 918                         if (strcmp16(block
.getElementName(&len
), declare_styleable16
.string()) == 0) { 
 922                         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 923                                 "Found tag </%s> where </attr> is expected\n", 
 924                                 String8(block
.getElementName(&len
)).string()); 
 925                         return UNKNOWN_ERROR
; 
 930             } else if (strcmp16(block
.getElementName(&len
), attr16
.string()) == 0) { 
 931                 err 
= compileAttribute(in
, block
, myPackage
, outTable
, NULL
); 
 932                 if (err 
!= NO_ERROR
) { 
 937             } else if (strcmp16(block
.getElementName(&len
), item16
.string()) == 0) { 
 939                 ssize_t attri 
= block
.indexOfAttribute(NULL
, "type"); 
 941                     curType 
= String16(block
.getAttributeStringValue(attri
, &len
)); 
 942                     ssize_t formatIdx 
= block
.indexOfAttribute(NULL
, "format"); 
 943                     if (formatIdx 
>= 0) { 
 944                         String16 formatStr 
= String16(block
.getAttributeStringValue( 
 946                         curFormat 
= parse_flags(formatStr
.string(), formatStr
.size(), 
 948                         if (curFormat 
== 0) { 
 949                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 950                                     "Tag <item> 'format' attribute value \"%s\" not valid\n", 
 951                                     String8(formatStr
).string()); 
 952                             hasErrors 
= localHasErrors 
= true; 
 956                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
 957                             "A 'type' attribute is required for <item>\n"); 
 958                     hasErrors 
= localHasErrors 
= true; 
 961             } else if (strcmp16(block
.getElementName(&len
), string16
.string()) == 0) { 
 962                 // Note the existence and locale of every string we process 
 964                 curParams
.getLocale(rawLocale
); 
 965                 String8 
locale(rawLocale
); 
 967                 String16 translatable
; 
 969                 size_t n 
= block
.getAttributeCount(); 
 970                 for (size_t i 
= 0; i 
< n
; i
++) { 
 972                     const uint16_t* attr 
= block
.getAttributeName(i
, &length
); 
 973                     if (strcmp16(attr
, name16
.string()) == 0) { 
 974                         name
.setTo(block
.getAttributeStringValue(i
, &length
)); 
 975                     } else if (strcmp16(attr
, translatable16
.string()) == 0) { 
 976                         translatable
.setTo(block
.getAttributeStringValue(i
, &length
)); 
 980                 if (name
.size() > 0) { 
 981                     if (translatable 
== false16
) { 
 982                         // Untranslatable strings must only exist in the default [empty] locale 
 983                         if (locale
.size() > 0) { 
 984                             fprintf(stderr
, "aapt: warning: string '%s' in %s marked untranslatable but exists" 
 985                                     " in locale '%s'\n", String8(name
).string(), 
 986                                     bundle
->getResourceSourceDirs()[0], 
 988                             // hasErrors = localHasErrors = true; 
 990                             // Intentionally empty block: 
 992                             // Don't add untranslatable strings to the localization table; that 
 993                             // way if we later see localizations of them, they'll be flagged as 
 994                             // having no default translation. 
 997                         outTable
->addLocalization(name
, locale
); 
1003                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_STRING
; 
1005                 curIsPseudolocalizable 
= true; 
1006             } else if (strcmp16(block
.getElementName(&len
), drawable16
.string()) == 0) { 
1007                 curTag 
= &drawable16
; 
1008                 curType 
= drawable16
; 
1009                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_COLOR
; 
1010             } else if (strcmp16(block
.getElementName(&len
), color16
.string()) == 0) { 
1013                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_COLOR
; 
1014             } else if (strcmp16(block
.getElementName(&len
), bool16
.string()) == 0) { 
1017                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_BOOLEAN
; 
1018             } else if (strcmp16(block
.getElementName(&len
), integer16
.string()) == 0) { 
1019                 curTag 
= &integer16
; 
1020                 curType 
= integer16
; 
1021                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_INTEGER
; 
1022             } else if (strcmp16(block
.getElementName(&len
), dimen16
.string()) == 0) { 
1025                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_DIMENSION
; 
1026             } else if (strcmp16(block
.getElementName(&len
), fraction16
.string()) == 0) { 
1027                 curTag 
= &fraction16
; 
1028                 curType 
= fraction16
; 
1029                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_FRACTION
; 
1030             } else if (strcmp16(block
.getElementName(&len
), bag16
.string()) == 0) { 
1033                 ssize_t attri 
= block
.indexOfAttribute(NULL
, "type"); 
1035                     curType 
= String16(block
.getAttributeStringValue(attri
, &len
)); 
1037                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1038                             "A 'type' attribute is required for <bag>\n"); 
1039                     hasErrors 
= localHasErrors 
= true; 
1041             } else if (strcmp16(block
.getElementName(&len
), style16
.string()) == 0) { 
1045             } else if (strcmp16(block
.getElementName(&len
), plurals16
.string()) == 0) { 
1046                 curTag 
= &plurals16
; 
1047                 curType 
= plurals16
; 
1049             } else if (strcmp16(block
.getElementName(&len
), array16
.string()) == 0) { 
1053                 ssize_t formatIdx 
= block
.indexOfAttribute(NULL
, "format"); 
1054                 if (formatIdx 
>= 0) { 
1055                     String16 formatStr 
= String16(block
.getAttributeStringValue( 
1057                     curFormat 
= parse_flags(formatStr
.string(), formatStr
.size(), 
1059                     if (curFormat 
== 0) { 
1060                         SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1061                                 "Tag <array> 'format' attribute value \"%s\" not valid\n", 
1062                                 String8(formatStr
).string()); 
1063                         hasErrors 
= localHasErrors 
= true; 
1066             } else if (strcmp16(block
.getElementName(&len
), string_array16
.string()) == 0) { 
1067                 curTag 
= &string_array16
; 
1069                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_STRING
; 
1071                 curIsPseudolocalizable 
= true; 
1072             } else if (strcmp16(block
.getElementName(&len
), integer_array16
.string()) == 0) { 
1073                 curTag 
= &integer_array16
; 
1075                 curFormat 
= ResTable_map::TYPE_REFERENCE
|ResTable_map::TYPE_INTEGER
; 
1078                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1079                         "Found tag %s where item is expected\n", 
1080                         String8(block
.getElementName(&len
)).string()); 
1081                 return UNKNOWN_ERROR
; 
1085             ssize_t identIdx 
= block
.indexOfAttribute(NULL
, "name"); 
1086             if (identIdx 
>= 0) { 
1087                 ident 
= String16(block
.getAttributeStringValue(identIdx
, &len
)); 
1089                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1090                         "A 'name' attribute is required for <%s>\n", 
1091                         String8(*curTag
).string()); 
1092                 hasErrors 
= localHasErrors 
= true; 
1095             String16 
comment(block
.getComment(&len
) ? block
.getComment(&len
) : nulStr
); 
1098                 // Figure out the parent of this bag... 
1099                 String16 parentIdent
; 
1100                 ssize_t parentIdentIdx 
= block
.indexOfAttribute(NULL
, "parent"); 
1101                 if (parentIdentIdx 
>= 0) { 
1102                     parentIdent 
= String16(block
.getAttributeStringValue(parentIdentIdx
, &len
)); 
1104                     ssize_t sep 
= ident
.findLast('.'); 
1106                         parentIdent
.setTo(ident
, sep
); 
1110                 if (!localHasErrors
) { 
1111                     err 
= outTable
->startBag(SourcePos(in
->getPrintableSource(), block
.getLineNumber()), 
1112                                              myPackage
, curType
, ident
, parentIdent
, &curParams
,  
1114                     if (err 
!= NO_ERROR
) { 
1115                         hasErrors 
= localHasErrors 
= true; 
1119                 ssize_t elmIndex 
= 0; 
1120                 char elmIndexStr
[14]; 
1121                 while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
1122                         && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
1124                     if (code 
== ResXMLTree::START_TAG
) { 
1125                         if (strcmp16(block
.getElementName(&len
), item16
.string()) != 0) { 
1126                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1127                                     "Tag <%s> can not appear inside <%s>, only <item>\n", 
1128                                     String8(block
.getElementName(&len
)).string(), 
1129                                     String8(*curTag
).string()); 
1130                             return UNKNOWN_ERROR
; 
1134                         if (curType 
== array16
) { 
1135                             sprintf(elmIndexStr
, "^index_%d", (int)elmIndex
++); 
1136                             itemIdent 
= String16(elmIndexStr
); 
1137                         } else if (curType 
== plurals16
) { 
1138                             ssize_t itemIdentIdx 
= block
.indexOfAttribute(NULL
, "quantity"); 
1139                             if (itemIdentIdx 
>= 0) { 
1140                                 String16 
quantity16(block
.getAttributeStringValue(itemIdentIdx
, &len
)); 
1141                                 if (quantity16 
== other16
) { 
1142                                     itemIdent 
= quantityOther16
; 
1144                                 else if (quantity16 
== zero16
) { 
1145                                     itemIdent 
= quantityZero16
; 
1147                                 else if (quantity16 
== one16
) { 
1148                                     itemIdent 
= quantityOne16
; 
1150                                 else if (quantity16 
== two16
) { 
1151                                     itemIdent 
= quantityTwo16
; 
1153                                 else if (quantity16 
== few16
) { 
1154                                     itemIdent 
= quantityFew16
; 
1156                                 else if (quantity16 
== many16
) { 
1157                                     itemIdent 
= quantityMany16
; 
1160                                     SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1161                                             "Illegal 'quantity' attribute is <item> inside <plurals>\n"); 
1162                                     hasErrors 
= localHasErrors 
= true; 
1165                                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1166                                         "A 'quantity' attribute is required for <item> inside <plurals>\n"); 
1167                                 hasErrors 
= localHasErrors 
= true; 
1170                             ssize_t itemIdentIdx 
= block
.indexOfAttribute(NULL
, "name"); 
1171                             if (itemIdentIdx 
>= 0) { 
1172                                 itemIdent 
= String16(block
.getAttributeStringValue(itemIdentIdx
, &len
)); 
1174                                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1175                                         "A 'name' attribute is required for <item>\n"); 
1176                                 hasErrors 
= localHasErrors 
= true; 
1180                         ResXMLParser::ResXMLPosition parserPosition
; 
1181                         block
.getPosition(&parserPosition
); 
1183                         err 
= parseAndAddBag(bundle
, in
, &block
, curParams
, myPackage
, curType
, 
1184                                 ident
, parentIdent
, itemIdent
, curFormat
,  
1185                                 false, overwrite
, outTable
); 
1186                         if (err 
== NO_ERROR
) { 
1187                             if (curIsPseudolocalizable 
&& localeIsDefined(curParams
) 
1188                                     && bundle
->getPseudolocalize()) { 
1189                                 // pseudolocalize here 
1191                                 block
.setPosition(parserPosition
); 
1192                                 err 
= parseAndAddBag(bundle
, in
, &block
, pseudoParams
, myPackage
, 
1193                                         curType
, ident
, parentIdent
, itemIdent
, curFormat
, true, 
1194                                         overwrite
, outTable
); 
1198                         if (err 
!= NO_ERROR
) { 
1199                             hasErrors 
= localHasErrors 
= true; 
1201                     } else if (code 
== ResXMLTree::END_TAG
) { 
1202                         if (strcmp16(block
.getElementName(&len
), curTag
->string()) != 0) { 
1203                             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1204                                     "Found tag </%s> where </%s> is expected\n", 
1205                                     String8(block
.getElementName(&len
)).string(), 
1206                                     String8(*curTag
).string()); 
1207                             return UNKNOWN_ERROR
; 
1213                 ResXMLParser::ResXMLPosition parserPosition
; 
1214                 block
.getPosition(&parserPosition
); 
1216                 err 
= parseAndAddEntry(bundle
, in
, &block
, curParams
, myPackage
, curType
, ident
, 
1217                         *curTag
, curIsStyled
, curFormat
, false, overwrite
, outTable
); 
1219                 if (err 
< NO_ERROR
) { // Why err < NO_ERROR instead of err != NO_ERROR? 
1220                     hasErrors 
= localHasErrors 
= true; 
1222                 else if (err 
== NO_ERROR
) { 
1223                     if (curIsPseudolocalizable 
&& localeIsDefined(curParams
) 
1224                             && bundle
->getPseudolocalize()) { 
1225                         // pseudolocalize here 
1226                         block
.setPosition(parserPosition
); 
1227                         err 
= parseAndAddEntry(bundle
, in
, &block
, pseudoParams
, myPackage
, curType
, 
1228                                 ident
, *curTag
, curIsStyled
, curFormat
, true, false, outTable
); 
1229                         if (err 
!= NO_ERROR
) { 
1230                             hasErrors 
= localHasErrors 
= true; 
1237             if (comment
.size() > 0) { 
1238                 printf("Comment for @%s:%s/%s: %s\n", String8(myPackage
).string(), 
1239                        String8(curType
).string(), String8(ident
).string(), 
1240                        String8(comment
).string()); 
1243             if (!localHasErrors
) { 
1244                 outTable
->appendComment(myPackage
, curType
, ident
, comment
, false); 
1247         else if (code 
== ResXMLTree::END_TAG
) { 
1248             if (strcmp16(block
.getElementName(&len
), resources16
.string()) != 0) { 
1249                 SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1250                         "Unexpected end tag %s\n", String8(block
.getElementName(&len
)).string()); 
1251                 return UNKNOWN_ERROR
; 
1254         else if (code 
== ResXMLTree::START_NAMESPACE 
|| code 
== ResXMLTree::END_NAMESPACE
) { 
1256         else if (code 
== ResXMLTree::TEXT
) { 
1257             if (isWhitespace(block
.getText(&len
))) { 
1260             SourcePos(in
->getPrintableSource(), block
.getLineNumber()).error( 
1261                     "Found text \"%s\" where item tag is expected\n", 
1262                     String8(block
.getText(&len
)).string()); 
1263             return UNKNOWN_ERROR
; 
1267     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
1270 ResourceTable::ResourceTable(Bundle
* bundle
, const String16
& assetsPackage
) 
1271     : mAssetsPackage(assetsPackage
), mNextPackageId(1), mHaveAppPackage(false), 
1272       mIsAppPackage(!bundle
->getExtending()), 
1278 status_t 
ResourceTable::addIncludedResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
1280     status_t err 
= assets
->buildIncludedResources(bundle
); 
1281     if (err 
!= NO_ERROR
) { 
1285     // For future reference to included resources. 
1288     const ResTable
& incl 
= assets
->getIncludedResources(); 
1290     // Retrieve all the packages. 
1291     const size_t N 
= incl
.getBasePackageCount(); 
1292     for (size_t phase
=0; phase
<2; phase
++) { 
1293         for (size_t i
=0; i
<N
; i
++) { 
1294             String16 
name(incl
.getBasePackageName(i
)); 
1295             uint32_t id 
= incl
.getBasePackageId(i
); 
1296             // First time through: only add base packages (id 
1297             // is not 0); second time through add the other 
1301                     // Skip base packages -- already one. 
1304                     // Assign a dynamic id. 
1305                     id 
= mNextPackageId
; 
1307             } else if (id 
!= 0) { 
1309                     if (mHaveAppPackage
) { 
1310                         fprintf(stderr
, "Included resource have two application packages!\n"); 
1311                         return UNKNOWN_ERROR
; 
1313                     mHaveAppPackage 
= true; 
1315                 if (mNextPackageId 
> id
) { 
1316                     fprintf(stderr
, "Included base package ID %d already in use!\n", id
); 
1317                     return UNKNOWN_ERROR
; 
1321                 NOISY(printf("Including package %s with ID=%d\n", 
1322                              String8(name
).string(), id
)); 
1323                 sp
<Package
> p 
= new Package(name
, id
); 
1324                 mPackages
.add(name
, p
); 
1325                 mOrderedPackages
.add(p
); 
1327                 if (id 
>= mNextPackageId
) { 
1328                     mNextPackageId 
= id
+1; 
1334     // Every resource table always has one first entry, the bag attributes. 
1335     const SourcePos 
unknown(String8("????"), 0); 
1336     sp
<Type
> attr 
= getType(mAssetsPackage
, String16("attr"), unknown
); 
1341 status_t 
ResourceTable::addPublic(const SourcePos
& sourcePos
, 
1342                                   const String16
& package
, 
1343                                   const String16
& type
, 
1344                                   const String16
& name
, 
1345                                   const uint32_t ident
) 
1347     uint32_t rid 
= mAssets
->getIncludedResources() 
1348         .identifierForName(name
.string(), name
.size(), 
1349                            type
.string(), type
.size(), 
1350                            package
.string(), package
.size()); 
1352         sourcePos
.error("Error declaring public resource %s/%s for included package %s\n", 
1353                 String8(type
).string(), String8(name
).string(), 
1354                 String8(package
).string()); 
1355         return UNKNOWN_ERROR
; 
1358     sp
<Type
> t 
= getType(package
, type
, sourcePos
); 
1360         return UNKNOWN_ERROR
; 
1362     return t
->addPublic(sourcePos
, name
, ident
); 
1365 status_t 
ResourceTable::addEntry(const SourcePos
& sourcePos
, 
1366                                  const String16
& package
, 
1367                                  const String16
& type
, 
1368                                  const String16
& name
, 
1369                                  const String16
& value
, 
1370                                  const Vector
<StringPool::entry_style_span
>* style
, 
1371                                  const ResTable_config
* params
, 
1372                                  const bool doSetIndex
, 
1373                                  const int32_t format
, 
1374                                  const bool overwrite
) 
1376     // Check for adding entries in other packages...  for now we do 
1377     // nothing.  We need to do the right thing here to support skinning. 
1378     uint32_t rid 
= mAssets
->getIncludedResources() 
1379         .identifierForName(name
.string(), name
.size(), 
1380                            type
.string(), type
.size(), 
1381                            package
.string(), package
.size()); 
1387     if (name 
== String16("left")) { 
1388         printf("Adding entry left: file=%s, line=%d, type=%s, value=%s\n", 
1389                sourcePos
.file
.string(), sourcePos
.line
, String8(type
).string(), 
1390                String8(value
).string()); 
1394     sp
<Entry
> e 
= getEntry(package
, type
, name
, sourcePos
, params
, doSetIndex
); 
1396         return UNKNOWN_ERROR
; 
1398     status_t err 
= e
->setItem(sourcePos
, value
, style
, format
, overwrite
); 
1399     if (err 
== NO_ERROR
) { 
1405 status_t 
ResourceTable::startBag(const SourcePos
& sourcePos
, 
1406                                  const String16
& package
, 
1407                                  const String16
& type
, 
1408                                  const String16
& name
, 
1409                                  const String16
& bagParent
, 
1410                                  const ResTable_config
* params
, 
1411                                  bool replace
, bool isId
) 
1413     status_t result 
= NO_ERROR
; 
1415     // Check for adding entries in other packages...  for now we do 
1416     // nothing.  We need to do the right thing here to support skinning. 
1417     uint32_t rid 
= mAssets
->getIncludedResources() 
1418     .identifierForName(name
.string(), name
.size(), 
1419                        type
.string(), type
.size(), 
1420                        package
.string(), package
.size()); 
1426     if (name 
== String16("left")) { 
1427         printf("Adding bag left: file=%s, line=%d, type=%s\n", 
1428                sourcePos
.file
.striing(), sourcePos
.line
, String8(type
).string()); 
1432     sp
<Entry
> e 
= getEntry(package
, type
, name
, sourcePos
, params
); 
1434         return UNKNOWN_ERROR
; 
1437     // If a parent is explicitly specified, set it. 
1438     if (bagParent
.size() > 0) { 
1439         String16 curPar 
= e
->getParent(); 
1440         if (curPar
.size() > 0 && curPar 
!= bagParent
) { 
1441             sourcePos
.error("Conflicting parents specified, was '%s', now '%s'\n", 
1442                             String8(e
->getParent()).string(), 
1443                             String8(bagParent
).string()); 
1444             return UNKNOWN_ERROR
; 
1446         e
->setParent(bagParent
); 
1449     if ((result 
= e
->makeItABag(sourcePos
)) != NO_ERROR
) { 
1453     return e
->emptyBag(sourcePos
); 
1456 status_t 
ResourceTable::addBag(const SourcePos
& sourcePos
, 
1457                                const String16
& package
, 
1458                                const String16
& type
, 
1459                                const String16
& name
, 
1460                                const String16
& bagParent
, 
1461                                const String16
& bagKey
, 
1462                                const String16
& value
, 
1463                                const Vector
<StringPool::entry_style_span
>* style
, 
1464                                const ResTable_config
* params
, 
1465                                bool replace
, bool isId
, const int32_t format
) 
1467     // Check for adding entries in other packages...  for now we do 
1468     // nothing.  We need to do the right thing here to support skinning. 
1469     uint32_t rid 
= mAssets
->getIncludedResources() 
1470         .identifierForName(name
.string(), name
.size(), 
1471                            type
.string(), type
.size(), 
1472                            package
.string(), package
.size()); 
1478     if (name 
== String16("left")) { 
1479         printf("Adding bag left: file=%s, line=%d, type=%s\n", 
1480                sourcePos
.file
.striing(), sourcePos
.line
, String8(type
).string()); 
1484     sp
<Entry
> e 
= getEntry(package
, type
, name
, sourcePos
, params
); 
1486         return UNKNOWN_ERROR
; 
1489     // If a parent is explicitly specified, set it. 
1490     if (bagParent
.size() > 0) { 
1491         String16 curPar 
= e
->getParent(); 
1492         if (curPar
.size() > 0 && curPar 
!= bagParent
) { 
1493             sourcePos
.error("Conflicting parents specified, was '%s', now '%s'\n", 
1494                     String8(e
->getParent()).string(), 
1495                     String8(bagParent
).string()); 
1496             return UNKNOWN_ERROR
; 
1498         e
->setParent(bagParent
); 
1501     const bool first 
= e
->getBag().indexOfKey(bagKey
) < 0; 
1502     status_t err 
= e
->addToBag(sourcePos
, bagKey
, value
, style
, replace
, isId
, format
); 
1503     if (err 
== NO_ERROR 
&& first
) { 
1509 bool ResourceTable::hasBagOrEntry(const String16
& package
, 
1510                                   const String16
& type
, 
1511                                   const String16
& name
) const 
1513     // First look for this in the included resources... 
1514     uint32_t rid 
= mAssets
->getIncludedResources() 
1515         .identifierForName(name
.string(), name
.size(), 
1516                            type
.string(), type
.size(), 
1517                            package
.string(), package
.size()); 
1522     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1524         sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1526             sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1527             if (c 
!= NULL
) return true; 
1534 bool ResourceTable::hasBagOrEntry(const String16
& ref
, 
1535                                   const String16
* defType
, 
1536                                   const String16
* defPackage
) 
1538     String16 package
, type
, name
; 
1539     if (!ResTable::expandResourceRef(ref
.string(), ref
.size(), &package
, &type
, &name
, 
1540                 defType
, defPackage 
? defPackage
:&mAssetsPackage
, NULL
)) { 
1543     return hasBagOrEntry(package
, type
, name
); 
1546 bool ResourceTable::appendComment(const String16
& package
, 
1547                                   const String16
& type
, 
1548                                   const String16
& name
, 
1549                                   const String16
& comment
, 
1552     if (comment
.size() <= 0) { 
1556     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1558         sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1560             sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1562                 c
->appendComment(comment
, onlyIfEmpty
); 
1570 bool ResourceTable::appendTypeComment(const String16
& package
, 
1571                                       const String16
& type
, 
1572                                       const String16
& name
, 
1573                                       const String16
& comment
) 
1575     if (comment
.size() <= 0) { 
1579     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1581         sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1583             sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1585                 c
->appendTypeComment(comment
); 
1593 size_t ResourceTable::size() const { 
1594     return mPackages
.size(); 
1597 size_t ResourceTable::numLocalResources() const { 
1601 bool ResourceTable::hasResources() const { 
1602     return mNumLocal 
> 0; 
1605 sp
<AaptFile
> ResourceTable::flatten(Bundle
* bundle
) 
1607     sp
<AaptFile
> data 
= new AaptFile(String8(), AaptGroupEntry(), String8()); 
1608     status_t err 
= flatten(bundle
, data
); 
1609     return err 
== NO_ERROR 
? data 
: NULL
; 
1612 inline uint32_t ResourceTable::getResId(const sp
<Package
>& p
, 
1616     return makeResId(p
->getAssignedId(), t
->getIndex(), nameId
); 
1619 uint32_t ResourceTable::getResId(const String16
& package
, 
1620                                  const String16
& type
, 
1621                                  const String16
& name
, 
1622                                  bool onlyPublic
) const 
1624     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1625     if (p 
== NULL
) return 0; 
1627     // First look for this in the included resources... 
1628     uint32_t specFlags 
= 0; 
1629     uint32_t rid 
= mAssets
->getIncludedResources() 
1630         .identifierForName(name
.string(), name
.size(), 
1631                            type
.string(), type
.size(), 
1632                            package
.string(), package
.size(), 
1636             if ((specFlags 
& ResTable_typeSpec::SPEC_PUBLIC
) == 0) { 
1641         if (Res_INTERNALID(rid
)) { 
1644         return Res_MAKEID(p
->getAssignedId()-1, 
1649     sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1650     if (t 
== NULL
) return 0; 
1651     sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1652     if (c 
== NULL
) return 0; 
1653     int32_t ei 
= c
->getEntryIndex(); 
1654     if (ei 
< 0) return 0; 
1655     return getResId(p
, t
, ei
); 
1658 uint32_t ResourceTable::getResId(const String16
& ref
, 
1659                                  const String16
* defType
, 
1660                                  const String16
* defPackage
, 
1661                                  const char** outErrorMsg
, 
1662                                  bool onlyPublic
) const 
1664     String16 package
, type
, name
; 
1665     if (!ResTable::expandResourceRef( 
1666         ref
.string(), ref
.size(), &package
, &type
, &name
, 
1667         defType
, defPackage 
? defPackage
:&mAssetsPackage
, 
1669         NOISY(printf("Expanding resource: ref=%s\n", 
1670                      String8(ref
).string())); 
1671         NOISY(printf("Expanding resource: defType=%s\n", 
1672                      defType 
? String8(*defType
).string() : "NULL")); 
1673         NOISY(printf("Expanding resource: defPackage=%s\n", 
1674                      defPackage 
? String8(*defPackage
).string() : "NULL")); 
1675         NOISY(printf("Expanding resource: ref=%s\n", String8(ref
).string())); 
1676         NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n", 
1677                      String8(package
).string(), String8(type
).string(), 
1678                      String8(name
).string())); 
1681     uint32_t res 
= getResId(package
, type
, name
, onlyPublic
); 
1682     NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n", 
1683                  String8(package
).string(), String8(type
).string(), 
1684                  String8(name
).string(), res
)); 
1687             *outErrorMsg 
= "No resource found that matches the given name"; 
1692 bool ResourceTable::isValidResourceName(const String16
& s
) 
1694     const char16_t* p 
= s
.string(); 
1697         if ((*p 
>= 'a' && *p 
<= 'z') 
1698             || (*p 
>= 'A' && *p 
<= 'Z') 
1700             || (!first 
&& *p 
>= '0' && *p 
<= '9')) { 
1710 bool ResourceTable::stringToValue(Res_value
* outValue
, StringPool
* pool
, 
1711                                   const String16
& str
, 
1712                                   bool preserveSpaces
, bool coerceType
, 
1714                                   const Vector
<StringPool::entry_style_span
>* style
, 
1715                                   String16
* outStr
, void* accessorCookie
, 
1721     if (style 
== NULL 
|| style
->size() == 0) { 
1722         // Text is not styled so it can be any type...  let's figure it out. 
1723         res 
= mAssets
->getIncludedResources() 
1724             .stringToValue(outValue
, &finalStr
, str
.string(), str
.size(), preserveSpaces
, 
1725                             coerceType
, attrID
, NULL
, &mAssetsPackage
, this, 
1726                            accessorCookie
, attrType
); 
1728         // Styled text can only be a string, and while collecting the style 
1729         // information we have already processed that string! 
1730         outValue
->size 
= sizeof(Res_value
); 
1732         outValue
->dataType 
= outValue
->TYPE_STRING
; 
1741     if (outValue
->dataType 
== outValue
->TYPE_STRING
) { 
1742         // Should do better merging styles. 
1744             if (style 
!= NULL 
&& style
->size() > 0) { 
1745                 outValue
->data 
= pool
->add(finalStr
, *style
); 
1747                 outValue
->data 
= pool
->add(finalStr
, true); 
1750             // Caller will fill this in later. 
1763 uint32_t ResourceTable::getCustomResource( 
1764     const String16
& package
, const String16
& type
, const String16
& name
) const 
1766     //printf("getCustomResource: %s %s %s\n", String8(package).string(), 
1767     //       String8(type).string(), String8(name).string()); 
1768     sp
<Package
> p 
= mPackages
.valueFor(package
); 
1769     if (p 
== NULL
) return 0; 
1770     sp
<Type
> t 
= p
->getTypes().valueFor(type
); 
1771     if (t 
== NULL
) return 0; 
1772     sp
<ConfigList
> c 
=  t
->getConfigs().valueFor(name
); 
1773     if (c 
== NULL
) return 0; 
1774     int32_t ei 
= c
->getEntryIndex(); 
1775     if (ei 
< 0) return 0; 
1776     return getResId(p
, t
, ei
); 
1779 uint32_t ResourceTable::getCustomResourceWithCreation( 
1780         const String16
& package
, const String16
& type
, const String16
& name
, 
1781         const bool createIfNotFound
) 
1783     uint32_t resId 
= getCustomResource(package
, type
, name
); 
1784     if (resId 
!= 0 || !createIfNotFound
) { 
1787     String16 
value("false"); 
1789     status_t status 
= addEntry(mCurrentXmlPos
, package
, type
, name
, value
, NULL
, NULL
, true); 
1790     if (status 
== NO_ERROR
) { 
1791         resId 
= getResId(package
, type
, name
); 
1797 uint32_t ResourceTable::getRemappedPackage(uint32_t origPackage
) const 
1802 bool ResourceTable::getAttributeType(uint32_t attrID
, uint32_t* outType
) 
1804     //printf("getAttributeType #%08x\n", attrID); 
1806     if (getItemValue(attrID
, ResTable_map::ATTR_TYPE
, &value
)) { 
1807         //printf("getAttributeType #%08x (%s): #%08x\n", attrID, 
1808         //       String8(getEntry(attrID)->getName()).string(), value.data); 
1809         *outType 
= value
.data
; 
1815 bool ResourceTable::getAttributeMin(uint32_t attrID
, uint32_t* outMin
) 
1817     //printf("getAttributeMin #%08x\n", attrID); 
1819     if (getItemValue(attrID
, ResTable_map::ATTR_MIN
, &value
)) { 
1820         *outMin 
= value
.data
; 
1826 bool ResourceTable::getAttributeMax(uint32_t attrID
, uint32_t* outMax
) 
1828     //printf("getAttributeMax #%08x\n", attrID); 
1830     if (getItemValue(attrID
, ResTable_map::ATTR_MAX
, &value
)) { 
1831         *outMax 
= value
.data
; 
1837 uint32_t ResourceTable::getAttributeL10N(uint32_t attrID
) 
1839     //printf("getAttributeL10N #%08x\n", attrID); 
1841     if (getItemValue(attrID
, ResTable_map::ATTR_L10N
, &value
)) { 
1844     return ResTable_map::L10N_NOT_REQUIRED
; 
1847 bool ResourceTable::getLocalizationSetting() 
1849     return mBundle
->getRequireLocalization(); 
1852 void ResourceTable::reportError(void* accessorCookie
, const char* fmt
, ...) 
1854     if (accessorCookie 
!= NULL 
&& fmt 
!= NULL
) { 
1855         AccessorCookie
* ac 
= (AccessorCookie
*)accessorCookie
; 
1860         retval 
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
); 
1862         ac
->sourcePos
.error("Error: %s (at '%s' with value '%s').\n", 
1863                             buf
, ac
->attr
.string(), ac
->value
.string()); 
1867 bool ResourceTable::getAttributeKeys( 
1868     uint32_t attrID
, Vector
<String16
>* outKeys
) 
1870     sp
<const Entry
> e 
= getEntry(attrID
); 
1872         const size_t N 
= e
->getBag().size(); 
1873         for (size_t i
=0; i
<N
; i
++) { 
1874             const String16
& key 
= e
->getBag().keyAt(i
); 
1875             if (key
.size() > 0 && key
.string()[0] != '^') { 
1884 bool ResourceTable::getAttributeEnum( 
1885     uint32_t attrID
, const char16_t* name
, size_t nameLen
, 
1886     Res_value
* outValue
) 
1888     //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).string()); 
1889     String16 
nameStr(name
, nameLen
); 
1890     sp
<const Entry
> e 
= getEntry(attrID
); 
1892         const size_t N 
= e
->getBag().size(); 
1893         for (size_t i
=0; i
<N
; i
++) { 
1894             //printf("Comparing %s to %s\n", String8(name, nameLen).string(), 
1895             //       String8(e->getBag().keyAt(i)).string()); 
1896             if (e
->getBag().keyAt(i
) == nameStr
) { 
1897                 return getItemValue(attrID
, e
->getBag().valueAt(i
).bagKeyId
, outValue
); 
1904 bool ResourceTable::getAttributeFlags( 
1905     uint32_t attrID
, const char16_t* name
, size_t nameLen
, 
1906     Res_value
* outValue
) 
1908     outValue
->dataType 
= Res_value::TYPE_INT_HEX
; 
1911     //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).string()); 
1912     String16 
nameStr(name
, nameLen
); 
1913     sp
<const Entry
> e 
= getEntry(attrID
); 
1915         const size_t N 
= e
->getBag().size(); 
1917         const char16_t* end 
= name 
+ nameLen
; 
1918         const char16_t* pos 
= name
; 
1919         bool failed 
= false; 
1920         while (pos 
< end 
&& !failed
) { 
1921             const char16_t* start 
= pos
; 
1923             while (pos 
< end 
&& *pos 
!= '|') { 
1927             String16 
nameStr(start
, pos
-start
); 
1929             for (i
=0; i
<N
; i
++) { 
1930                 //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).string(), 
1931                 //       String8(e->getBag().keyAt(i)).string()); 
1932                 if (e
->getBag().keyAt(i
) == nameStr
) { 
1934                     bool got 
= getItemValue(attrID
, e
->getBag().valueAt(i
).bagKeyId
, &val
); 
1938                     //printf("Got value: 0x%08x\n", val.data); 
1939                     outValue
->data 
|= val
.data
; 
1945                 // Didn't find this flag identifier. 
1958 status_t 
ResourceTable::assignResourceIds() 
1960     const size_t N 
= mOrderedPackages
.size(); 
1962     status_t firstError 
= NO_ERROR
; 
1964     // First generate all bag attributes and assign indices. 
1965     for (pi
=0; pi
<N
; pi
++) { 
1966         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
1967         if (p 
== NULL 
|| p
->getTypes().size() == 0) { 
1972         status_t err 
= p
->applyPublicTypeOrder(); 
1973         if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
1977         // Generate attributes... 
1978         const size_t N 
= p
->getOrderedTypes().size(); 
1980         for (ti
=0; ti
<N
; ti
++) { 
1981             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
1985             const size_t N 
= t
->getOrderedConfigs().size(); 
1986             for (size_t ci
=0; ci
<N
; ci
++) { 
1987                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
1991                 const size_t N 
= c
->getEntries().size(); 
1992                 for (size_t ei
=0; ei
<N
; ei
++) { 
1993                     sp
<Entry
> e 
= c
->getEntries().valueAt(ei
); 
1997                     status_t err 
= e
->generateAttributes(this, p
->getName()); 
1998                     if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
2005         const SourcePos 
unknown(String8("????"), 0); 
2006         sp
<Type
> attr 
= p
->getType(String16("attr"), unknown
); 
2008         // Assign indices... 
2009         for (ti
=0; ti
<N
; ti
++) { 
2010             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2014             err 
= t
->applyPublicEntryOrder(); 
2015             if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
2019             const size_t N 
= t
->getOrderedConfigs().size(); 
2022             LOG_ALWAYS_FATAL_IF(ti 
== 0 && attr 
!= t
, 
2023                                 "First type is not attr!"); 
2025             for (size_t ei
=0; ei
<N
; ei
++) { 
2026                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ei
); 
2030                 c
->setEntryIndex(ei
); 
2034         // Assign resource IDs to keys in bags... 
2035         for (ti
=0; ti
<N
; ti
++) { 
2036             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2040             const size_t N 
= t
->getOrderedConfigs().size(); 
2041             for (size_t ci
=0; ci
<N
; ci
++) { 
2042                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
2043                 //printf("Ordered config #%d: %p\n", ci, c.get()); 
2044                 const size_t N 
= c
->getEntries().size(); 
2045                 for (size_t ei
=0; ei
<N
; ei
++) { 
2046                     sp
<Entry
> e 
= c
->getEntries().valueAt(ei
); 
2050                     status_t err 
= e
->assignResourceIds(this, p
->getName()); 
2051                     if (err 
!= NO_ERROR 
&& firstError 
== NO_ERROR
) { 
2061 status_t 
ResourceTable::addSymbols(const sp
<AaptSymbols
>& outSymbols
) { 
2062     const size_t N 
= mOrderedPackages
.size(); 
2065     for (pi
=0; pi
<N
; pi
++) { 
2066         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
2067         if (p
->getTypes().size() == 0) { 
2072         const size_t N 
= p
->getOrderedTypes().size(); 
2075         for (ti
=0; ti
<N
; ti
++) { 
2076             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2080             const size_t N 
= t
->getOrderedConfigs().size(); 
2081             sp
<AaptSymbols
> typeSymbols
; 
2082             typeSymbols 
= outSymbols
->addNestedSymbol(String8(t
->getName()), t
->getPos()); 
2083             for (size_t ci
=0; ci
<N
; ci
++) { 
2084                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
2088                 uint32_t rid 
= getResId(p
, t
, ci
); 
2090                     return UNKNOWN_ERROR
; 
2092                 if (Res_GETPACKAGE(rid
) == (size_t)(p
->getAssignedId()-1)) { 
2093                     typeSymbols
->addSymbol(String8(c
->getName()), rid
, c
->getPos()); 
2095                     String16 
comment(c
->getComment()); 
2096                     typeSymbols
->appendComment(String8(c
->getName()), comment
, c
->getPos()); 
2097                     //printf("Type symbol %s comment: %s\n", String8(e->getName()).string(), 
2098                     //     String8(comment).string()); 
2099                     comment 
= c
->getTypeComment(); 
2100                     typeSymbols
->appendTypeComment(String8(c
->getName()), comment
); 
2103                     printf("**** NO MATCH: 0x%08x vs 0x%08x\n", 
2104                            Res_GETPACKAGE(rid
), p
->getAssignedId()); 
2115 ResourceTable::addLocalization(const String16
& name
, const String8
& locale
) 
2117     mLocalizations
[name
].insert(locale
); 
2122  * Flag various sorts of localization problems.  '+' indicates checks already implemented; 
2123  * '-' indicates checks that will be implemented in the future. 
2125  * + A localized string for which no default-locale version exists => warning 
2126  * + A string for which no version in an explicitly-requested locale exists => warning 
2127  * + A localized translation of an translateable="false" string => warning 
2128  * - A localized string not provided in every locale used by the table 
2131 ResourceTable::validateLocalizations(void) 
2133     status_t err 
= NO_ERROR
; 
2134     const String8 defaultLocale
; 
2136     // For all strings... 
2137     for (map
<String16
, set
<String8
> >::iterator nameIter 
= mLocalizations
.begin(); 
2138          nameIter 
!= mLocalizations
.end(); 
2140         const set
<String8
>& configSet 
= nameIter
->second
;   // naming convenience 
2142         // Look for strings with no default localization 
2143         if (configSet
.count(defaultLocale
) == 0) { 
2144             fprintf(stdout
, "aapt: warning: string '%s' has no default translation in %s; found:", 
2145                     String8(nameIter
->first
).string(), mBundle
->getResourceSourceDirs()[0]); 
2146             for (set
<String8
>::iterator locales 
= configSet
.begin(); 
2147                  locales 
!= configSet
.end(); 
2149                 fprintf(stdout
, " %s", (*locales
).string()); 
2151             fprintf(stdout
, "\n"); 
2152             // !!! TODO: throw an error here in some circumstances 
2155         // Check that all requested localizations are present for this string 
2156         if (mBundle
->getConfigurations() != NULL 
&& mBundle
->getRequireLocalization()) { 
2157             const char* allConfigs 
= mBundle
->getConfigurations(); 
2158             const char* start 
= allConfigs
; 
2163                 comma 
= strchr(start
, ','); 
2164                 if (comma 
!= NULL
) { 
2165                     config
.setTo(start
, comma 
- start
); 
2168                     config
.setTo(start
); 
2171                 // don't bother with the pseudolocale "zz_ZZ" 
2172                 if (config 
!= "zz_ZZ") { 
2173                     if (configSet
.find(config
) == configSet
.end()) { 
2174                         // okay, no specific localization found.  it's possible that we are 
2175                         // requiring a specific regional localization [e.g. de_DE] but there is an 
2176                         // available string in the generic language localization [e.g. de]; 
2177                         // consider that string to have fulfilled the localization requirement. 
2178                         String8 
region(config
.string(), 2); 
2179                         if (configSet
.find(region
) == configSet
.end()) { 
2180                             if (configSet
.count(defaultLocale
) == 0) { 
2181                                 fprintf(stdout
, "aapt: error: " 
2182                                         "*** string '%s' has no default or required localization " 
2184                                         String8(nameIter
->first
).string(), 
2186                                         mBundle
->getResourceSourceDirs()[0]); 
2187                                 err 
= UNKNOWN_ERROR
; 
2192            } while (comma 
!= NULL
); 
2201 ResourceFilter::parse(const char* arg
) 
2207     const char* p 
= arg
; 
2216         String8 
part(p
, q
-p
); 
2218         if (part 
== "zz_ZZ") { 
2219             mContainsPseudo 
= true; 
2223         if (AaptGroupEntry::parseNamePart(part
, &axis
, &value
)) { 
2224             fprintf(stderr
, "Invalid configuration: %s\n", arg
); 
2225             fprintf(stderr
, "                       "); 
2226             for (int i
=0; i
<p
-arg
; i
++) { 
2227                 fprintf(stderr
, " "); 
2229             for (int i
=0; i
<q
-p
; i
++) { 
2230                 fprintf(stderr
, "^"); 
2232             fprintf(stderr
, "\n"); 
2236         ssize_t index 
= mData
.indexOfKey(axis
); 
2238             mData
.add(axis
, SortedVector
<uint32_t>()); 
2240         SortedVector
<uint32_t>& sv 
= mData
.editValueFor(axis
); 
2242         // if it's a locale with a region, also match an unmodified locale of the 
2244         if (axis 
== AXIS_LANGUAGE
) { 
2245             if (value 
& 0xffff0000) { 
2246                 sv
.add(value 
& 0x0000ffff); 
2258 ResourceFilter::match(int axis
, uint32_t value
) 
2261         // they didn't specify anything so take everything 
2264     ssize_t index 
= mData
.indexOfKey(axis
); 
2266         // we didn't request anything on this axis so take everything 
2269     const SortedVector
<uint32_t>& sv 
= mData
.valueAt(index
); 
2270     return sv
.indexOf(value
) >= 0; 
2274 ResourceFilter::match(const ResTable_config
& config
) 
2276     if (config
.locale
) { 
2277         uint32_t locale 
= (config
.country
[1] << 24) | (config
.country
[0] << 16) 
2278                 | (config
.language
[1] << 8) | (config
.language
[0]); 
2279         if (!match(AXIS_LANGUAGE
, locale
)) { 
2283     if (!match(AXIS_ORIENTATION
, config
.orientation
)) { 
2286     if (!match(AXIS_DENSITY
, config
.density
)) { 
2289     if (!match(AXIS_TOUCHSCREEN
, config
.touchscreen
)) { 
2292     if (!match(AXIS_KEYSHIDDEN
, config
.inputFlags
)) { 
2295     if (!match(AXIS_KEYBOARD
, config
.keyboard
)) { 
2298     if (!match(AXIS_NAVIGATION
, config
.navigation
)) { 
2301     if (!match(AXIS_SCREENSIZE
, config
.screenSize
)) { 
2304     if (!match(AXIS_VERSION
, config
.version
)) { 
2310 status_t 
ResourceTable::flatten(Bundle
* bundle
, const sp
<AaptFile
>& dest
) 
2312     ResourceFilter filter
; 
2313     status_t err 
= filter
.parse(bundle
->getConfigurations()); 
2314     if (err 
!= NO_ERROR
) { 
2318     const size_t N 
= mOrderedPackages
.size(); 
2321     // Iterate through all data, collecting all values (strings, 
2322     // references, etc). 
2323     StringPool valueStrings
; 
2324     for (pi
=0; pi
<N
; pi
++) { 
2325         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
2326         if (p
->getTypes().size() == 0) { 
2331         StringPool typeStrings
; 
2332         StringPool keyStrings
; 
2334         const size_t N 
= p
->getOrderedTypes().size(); 
2335         for (size_t ti
=0; ti
<N
; ti
++) { 
2336             sp
<Type
> t 
= p
->getOrderedTypes().itemAt(ti
); 
2338                 typeStrings
.add(String16("<empty>"), false); 
2341             typeStrings
.add(t
->getName(), false); 
2343             const size_t N 
= t
->getOrderedConfigs().size(); 
2344             for (size_t ci
=0; ci
<N
; ci
++) { 
2345                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(ci
); 
2349                 const size_t N 
= c
->getEntries().size(); 
2350                 for (size_t ei
=0; ei
<N
; ei
++) { 
2351                     ConfigDescription config 
= c
->getEntries().keyAt(ei
); 
2352                     if (!filter
.match(config
)) { 
2355                     sp
<Entry
> e 
= c
->getEntries().valueAt(ei
); 
2359                     e
->setNameIndex(keyStrings
.add(e
->getName(), true)); 
2360                     status_t err 
= e
->prepareFlatten(&valueStrings
, this); 
2361                     if (err 
!= NO_ERROR
) { 
2368         p
->setTypeStrings(typeStrings
.createStringBlock()); 
2369         p
->setKeyStrings(keyStrings
.createStringBlock()); 
2374     // Now build the array of package chunks. 
2375     Vector
<sp
<AaptFile
> > flatPackages
; 
2376     for (pi
=0; pi
<N
; pi
++) { 
2377         sp
<Package
> p 
= mOrderedPackages
.itemAt(pi
); 
2378         if (p
->getTypes().size() == 0) { 
2383         const size_t N 
= p
->getTypeStrings().size(); 
2385         const size_t baseSize 
= sizeof(ResTable_package
); 
2387         // Start the package data. 
2388         sp
<AaptFile
> data 
= new AaptFile(String8(), AaptGroupEntry(), String8()); 
2389         ResTable_package
* header 
= (ResTable_package
*)data
->editData(baseSize
); 
2390         if (header 
== NULL
) { 
2391             fprintf(stderr
, "ERROR: out of memory creating ResTable_package\n"); 
2394         memset(header
, 0, sizeof(*header
)); 
2395         header
->header
.type 
= htods(RES_TABLE_PACKAGE_TYPE
); 
2396         header
->header
.headerSize 
= htods(sizeof(*header
)); 
2397         header
->id 
= htodl(p
->getAssignedId()); 
2398         strcpy16_htod(header
->name
, p
->getName().string()); 
2400         // Write the string blocks. 
2401         const size_t typeStringsStart 
= data
->getSize(); 
2402         sp
<AaptFile
> strFile 
= p
->getTypeStringsData(); 
2403         ssize_t amt 
= data
->writeData(strFile
->getData(), strFile
->getSize()); 
2404         #if PRINT_STRING_METRICS 
2405         fprintf(stderr
, "**** type strings: %d\n", amt
); 
2411         const size_t keyStringsStart 
= data
->getSize(); 
2412         strFile 
= p
->getKeyStringsData(); 
2413         amt 
= data
->writeData(strFile
->getData(), strFile
->getSize()); 
2414         #if PRINT_STRING_METRICS 
2415         fprintf(stderr
, "**** key strings: %d\n", amt
); 
2422         // Build the type chunks inside of this package. 
2423         for (size_t ti
=0; ti
<N
; ti
++) { 
2424             // Retrieve them in the same order as the type string block. 
2426             String16 
typeName(p
->getTypeStrings().stringAt(ti
, &len
)); 
2427             sp
<Type
> t 
= p
->getTypes().valueFor(typeName
); 
2428             LOG_ALWAYS_FATAL_IF(t 
== NULL 
&& typeName 
!= String16("<empty>"), 
2429                                 "Type name %s not found", 
2430                                 String8(typeName
).string()); 
2432             const size_t N 
= t 
!= NULL 
? t
->getOrderedConfigs().size() : 0; 
2434             // First write the typeSpec chunk, containing information about 
2435             // each resource entry in this type. 
2437                 const size_t typeSpecSize 
= sizeof(ResTable_typeSpec
) + sizeof(uint32_t)*N
; 
2438                 const size_t typeSpecStart 
= data
->getSize(); 
2439                 ResTable_typeSpec
* tsHeader 
= (ResTable_typeSpec
*) 
2440                     (((uint8_t*)data
->editData(typeSpecStart
+typeSpecSize
)) + typeSpecStart
); 
2441                 if (tsHeader 
== NULL
) { 
2442                     fprintf(stderr
, "ERROR: out of memory creating ResTable_typeSpec\n"); 
2445                 memset(tsHeader
, 0, sizeof(*tsHeader
)); 
2446                 tsHeader
->header
.type 
= htods(RES_TABLE_TYPE_SPEC_TYPE
); 
2447                 tsHeader
->header
.headerSize 
= htods(sizeof(*tsHeader
)); 
2448                 tsHeader
->header
.size 
= htodl(typeSpecSize
); 
2449                 tsHeader
->id 
= ti
+1; 
2450                 tsHeader
->entryCount 
= htodl(N
); 
2452                 uint32_t* typeSpecFlags 
= (uint32_t*) 
2453                     (((uint8_t*)data
->editData()) 
2454                         + typeSpecStart 
+ sizeof(ResTable_typeSpec
)); 
2455                 memset(typeSpecFlags
, 0, sizeof(uint32_t)*N
); 
2457                 for (size_t ei
=0; ei
<N
; ei
++) { 
2458                     sp
<ConfigList
> cl 
= t
->getOrderedConfigs().itemAt(ei
); 
2459                     if (cl
->getPublic()) { 
2460                         typeSpecFlags
[ei
] |= htodl(ResTable_typeSpec::SPEC_PUBLIC
); 
2462                     const size_t CN 
= cl
->getEntries().size(); 
2463                     for (size_t ci
=0; ci
<CN
; ci
++) { 
2464                         if (!filter
.match(cl
->getEntries().keyAt(ci
))) { 
2467                         for (size_t cj
=ci
+1; cj
<CN
; cj
++) { 
2468                             if (!filter
.match(cl
->getEntries().keyAt(cj
))) { 
2471                             typeSpecFlags
[ei
] |= htodl( 
2472                                 cl
->getEntries().keyAt(ci
).diff(cl
->getEntries().keyAt(cj
))); 
2478             // We need to write one type chunk for each configuration for 
2479             // which we have entries in this type. 
2480             const size_t NC 
= t
->getUniqueConfigs().size(); 
2482             const size_t typeSize 
= sizeof(ResTable_type
) + sizeof(uint32_t)*N
; 
2484             for (size_t ci
=0; ci
<NC
; ci
++) { 
2485                 ConfigDescription config 
= t
->getUniqueConfigs().itemAt(ci
); 
2487                 NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c " 
2488                      "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", 
2490                       config
.mcc
, config
.mnc
, 
2491                       config
.language
[0] ? config
.language
[0] : '-', 
2492                       config
.language
[1] ? config
.language
[1] : '-', 
2493                       config
.country
[0] ? config
.country
[0] : '-', 
2494                       config
.country
[1] ? config
.country
[1] : '-', 
2502                       config
.screenHeight
)); 
2504                 if (!filter
.match(config
)) { 
2508                 const size_t typeStart 
= data
->getSize(); 
2510                 ResTable_type
* tHeader 
= (ResTable_type
*) 
2511                     (((uint8_t*)data
->editData(typeStart
+typeSize
)) + typeStart
); 
2512                 if (tHeader 
== NULL
) { 
2513                     fprintf(stderr
, "ERROR: out of memory creating ResTable_type\n"); 
2517                 memset(tHeader
, 0, sizeof(*tHeader
)); 
2518                 tHeader
->header
.type 
= htods(RES_TABLE_TYPE_TYPE
); 
2519                 tHeader
->header
.headerSize 
= htods(sizeof(*tHeader
)); 
2521                 tHeader
->entryCount 
= htodl(N
); 
2522                 tHeader
->entriesStart 
= htodl(typeSize
); 
2523                 tHeader
->config 
= config
; 
2524                 NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c " 
2525                      "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", 
2527                       tHeader
->config
.mcc
, tHeader
->config
.mnc
, 
2528                       tHeader
->config
.language
[0] ? tHeader
->config
.language
[0] : '-', 
2529                       tHeader
->config
.language
[1] ? tHeader
->config
.language
[1] : '-', 
2530                       tHeader
->config
.country
[0] ? tHeader
->config
.country
[0] : '-', 
2531                       tHeader
->config
.country
[1] ? tHeader
->config
.country
[1] : '-', 
2532                       tHeader
->config
.orientation
, 
2533                       tHeader
->config
.touchscreen
, 
2534                       tHeader
->config
.density
, 
2535                       tHeader
->config
.keyboard
, 
2536                       tHeader
->config
.inputFlags
, 
2537                       tHeader
->config
.navigation
, 
2538                       tHeader
->config
.screenWidth
, 
2539                       tHeader
->config
.screenHeight
)); 
2540                 tHeader
->config
.swapHtoD(); 
2542                 // Build the entries inside of this type. 
2543                 for (size_t ei
=0; ei
<N
; ei
++) { 
2544                     sp
<ConfigList
> cl 
= t
->getOrderedConfigs().itemAt(ei
); 
2545                     sp
<Entry
> e 
= cl
->getEntries().valueFor(config
); 
2547                     // Set the offset for this entry in its type. 
2548                     uint32_t* index 
= (uint32_t*) 
2549                         (((uint8_t*)data
->editData()) 
2550                             + typeStart 
+ sizeof(ResTable_type
)); 
2552                         index
[ei
] = htodl(data
->getSize()-typeStart
-typeSize
); 
2554                         // Create the entry. 
2555                         ssize_t amt 
= e
->flatten(bundle
, data
, cl
->getPublic()); 
2560                         index
[ei
] = htodl(ResTable_type::NO_ENTRY
); 
2564                 // Fill in the rest of the type information. 
2565                 tHeader 
= (ResTable_type
*) 
2566                     (((uint8_t*)data
->editData()) + typeStart
); 
2567                 tHeader
->header
.size 
= htodl(data
->getSize()-typeStart
); 
2571         // Fill in the rest of the package information. 
2572         header 
= (ResTable_package
*)data
->editData(); 
2573         header
->header
.size 
= htodl(data
->getSize()); 
2574         header
->typeStrings 
= htodl(typeStringsStart
); 
2575         header
->lastPublicType 
= htodl(p
->getTypeStrings().size()); 
2576         header
->keyStrings 
= htodl(keyStringsStart
); 
2577         header
->lastPublicKey 
= htodl(p
->getKeyStrings().size()); 
2579         flatPackages
.add(data
); 
2582     // And now write out the final chunks. 
2583     const size_t dataStart 
= dest
->getSize(); 
2587         ResTable_header header
; 
2588         memset(&header
, 0, sizeof(header
)); 
2589         header
.header
.type 
= htods(RES_TABLE_TYPE
); 
2590         header
.header
.headerSize 
= htods(sizeof(header
)); 
2591         header
.packageCount 
= htodl(flatPackages
.size()); 
2592         status_t err 
= dest
->writeData(&header
, sizeof(header
)); 
2593         if (err 
!= NO_ERROR
) { 
2594             fprintf(stderr
, "ERROR: out of memory creating ResTable_header\n"); 
2599     ssize_t strStart 
= dest
->getSize(); 
2600     err 
= valueStrings
.writeStringBlock(dest
); 
2601     if (err 
!= NO_ERROR
) { 
2605     ssize_t amt 
= (dest
->getSize()-strStart
); 
2607     #if PRINT_STRING_METRICS 
2608     fprintf(stderr
, "**** value strings: %d\n", amt
); 
2609     fprintf(stderr
, "**** total strings: %d\n", strAmt
); 
2612     for (pi
=0; pi
<flatPackages
.size(); pi
++) { 
2613         err 
= dest
->writeData(flatPackages
[pi
]->getData(), 
2614                               flatPackages
[pi
]->getSize()); 
2615         if (err 
!= NO_ERROR
) { 
2616             fprintf(stderr
, "ERROR: out of memory creating package chunk for ResTable_header\n"); 
2621     ResTable_header
* header 
= (ResTable_header
*) 
2622         (((uint8_t*)dest
->getData()) + dataStart
); 
2623     header
->header
.size 
= htodl(dest
->getSize() - dataStart
); 
2625     NOISY(aout 
<< "Resource table:" 
2626           << HexDump(dest
->getData(), dest
->getSize()) << endl
); 
2628     #if PRINT_STRING_METRICS 
2629     fprintf(stderr
, "**** total resource table size: %d / %d%% strings\n", 
2630         dest
->getSize(), (strAmt
*100)/dest
->getSize()); 
2636 void ResourceTable::writePublicDefinitions(const String16
& package
, FILE* fp
) 
2639     "<!-- This file contains <public> resource definitions for all\n" 
2640     "     resources that were generated from the source data. -->\n" 
2644     writePublicDefinitions(package
, fp
, true); 
2645     writePublicDefinitions(package
, fp
, false); 
2652 void ResourceTable::writePublicDefinitions(const String16
& package
, FILE* fp
, bool pub
) 
2654     bool didHeader 
= false; 
2656     sp
<Package
> pkg 
= mPackages
.valueFor(package
); 
2658         const size_t NT 
= pkg
->getOrderedTypes().size(); 
2659         for (size_t i
=0; i
<NT
; i
++) { 
2660             sp
<Type
> t 
= pkg
->getOrderedTypes().itemAt(i
); 
2665             bool didType 
= false; 
2667             const size_t NC 
= t
->getOrderedConfigs().size(); 
2668             for (size_t j
=0; j
<NC
; j
++) { 
2669                 sp
<ConfigList
> c 
= t
->getOrderedConfigs().itemAt(j
); 
2674                 if (c
->getPublic() != pub
) { 
2684                         fprintf(fp
,"  <!-- PUBLIC SECTION.  These resources have been declared public.\n"); 
2685                         fprintf(fp
,"       Changes to these definitions will break binary compatibility. -->\n\n"); 
2687                         fprintf(fp
,"  <!-- PRIVATE SECTION.  These resources have not been declared public.\n"); 
2688                         fprintf(fp
,"       You can make them public my moving these lines into a file in res/values. -->\n\n"); 
2693                     const size_t NE 
= c
->getEntries().size(); 
2694                     for (size_t k
=0; k
<NE
; k
++) { 
2695                         const SourcePos
& pos 
= c
->getEntries().valueAt(k
)->getPos(); 
2696                         if (pos
.file 
!= "") { 
2697                             fprintf(fp
,"  <!-- Declared at %s:%d -->\n", 
2698                                     pos
.file
.string(), pos
.line
); 
2702                 fprintf(fp
, "  <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n", 
2703                         String8(t
->getName()).string(), 
2704                         String8(c
->getName()).string(), 
2705                         getResId(pkg
, t
, c
->getEntryIndex())); 
2711 ResourceTable::Item::Item(const SourcePos
& _sourcePos
, 
2713                           const String16
& _value
, 
2714                           const Vector
<StringPool::entry_style_span
>* _style
, 
2716     : sourcePos(_sourcePos
) 
2728 status_t 
ResourceTable::Entry::makeItABag(const SourcePos
& sourcePos
) 
2730     if (mType 
== TYPE_BAG
) { 
2733     if (mType 
== TYPE_UNKNOWN
) { 
2737     sourcePos
.error("Resource entry %s is already defined as a single item.\n" 
2738                     "%s:%d: Originally defined here.\n", 
2739                     String8(mName
).string(), 
2740                     mItem
.sourcePos
.file
.string(), mItem
.sourcePos
.line
); 
2741     return UNKNOWN_ERROR
; 
2744 status_t 
ResourceTable::Entry::setItem(const SourcePos
& sourcePos
, 
2745                                        const String16
& value
, 
2746                                        const Vector
<StringPool::entry_style_span
>* style
, 
2748                                        const bool overwrite
) 
2750     Item 
item(sourcePos
, false, value
, style
); 
2752     if (mType 
== TYPE_BAG
) { 
2753         const Item
& item(mBag
.valueAt(0)); 
2754         sourcePos
.error("Resource entry %s is already defined as a bag.\n" 
2755                         "%s:%d: Originally defined here.\n", 
2756                         String8(mName
).string(), 
2757                         item
.sourcePos
.file
.string(), item
.sourcePos
.line
); 
2758         return UNKNOWN_ERROR
; 
2760     if ( (mType 
!= TYPE_UNKNOWN
) && (overwrite 
== false) ) { 
2761         sourcePos
.error("Resource entry %s is already defined.\n" 
2762                         "%s:%d: Originally defined here.\n", 
2763                         String8(mName
).string(), 
2764                         mItem
.sourcePos
.file
.string(), mItem
.sourcePos
.line
); 
2765         return UNKNOWN_ERROR
; 
2770     mItemFormat 
= format
; 
2774 status_t 
ResourceTable::Entry::addToBag(const SourcePos
& sourcePos
, 
2775                                         const String16
& key
, const String16
& value
, 
2776                                         const Vector
<StringPool::entry_style_span
>* style
, 
2777                                         bool replace
, bool isId
, int32_t format
) 
2779     status_t err 
= makeItABag(sourcePos
); 
2780     if (err 
!= NO_ERROR
) { 
2784     Item 
item(sourcePos
, isId
, value
, style
, format
); 
2786     // XXX NOTE: there is an error if you try to have a bag with two keys, 
2787     // one an attr and one an id, with the same name.  Not something we 
2788     // currently ever have to worry about. 
2789     ssize_t origKey 
= mBag
.indexOfKey(key
); 
2792             const Item
& item(mBag
.valueAt(origKey
)); 
2793             sourcePos
.error("Resource entry %s already has bag item %s.\n" 
2794                     "%s:%d: Originally defined here.\n", 
2795                     String8(mName
).string(), String8(key
).string(), 
2796                     item
.sourcePos
.file
.string(), item
.sourcePos
.line
); 
2797             return UNKNOWN_ERROR
; 
2799         //printf("Replacing %s with %s\n", 
2800         //       String8(mBag.valueFor(key).value).string(), String8(value).string()); 
2801         mBag
.replaceValueFor(key
, item
); 
2804     mBag
.add(key
, item
); 
2808 status_t 
ResourceTable::Entry::emptyBag(const SourcePos
& sourcePos
) 
2810     status_t err 
= makeItABag(sourcePos
); 
2811     if (err 
!= NO_ERROR
) { 
2819 status_t 
ResourceTable::Entry::generateAttributes(ResourceTable
* table
, 
2820                                                   const String16
& package
) 
2822     const String16 
attr16("attr"); 
2823     const String16 
id16("id"); 
2824     const size_t N 
= mBag
.size(); 
2825     for (size_t i
=0; i
<N
; i
++) { 
2826         const String16
& key 
= mBag
.keyAt(i
); 
2827         const Item
& it 
= mBag
.valueAt(i
); 
2829             if (!table
->hasBagOrEntry(key
, &id16
, &package
)) { 
2830                 String16 
value("false"); 
2831                 status_t err 
= table
->addEntry(SourcePos(String8("<generated>"), 0), package
, 
2833                 if (err 
!= NO_ERROR
) { 
2837         } else if (!table
->hasBagOrEntry(key
, &attr16
, &package
)) { 
2840 //             fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n", 
2841 //                     String8(key).string()); 
2842 //             const Item& item(mBag.valueAt(i)); 
2843 //             fprintf(stderr, "Referenced from file %s line %d\n", 
2844 //                     item.sourcePos.file.string(), item.sourcePos.line); 
2845 //             return UNKNOWN_ERROR; 
2848             sprintf(numberStr
, "%d", ResTable_map::TYPE_ANY
); 
2849             status_t err 
= table
->addBag(SourcePos("<generated>", 0), package
, 
2850                                          attr16
, key
, String16(""), 
2852                                          String16(numberStr
), NULL
, NULL
); 
2853             if (err 
!= NO_ERROR
) { 
2862 status_t 
ResourceTable::Entry::assignResourceIds(ResourceTable
* table
, 
2863                                                  const String16
& package
) 
2865     bool hasErrors 
= false; 
2867     if (mType 
== TYPE_BAG
) { 
2868         const char* errorMsg
; 
2869         const String16 
style16("style"); 
2870         const String16 
attr16("attr"); 
2871         const String16 
id16("id"); 
2873         if (mParent
.size() > 0) { 
2874             mParentId 
= table
->getResId(mParent
, &style16
, NULL
, &errorMsg
); 
2875             if (mParentId 
== 0) { 
2876                 mPos
.error("Error retrieving parent for item: %s '%s'.\n", 
2877                         errorMsg
, String8(mParent
).string()); 
2881         const size_t N 
= mBag
.size(); 
2882         for (size_t i
=0; i
<N
; i
++) { 
2883             const String16
& key 
= mBag
.keyAt(i
); 
2884             Item
& it 
= mBag
.editValueAt(i
); 
2885             it
.bagKeyId 
= table
->getResId(key
, 
2886                     it
.isId 
? &id16 
: &attr16
, NULL
, &errorMsg
); 
2887             //printf("Bag key of %s: #%08x\n", String8(key).string(), it.bagKeyId); 
2888             if (it
.bagKeyId 
== 0) { 
2889                 it
.sourcePos
.error("Error: %s: %s '%s'.\n", errorMsg
, 
2890                         String8(it
.isId 
? id16 
: attr16
).string(), 
2891                         String8(key
).string()); 
2896     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
2899 status_t 
ResourceTable::Entry::prepareFlatten(StringPool
* strings
, ResourceTable
* table
) 
2901     if (mType 
== TYPE_ITEM
) { 
2903         AccessorCookie 
ac(it
.sourcePos
, String8(mName
), String8(it
.value
)); 
2904         if (!table
->stringToValue(&it
.parsedValue
, strings
, 
2905                                   it
.value
, false, true, 0, 
2906                                   &it
.style
, NULL
, &ac
, mItemFormat
)) { 
2907             return UNKNOWN_ERROR
; 
2909     } else if (mType 
== TYPE_BAG
) { 
2910         const size_t N 
= mBag
.size(); 
2911         for (size_t i
=0; i
<N
; i
++) { 
2912             const String16
& key 
= mBag
.keyAt(i
); 
2913             Item
& it 
= mBag
.editValueAt(i
); 
2914             AccessorCookie 
ac(it
.sourcePos
, String8(key
), String8(it
.value
)); 
2915             if (!table
->stringToValue(&it
.parsedValue
, strings
, 
2916                                       it
.value
, false, true, it
.bagKeyId
, 
2917                                       &it
.style
, NULL
, &ac
, it
.format
)) { 
2918                 return UNKNOWN_ERROR
; 
2922         mPos
.error("Error: entry %s is not a single item or a bag.\n", 
2923                    String8(mName
).string()); 
2924         return UNKNOWN_ERROR
; 
2929 ssize_t 
ResourceTable::Entry::flatten(Bundle
* bundle
, const sp
<AaptFile
>& data
, bool isPublic
) 
2932     ResTable_entry header
; 
2933     memset(&header
, 0, sizeof(header
)); 
2934     header
.size 
= htods(sizeof(header
)); 
2935     const type ty 
= this != NULL 
? mType 
: TYPE_ITEM
; 
2937         if (ty 
== TYPE_BAG
) { 
2938             header
.flags 
|= htods(header
.FLAG_COMPLEX
); 
2941             header
.flags 
|= htods(header
.FLAG_PUBLIC
); 
2943         header
.key
.index 
= htodl(mNameIndex
); 
2945     if (ty 
!= TYPE_BAG
) { 
2946         status_t err 
= data
->writeData(&header
, sizeof(header
)); 
2947         if (err 
!= NO_ERROR
) { 
2948             fprintf(stderr
, "ERROR: out of memory creating ResTable_entry\n"); 
2952         const Item
& it 
= mItem
; 
2954         memset(&par
, 0, sizeof(par
)); 
2955         par
.size 
= htods(it
.parsedValue
.size
); 
2956         par
.dataType 
= it
.parsedValue
.dataType
; 
2957         par
.res0 
= it
.parsedValue
.res0
; 
2958         par
.data 
= htodl(it
.parsedValue
.data
); 
2960         printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n", 
2961                String8(mName
).string(), it
.parsedValue
.dataType
, 
2962                it
.parsedValue
.data
, par
.res0
); 
2964         err 
= data
->writeData(&par
, it
.parsedValue
.size
); 
2965         if (err 
!= NO_ERROR
) { 
2966             fprintf(stderr
, "ERROR: out of memory creating Res_value\n"); 
2969         amt 
+= it
.parsedValue
.size
; 
2971         size_t N 
= mBag
.size(); 
2973         // Create correct ordering of items. 
2974         KeyedVector
<uint32_t, const Item
*> items
; 
2975         for (i
=0; i
<N
; i
++) { 
2976             const Item
& it 
= mBag
.valueAt(i
); 
2977             items
.add(it
.bagKeyId
, &it
); 
2981         ResTable_map_entry mapHeader
; 
2982         memcpy(&mapHeader
, &header
, sizeof(header
)); 
2983         mapHeader
.size 
= htods(sizeof(mapHeader
)); 
2984         mapHeader
.parent
.ident 
= htodl(mParentId
); 
2985         mapHeader
.count 
= htodl(N
); 
2986         status_t err 
= data
->writeData(&mapHeader
, sizeof(mapHeader
)); 
2987         if (err 
!= NO_ERROR
) { 
2988             fprintf(stderr
, "ERROR: out of memory creating ResTable_entry\n"); 
2992         for (i
=0; i
<N
; i
++) { 
2993             const Item
& it 
= *items
.valueAt(i
); 
2995             map
.name
.ident 
= htodl(it
.bagKeyId
); 
2996             map
.value
.size 
= htods(it
.parsedValue
.size
); 
2997             map
.value
.dataType 
= it
.parsedValue
.dataType
; 
2998             map
.value
.res0 
= it
.parsedValue
.res0
; 
2999             map
.value
.data 
= htodl(it
.parsedValue
.data
); 
3000             err 
= data
->writeData(&map
, sizeof(map
)); 
3001             if (err 
!= NO_ERROR
) { 
3002                 fprintf(stderr
, "ERROR: out of memory creating Res_value\n"); 
3011 void ResourceTable::ConfigList::appendComment(const String16
& comment
, 
3014     if (comment
.size() <= 0) { 
3017     if (onlyIfEmpty 
&& mComment
.size() > 0) { 
3020     if (mComment
.size() > 0) { 
3021         mComment
.append(String16("\n")); 
3023     mComment
.append(comment
); 
3026 void ResourceTable::ConfigList::appendTypeComment(const String16
& comment
) 
3028     if (comment
.size() <= 0) { 
3031     if (mTypeComment
.size() > 0) { 
3032         mTypeComment
.append(String16("\n")); 
3034     mTypeComment
.append(comment
); 
3037 status_t 
ResourceTable::Type::addPublic(const SourcePos
& sourcePos
, 
3038                                         const String16
& name
, 
3039                                         const uint32_t ident
) 
3042     int32_t entryIdx 
= Res_GETENTRY(ident
); 
3044         sourcePos
.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n", 
3045                 String8(mName
).string(), String8(name
).string(), ident
); 
3046         return UNKNOWN_ERROR
; 
3050     int32_t typeIdx 
= Res_GETTYPE(ident
); 
3053         if (mPublicIndex 
> 0 && mPublicIndex 
!= typeIdx
) { 
3054             sourcePos
.error("Public resource %s/%s has conflicting type codes for its" 
3055                     " public identifiers (0x%x vs 0x%x).\n", 
3056                     String8(mName
).string(), String8(name
).string(), 
3057                     mPublicIndex
, typeIdx
); 
3058             return UNKNOWN_ERROR
; 
3060         mPublicIndex 
= typeIdx
; 
3063     if (mFirstPublicSourcePos 
== NULL
) { 
3064         mFirstPublicSourcePos 
= new SourcePos(sourcePos
); 
3067     if (mPublic
.indexOfKey(name
) < 0) { 
3068         mPublic
.add(name
, Public(sourcePos
, String16(), ident
)); 
3070         Public
& p 
= mPublic
.editValueFor(name
); 
3071         if (p
.ident 
!= ident
) { 
3072             sourcePos
.error("Public resource %s/%s has conflicting public identifiers" 
3073                     " (0x%08x vs 0x%08x).\n" 
3074                     "%s:%d: Originally defined here.\n", 
3075                     String8(mName
).string(), String8(name
).string(), p
.ident
, ident
, 
3076                     p
.sourcePos
.file
.string(), p
.sourcePos
.line
); 
3077             return UNKNOWN_ERROR
; 
3084 sp
<ResourceTable::Entry
> ResourceTable::Type::getEntry(const String16
& entry
, 
3085                                                        const SourcePos
& sourcePos
, 
3086                                                        const ResTable_config
* config
, 
3090     sp
<ConfigList
> c 
= mConfigs
.valueFor(entry
); 
3092         c 
= new ConfigList(entry
, sourcePos
); 
3093         mConfigs
.add(entry
, c
); 
3094         pos 
= (int)mOrderedConfigs
.size(); 
3095         mOrderedConfigs
.add(c
); 
3097             c
->setEntryIndex(pos
); 
3101     ConfigDescription cdesc
; 
3102     if (config
) cdesc 
= *config
; 
3104     sp
<Entry
> e 
= c
->getEntries().valueFor(cdesc
); 
3106         if (config 
!= NULL
) { 
3107             NOISY(printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c " 
3108                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", 
3109                       sourcePos
.file
.string(), sourcePos
.line
, 
3110                       config
->mcc
, config
->mnc
, 
3111                       config
->language
[0] ? config
->language
[0] : '-', 
3112                       config
->language
[1] ? config
->language
[1] : '-', 
3113                       config
->country
[0] ? config
->country
[0] : '-', 
3114                       config
->country
[1] ? config
->country
[1] : '-', 
3115                       config
->orientation
, 
3116                       config
->touchscreen
, 
3121                       config
->screenWidth
, 
3122                       config
->screenHeight
)); 
3124             NOISY(printf("New entry at %s:%d: NULL config\n", 
3125                       sourcePos
.file
.string(), sourcePos
.line
)); 
3127         e 
= new Entry(entry
, sourcePos
); 
3128         c
->addEntry(cdesc
, e
); 
3132                 for (pos=0; pos<(int)mOrderedConfigs.size(); pos++) { 
3133                     if (mOrderedConfigs[pos] == c) { 
3137                 if (pos >= (int)mOrderedConfigs.size()) { 
3138                     sourcePos.error("Internal error: config not found in mOrderedConfigs when adding entry"); 
3142             e->setEntryIndex(pos); 
3147     mUniqueConfigs
.add(cdesc
); 
3152 status_t 
ResourceTable::Type::applyPublicEntryOrder() 
3154     size_t N 
= mOrderedConfigs
.size(); 
3155     Vector
<sp
<ConfigList
> > origOrder(mOrderedConfigs
); 
3156     bool hasError 
= false; 
3159     for (i
=0; i
<N
; i
++) { 
3160         mOrderedConfigs
.replaceAt(NULL
, i
); 
3163     const size_t NP 
= mPublic
.size(); 
3164     //printf("Ordering %d configs from %d public defs\n", N, NP); 
3166     for (j
=0; j
<NP
; j
++) { 
3167         const String16
& name 
= mPublic
.keyAt(j
); 
3168         const Public
& p 
= mPublic
.valueAt(j
); 
3169         int32_t idx 
= Res_GETENTRY(p
.ident
); 
3170         //printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n", 
3171         //       String8(mName).string(), String8(name).string(), p.ident, N); 
3173         for (i
=0; i
<N
; i
++) { 
3174             sp
<ConfigList
> e 
= origOrder
.itemAt(i
); 
3175             //printf("#%d: \"%s\"\n", i, String8(e->getName()).string()); 
3176             if (e
->getName() == name
) { 
3177                 if (idx 
>= (int32_t)mOrderedConfigs
.size()) { 
3178                     p
.sourcePos
.error("Public entry identifier 0x%x entry index " 
3179                             "is larger than available symbols (index %d, total symbols %d).\n", 
3180                             p
.ident
, idx
, mOrderedConfigs
.size()); 
3182                 } else if (mOrderedConfigs
.itemAt(idx
) == NULL
) { 
3184                     e
->setPublicSourcePos(p
.sourcePos
); 
3185                     mOrderedConfigs
.replaceAt(e
, idx
); 
3186                     origOrder
.removeAt(i
); 
3191                     sp
<ConfigList
> oe 
= mOrderedConfigs
.itemAt(idx
); 
3193                     p
.sourcePos
.error("Multiple entry names declared for public entry" 
3194                             " identifier 0x%x in type %s (%s vs %s).\n" 
3195                             "%s:%d: Originally defined here.", 
3196                             idx
+1, String8(mName
).string(), 
3197                             String8(oe
->getName()).string(), 
3198                             String8(name
).string(), 
3199                             oe
->getPublicSourcePos().file
.string(), 
3200                             oe
->getPublicSourcePos().line
); 
3207             p
.sourcePos
.error("Public symbol %s/%s declared here is not defined.", 
3208                     String8(mName
).string(), String8(name
).string()); 
3213     //printf("Copying back in %d non-public configs, have %d\n", N, origOrder.size()); 
3215     if (N 
!= origOrder
.size()) { 
3216         printf("Internal error: remaining private symbol count mismatch\n"); 
3217         N 
= origOrder
.size(); 
3221     for (i
=0; i
<N
; i
++) { 
3222         sp
<ConfigList
> e 
= origOrder
.itemAt(i
); 
3223         // There will always be enough room for the remaining entries. 
3224         while (mOrderedConfigs
.itemAt(j
) != NULL
) { 
3227         mOrderedConfigs
.replaceAt(e
, j
); 
3231     return hasError 
? UNKNOWN_ERROR 
: NO_ERROR
; 
3234 ResourceTable::Package::Package(const String16
& name
, ssize_t includedId
) 
3235     : mName(name
), mIncludedId(includedId
), 
3236       mTypeStringsMapping(0xffffffff), 
3237       mKeyStringsMapping(0xffffffff) 
3241 sp
<ResourceTable::Type
> ResourceTable::Package::getType(const String16
& type
, 
3242                                                         const SourcePos
& sourcePos
, 
3245     sp
<Type
> t 
= mTypes
.valueFor(type
); 
3247         t 
= new Type(type
, sourcePos
); 
3248         mTypes
.add(type
, t
); 
3249         mOrderedTypes
.add(t
); 
3251             // For some reason the type's index is set to one plus the index 
3252             // in the mOrderedTypes list, rather than just the index. 
3253             t
->setIndex(mOrderedTypes
.size()); 
3259 status_t 
ResourceTable::Package::setTypeStrings(const sp
<AaptFile
>& data
) 
3261     mTypeStringsData 
= data
; 
3262     status_t err 
= setStrings(data
, &mTypeStrings
, &mTypeStringsMapping
); 
3263     if (err 
!= NO_ERROR
) { 
3264         fprintf(stderr
, "ERROR: Type string data is corrupt!\n"); 
3269 status_t 
ResourceTable::Package::setKeyStrings(const sp
<AaptFile
>& data
) 
3271     mKeyStringsData 
= data
; 
3272     status_t err 
= setStrings(data
, &mKeyStrings
, &mKeyStringsMapping
); 
3273     if (err 
!= NO_ERROR
) { 
3274         fprintf(stderr
, "ERROR: Key string data is corrupt!\n"); 
3279 status_t 
ResourceTable::Package::setStrings(const sp
<AaptFile
>& data
, 
3280                                             ResStringPool
* strings
, 
3281                                             DefaultKeyedVector
<String16
, uint32_t>* mappings
) 
3283     if (data
->getData() == NULL
) { 
3284         return UNKNOWN_ERROR
; 
3287     NOISY(aout 
<< "Setting restable string pool: " 
3288           << HexDump(data
->getData(), data
->getSize()) << endl
); 
3290     status_t err 
= strings
->setTo(data
->getData(), data
->getSize()); 
3291     if (err 
== NO_ERROR
) { 
3292         const size_t N 
= strings
->size(); 
3293         for (size_t i
=0; i
<N
; i
++) { 
3295             mappings
->add(String16(strings
->stringAt(i
, &len
)), i
); 
3301 status_t 
ResourceTable::Package::applyPublicTypeOrder() 
3303     size_t N 
= mOrderedTypes
.size(); 
3304     Vector
<sp
<Type
> > origOrder(mOrderedTypes
); 
3307     for (i
=0; i
<N
; i
++) { 
3308         mOrderedTypes
.replaceAt(NULL
, i
); 
3311     for (i
=0; i
<N
; i
++) { 
3312         sp
<Type
> t 
= origOrder
.itemAt(i
); 
3313         int32_t idx 
= t
->getPublicIndex(); 
3316             while (idx 
>= (int32_t)mOrderedTypes
.size()) { 
3317                 mOrderedTypes
.add(); 
3319             if (mOrderedTypes
.itemAt(idx
) != NULL
) { 
3320                 sp
<Type
> ot 
= mOrderedTypes
.itemAt(idx
); 
3321                 t
->getFirstPublicSourcePos().error("Multiple type names declared for public type" 
3322                         " identifier 0x%x (%s vs %s).\n" 
3323                         "%s:%d: Originally defined here.", 
3324                         idx
, String8(ot
->getName()).string(), 
3325                         String8(t
->getName()).string(), 
3326                         ot
->getFirstPublicSourcePos().file
.string(), 
3327                         ot
->getFirstPublicSourcePos().line
); 
3328                 return UNKNOWN_ERROR
; 
3330             mOrderedTypes
.replaceAt(t
, idx
); 
3331             origOrder
.removeAt(i
); 
3338     for (i
=0; i
<N
; i
++) { 
3339         sp
<Type
> t 
= origOrder
.itemAt(i
); 
3340         // There will always be enough room for the remaining types. 
3341         while (mOrderedTypes
.itemAt(j
) != NULL
) { 
3344         mOrderedTypes
.replaceAt(t
, j
); 
3350 sp
<ResourceTable::Package
> ResourceTable::getPackage(const String16
& package
) 
3352     sp
<Package
> p 
= mPackages
.valueFor(package
); 
3354         if (mIsAppPackage
) { 
3355             if (mHaveAppPackage
) { 
3356                 fprintf(stderr
, "Adding multiple application package resources; only one is allowed.\n" 
3357                                 "Use -x to create extended resources.\n"); 
3360             mHaveAppPackage 
= true; 
3361             p 
= new Package(package
, 127); 
3363             p 
= new Package(package
, mNextPackageId
); 
3365         //printf("*** NEW PACKAGE: \"%s\" id=%d\n", 
3366         //       String8(package).string(), p->getAssignedId()); 
3367         mPackages
.add(package
, p
); 
3368         mOrderedPackages
.add(p
); 
3374 sp
<ResourceTable::Type
> ResourceTable::getType(const String16
& package
, 
3375                                                const String16
& type
, 
3376                                                const SourcePos
& sourcePos
, 
3379     sp
<Package
> p 
= getPackage(package
); 
3383     return p
->getType(type
, sourcePos
, doSetIndex
); 
3386 sp
<ResourceTable::Entry
> ResourceTable::getEntry(const String16
& package
, 
3387                                                  const String16
& type
, 
3388                                                  const String16
& name
, 
3389                                                  const SourcePos
& sourcePos
, 
3390                                                  const ResTable_config
* config
, 
3393     sp
<Type
> t 
= getType(package
, type
, sourcePos
, doSetIndex
); 
3397     return t
->getEntry(name
, sourcePos
, config
, doSetIndex
); 
3400 sp
<const ResourceTable::Entry
> ResourceTable::getEntry(uint32_t resID
, 
3401                                                        const ResTable_config
* config
) const 
3403     int pid 
= Res_GETPACKAGE(resID
)+1; 
3404     const size_t N 
= mOrderedPackages
.size(); 
3407     for (i
=0; i
<N
; i
++) { 
3408         sp
<Package
> check 
= mOrderedPackages
[i
]; 
3409         if (check
->getAssignedId() == pid
) { 
3416         fprintf(stderr
, "WARNING: Package not found for resource #%08x\n", resID
); 
3420     int tid 
= Res_GETTYPE(resID
); 
3421     if (tid 
< 0 || tid 
>= (int)p
->getOrderedTypes().size()) { 
3422         fprintf(stderr
, "WARNING: Type not found for resource #%08x\n", resID
); 
3425     sp
<Type
> t 
= p
->getOrderedTypes()[tid
]; 
3427     int eid 
= Res_GETENTRY(resID
); 
3428     if (eid 
< 0 || eid 
>= (int)t
->getOrderedConfigs().size()) { 
3429         fprintf(stderr
, "WARNING: Entry not found for resource #%08x\n", resID
); 
3433     sp
<ConfigList
> c 
= t
->getOrderedConfigs()[eid
]; 
3435         fprintf(stderr
, "WARNING: Entry not found for resource #%08x\n", resID
); 
3439     ConfigDescription cdesc
; 
3440     if (config
) cdesc 
= *config
; 
3441     sp
<Entry
> e 
= c
->getEntries().valueFor(cdesc
); 
3443         fprintf(stderr
, "WARNING: Entry configuration not found for resource #%08x\n", resID
); 
3450 const ResourceTable::Item
* ResourceTable::getItem(uint32_t resID
, uint32_t attrID
) const 
3452     sp
<const Entry
> e 
= getEntry(resID
); 
3457     const size_t N 
= e
->getBag().size(); 
3458     for (size_t i
=0; i
<N
; i
++) { 
3459         const Item
& it 
= e
->getBag().valueAt(i
); 
3460         if (it
.bagKeyId 
== 0) { 
3461             fprintf(stderr
, "WARNING: ID not yet assigned to '%s' in bag '%s'\n", 
3462                     String8(e
->getName()).string(), 
3463                     String8(e
->getBag().keyAt(i
)).string()); 
3465         if (it
.bagKeyId 
== attrID
) { 
3473 bool ResourceTable::getItemValue( 
3474     uint32_t resID
, uint32_t attrID
, Res_value
* outValue
) 
3476     const Item
* item 
= getItem(resID
, attrID
); 
3480         if (item
->evaluating
) { 
3481             sp
<const Entry
> e 
= getEntry(resID
); 
3482             const size_t N 
= e
->getBag().size(); 
3484             for (i
=0; i
<N
; i
++) { 
3485                 if (&e
->getBag().valueAt(i
) == item
) { 
3489             fprintf(stderr
, "WARNING: Circular reference detected in key '%s' of bag '%s'\n", 
3490                     String8(e
->getName()).string(), 
3491                     String8(e
->getBag().keyAt(i
)).string()); 
3494         item
->evaluating 
= true; 
3495         res 
= stringToValue(outValue
, NULL
, item
->value
, false, false, item
->bagKeyId
); 
3498                 printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n", 
3499                        resID
, attrID
, String8(getEntry(resID
)->getName()).string(), 
3500                        outValue
->dataType
, outValue
->data
); 
3502                 printf("getItemValue of #%08x[#%08x]: failed\n", 
3506         item
->evaluating 
= false;