2 // Copyright 2006 The Android Open Source Project 
   4 // Build resource files from raw assets. 
   7 #include "AaptAssets.h" 
   8 #include "StringPool.h" 
  10 #include "ResourceTable.h" 
  15 // ========================================================================== 
  16 // ========================================================================== 
  17 // ========================================================================== 
  29     status_t 
parsePackage(const sp
<AaptGroup
>& grp
); 
  32 // ========================================================================== 
  33 // ========================================================================== 
  34 // ========================================================================== 
  36 static String8 
parseResourceName(const String8
& leaf
) 
  38     const char* firstDot 
= strchr(leaf
.string(), '.'); 
  39     const char* str 
= leaf
.string(); 
  42         return String8(str
, firstDot
-str
); 
  48 ResourceTypeSet::ResourceTypeSet() 
  50      KeyedVector
<String8
,sp
<AaptGroup
> >() 
  54 class ResourceDirIterator
 
  57     ResourceDirIterator(const sp
<ResourceTypeSet
>& set
, const String8
& resType
) 
  58         : mResType(resType
), mSet(set
), mSetPos(0), mGroupPos(0) 
  62     inline const sp
<AaptGroup
>& getGroup() const { return mGroup
; } 
  63     inline const sp
<AaptFile
>& getFile() const { return mFile
; } 
  65     inline const String8
& getBaseName() const { return mBaseName
; } 
  66     inline const String8
& getLeafName() const { return mLeafName
; } 
  67     inline String8 
getPath() const { return mPath
; } 
  68     inline const ResTable_config
& getParams() const { return mParams
; } 
  80             // Try to get next file in this current group. 
  81             if (mGroup 
!= NULL 
&& mGroupPos 
< mGroup
->getFiles().size()) { 
  83                 file 
= group
->getFiles().valueAt(mGroupPos
++); 
  85             // Try to get the next group/file in this directory 
  86             } else if (mSetPos 
< mSet
->size()) { 
  87                 mGroup 
= group 
= mSet
->valueAt(mSetPos
++); 
  88                 if (group
->getFiles().size() < 1) { 
  91                 file 
= group
->getFiles().valueAt(0); 
 101             String8 
leaf(group
->getLeaf()); 
 102             mLeafName 
= String8(leaf
); 
 103             mParams 
= file
->getGroupEntry().toParams(); 
 104             NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n", 
 105                    group
->getPath().string(), mParams
.mcc
, mParams
.mnc
, 
 106                    mParams
.language
[0] ? mParams
.language
[0] : '-', 
 107                    mParams
.language
[1] ? mParams
.language
[1] : '-', 
 108                    mParams
.country
[0] ? mParams
.country
[0] : '-', 
 109                    mParams
.country
[1] ? mParams
.country
[1] : '-', 
 110                    mParams
.orientation
, mParams
.uiMode
, 
 111                    mParams
.density
, mParams
.touchscreen
, mParams
.keyboard
, 
 112                    mParams
.inputFlags
, mParams
.navigation
)); 
 114             mPath
.appendPath(file
->getGroupEntry().toDirName(mResType
)); 
 115             mPath
.appendPath(leaf
); 
 116             mBaseName 
= parseResourceName(leaf
); 
 117             if (mBaseName 
== "") { 
 118                 fprintf(stderr
, "Error: malformed resource filename %s\n", 
 119                         file
->getPrintableSource().string()); 
 120                 return UNKNOWN_ERROR
; 
 123             NOISY(printf("file name=%s\n", mBaseName
.string())); 
 132     const sp
<ResourceTypeSet
> mSet
; 
 135     sp
<AaptGroup
> mGroup
; 
 142     ResTable_config mParams
; 
 145 // ========================================================================== 
 146 // ========================================================================== 
 147 // ========================================================================== 
 149 bool isValidResourceType(const String8
& type
) 
 151     return type 
== "anim" || type 
== "drawable" || type 
== "layout" 
 152         || type 
== "values" || type 
== "xml" || type 
== "raw" 
 153         || type 
== "color" || type 
== "menu"; 
 156 static sp
<AaptFile
> getResourceFile(const sp
<AaptAssets
>& assets
, bool makeIfNecessary
=true) 
 158     sp
<AaptGroup
> group 
= assets
->getFiles().valueFor(String8("resources.arsc")); 
 161         file 
= group
->getFiles().valueFor(AaptGroupEntry()); 
 167     if (!makeIfNecessary
) { 
 170     return assets
->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(), 
 174 static status_t 
parsePackage(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 175     const sp
<AaptGroup
>& grp
) 
 177     if (grp
->getFiles().size() != 1) { 
 178         fprintf(stderr
, "warning: Multiple AndroidManifest.xml files found, using %s\n", 
 179                 grp
->getFiles().valueAt(0)->getPrintableSource().string()); 
 182     sp
<AaptFile
> file 
= grp
->getFiles().valueAt(0); 
 185     status_t err 
= parseXMLResource(file
, &block
); 
 186     if (err 
!= NO_ERROR
) { 
 189     //printXMLBlock(&block); 
 191     ResXMLTree::event_code_t code
; 
 192     while ((code
=block
.next()) != ResXMLTree::START_TAG
 
 193            && code 
!= ResXMLTree::END_DOCUMENT
 
 194            && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 198     if (code 
!= ResXMLTree::START_TAG
) { 
 199         fprintf(stderr
, "%s:%d: No start tag found\n", 
 200                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 201         return UNKNOWN_ERROR
; 
 203     if (strcmp16(block
.getElementName(&len
), String16("manifest").string()) != 0) { 
 204         fprintf(stderr
, "%s:%d: Invalid start tag %s, expected <manifest>\n", 
 205                 file
->getPrintableSource().string(), block
.getLineNumber(), 
 206                 String8(block
.getElementName(&len
)).string()); 
 207         return UNKNOWN_ERROR
; 
 210     ssize_t nameIndex 
= block
.indexOfAttribute(NULL
, "package"); 
 212         fprintf(stderr
, "%s:%d: <manifest> does not have package attribute.\n", 
 213                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 214         return UNKNOWN_ERROR
; 
 217     assets
->setPackage(String8(block
.getAttributeStringValue(nameIndex
, &len
))); 
 219     String16 
uses_sdk16("uses-sdk"); 
 220     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 221            && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 222         if (code 
== ResXMLTree::START_TAG
) { 
 223             if (strcmp16(block
.getElementName(&len
), uses_sdk16
.string()) == 0) { 
 224                 ssize_t minSdkIndex 
= block
.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE
, 
 226                 if (minSdkIndex 
>= 0) { 
 227                     const uint16_t* minSdk16 
= block
.getAttributeStringValue(minSdkIndex
, &len
); 
 228                     const char* minSdk8 
= strdup(String8(minSdk16
).string()); 
 229                     bundle
->setManifestMinSdkVersion(minSdk8
); 
 238 // ========================================================================== 
 239 // ========================================================================== 
 240 // ========================================================================== 
 242 static status_t 
makeFileResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 243                                   ResourceTable
* table
, 
 244                                   const sp
<ResourceTypeSet
>& set
, 
 247     String8 
type8(resType
); 
 248     String16 
type16(resType
); 
 250     bool hasErrors 
= false; 
 252     ResourceDirIterator 
it(set
, String8(resType
)); 
 254     while ((res
=it
.next()) == NO_ERROR
) { 
 255         if (bundle
->getVerbose()) { 
 256             printf("    (new resource id %s from %s)\n", 
 257                    it
.getBaseName().string(), it
.getFile()->getPrintableSource().string()); 
 259         String16 
baseName(it
.getBaseName()); 
 260         const char16_t* str 
= baseName
.string(); 
 261         const char16_t* const end 
= str 
+ baseName
.size(); 
 263             if (!((*str 
>= 'a' && *str 
<= 'z') 
 264                     || (*str 
>= '0' && *str 
<= '9') 
 265                     || *str 
== '_' || *str 
== '.')) { 
 266                 fprintf(stderr
, "%s: Invalid file name: must contain only [a-z0-9_.]\n", 
 267                         it
.getPath().string()); 
 272         String8 resPath 
= it
.getPath(); 
 273         resPath
.convertToResPath(); 
 274         table
->addEntry(SourcePos(it
.getPath(), 0), String16(assets
->getPackage()), 
 280         assets
->addResource(it
.getLeafName(), resPath
, it
.getFile(), type8
); 
 283     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
 286 static status_t 
preProcessImages(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 287                           const sp
<ResourceTypeSet
>& set
) 
 289     ResourceDirIterator 
it(set
, String8("drawable")); 
 290     Vector
<sp
<AaptFile
> > newNameFiles
; 
 291     Vector
<String8
> newNamePaths
; 
 292     bool hasErrors 
= false; 
 294     while ((res
=it
.next()) == NO_ERROR
) { 
 295         res 
= preProcessImage(bundle
, assets
, it
.getFile(), NULL
); 
 296         if (res 
< NO_ERROR
) { 
 301     return (hasErrors 
|| (res 
< NO_ERROR
)) ? UNKNOWN_ERROR 
: NO_ERROR
; 
 304 status_t 
postProcessImages(const sp
<AaptAssets
>& assets
, 
 305                            ResourceTable
* table
, 
 306                            const sp
<ResourceTypeSet
>& set
) 
 308     ResourceDirIterator 
it(set
, String8("drawable")); 
 309     bool hasErrors 
= false; 
 311     while ((res
=it
.next()) == NO_ERROR
) { 
 312         res 
= postProcessImage(assets
, table
, it
.getFile()); 
 313         if (res 
< NO_ERROR
) { 
 318     return (hasErrors 
|| (res 
< NO_ERROR
)) ? UNKNOWN_ERROR 
: NO_ERROR
; 
 321 static void collect_files(const sp
<AaptDir
>& dir
, 
 322         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 324     const DefaultKeyedVector
<String8
, sp
<AaptGroup
> >& groups 
= dir
->getFiles(); 
 325     int N 
= groups
.size(); 
 326     for (int i
=0; i
<N
; i
++) { 
 327         String8 leafName 
= groups
.keyAt(i
); 
 328         const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
 330         const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files
 
 333         if (files
.size() == 0) { 
 337         String8 resType 
= files
.valueAt(0)->getResourceType(); 
 339         ssize_t index 
= resources
->indexOfKey(resType
); 
 342             sp
<ResourceTypeSet
> set 
= new ResourceTypeSet(); 
 343             set
->add(leafName
, group
); 
 344             resources
->add(resType
, set
); 
 346             sp
<ResourceTypeSet
> set 
= resources
->valueAt(index
); 
 347             index 
= set
->indexOfKey(leafName
); 
 349                 set
->add(leafName
, group
); 
 351                 sp
<AaptGroup
> existingGroup 
= set
->valueAt(index
); 
 352                 int M 
= files
.size(); 
 353                 for (int j
=0; j
<M
; j
++) { 
 354                     existingGroup
->addFile(files
.valueAt(j
)); 
 361 static void collect_files(const sp
<AaptAssets
>& ass
, 
 362         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 364     const Vector
<sp
<AaptDir
> >& dirs 
= ass
->resDirs(); 
 367     for (int i
=0; i
<N
; i
++) { 
 368         sp
<AaptDir
> d 
= dirs
.itemAt(i
); 
 369         collect_files(d
, resources
); 
 371         // don't try to include the res dir 
 372         ass
->removeDir(d
->getLeaf()); 
 379     ATTR_LEADING_SPACES 
= -3, 
 380     ATTR_TRAILING_SPACES 
= -4 
 382 static int validateAttr(const String8
& path
, const ResTable
& table
, 
 383         const ResXMLParser
& parser
, 
 384         const char* ns
, const char* attr
, const char* validChars
, bool required
) 
 388     ssize_t index 
= parser
.indexOfAttribute(ns
, attr
); 
 391     if (index 
>= 0 && parser
.getAttributeValue(index
, &value
) >= 0) { 
 392         const ResStringPool
* pool 
= &parser
.getStrings(); 
 393         if (value
.dataType 
== Res_value::TYPE_REFERENCE
) { 
 394             uint32_t specFlags 
= 0; 
 396             if ((strIdx
=table
.resolveReference(&value
, 0x10000000, NULL
, &specFlags
)) < 0) { 
 397                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s references unknown resid 0x%08x.\n", 
 398                         path
.string(), parser
.getLineNumber(), 
 399                         String8(parser
.getElementName(&len
)).string(), attr
, 
 401                 return ATTR_NOT_FOUND
; 
 404             pool 
= table
.getTableStringBlock(strIdx
); 
 407                 str 
= pool
->stringAt(value
.data
, &len
); 
 409             printf("***** RES ATTR: %s specFlags=0x%x strIdx=%d: %s\n", attr
, 
 410                     specFlags
, strIdx
, str 
!= NULL 
? String8(str
).string() : "???"); 
 412             if ((specFlags
&~ResTable_typeSpec::SPEC_PUBLIC
) != 0 && false) { 
 413                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s varies by configurations 0x%x.\n", 
 414                         path
.string(), parser
.getLineNumber(), 
 415                         String8(parser
.getElementName(&len
)).string(), attr
, 
 417                 return ATTR_NOT_FOUND
; 
 420         if (value
.dataType 
== Res_value::TYPE_STRING
) { 
 422                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has no string block.\n", 
 423                         path
.string(), parser
.getLineNumber(), 
 424                         String8(parser
.getElementName(&len
)).string(), attr
); 
 425                 return ATTR_NOT_FOUND
; 
 427             if ((str
=pool
->stringAt(value
.data
, &len
)) == NULL
) { 
 428                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n", 
 429                         path
.string(), parser
.getLineNumber(), 
 430                         String8(parser
.getElementName(&len
)).string(), attr
); 
 431                 return ATTR_NOT_FOUND
; 
 434             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has invalid type %d.\n", 
 435                     path
.string(), parser
.getLineNumber(), 
 436                     String8(parser
.getElementName(&len
)).string(), attr
, 
 438             return ATTR_NOT_FOUND
; 
 441             for (size_t i
=0; i
<len
; i
++) { 
 443                 const char* p 
= validChars
; 
 453                     fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n", 
 454                             path
.string(), parser
.getLineNumber(), 
 455                             String8(parser
.getElementName(&len
)).string(), attr
, (char)str
[i
]); 
 461             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not start with a space.\n", 
 462                     path
.string(), parser
.getLineNumber(), 
 463                     String8(parser
.getElementName(&len
)).string(), attr
); 
 464             return ATTR_LEADING_SPACES
; 
 466         if (str
[len
-1] == ' ') { 
 467             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not end with a space.\n", 
 468                     path
.string(), parser
.getLineNumber(), 
 469                     String8(parser
.getElementName(&len
)).string(), attr
); 
 470             return ATTR_TRAILING_SPACES
; 
 475         fprintf(stderr
, "%s:%d: Tag <%s> missing required attribute %s.\n", 
 476                 path
.string(), parser
.getLineNumber(), 
 477                 String8(parser
.getElementName(&len
)).string(), attr
); 
 478         return ATTR_NOT_FOUND
; 
 483 static void checkForIds(const String8
& path
, ResXMLParser
& parser
) 
 485     ResXMLTree::event_code_t code
; 
 486     while ((code
=parser
.next()) != ResXMLTree::END_DOCUMENT
 
 487            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
 488         if (code 
== ResXMLTree::START_TAG
) { 
 489             ssize_t index 
= parser
.indexOfAttribute(NULL
, "id"); 
 491                 fprintf(stderr
, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n", 
 492                         path
.string(), parser
.getLineNumber()); 
 498 static bool applyFileOverlay(Bundle 
*bundle
, 
 499                              const sp
<AaptAssets
>& assets
, 
 500                              sp
<ResourceTypeSet
> *baseSet
, 
 503     if (bundle
->getVerbose()) { 
 504         printf("applyFileOverlay for %s\n", resType
); 
 507     // Replace any base level files in this category with any found from the overlay 
 508     // Also add any found only in the overlay. 
 509     sp
<AaptAssets
> overlay 
= assets
->getOverlay(); 
 510     String8 
resTypeString(resType
); 
 512     // work through the linked list of overlays 
 513     while (overlay
.get()) { 
 514         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* overlayRes 
= overlay
->getResources(); 
 516         // get the overlay resources of the requested type 
 517         ssize_t index 
= overlayRes
->indexOfKey(resTypeString
); 
 519             sp
<ResourceTypeSet
> overlaySet 
= overlayRes
->valueAt(index
); 
 521             // for each of the resources, check for a match in the previously built 
 522             // non-overlay "baseset". 
 523             size_t overlayCount 
= overlaySet
->size(); 
 524             for (size_t overlayIndex
=0; overlayIndex
<overlayCount
; overlayIndex
++) { 
 525                 if (bundle
->getVerbose()) { 
 526                     printf("trying overlaySet Key=%s\n",overlaySet
->keyAt(overlayIndex
).string()); 
 528                 size_t baseIndex 
= UNKNOWN_ERROR
; 
 529                 if (baseSet
->get() != NULL
) { 
 530                     baseIndex 
= (*baseSet
)->indexOfKey(overlaySet
->keyAt(overlayIndex
)); 
 532                 if (baseIndex 
< UNKNOWN_ERROR
) { 
 533                     // look for same flavor.  For a given file (strings.xml, for example) 
 534                     // there may be a locale specific or other flavors - we want to match 
 536                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 537                     sp
<AaptGroup
> baseGroup 
= (*baseSet
)->valueAt(baseIndex
); 
 539                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
= 
 540                             overlayGroup
->getFiles(); 
 541                     if (bundle
->getVerbose()) { 
 542                         DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > baseFiles 
= 
 543                                 baseGroup
->getFiles(); 
 544                         for (size_t i
=0; i 
< baseFiles
.size(); i
++) { 
 545                             printf("baseFile %d has flavor %s\n", i
, 
 546                                     baseFiles
.keyAt(i
).toString().string()); 
 548                         for (size_t i
=0; i 
< overlayFiles
.size(); i
++) { 
 549                             printf("overlayFile %d has flavor %s\n", i
, 
 550                                     overlayFiles
.keyAt(i
).toString().string()); 
 554                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 555                     for (size_t overlayGroupIndex 
= 0; 
 556                             overlayGroupIndex
<overlayGroupSize
; 
 557                             overlayGroupIndex
++) { 
 558                         size_t baseFileIndex 
= 
 559                                 baseGroup
->getFiles().indexOfKey(overlayFiles
. 
 560                                 keyAt(overlayGroupIndex
)); 
 561                         if(baseFileIndex 
< UNKNOWN_ERROR
) { 
 562                             if (bundle
->getVerbose()) { 
 563                                 printf("found a match (%d) for overlay file %s, for flavor %s\n", 
 565                                         overlayGroup
->getLeaf().string(), 
 566                                         overlayFiles
.keyAt(overlayGroupIndex
).toString().string()); 
 568                             baseGroup
->removeFile(baseFileIndex
); 
 570                             // didn't find a match fall through and add it.. 
 572                         baseGroup
->addFile(overlayFiles
.valueAt(overlayGroupIndex
)); 
 573                         assets
->addGroupEntry(overlayFiles
.keyAt(overlayGroupIndex
)); 
 576                     if (baseSet
->get() == NULL
) { 
 577                         *baseSet 
= new ResourceTypeSet(); 
 578                         assets
->getResources()->add(String8(resType
), *baseSet
); 
 580                     // this group doesn't exist (a file that's only in the overlay) 
 581                     (*baseSet
)->add(overlaySet
->keyAt(overlayIndex
), 
 582                             overlaySet
->valueAt(overlayIndex
)); 
 583                     // make sure all flavors are defined in the resources. 
 584                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 585                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
= 
 586                             overlayGroup
->getFiles(); 
 587                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 588                     for (size_t overlayGroupIndex 
= 0; 
 589                             overlayGroupIndex
<overlayGroupSize
; 
 590                             overlayGroupIndex
++) { 
 591                         assets
->addGroupEntry(overlayFiles
.keyAt(overlayGroupIndex
)); 
 595             // this overlay didn't have resources for this type 
 598         overlay 
= overlay
->getOverlay(); 
 603 void addTagAttribute(const sp
<XMLNode
>& node
, const char* ns8
, 
 604         const char* attr8
, const char* value
) 
 610     const String16 
ns(ns8
); 
 611     const String16 
attr(attr8
); 
 613     if (node
->getAttribute(ns
, attr
) != NULL
) { 
 614         fprintf(stderr
, "Warning: AndroidManifest.xml already defines %s (in %s);" 
 615                         " using existing value in manifest.\n", 
 616                 String8(attr
).string(), String8(ns
).string()); 
 620     node
->addAttribute(ns
, attr
, String16(value
)); 
 623 static void fullyQualifyClassName(const String8
& package
, sp
<XMLNode
> node
, 
 624         const String16
& attrName
) { 
 625     XMLNode::attribute_entry
* attr 
= node
->editAttribute( 
 626             String16("http://schemas.android.com/apk/res/android"), attrName
); 
 628         String8 
name(attr
->string
); 
 630         // asdf     --> package.asdf 
 631         // .asdf  .a.b  --> package.asdf package.a.b 
 632         // asdf.adsf --> asdf.asdf 
 634         const char* p 
= name
.string(); 
 635         const char* q 
= strchr(p
, '.'); 
 637             className 
+= package
; 
 639         } else if (q 
== NULL
) { 
 640             className 
+= package
; 
 646         NOISY(printf("Qualifying class '%s' to '%s'", name
.string(), className
.string())); 
 647         attr
->string
.setTo(String16(className
)); 
 651 status_t 
massageManifest(Bundle
* bundle
, sp
<XMLNode
> root
) 
 653     root 
= root
->searchElement(String16(), String16("manifest")); 
 655         fprintf(stderr
, "No <manifest> tag.\n"); 
 656         return UNKNOWN_ERROR
; 
 659     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionCode", 
 660             bundle
->getVersionCode()); 
 661     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionName", 
 662             bundle
->getVersionName()); 
 664     if (bundle
->getMinSdkVersion() != NULL
 
 665             || bundle
->getTargetSdkVersion() != NULL
 
 666             || bundle
->getMaxSdkVersion() != NULL
) { 
 667         sp
<XMLNode
> vers 
= root
->getChildElement(String16(), String16("uses-sdk")); 
 669             vers 
= XMLNode::newElement(root
->getFilename(), String16(), String16("uses-sdk")); 
 670             root
->insertChildAt(vers
, 0); 
 673         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "minSdkVersion", 
 674                 bundle
->getMinSdkVersion()); 
 675         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "targetSdkVersion", 
 676                 bundle
->getTargetSdkVersion()); 
 677         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "maxSdkVersion", 
 678                 bundle
->getMaxSdkVersion()); 
 681     // Deal with manifest package name overrides 
 682     const char* manifestPackageNameOverride 
= bundle
->getManifestPackageNameOverride(); 
 683     if (manifestPackageNameOverride 
!= NULL
) { 
 684         // Update the actual package name 
 685         XMLNode::attribute_entry
* attr 
= root
->editAttribute(String16(), String16("package")); 
 687             fprintf(stderr
, "package name is required with --rename-manifest-package.\n"); 
 688             return UNKNOWN_ERROR
; 
 690         String8 
origPackage(attr
->string
); 
 691         attr
->string
.setTo(String16(manifestPackageNameOverride
)); 
 692         NOISY(printf("Overriding package '%s' to be '%s'\n", origPackage
.string(), manifestPackageNameOverride
)); 
 694         // Make class names fully qualified 
 695         sp
<XMLNode
> application 
= root
->getChildElement(String16(), String16("application")); 
 696         if (application 
!= NULL
) { 
 697             fullyQualifyClassName(origPackage
, application
, String16("name")); 
 698             fullyQualifyClassName(origPackage
, application
, String16("backupAgent")); 
 700             Vector
<sp
<XMLNode
> >& children 
= const_cast<Vector
<sp
<XMLNode
> >&>(application
->getChildren()); 
 701             for (size_t i 
= 0; i 
< children
.size(); i
++) { 
 702                 sp
<XMLNode
> child 
= children
.editItemAt(i
); 
 703                 String8 
tag(child
->getElementName()); 
 704                 if (tag 
== "activity" || tag 
== "service" || tag 
== "receiver" || tag 
== "provider") { 
 705                     fullyQualifyClassName(origPackage
, child
, String16("name")); 
 706                 } else if (tag 
== "activity-alias") { 
 707                     fullyQualifyClassName(origPackage
, child
, String16("name")); 
 708                     fullyQualifyClassName(origPackage
, child
, String16("targetActivity")); 
 714     // Deal with manifest package name overrides 
 715     const char* instrumentationPackageNameOverride 
= bundle
->getInstrumentationPackageNameOverride(); 
 716     if (instrumentationPackageNameOverride 
!= NULL
) { 
 717         // Fix up instrumentation targets. 
 718         Vector
<sp
<XMLNode
> >& children 
= const_cast<Vector
<sp
<XMLNode
> >&>(root
->getChildren()); 
 719         for (size_t i 
= 0; i 
< children
.size(); i
++) { 
 720             sp
<XMLNode
> child 
= children
.editItemAt(i
); 
 721             String8 
tag(child
->getElementName()); 
 722             if (tag 
== "instrumentation") { 
 723                 XMLNode::attribute_entry
* attr 
= child
->editAttribute( 
 724                         String16("http://schemas.android.com/apk/res/android"), String16("targetPackage")); 
 726                     attr
->string
.setTo(String16(instrumentationPackageNameOverride
)); 
 735 #define ASSIGN_IT(n) \ 
 737             ssize_t index = resources->indexOfKey(String8(#n)); \ 
 739                 n ## s = resources->valueAt(index); \ 
 743 status_t 
buildResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
 745     // First, look for a package file to parse.  This is required to 
 746     // be able to generate the resource information. 
 747     sp
<AaptGroup
> androidManifestFile 
= 
 748             assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
 749     if (androidManifestFile 
== NULL
) { 
 750         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
 751         return UNKNOWN_ERROR
; 
 754     status_t err 
= parsePackage(bundle
, assets
, androidManifestFile
); 
 755     if (err 
!= NO_ERROR
) { 
 759     NOISY(printf("Creating resources for package %s\n", 
 760                  assets
->getPackage().string())); 
 762     ResourceTable 
table(bundle
, String16(assets
->getPackage())); 
 763     err 
= table
.addIncludedResources(bundle
, assets
); 
 764     if (err 
!= NO_ERROR
) { 
 768     NOISY(printf("Found %d included resource packages\n", (int)table
.size())); 
 770     // Standard flags for compiled XML and optional UTF-8 encoding 
 771     int xmlFlags 
= XML_COMPILE_STANDARD_RESOURCE
; 
 773     /* Only enable UTF-8 if the caller of aapt didn't specifically 
 774      * request UTF-16 encoding and the parameters of this package 
 775      * allow UTF-8 to be used. 
 777     if (!bundle
->getWantUTF16() 
 778             && bundle
->isMinSdkAtLeast(SDK_FROYO
)) { 
 779         xmlFlags 
|= XML_COMPILE_UTF8
; 
 782     // -------------------------------------------------------------- 
 783     // First, gather all resource information. 
 784     // -------------------------------------------------------------- 
 786     // resType -> leafName -> group 
 787     KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 788             new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 789     collect_files(assets
, resources
); 
 791     sp
<ResourceTypeSet
> drawables
; 
 792     sp
<ResourceTypeSet
> layouts
; 
 793     sp
<ResourceTypeSet
> anims
; 
 794     sp
<ResourceTypeSet
> xmls
; 
 795     sp
<ResourceTypeSet
> raws
; 
 796     sp
<ResourceTypeSet
> colors
; 
 797     sp
<ResourceTypeSet
> menus
; 
 807     assets
->setResources(resources
); 
 808     // now go through any resource overlays and collect their files 
 809     sp
<AaptAssets
> current 
= assets
->getOverlay(); 
 810     while(current
.get()) { 
 811         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 812                 new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 813         current
->setResources(resources
); 
 814         collect_files(current
, resources
); 
 815         current 
= current
->getOverlay(); 
 817     // apply the overlay files to the base set 
 818     if (!applyFileOverlay(bundle
, assets
, &drawables
, "drawable") || 
 819             !applyFileOverlay(bundle
, assets
, &layouts
, "layout") || 
 820             !applyFileOverlay(bundle
, assets
, &anims
, "anim") || 
 821             !applyFileOverlay(bundle
, assets
, &xmls
, "xml") || 
 822             !applyFileOverlay(bundle
, assets
, &raws
, "raw") || 
 823             !applyFileOverlay(bundle
, assets
, &colors
, "color") || 
 824             !applyFileOverlay(bundle
, assets
, &menus
, "menu")) { 
 825         return UNKNOWN_ERROR
; 
 828     bool hasErrors 
= false; 
 830     if (drawables 
!= NULL
) { 
 831         err 
= preProcessImages(bundle
, assets
, drawables
); 
 832         if (err 
== NO_ERROR
) { 
 833             err 
= makeFileResources(bundle
, assets
, &table
, drawables
, "drawable"); 
 834             if (err 
!= NO_ERROR
) { 
 842     if (layouts 
!= NULL
) { 
 843         err 
= makeFileResources(bundle
, assets
, &table
, layouts
, "layout"); 
 844         if (err 
!= NO_ERROR
) { 
 850         err 
= makeFileResources(bundle
, assets
, &table
, anims
, "anim"); 
 851         if (err 
!= NO_ERROR
) { 
 857         err 
= makeFileResources(bundle
, assets
, &table
, xmls
, "xml"); 
 858         if (err 
!= NO_ERROR
) { 
 864         err 
= makeFileResources(bundle
, assets
, &table
, raws
, "raw"); 
 865         if (err 
!= NO_ERROR
) { 
 872     while(current
.get()) { 
 873         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 874                 current
->getResources(); 
 876         ssize_t index 
= resources
->indexOfKey(String8("values")); 
 878             ResourceDirIterator 
it(resources
->valueAt(index
), String8("values")); 
 880             while ((res
=it
.next()) == NO_ERROR
) { 
 881                 sp
<AaptFile
> file 
= it
.getFile(); 
 882                 res 
= compileResourceFile(bundle
, assets
, file
, it
.getParams(),  
 883                                           (current
!=assets
), &table
); 
 884                 if (res 
!= NO_ERROR
) { 
 889         current 
= current
->getOverlay(); 
 892     if (colors 
!= NULL
) { 
 893         err 
= makeFileResources(bundle
, assets
, &table
, colors
, "color"); 
 894         if (err 
!= NO_ERROR
) { 
 900         err 
= makeFileResources(bundle
, assets
, &table
, menus
, "menu"); 
 901         if (err 
!= NO_ERROR
) { 
 906     // -------------------------------------------------------------------- 
 907     // Assignment of resource IDs and initial generation of resource table. 
 908     // -------------------------------------------------------------------- 
 910     if (table
.hasResources()) { 
 911         sp
<AaptFile
> resFile(getResourceFile(assets
)); 
 912         if (resFile 
== NULL
) { 
 913             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
 914             return UNKNOWN_ERROR
; 
 917         err 
= table
.assignResourceIds(); 
 918         if (err 
< NO_ERROR
) { 
 923     // -------------------------------------------------------------- 
 924     // Finally, we can now we can compile XML files, which may reference 
 926     // -------------------------------------------------------------- 
 928     if (layouts 
!= NULL
) { 
 929         ResourceDirIterator 
it(layouts
, String8("layout")); 
 930         while ((err
=it
.next()) == NO_ERROR
) { 
 931             String8 src 
= it
.getFile()->getPrintableSource(); 
 932             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
 933             if (err 
== NO_ERROR
) { 
 935                 block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
 936                 checkForIds(src
, block
); 
 942         if (err 
< NO_ERROR
) { 
 949         ResourceDirIterator 
it(anims
, String8("anim")); 
 950         while ((err
=it
.next()) == NO_ERROR
) { 
 951             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
 952             if (err 
!= NO_ERROR
) { 
 957         if (err 
< NO_ERROR
) { 
 964         ResourceDirIterator 
it(xmls
, String8("xml")); 
 965         while ((err
=it
.next()) == NO_ERROR
) { 
 966             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
 967             if (err 
!= NO_ERROR
) { 
 972         if (err 
< NO_ERROR
) { 
 978     if (drawables 
!= NULL
) { 
 979         err 
= postProcessImages(assets
, &table
, drawables
); 
 980         if (err 
!= NO_ERROR
) { 
 985     if (colors 
!= NULL
) { 
 986         ResourceDirIterator 
it(colors
, String8("color")); 
 987         while ((err
=it
.next()) == NO_ERROR
) { 
 988           err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
 989             if (err 
!= NO_ERROR
) { 
 994         if (err 
< NO_ERROR
) { 
1000     if (menus 
!= NULL
) { 
1001         ResourceDirIterator 
it(menus
, String8("menu")); 
1002         while ((err
=it
.next()) == NO_ERROR
) { 
1003             String8 src 
= it
.getFile()->getPrintableSource(); 
1004             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1005             if (err 
!= NO_ERROR
) { 
1009             block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
1010             checkForIds(src
, block
); 
1013         if (err 
< NO_ERROR
) { 
1019     if (table
.validateLocalizations()) { 
1024         return UNKNOWN_ERROR
; 
1027     const sp
<AaptFile
> manifestFile(androidManifestFile
->getFiles().valueAt(0)); 
1028     String8 
manifestPath(manifestFile
->getPrintableSource()); 
1030     // Generate final compiled manifest file. 
1031     manifestFile
->clearData(); 
1032     sp
<XMLNode
> manifestTree 
= XMLNode::parse(manifestFile
); 
1033     if (manifestTree 
== NULL
) { 
1034         return UNKNOWN_ERROR
; 
1036     err 
= massageManifest(bundle
, manifestTree
); 
1037     if (err 
< NO_ERROR
) { 
1040     err 
= compileXmlFile(assets
, manifestTree
, manifestFile
, &table
); 
1041     if (err 
< NO_ERROR
) { 
1046     //printXMLBlock(&block); 
1048     // -------------------------------------------------------------- 
1049     // Generate the final resource table. 
1050     // Re-flatten because we may have added new resource IDs 
1051     // -------------------------------------------------------------- 
1053     ResTable finalResTable
; 
1054     sp
<AaptFile
> resFile
; 
1056     if (table
.hasResources()) { 
1057         sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
1058         err 
= table
.addSymbols(symbols
); 
1059         if (err 
< NO_ERROR
) { 
1063         resFile 
= getResourceFile(assets
); 
1064         if (resFile 
== NULL
) { 
1065             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
1066             return UNKNOWN_ERROR
; 
1069         err 
= table
.flatten(bundle
, resFile
); 
1070         if (err 
< NO_ERROR
) { 
1074         if (bundle
->getPublicOutputFile()) { 
1075             FILE* fp 
= fopen(bundle
->getPublicOutputFile(), "w+"); 
1077                 fprintf(stderr
, "ERROR: Unable to open public definitions output file %s: %s\n", 
1078                         (const char*)bundle
->getPublicOutputFile(), strerror(errno
)); 
1079                 return UNKNOWN_ERROR
; 
1081             if (bundle
->getVerbose()) { 
1082                 printf("  Writing public definitions to %s.\n", bundle
->getPublicOutputFile()); 
1084             table
.writePublicDefinitions(String16(assets
->getPackage()), fp
); 
1088         // Read resources back in, 
1089         finalResTable
.add(resFile
->getData(), resFile
->getSize(), NULL
); 
1093               printf("Generated resources:\n"); 
1094               finalResTable
.print(); 
1099     // Perform a basic validation of the manifest file.  This time we 
1100     // parse it with the comments intact, so that we can use them to 
1101     // generate java docs...  so we are not going to write this one 
1102     // back out to the final manifest data. 
1103     sp
<AaptFile
> outManifestFile 
= new AaptFile(manifestFile
->getSourceFile(), 
1104             manifestFile
->getGroupEntry(), 
1105             manifestFile
->getResourceType()); 
1106     err 
= compileXmlFile(assets
, manifestFile
, 
1107             outManifestFile
, &table
, 
1108             XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
 
1109             | XML_COMPILE_STRIP_WHITESPACE 
| XML_COMPILE_STRIP_RAW_VALUES
); 
1110     if (err 
< NO_ERROR
) { 
1114     block
.setTo(outManifestFile
->getData(), outManifestFile
->getSize(), true); 
1115     String16 
manifest16("manifest"); 
1116     String16 
permission16("permission"); 
1117     String16 
permission_group16("permission-group"); 
1118     String16 
uses_permission16("uses-permission"); 
1119     String16 
instrumentation16("instrumentation"); 
1120     String16 
application16("application"); 
1121     String16 
provider16("provider"); 
1122     String16 
service16("service"); 
1123     String16 
receiver16("receiver"); 
1124     String16 
activity16("activity"); 
1125     String16 
action16("action"); 
1126     String16 
category16("category"); 
1127     String16 
data16("scheme"); 
1128     const char* packageIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1129         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789"; 
1130     const char* packageIdentCharsWithTheStupid 
= "abcdefghijklmnopqrstuvwxyz" 
1131         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
1132     const char* classIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1133         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789$"; 
1134     const char* processIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1135         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:"; 
1136     const char* authoritiesIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1137         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-:;"; 
1138     const char* typeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1139         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:-/*+"; 
1140     const char* schemeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1141         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
1142     ResXMLTree::event_code_t code
; 
1143     sp
<AaptSymbols
> permissionSymbols
; 
1144     sp
<AaptSymbols
> permissionGroupSymbols
; 
1145     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
1146            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
1147         if (code 
== ResXMLTree::START_TAG
) { 
1149             if (block
.getElementNamespace(&len
) != NULL
) { 
1152             if (strcmp16(block
.getElementName(&len
), manifest16
.string()) == 0) { 
1153                 if (validateAttr(manifestPath
, finalResTable
, block
, NULL
, "package", 
1154                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1157                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1158                                  "sharedUserId", packageIdentChars
, false) != ATTR_OKAY
) { 
1161             } else if (strcmp16(block
.getElementName(&len
), permission16
.string()) == 0 
1162                     || strcmp16(block
.getElementName(&len
), permission_group16
.string()) == 0) { 
1163                 const bool isGroup 
= strcmp16(block
.getElementName(&len
), 
1164                         permission_group16
.string()) == 0; 
1165                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1166                                  "name", isGroup 
? packageIdentCharsWithTheStupid
 
1167                                  : packageIdentChars
, true) != ATTR_OKAY
) { 
1170                 SourcePos 
srcPos(manifestPath
, block
.getLineNumber()); 
1171                 sp
<AaptSymbols
> syms
; 
1173                     syms 
= permissionSymbols
; 
1175                         sp
<AaptSymbols
> symbols 
= 
1176                                 assets
->getSymbolsFor(String8("Manifest")); 
1177                         syms 
= permissionSymbols 
= symbols
->addNestedSymbol( 
1178                                 String8("permission"), srcPos
); 
1181                     syms 
= permissionGroupSymbols
; 
1183                         sp
<AaptSymbols
> symbols 
= 
1184                                 assets
->getSymbolsFor(String8("Manifest")); 
1185                         syms 
= permissionGroupSymbols 
= symbols
->addNestedSymbol( 
1186                                 String8("permission_group"), srcPos
); 
1190                 ssize_t index 
= block
.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE
, "name"); 
1191                 const uint16_t* id 
= block
.getAttributeStringValue(index
, &len
); 
1193                     fprintf(stderr
, "%s:%d: missing name attribute in element <%s>.\n",  
1194                             manifestPath
.string(), block
.getLineNumber(), 
1195                             String8(block
.getElementName(&len
)).string()); 
1200                 char* p 
= idStr
.lockBuffer(idStr
.size()); 
1201                 char* e 
= p 
+ idStr
.size(); 
1202                 bool begins_with_digit 
= true;  // init to true so an empty string fails 
1205                     if (*e 
>= '0' && *e 
<= '9') { 
1206                       begins_with_digit 
= true; 
1209                     if ((*e 
>= 'a' && *e 
<= 'z') || 
1210                         (*e 
>= 'A' && *e 
<= 'Z') || 
1212                       begins_with_digit 
= false; 
1215                     if (isGroup 
&& (*e 
== '-')) { 
1217                         begins_with_digit 
= false; 
1223                 idStr
.unlockBuffer(); 
1224                 // verify that we stopped because we hit a period or 
1225                 // the beginning of the string, and that the 
1226                 // identifier didn't begin with a digit. 
1227                 if (begins_with_digit 
|| (e 
!= p 
&& *(e
-1) != '.')) { 
1229                           "%s:%d: Permission name <%s> is not a valid Java symbol\n", 
1230                           manifestPath
.string(), block
.getLineNumber(), idStr
.string()); 
1233                 syms
->addStringSymbol(String8(e
), idStr
, srcPos
); 
1234                 const uint16_t* cmt 
= block
.getComment(&len
); 
1235                 if (cmt 
!= NULL 
&& *cmt 
!= 0) { 
1236                     //printf("Comment of %s: %s\n", String8(e).string(), 
1237                     //        String8(cmt).string()); 
1238                     syms
->appendComment(String8(e
), String16(cmt
), srcPos
); 
1240                     //printf("No comment for %s\n", String8(e).string()); 
1242                 syms
->makeSymbolPublic(String8(e
), srcPos
); 
1243             } else if (strcmp16(block
.getElementName(&len
), uses_permission16
.string()) == 0) { 
1244                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1245                                  "name", packageIdentChars
, true) != ATTR_OKAY
) { 
1248             } else if (strcmp16(block
.getElementName(&len
), instrumentation16
.string()) == 0) { 
1249                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1250                                  "name", classIdentChars
, true) != ATTR_OKAY
) { 
1253                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1254                                  RESOURCES_ANDROID_NAMESPACE
, "targetPackage", 
1255                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1258             } else if (strcmp16(block
.getElementName(&len
), application16
.string()) == 0) { 
1259                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1260                                  "name", classIdentChars
, false) != ATTR_OKAY
) { 
1263                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1264                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1265                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1268                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1269                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1270                                  processIdentChars
, false) != ATTR_OKAY
) { 
1273                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1274                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1275                                  processIdentChars
, false) != ATTR_OKAY
) { 
1278             } else if (strcmp16(block
.getElementName(&len
), provider16
.string()) == 0) { 
1279                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1280                                  "name", classIdentChars
, true) != ATTR_OKAY
) { 
1283                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1284                                  RESOURCES_ANDROID_NAMESPACE
, "authorities", 
1285                                  authoritiesIdentChars
, true) != ATTR_OKAY
) { 
1288                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1289                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1290                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1293                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1294                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1295                                  processIdentChars
, false) != ATTR_OKAY
) { 
1298             } else if (strcmp16(block
.getElementName(&len
), service16
.string()) == 0 
1299                        || strcmp16(block
.getElementName(&len
), receiver16
.string()) == 0 
1300                        || strcmp16(block
.getElementName(&len
), activity16
.string()) == 0) { 
1301                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1302                                  "name", classIdentChars
, true) != ATTR_OKAY
) { 
1305                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1306                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1307                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1310                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1311                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1312                                  processIdentChars
, false) != ATTR_OKAY
) { 
1315                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1316                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1317                                  processIdentChars
, false) != ATTR_OKAY
) { 
1320             } else if (strcmp16(block
.getElementName(&len
), action16
.string()) == 0 
1321                        || strcmp16(block
.getElementName(&len
), category16
.string()) == 0) { 
1322                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1323                                  RESOURCES_ANDROID_NAMESPACE
, "name", 
1324                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1327             } else if (strcmp16(block
.getElementName(&len
), data16
.string()) == 0) { 
1328                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1329                                  RESOURCES_ANDROID_NAMESPACE
, "mimeType", 
1330                                  typeIdentChars
, true) != ATTR_OKAY
) { 
1333                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1334                                  RESOURCES_ANDROID_NAMESPACE
, "scheme", 
1335                                  schemeIdentChars
, true) != ATTR_OKAY
) { 
1342     if (resFile 
!= NULL
) { 
1343         // These resources are now considered to be a part of the included 
1344         // resources, for others to reference. 
1345         err 
= assets
->addIncludedResources(resFile
); 
1346         if (err 
< NO_ERROR
) { 
1347             fprintf(stderr
, "ERROR: Unable to parse generated resources, aborting.\n"); 
1355 static const char* getIndentSpace(int indent
) 
1357 static const char whitespace
[] = 
1360     return whitespace 
+ sizeof(whitespace
) - 1 - indent
*4; 
1363 static status_t 
fixupSymbol(String16
* inoutSymbol
) 
1365     inoutSymbol
->replaceAll('.', '_'); 
1366     inoutSymbol
->replaceAll(':', '_'); 
1370 static String16 
getAttributeComment(const sp
<AaptAssets
>& assets
, 
1371                                     const String8
& name
, 
1372                                     String16
* outTypeComment 
= NULL
) 
1374     sp
<AaptSymbols
> asym 
= assets
->getSymbolsFor(String8("R")); 
1376         //printf("Got R symbols!\n"); 
1377         asym 
= asym
->getNestedSymbols().valueFor(String8("attr")); 
1379             //printf("Got attrs symbols! comment %s=%s\n", 
1380             //     name.string(), String8(asym->getComment(name)).string()); 
1381             if (outTypeComment 
!= NULL
) { 
1382                 *outTypeComment 
= asym
->getTypeComment(name
); 
1384             return asym
->getComment(name
); 
1390 static status_t 
writeLayoutClasses( 
1391     FILE* fp
, const sp
<AaptAssets
>& assets
, 
1392     const sp
<AaptSymbols
>& symbols
, int indent
, bool includePrivate
) 
1394     const char* indentStr 
= getIndentSpace(indent
); 
1395     if (!includePrivate
) { 
1396         fprintf(fp
, "%s/** @doconly */\n", indentStr
); 
1398     fprintf(fp
, "%spublic static final class styleable {\n", indentStr
); 
1401     String16 
attr16("attr"); 
1402     String16 
package16(assets
->getPackage()); 
1404     indentStr 
= getIndentSpace(indent
); 
1405     bool hasErrors 
= false; 
1408     size_t N 
= symbols
->getNestedSymbols().size(); 
1409     for (i
=0; i
<N
; i
++) { 
1410         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1411         String16 
nclassName16(symbols
->getNestedSymbols().keyAt(i
)); 
1412         String8 
realClassName(nclassName16
); 
1413         if (fixupSymbol(&nclassName16
) != NO_ERROR
) { 
1416         String8 
nclassName(nclassName16
); 
1418         SortedVector
<uint32_t> idents
; 
1419         Vector
<uint32_t> origOrder
; 
1420         Vector
<bool> publicFlags
; 
1423         size_t NA 
= nsymbols
->getSymbols().size(); 
1424         for (a
=0; a
<NA
; a
++) { 
1425             const AaptSymbolEntry
& sym(nsymbols
->getSymbols().valueAt(a
)); 
1426             int32_t code 
= sym
.typeCode 
== AaptSymbolEntry::TYPE_INT32
 
1428             bool isPublic 
= true; 
1430                 String16 
name16(sym
.name
); 
1431                 uint32_t typeSpecFlags
; 
1432                 code 
= assets
->getIncludedResources().identifierForName( 
1433                     name16
.string(), name16
.size(), 
1434                     attr16
.string(), attr16
.size(), 
1435                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1437                     fprintf(stderr
, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n", 
1438                             nclassName
.string(), sym
.name
.string()); 
1441                 isPublic 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1444             origOrder
.add(code
); 
1445             publicFlags
.add(isPublic
); 
1450         bool deprecated 
= false; 
1452         String16 comment 
= symbols
->getComment(realClassName
); 
1453         fprintf(fp
, "%s/** ", indentStr
); 
1454         if (comment
.size() > 0) { 
1455             String8 
cmt(comment
); 
1456             fprintf(fp
, "%s\n", cmt
.string()); 
1457             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1461             fprintf(fp
, "Attributes that can be used with a %s.\n", nclassName
.string()); 
1463         bool hasTable 
= false; 
1464         for (a
=0; a
<NA
; a
++) { 
1465             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1470                             "%s   <p>Includes the following attributes:</p>\n" 
1472                             "%s   <colgroup align=\"left\" />\n" 
1473                             "%s   <colgroup align=\"left\" />\n" 
1474                             "%s   <tr><th>Attribute</th><th>Description</th></tr>\n", 
1481                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1482                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1485                 String8 
name8(sym
.name
); 
1486                 String16 
comment(sym
.comment
); 
1487                 if (comment
.size() <= 0) { 
1488                     comment 
= getAttributeComment(assets
, name8
); 
1490                 if (comment
.size() > 0) { 
1491                     const char16_t* p 
= comment
.string(); 
1492                     while (*p 
!= 0 && *p 
!= '.') { 
1494                             while (*p 
!= 0 && *p 
!= '}') { 
1504                     comment 
= String16(comment
.string(), p
-comment
.string()); 
1506                 String16 
name(name8
); 
1508                 fprintf(fp
, "%s   <tr><td><code>{@link #%s_%s %s:%s}</code></td><td>%s</td></tr>\n", 
1509                         indentStr
, nclassName
.string(), 
1510                         String8(name
).string(), 
1511                         assets
->getPackage().string(), 
1512                         String8(name
).string(), 
1513                         String8(comment
).string()); 
1517             fprintf(fp
, "%s   </table>\n", indentStr
); 
1519         for (a
=0; a
<NA
; a
++) { 
1520             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1522                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1523                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1526                 String16 
name(sym
.name
); 
1528                 fprintf(fp
, "%s   @see #%s_%s\n", 
1529                         indentStr
, nclassName
.string(), 
1530                         String8(name
).string()); 
1533         fprintf(fp
, "%s */\n", getIndentSpace(indent
)); 
1536             fprintf(fp
, "%s@Deprecated\n", indentStr
); 
1540                 "%spublic static final int[] %s = {\n" 
1542                 indentStr
, nclassName
.string(), 
1543                 getIndentSpace(indent
+1)); 
1545         for (a
=0; a
<NA
; a
++) { 
1548                     fprintf(fp
, ",\n%s", getIndentSpace(indent
+1)); 
1553             fprintf(fp
, "0x%08x", idents
[a
]); 
1556         fprintf(fp
, "\n%s};\n", indentStr
); 
1558         for (a
=0; a
<NA
; a
++) { 
1559             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1561                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1562                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1565                 String8 
name8(sym
.name
); 
1566                 String16 
comment(sym
.comment
); 
1567                 String16 typeComment
; 
1568                 if (comment
.size() <= 0) { 
1569                     comment 
= getAttributeComment(assets
, name8
, &typeComment
); 
1571                     getAttributeComment(assets
, name8
, &typeComment
); 
1573                 String16 
name(name8
); 
1574                 if (fixupSymbol(&name
) != NO_ERROR
) { 
1578                 uint32_t typeSpecFlags 
= 0; 
1579                 String16 
name16(sym
.name
); 
1580                 assets
->getIncludedResources().identifierForName( 
1581                     name16
.string(), name16
.size(), 
1582                     attr16
.string(), attr16
.size(), 
1583                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1584                 //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), 
1585                 //    String8(attr16).string(), String8(name16).string(), typeSpecFlags); 
1586                 const bool pub 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1588                 bool deprecated 
= false; 
1590                 fprintf(fp
, "%s/**\n", indentStr
); 
1591                 if (comment
.size() > 0) { 
1592                     String8 
cmt(comment
); 
1593                     fprintf(fp
, "%s  <p>\n%s  @attr description\n", indentStr
, indentStr
); 
1594                     fprintf(fp
, "%s  %s\n", indentStr
, cmt
.string()); 
1595                     if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1600                             "%s  <p>This symbol is the offset where the {@link %s.R.attr#%s}\n" 
1601                             "%s  attribute's value can be found in the {@link #%s} array.\n", 
1603                             pub 
? assets
->getPackage().string() 
1604                                 : assets
->getSymbolsPrivatePackage().string(), 
1605                             String8(name
).string(), 
1606                             indentStr
, nclassName
.string()); 
1608                 if (typeComment
.size() > 0) { 
1609                     String8 
cmt(typeComment
); 
1610                     fprintf(fp
, "\n\n%s  %s\n", indentStr
, cmt
.string()); 
1611                     if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1615                 if (comment
.size() > 0) { 
1618                                 "%s  <p>This corresponds to the global attribute" 
1619                                 "%s  resource symbol {@link %s.R.attr#%s}.\n", 
1620                                 indentStr
, indentStr
, 
1621                                 assets
->getPackage().string(), 
1622                                 String8(name
).string()); 
1625                                 "%s  <p>This is a private symbol.\n", indentStr
); 
1628                 fprintf(fp
, "%s  @attr name %s:%s\n", indentStr
, 
1629                         "android", String8(name
).string()); 
1630                 fprintf(fp
, "%s*/\n", indentStr
); 
1632                     fprintf(fp
, "%s@Deprecated\n", indentStr
); 
1635                         "%spublic static final int %s_%s = %d;\n", 
1636                         indentStr
, nclassName
.string(), 
1637                         String8(name
).string(), (int)pos
); 
1643     fprintf(fp
, "%s};\n", getIndentSpace(indent
)); 
1644     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
1647 static status_t 
writeSymbolClass( 
1648     FILE* fp
, const sp
<AaptAssets
>& assets
, bool includePrivate
, 
1649     const sp
<AaptSymbols
>& symbols
, const String8
& className
, int indent
) 
1651     fprintf(fp
, "%spublic %sfinal class %s {\n", 
1652             getIndentSpace(indent
), 
1653             indent 
!= 0 ? "static " : "", className
.string()); 
1657     status_t err 
= NO_ERROR
; 
1659     size_t N 
= symbols
->getSymbols().size(); 
1660     for (i
=0; i
<N
; i
++) { 
1661         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1662         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_INT32
) { 
1665         if (!includePrivate 
&& !sym
.isPublic
) { 
1668         String16 
name(sym
.name
); 
1669         String8 
realName(name
); 
1670         if (fixupSymbol(&name
) != NO_ERROR
) { 
1671             return UNKNOWN_ERROR
; 
1673         String16 
comment(sym
.comment
); 
1674         bool haveComment 
= false; 
1675         bool deprecated 
= false; 
1676         if (comment
.size() > 0) { 
1678             String8 
cmt(comment
); 
1681                     getIndentSpace(indent
), cmt
.string()); 
1682             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1685         } else if (sym
.isPublic 
&& !includePrivate
) { 
1686             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1687                 assets
->getPackage().string(), className
.string(), 
1688                 String8(sym
.name
).string()); 
1690         String16 
typeComment(sym
.typeComment
); 
1691         if (typeComment
.size() > 0) { 
1692             String8 
cmt(typeComment
); 
1696                         "%s/** %s\n", getIndentSpace(indent
), cmt
.string()); 
1699                         "%s %s\n", getIndentSpace(indent
), cmt
.string()); 
1701             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1706             fprintf(fp
,"%s */\n", getIndentSpace(indent
)); 
1709             fprintf(fp
, "%s@Deprecated\n", getIndentSpace(indent
)); 
1711         fprintf(fp
, "%spublic static final int %s=0x%08x;\n", 
1712                 getIndentSpace(indent
), 
1713                 String8(name
).string(), (int)sym
.int32Val
); 
1716     for (i
=0; i
<N
; i
++) { 
1717         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1718         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_STRING
) { 
1721         if (!includePrivate 
&& !sym
.isPublic
) { 
1724         String16 
name(sym
.name
); 
1725         if (fixupSymbol(&name
) != NO_ERROR
) { 
1726             return UNKNOWN_ERROR
; 
1728         String16 
comment(sym
.comment
); 
1729         bool deprecated 
= false; 
1730         if (comment
.size() > 0) { 
1731             String8 
cmt(comment
); 
1735                     getIndentSpace(indent
), cmt
.string(), 
1736                     getIndentSpace(indent
)); 
1737             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1740         } else if (sym
.isPublic 
&& !includePrivate
) { 
1741             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1742                 assets
->getPackage().string(), className
.string(), 
1743                 String8(sym
.name
).string()); 
1746             fprintf(fp
, "%s@Deprecated\n", getIndentSpace(indent
)); 
1748         fprintf(fp
, "%spublic static final String %s=\"%s\";\n", 
1749                 getIndentSpace(indent
), 
1750                 String8(name
).string(), sym
.stringVal
.string()); 
1753     sp
<AaptSymbols
> styleableSymbols
; 
1755     N 
= symbols
->getNestedSymbols().size(); 
1756     for (i
=0; i
<N
; i
++) { 
1757         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1758         String8 
nclassName(symbols
->getNestedSymbols().keyAt(i
)); 
1759         if (nclassName 
== "styleable") { 
1760             styleableSymbols 
= nsymbols
; 
1762             err 
= writeSymbolClass(fp
, assets
, includePrivate
, nsymbols
, nclassName
, indent
); 
1764         if (err 
!= NO_ERROR
) { 
1769     if (styleableSymbols 
!= NULL
) { 
1770         err 
= writeLayoutClasses(fp
, assets
, styleableSymbols
, indent
, includePrivate
); 
1771         if (err 
!= NO_ERROR
) { 
1777     fprintf(fp
, "%s}\n", getIndentSpace(indent
)); 
1781 status_t 
writeResourceSymbols(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
1782     const String8
& package
, bool includePrivate
) 
1784     if (!bundle
->getRClassDir()) { 
1788     const size_t N 
= assets
->getSymbols().size(); 
1789     for (size_t i
=0; i
<N
; i
++) { 
1790         sp
<AaptSymbols
> symbols 
= assets
->getSymbols().valueAt(i
); 
1791         String8 
className(assets
->getSymbols().keyAt(i
)); 
1792         String8 
dest(bundle
->getRClassDir()); 
1793         if (bundle
->getMakePackageDirs()) { 
1794             String8 
pkg(package
); 
1795             const char* last 
= pkg
.string(); 
1796             const char* s 
= last
-1; 
1799                 if (s 
> last 
&& (*s 
== '.' || *s 
== 0)) { 
1800                     String8 
part(last
, s
-last
); 
1801                     dest
.appendPath(part
); 
1802 #ifdef HAVE_MS_C_RUNTIME 
1803                     _mkdir(dest
.string()); 
1805                     mkdir(dest
.string(), S_IRUSR
|S_IWUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
); 
1811         dest
.appendPath(className
); 
1812         dest
.append(".java"); 
1813         FILE* fp 
= fopen(dest
.string(), "w+"); 
1815             fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
1816                     dest
.string(), strerror(errno
)); 
1817             return UNKNOWN_ERROR
; 
1819         if (bundle
->getVerbose()) { 
1820             printf("  Writing symbols for class %s.\n", className
.string()); 
1824         "/* AUTO-GENERATED FILE.  DO NOT MODIFY.\n" 
1826         " * This class was automatically generated by the\n" 
1827         " * aapt tool from the resource data it found.  It\n" 
1828         " * should not be modified by hand.\n" 
1831         "package %s;\n\n", package
.string()); 
1833         status_t err 
= writeSymbolClass(fp
, assets
, includePrivate
, symbols
, className
, 0); 
1834         if (err 
!= NO_ERROR
) { 
1845 class ProguardKeepSet
 
1848     // { rule --> { file locations } } 
1849     KeyedVector
<String8
, SortedVector
<String8
> > rules
; 
1851     void add(const String8
& rule
, const String8
& where
); 
1854 void ProguardKeepSet::add(const String8
& rule
, const String8
& where
) 
1856     ssize_t index 
= rules
.indexOfKey(rule
); 
1858         index 
= rules
.add(rule
, SortedVector
<String8
>()); 
1860     rules
.editValueAt(index
).add(where
); 
1864 addProguardKeepRule(ProguardKeepSet
* keep
, const String8
& inClassName
, 
1865         const char* pkg
, const String8
& srcName
, int line
) 
1867     String8 
className(inClassName
); 
1869         // asdf     --> package.asdf 
1870         // .asdf  .a.b  --> package.asdf package.a.b 
1871         // asdf.adsf --> asdf.asdf 
1872         const char* p 
= className
.string(); 
1873         const char* q 
= strchr(p
, '.'); 
1876             className
.append(inClassName
); 
1877         } else if (q 
== NULL
) { 
1879             className
.append("."); 
1880             className
.append(inClassName
); 
1884     String8 
rule("-keep class "); 
1886     rule 
+= " { <init>(...); }"; 
1888     String8 
location("view "); 
1889     location 
+= srcName
; 
1891     sprintf(lineno
, ":%d", line
); 
1894     keep
->add(rule
, location
); 
1898 writeProguardForAndroidManifest(ProguardKeepSet
* keep
, const sp
<AaptAssets
>& assets
) 
1903     ResXMLTree::event_code_t code
; 
1905     bool inApplication 
= false; 
1907     sp
<AaptGroup
> assGroup
; 
1908     sp
<AaptFile
> assFile
; 
1911     // First, look for a package file to parse.  This is required to 
1912     // be able to generate the resource information. 
1913     assGroup 
= assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
1914     if (assGroup 
== NULL
) { 
1915         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
1919     if (assGroup
->getFiles().size() != 1) { 
1920         fprintf(stderr
, "warning: Multiple AndroidManifest.xml files found, using %s\n", 
1921                 assGroup
->getFiles().valueAt(0)->getPrintableSource().string()); 
1924     assFile 
= assGroup
->getFiles().valueAt(0); 
1926     err 
= parseXMLResource(assFile
, &tree
); 
1927     if (err 
!= NO_ERROR
) { 
1933     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
1934         if (code 
== ResXMLTree::END_TAG
) { 
1935             if (/* name == "Application" && */ depth 
== 2) { 
1936                 inApplication 
= false; 
1941         if (code 
!= ResXMLTree::START_TAG
) { 
1945         String8 
tag(tree
.getElementName(&len
)); 
1946         // printf("Depth %d tag %s\n", depth, tag.string()); 
1947         bool keepTag 
= false; 
1949             if (tag 
!= "manifest") { 
1950                 fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
1953             pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
1954         } else if (depth 
== 2) { 
1955             if (tag 
== "application") { 
1956                 inApplication 
= true; 
1959                 String8 agent 
= getAttribute(tree
, "http://schemas.android.com/apk/res/android", 
1960                         "backupAgent", &error
); 
1961                 if (agent
.length() > 0) { 
1962                     addProguardKeepRule(keep
, agent
, pkg
.string(), 
1963                             assFile
->getPrintableSource(), tree
.getLineNumber()); 
1965             } else if (tag 
== "instrumentation") { 
1969         if (!keepTag 
&& inApplication 
&& depth 
== 3) { 
1970             if (tag 
== "activity" || tag 
== "service" || tag 
== "receiver" || tag 
== "provider") { 
1975             String8 name 
= getAttribute(tree
, "http://schemas.android.com/apk/res/android", 
1978                 fprintf(stderr
, "ERROR: %s\n", error
.string()); 
1981             if (name
.length() > 0) { 
1982                 addProguardKeepRule(keep
, name
, pkg
.string(), 
1983                         assFile
->getPrintableSource(), tree
.getLineNumber()); 
1992 writeProguardForXml(ProguardKeepSet
* keep
, const sp
<AaptFile
>& layoutFile
, 
1993         const char* startTag
, const char* altTag
) 
1998     ResXMLTree::event_code_t code
; 
2000     err 
= parseXMLResource(layoutFile
, &tree
); 
2001     if (err 
!= NO_ERROR
) { 
2007     if (startTag 
!= NULL
) { 
2008         bool haveStart 
= false; 
2009         while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
2010             if (code 
!= ResXMLTree::START_TAG
) { 
2013             String8 
tag(tree
.getElementName(&len
)); 
2014             if (tag 
== startTag
) { 
2024     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
2025         if (code 
!= ResXMLTree::START_TAG
) { 
2028         String8 
tag(tree
.getElementName(&len
)); 
2030         // If there is no '.', we'll assume that it's one of the built in names. 
2031         if (strchr(tag
.string(), '.')) { 
2032             addProguardKeepRule(keep
, tag
, NULL
, 
2033                     layoutFile
->getPrintableSource(), tree
.getLineNumber()); 
2034         } else if (altTag 
!= NULL 
&& tag 
== altTag
) { 
2035             ssize_t classIndex 
= tree
.indexOfAttribute(NULL
, "class"); 
2036             if (classIndex 
< 0) { 
2037                 fprintf(stderr
, "%s:%d: <view> does not have class attribute.\n", 
2038                         layoutFile
->getPrintableSource().string(), tree
.getLineNumber()); 
2041                 addProguardKeepRule(keep
, 
2042                         String8(tree
.getAttributeStringValue(classIndex
, &len
)), NULL
, 
2043                         layoutFile
->getPrintableSource(), tree
.getLineNumber()); 
2052 writeProguardForLayouts(ProguardKeepSet
* keep
, const sp
<AaptAssets
>& assets
) 
2055     const Vector
<sp
<AaptDir
> >& dirs 
= assets
->resDirs(); 
2056     const size_t K 
= dirs
.size(); 
2057     for (size_t k
=0; k
<K
; k
++) { 
2058         const sp
<AaptDir
>& d 
= dirs
.itemAt(k
); 
2059         const String8
& dirName 
= d
->getLeaf(); 
2060         const char* startTag 
= NULL
; 
2061         const char* altTag 
= NULL
; 
2062         if ((dirName 
== String8("layout")) || (strncmp(dirName
.string(), "layout-", 7) == 0)) { 
2064         } else if ((dirName 
== String8("xml")) || (strncmp(dirName
.string(), "xml-", 4) == 0)) { 
2065             startTag 
= "PreferenceScreen"; 
2070         const KeyedVector
<String8
,sp
<AaptGroup
> > groups 
= d
->getFiles(); 
2071         const size_t N 
= groups
.size(); 
2072         for (size_t i
=0; i
<N
; i
++) { 
2073             const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
2074             const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files 
= group
->getFiles(); 
2075             const size_t M 
= files
.size(); 
2076             for (size_t j
=0; j
<M
; j
++) { 
2077                 err 
= writeProguardForXml(keep
, files
.valueAt(j
), startTag
, altTag
); 
2088 writeProguardFile(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
2092     if (!bundle
->getProguardFile()) { 
2096     ProguardKeepSet keep
; 
2098     err 
= writeProguardForAndroidManifest(&keep
, assets
); 
2103     err 
= writeProguardForLayouts(&keep
, assets
); 
2108     FILE* fp 
= fopen(bundle
->getProguardFile(), "w+"); 
2110         fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
2111                 bundle
->getProguardFile(), strerror(errno
)); 
2112         return UNKNOWN_ERROR
; 
2115     const KeyedVector
<String8
, SortedVector
<String8
> >& rules 
= keep
.rules
; 
2116     const size_t N 
= rules
.size(); 
2117     for (size_t i
=0; i
<N
; i
++) { 
2118         const SortedVector
<String8
>& locations 
= rules
.valueAt(i
); 
2119         const size_t M 
= locations
.size(); 
2120         for (size_t j
=0; j
<M
; j
++) { 
2121             fprintf(fp
, "# %s\n", locations
.itemAt(j
).string()); 
2123         fprintf(fp
, "%s\n\n", rules
.keyAt(i
).string());