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 class ResourceTypeSet 
: public RefBase
, 
  49                         public KeyedVector
<String8
,sp
<AaptGroup
> > 
  55 ResourceTypeSet::ResourceTypeSet() 
  57      KeyedVector
<String8
,sp
<AaptGroup
> >() 
  61 class ResourceDirIterator
 
  64     ResourceDirIterator(const sp
<ResourceTypeSet
>& set
, const String8
& resType
) 
  65         : mResType(resType
), mSet(set
), mSetPos(0), mGroupPos(0) 
  69     inline const sp
<AaptGroup
>& getGroup() const { return mGroup
; } 
  70     inline const sp
<AaptFile
>& getFile() const { return mFile
; } 
  72     inline const String8
& getBaseName() const { return mBaseName
; } 
  73     inline const String8
& getLeafName() const { return mLeafName
; } 
  74     inline String8 
getPath() const { return mPath
; } 
  75     inline const ResTable_config
& getParams() const { return mParams
; } 
  87             // Try to get next file in this current group. 
  88             if (mGroup 
!= NULL 
&& mGroupPos 
< mGroup
->getFiles().size()) { 
  90                 file 
= group
->getFiles().valueAt(mGroupPos
++); 
  92             // Try to get the next group/file in this directory 
  93             } else if (mSetPos 
< mSet
->size()) { 
  94                 mGroup 
= group 
= mSet
->valueAt(mSetPos
++); 
  95                 if (group
->getFiles().size() < 1) { 
  98                 file 
= group
->getFiles().valueAt(0); 
 108             String8 
leaf(group
->getLeaf()); 
 109             mLeafName 
= String8(leaf
); 
 110             mParams 
= file
->getGroupEntry().toParams(); 
 111             NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d density=%d touch=%d key=%d inp=%d nav=%d\n", 
 112                    group
->getPath().string(), mParams
.mcc
, mParams
.mnc
, 
 113                    mParams
.language
[0] ? mParams
.language
[0] : '-', 
 114                    mParams
.language
[1] ? mParams
.language
[1] : '-', 
 115                    mParams
.country
[0] ? mParams
.country
[0] : '-', 
 116                    mParams
.country
[1] ? mParams
.country
[1] : '-', 
 118                    mParams
.density
, mParams
.touchscreen
, mParams
.keyboard
, 
 119                    mParams
.inputFlags
, mParams
.navigation
)); 
 121             mPath
.appendPath(file
->getGroupEntry().toDirName(mResType
)); 
 122             mPath
.appendPath(leaf
); 
 123             mBaseName 
= parseResourceName(leaf
); 
 124             if (mBaseName 
== "") { 
 125                 fprintf(stderr
, "Error: malformed resource filename %s\n", 
 126                         file
->getPrintableSource().string()); 
 127                 return UNKNOWN_ERROR
; 
 130             NOISY(printf("file name=%s\n", mBaseName
.string())); 
 139     const sp
<ResourceTypeSet
> mSet
; 
 142     sp
<AaptGroup
> mGroup
; 
 149     ResTable_config mParams
; 
 152 // ========================================================================== 
 153 // ========================================================================== 
 154 // ========================================================================== 
 156 bool isValidResourceType(const String8
& type
) 
 158     return type 
== "anim" || type 
== "drawable" || type 
== "layout" 
 159         || type 
== "values" || type 
== "xml" || type 
== "raw" 
 160         || type 
== "color" || type 
== "menu"; 
 163 static sp
<AaptFile
> getResourceFile(const sp
<AaptAssets
>& assets
, bool makeIfNecessary
=true) 
 165     sp
<AaptGroup
> group 
= assets
->getFiles().valueFor(String8("resources.arsc")); 
 168         file 
= group
->getFiles().valueFor(AaptGroupEntry()); 
 174     if (!makeIfNecessary
) { 
 177     return assets
->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(), 
 181 static status_t 
parsePackage(const sp
<AaptAssets
>& assets
, const sp
<AaptGroup
>& grp
) 
 183     if (grp
->getFiles().size() != 1) { 
 184         fprintf(stderr
, "WARNING: Multiple AndroidManifest.xml files found, using %s\n", 
 185                 grp
->getFiles().valueAt(0)->getPrintableSource().string()); 
 188     sp
<AaptFile
> file 
= grp
->getFiles().valueAt(0); 
 191     status_t err 
= parseXMLResource(file
, &block
); 
 192     if (err 
!= NO_ERROR
) { 
 195     //printXMLBlock(&block); 
 197     ResXMLTree::event_code_t code
; 
 198     while ((code
=block
.next()) != ResXMLTree::START_TAG
 
 199            && code 
!= ResXMLTree::END_DOCUMENT
 
 200            && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 204     if (code 
!= ResXMLTree::START_TAG
) { 
 205         fprintf(stderr
, "%s:%d: No start tag found\n", 
 206                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 207         return UNKNOWN_ERROR
; 
 209     if (strcmp16(block
.getElementName(&len
), String16("manifest").string()) != 0) { 
 210         fprintf(stderr
, "%s:%d: Invalid start tag %s, expected <manifest>\n", 
 211                 file
->getPrintableSource().string(), block
.getLineNumber(), 
 212                 String8(block
.getElementName(&len
)).string()); 
 213         return UNKNOWN_ERROR
; 
 216     ssize_t nameIndex 
= block
.indexOfAttribute(NULL
, "package"); 
 218         fprintf(stderr
, "%s:%d: <manifest> does not have package attribute.\n", 
 219                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 220         return UNKNOWN_ERROR
; 
 223     assets
->setPackage(String8(block
.getAttributeStringValue(nameIndex
, &len
))); 
 228 // ========================================================================== 
 229 // ========================================================================== 
 230 // ========================================================================== 
 232 static status_t 
makeFileResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 233                                   ResourceTable
* table
, 
 234                                   const sp
<ResourceTypeSet
>& set
, 
 237     String8 
type8(resType
); 
 238     String16 
type16(resType
); 
 240     bool hasErrors 
= false; 
 242     ResourceDirIterator 
it(set
, String8(resType
)); 
 244     while ((res
=it
.next()) == NO_ERROR
) { 
 245         if (bundle
->getVerbose()) { 
 246             printf("    (new resource id %s from %s)\n", 
 247                    it
.getBaseName().string(), it
.getFile()->getPrintableSource().string()); 
 249         String16 
baseName(it
.getBaseName()); 
 250         const char16_t* str 
= baseName
.string(); 
 251         const char16_t* const end 
= str 
+ baseName
.size(); 
 253             if (!((*str 
>= 'a' && *str 
<= 'z') 
 254                     || (*str 
>= '0' && *str 
<= '9') 
 255                     || *str 
== '_' || *str 
== '.')) { 
 256                 fprintf(stderr
, "%s: Invalid file name: must contain only [a-z0-9_.]\n", 
 257                         it
.getPath().string()); 
 262         String8 resPath 
= it
.getPath(); 
 263         resPath
.convertToResPath(); 
 264         table
->addEntry(SourcePos(it
.getPath(), 0), String16(assets
->getPackage()), 
 270         assets
->addResource(it
.getLeafName(), resPath
, it
.getFile(), type8
); 
 273     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
 276 static status_t 
preProcessImages(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 277                           const sp
<ResourceTypeSet
>& set
) 
 279     ResourceDirIterator 
it(set
, String8("drawable")); 
 280     Vector
<sp
<AaptFile
> > newNameFiles
; 
 281     Vector
<String8
> newNamePaths
; 
 283     while ((res
=it
.next()) == NO_ERROR
) { 
 284         res 
= preProcessImage(bundle
, assets
, it
.getFile(), NULL
); 
 285         if (res 
!= NO_ERROR
) { 
 293 status_t 
postProcessImages(const sp
<AaptAssets
>& assets
, 
 294                            ResourceTable
* table
, 
 295                            const sp
<ResourceTypeSet
>& set
) 
 297     ResourceDirIterator 
it(set
, String8("drawable")); 
 299     while ((res
=it
.next()) == NO_ERROR
) { 
 300         res 
= postProcessImage(assets
, table
, it
.getFile()); 
 301         if (res 
!= NO_ERROR
) { 
 306     return res 
< NO_ERROR 
? res 
: (status_t
)NO_ERROR
; 
 309 static void collect_files(const sp
<AaptDir
>& dir
, 
 310         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 312     const DefaultKeyedVector
<String8
, sp
<AaptGroup
> >& groups 
= dir
->getFiles(); 
 313     int N 
= groups
.size(); 
 314     for (int i
=0; i
<N
; i
++) { 
 315         String8 leafName 
= groups
.keyAt(i
); 
 316         const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
 318         const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files
 
 321         if (files
.size() == 0) { 
 325         String8 resType 
= files
.valueAt(0)->getResourceType(); 
 327         ssize_t index 
= resources
->indexOfKey(resType
); 
 330             sp
<ResourceTypeSet
> set 
= new ResourceTypeSet(); 
 331             set
->add(leafName
, group
); 
 332             resources
->add(resType
, set
); 
 334             sp
<ResourceTypeSet
> set 
= resources
->valueAt(index
); 
 335             index 
= set
->indexOfKey(leafName
); 
 337                 set
->add(leafName
, group
); 
 339                 sp
<AaptGroup
> existingGroup 
= set
->valueAt(index
); 
 340                 int M 
= files
.size(); 
 341                 for (int j
=0; j
<M
; j
++) { 
 342                     existingGroup
->addFile(files
.valueAt(j
)); 
 349 static void collect_files(const sp
<AaptAssets
>& ass
, 
 350         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 352     const Vector
<sp
<AaptDir
> >& dirs 
= ass
->resDirs(); 
 355     for (int i
=0; i
<N
; i
++) { 
 356         sp
<AaptDir
> d 
= dirs
.itemAt(i
); 
 357         collect_files(d
, resources
); 
 359         // don't try to include the res dir 
 360         ass
->removeDir(d
->getLeaf()); 
 367     ATTR_LEADING_SPACES 
= -3, 
 368     ATTR_TRAILING_SPACES 
= -4 
 370 static int validateAttr(const String8
& path
, const ResXMLParser
& parser
, 
 371         const char* ns
, const char* attr
, const char* validChars
, bool required
) 
 375     ssize_t index 
= parser
.indexOfAttribute(ns
, attr
); 
 377     if (index 
>= 0 && (str
=parser
.getAttributeStringValue(index
, &len
)) != NULL
) { 
 379             for (size_t i
=0; i
<len
; i
++) { 
 381                 const char* p 
= validChars
; 
 391                     fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n", 
 392                             path
.string(), parser
.getLineNumber(), 
 393                             String8(parser
.getElementName(&len
)).string(), attr
, (char)str
[i
]); 
 399             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not start with a space.\n", 
 400                     path
.string(), parser
.getLineNumber(), 
 401                     String8(parser
.getElementName(&len
)).string(), attr
); 
 402             return ATTR_LEADING_SPACES
; 
 404         if (str
[len
-1] == ' ') { 
 405             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not end with a space.\n", 
 406                     path
.string(), parser
.getLineNumber(), 
 407                     String8(parser
.getElementName(&len
)).string(), attr
); 
 408             return ATTR_TRAILING_SPACES
; 
 413         fprintf(stderr
, "%s:%d: Tag <%s> missing required attribute %s.\n", 
 414                 path
.string(), parser
.getLineNumber(), 
 415                 String8(parser
.getElementName(&len
)).string(), attr
); 
 416         return ATTR_NOT_FOUND
; 
 421 static void checkForIds(const String8
& path
, ResXMLParser
& parser
) 
 423     ResXMLTree::event_code_t code
; 
 424     while ((code
=parser
.next()) != ResXMLTree::END_DOCUMENT
 
 425            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
 426         if (code 
== ResXMLTree::START_TAG
) { 
 427             ssize_t index 
= parser
.indexOfAttribute(NULL
, "id"); 
 429                 fprintf(stderr
, "%s:%d: WARNING: found plain 'id' attribute; did you mean the new 'android:id' name?\n", 
 430                         path
.string(), parser
.getLineNumber()); 
 436 static void applyFileOverlay(const sp
<AaptAssets
>& assets
,  
 437                              const sp
<ResourceTypeSet
>& baseSet
, 
 440     // Replace any base level files in this category with any found from the overlay 
 441     // Also add any found only in the overlay. 
 442     sp
<AaptAssets
> overlay 
= assets
->getOverlay(); 
 443     String8 
resTypeString(resType
); 
 445     // work through the linked list of overlays 
 446     while (overlay
.get()) { 
 447         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* overlayRes 
= overlay
->getResources(); 
 449         // get the overlay resources of the requested type 
 450         ssize_t index 
= overlayRes
->indexOfKey(resTypeString
); 
 452             sp
<ResourceTypeSet
> overlaySet 
= overlayRes
->valueAt(index
); 
 454             // for each of the resources, check for a match in the previously built 
 455             // non-overlay "baseset". 
 456             size_t overlayCount 
= overlaySet
->size(); 
 457             for (size_t overlayIndex
=0; overlayIndex
<overlayCount
; overlayIndex
++) { 
 458                 size_t baseIndex 
= baseSet
->indexOfKey(overlaySet
->keyAt(overlayIndex
)); 
 459                 if (baseIndex 
!= UNKNOWN_ERROR
) { 
 460                     // look for same flavor.  For a given file (strings.xml, for example) 
 461                     // there may be a locale specific or other flavors - we want to match 
 463                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 464                     sp
<AaptGroup
> baseGroup 
= baseSet
->valueAt(baseIndex
); 
 466                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > baseFiles 
=  
 467                             baseGroup
->getFiles(); 
 468                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
=  
 469                             overlayGroup
->getFiles(); 
 470                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 471                     for (size_t overlayGroupIndex 
= 0;  
 472                             overlayGroupIndex
<overlayGroupSize
;  
 473                             overlayGroupIndex
++) { 
 474                         size_t baseFileIndex 
=  
 475                                 baseFiles
.indexOfKey(overlayFiles
.keyAt(overlayGroupIndex
)); 
 476                         if(baseFileIndex 
< UNKNOWN_ERROR
) { 
 477                             baseGroup
->removeFile(baseFileIndex
); 
 479                             // didn't find a match fall through and add it.. 
 481                         baseGroup
->addFile(overlayFiles
.valueAt(overlayGroupIndex
)); 
 484                     // this group doesn't exist (a file that's only in the overlay) 
 486                     baseSet
->add(overlaySet
->keyAt(overlayIndex
), 
 487                                  overlaySet
->valueAt(overlayIndex
)); 
 490             // this overlay didn't have resources for this type 
 493         overlay 
= overlay
->getOverlay(); 
 498 void addTagAttribute(const sp
<XMLNode
>& node
, const char* ns8
, 
 499         const char* attr8
, const char* value
) 
 505     const String16 
ns(ns8
); 
 506     const String16 
attr(attr8
); 
 508     if (node
->getAttribute(ns
, attr
) != NULL
) { 
 509         fprintf(stderr
, "Warning: AndroidManifest.xml already defines %s (in %s)\n", 
 510                 String8(attr
).string(), String8(ns
).string()); 
 514     node
->addAttribute(ns
, attr
, String16(value
)); 
 517 status_t 
massageManifest(Bundle
* bundle
, sp
<XMLNode
> root
) 
 519     root 
= root
->searchElement(String16(), String16("manifest")); 
 521         fprintf(stderr
, "No <manifest> tag.\n"); 
 522         return UNKNOWN_ERROR
; 
 525     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionCode", 
 526             bundle
->getVersionCode()); 
 527     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionName", 
 528             bundle
->getVersionName()); 
 530     if (bundle
->getMinSdkVersion() != NULL
 
 531             || bundle
->getTargetSdkVersion() != NULL
 
 532             || bundle
->getMaxSdkVersion() != NULL
) { 
 533         sp
<XMLNode
> vers 
= root
->getChildElement(String16(), String16("uses-sdk")); 
 535             vers 
= XMLNode::newElement(root
->getFilename(), String16(), String16("uses-sdk")); 
 536             root
->insertChildAt(vers
, 0); 
 539         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "minSdkVersion", 
 540                 bundle
->getMinSdkVersion()); 
 541         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "targetSdkVersion", 
 542                 bundle
->getTargetSdkVersion()); 
 543         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "maxSdkVersion", 
 544                 bundle
->getMaxSdkVersion()); 
 550 #define ASSIGN_IT(n) \ 
 552             ssize_t index = resources->indexOfKey(String8(#n)); \ 
 554                 n ## s = resources->valueAt(index); \ 
 558 status_t 
buildResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
 560     // First, look for a package file to parse.  This is required to 
 561     // be able to generate the resource information. 
 562     sp
<AaptGroup
> androidManifestFile 
= 
 563             assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
 564     if (androidManifestFile 
== NULL
) { 
 565         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
 566         return UNKNOWN_ERROR
; 
 569     status_t err 
= parsePackage(assets
, androidManifestFile
); 
 570     if (err 
!= NO_ERROR
) { 
 574     NOISY(printf("Creating resources for package %s\n", 
 575                  assets
->getPackage().string())); 
 577     ResourceTable 
table(bundle
, String16(assets
->getPackage())); 
 578     err 
= table
.addIncludedResources(bundle
, assets
); 
 579     if (err 
!= NO_ERROR
) { 
 583     NOISY(printf("Found %d included resource packages\n", (int)table
.size())); 
 585     // -------------------------------------------------------------- 
 586     // First, gather all resource information. 
 587     // -------------------------------------------------------------- 
 589     // resType -> leafName -> group 
 590     KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 591             new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 592     collect_files(assets
, resources
); 
 594     sp
<ResourceTypeSet
> drawables
; 
 595     sp
<ResourceTypeSet
> layouts
; 
 596     sp
<ResourceTypeSet
> anims
; 
 597     sp
<ResourceTypeSet
> xmls
; 
 598     sp
<ResourceTypeSet
> raws
; 
 599     sp
<ResourceTypeSet
> colors
; 
 600     sp
<ResourceTypeSet
> menus
; 
 610     assets
->setResources(resources
); 
 611     // now go through any resource overlays and collect their files 
 612     sp
<AaptAssets
> current 
= assets
->getOverlay(); 
 613     while(current
.get()) { 
 614         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 615                 new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 616         current
->setResources(resources
); 
 617         collect_files(current
, resources
); 
 618         current 
= current
->getOverlay(); 
 620     // apply the overlay files to the base set 
 621     applyFileOverlay(assets
, drawables
, "drawable"); 
 622     applyFileOverlay(assets
, layouts
, "layout"); 
 623     applyFileOverlay(assets
, anims
, "anim"); 
 624     applyFileOverlay(assets
, xmls
, "xml"); 
 625     applyFileOverlay(assets
, raws
, "raw"); 
 626     applyFileOverlay(assets
, colors
, "color"); 
 627     applyFileOverlay(assets
, menus
, "menu"); 
 629     bool hasErrors 
= false; 
 631     if (drawables 
!= NULL
) { 
 632         err 
= preProcessImages(bundle
, assets
, drawables
); 
 633         if (err 
== NO_ERROR
) { 
 634             err 
= makeFileResources(bundle
, assets
, &table
, drawables
, "drawable"); 
 635             if (err 
!= NO_ERROR
) { 
 643     if (layouts 
!= NULL
) { 
 644         err 
= makeFileResources(bundle
, assets
, &table
, layouts
, "layout"); 
 645         if (err 
!= NO_ERROR
) { 
 651         err 
= makeFileResources(bundle
, assets
, &table
, anims
, "anim"); 
 652         if (err 
!= NO_ERROR
) { 
 658         err 
= makeFileResources(bundle
, assets
, &table
, xmls
, "xml"); 
 659         if (err 
!= NO_ERROR
) { 
 665         err 
= makeFileResources(bundle
, assets
, &table
, raws
, "raw"); 
 666         if (err 
!= NO_ERROR
) { 
 673     while(current
.get()) { 
 674         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 675                 current
->getResources(); 
 677         ssize_t index 
= resources
->indexOfKey(String8("values")); 
 679             ResourceDirIterator 
it(resources
->valueAt(index
), String8("values")); 
 681             while ((res
=it
.next()) == NO_ERROR
) { 
 682                 sp
<AaptFile
> file 
= it
.getFile(); 
 683                 res 
= compileResourceFile(bundle
, assets
, file
, it
.getParams(),  
 684                                           (current
!=assets
), &table
); 
 685                 if (res 
!= NO_ERROR
) { 
 690         current 
= current
->getOverlay(); 
 693     if (colors 
!= NULL
) { 
 694         err 
= makeFileResources(bundle
, assets
, &table
, colors
, "color"); 
 695         if (err 
!= NO_ERROR
) { 
 701         err 
= makeFileResources(bundle
, assets
, &table
, menus
, "menu"); 
 702         if (err 
!= NO_ERROR
) { 
 707     // -------------------------------------------------------------------- 
 708     // Assignment of resource IDs and initial generation of resource table. 
 709     // -------------------------------------------------------------------- 
 711     if (table
.hasResources()) { 
 712         sp
<AaptFile
> resFile(getResourceFile(assets
)); 
 713         if (resFile 
== NULL
) { 
 714             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
 715             return UNKNOWN_ERROR
; 
 718         err 
= table
.assignResourceIds(); 
 719         if (err 
< NO_ERROR
) { 
 724     // -------------------------------------------------------------- 
 725     // Finally, we can now we can compile XML files, which may reference 
 727     // -------------------------------------------------------------- 
 729     if (layouts 
!= NULL
) { 
 730         ResourceDirIterator 
it(layouts
, String8("layout")); 
 731         while ((err
=it
.next()) == NO_ERROR
) { 
 732             String8 src 
= it
.getFile()->getPrintableSource(); 
 733             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 734             if (err 
== NO_ERROR
) { 
 736                 block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
 737                 checkForIds(src
, block
); 
 743         if (err 
< NO_ERROR
) { 
 750         ResourceDirIterator 
it(anims
, String8("anim")); 
 751         while ((err
=it
.next()) == NO_ERROR
) { 
 752             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 753             if (err 
!= NO_ERROR
) { 
 758         if (err 
< NO_ERROR
) { 
 765         ResourceDirIterator 
it(xmls
, String8("xml")); 
 766         while ((err
=it
.next()) == NO_ERROR
) { 
 767             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 768             if (err 
!= NO_ERROR
) { 
 773         if (err 
< NO_ERROR
) { 
 779     if (drawables 
!= NULL
) { 
 780         err 
= postProcessImages(assets
, &table
, drawables
); 
 781         if (err 
!= NO_ERROR
) { 
 786     if (colors 
!= NULL
) { 
 787         ResourceDirIterator 
it(colors
, String8("color")); 
 788         while ((err
=it
.next()) == NO_ERROR
) { 
 789           err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 790             if (err 
!= NO_ERROR
) { 
 795         if (err 
< NO_ERROR
) { 
 802         ResourceDirIterator 
it(menus
, String8("menu")); 
 803         while ((err
=it
.next()) == NO_ERROR
) { 
 804             String8 src 
= it
.getFile()->getPrintableSource(); 
 805             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 806             if (err 
!= NO_ERROR
) { 
 810             block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
 811             checkForIds(src
, block
); 
 814         if (err 
< NO_ERROR
) { 
 820     const sp
<AaptFile
> manifestFile(androidManifestFile
->getFiles().valueAt(0)); 
 821     String8 
manifestPath(manifestFile
->getPrintableSource()); 
 823     // Perform a basic validation of the manifest file.  This time we 
 824     // parse it with the comments intact, so that we can use them to 
 825     // generate java docs...  so we are not going to write this one 
 826     // back out to the final manifest data. 
 827     err 
= compileXmlFile(assets
, manifestFile
, &table
, 
 828             XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
 
 829             | XML_COMPILE_STRIP_WHITESPACE 
| XML_COMPILE_STRIP_RAW_VALUES
); 
 830     if (err 
< NO_ERROR
) { 
 834     block
.setTo(manifestFile
->getData(), manifestFile
->getSize(), true); 
 835     String16 
manifest16("manifest"); 
 836     String16 
permission16("permission"); 
 837     String16 
permission_group16("permission-group"); 
 838     String16 
uses_permission16("uses-permission"); 
 839     String16 
instrumentation16("instrumentation"); 
 840     String16 
application16("application"); 
 841     String16 
provider16("provider"); 
 842     String16 
service16("service"); 
 843     String16 
receiver16("receiver"); 
 844     String16 
activity16("activity"); 
 845     String16 
action16("action"); 
 846     String16 
category16("category"); 
 847     String16 
data16("scheme"); 
 848     const char* packageIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 849         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789"; 
 850     const char* packageIdentCharsWithTheStupid 
= "abcdefghijklmnopqrstuvwxyz" 
 851         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
 852     const char* classIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 853         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789$"; 
 854     const char* processIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 855         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:"; 
 856     const char* authoritiesIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 857         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-:;"; 
 858     const char* typeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 859         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:-/*+"; 
 860     const char* schemeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 861         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
 862     ResXMLTree::event_code_t code
; 
 863     sp
<AaptSymbols
> permissionSymbols
; 
 864     sp
<AaptSymbols
> permissionGroupSymbols
; 
 865     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 866            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
 867         if (code 
== ResXMLTree::START_TAG
) { 
 869             if (block
.getElementNamespace(&len
) != NULL
) { 
 872             if (strcmp16(block
.getElementName(&len
), manifest16
.string()) == 0) { 
 873                 if (validateAttr(manifestPath
, block
, NULL
, "package", 
 874                                  packageIdentChars
, true) != ATTR_OKAY
) { 
 877             } else if (strcmp16(block
.getElementName(&len
), permission16
.string()) == 0 
 878                     || strcmp16(block
.getElementName(&len
), permission_group16
.string()) == 0) { 
 879                 const bool isGroup 
= strcmp16(block
.getElementName(&len
), 
 880                         permission_group16
.string()) == 0; 
 881                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 882                                  isGroup 
? packageIdentCharsWithTheStupid
 
 883                                  : packageIdentChars
, true) != ATTR_OKAY
) { 
 886                 SourcePos 
srcPos(manifestPath
, block
.getLineNumber()); 
 887                 sp
<AaptSymbols
> syms
; 
 889                     syms 
= permissionSymbols
; 
 891                         sp
<AaptSymbols
> symbols 
= 
 892                                 assets
->getSymbolsFor(String8("Manifest")); 
 893                         syms 
= permissionSymbols 
= symbols
->addNestedSymbol( 
 894                                 String8("permission"), srcPos
); 
 897                     syms 
= permissionGroupSymbols
; 
 899                         sp
<AaptSymbols
> symbols 
= 
 900                                 assets
->getSymbolsFor(String8("Manifest")); 
 901                         syms 
= permissionGroupSymbols 
= symbols
->addNestedSymbol( 
 902                                 String8("permission_group"), srcPos
); 
 906                 ssize_t index 
= block
.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE
, "name"); 
 907                 const uint16_t* id 
= block
.getAttributeStringValue(index
, &len
); 
 909                     fprintf(stderr
, "%s:%d: missing name attribute in element <%s>.\n",  
 910                             manifestPath
.string(), block
.getLineNumber(), 
 911                             String8(block
.getElementName(&len
)).string()); 
 916                 char* p 
= idStr
.lockBuffer(idStr
.size()); 
 917                 char* e 
= p 
+ idStr
.size(); 
 918                 bool begins_with_digit 
= true;  // init to true so an empty string fails 
 921                     if (*e 
>= '0' && *e 
<= '9') { 
 922                       begins_with_digit 
= true; 
 925                     if ((*e 
>= 'a' && *e 
<= 'z') || 
 926                         (*e 
>= 'A' && *e 
<= 'Z') || 
 928                       begins_with_digit 
= false; 
 931                     if (isGroup 
&& (*e 
== '-')) { 
 933                         begins_with_digit 
= false; 
 939                 idStr
.unlockBuffer(); 
 940                 // verify that we stopped because we hit a period or 
 941                 // the beginning of the string, and that the 
 942                 // identifier didn't begin with a digit. 
 943                 if (begins_with_digit 
|| (e 
!= p 
&& *(e
-1) != '.')) { 
 945                           "%s:%d: Permission name <%s> is not a valid Java symbol\n", 
 946                           manifestPath
.string(), block
.getLineNumber(), idStr
.string()); 
 949                 syms
->addStringSymbol(String8(e
), idStr
, srcPos
); 
 950                 const uint16_t* cmt 
= block
.getComment(&len
); 
 951                 if (cmt 
!= NULL 
&& *cmt 
!= 0) { 
 952                     //printf("Comment of %s: %s\n", String8(e).string(), 
 953                     //        String8(cmt).string()); 
 954                     syms
->appendComment(String8(e
), String16(cmt
), srcPos
); 
 956                     //printf("No comment for %s\n", String8(e).string()); 
 958                 syms
->makeSymbolPublic(String8(e
), srcPos
); 
 959             } else if (strcmp16(block
.getElementName(&len
), uses_permission16
.string()) == 0) { 
 960                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 961                                  packageIdentChars
, true) != ATTR_OKAY
) { 
 964             } else if (strcmp16(block
.getElementName(&len
), instrumentation16
.string()) == 0) { 
 965                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 966                                  classIdentChars
, true) != ATTR_OKAY
) { 
 969                 if (validateAttr(manifestPath
, block
, 
 970                                  RESOURCES_ANDROID_NAMESPACE
, "targetPackage", 
 971                                  packageIdentChars
, true) != ATTR_OKAY
) { 
 974             } else if (strcmp16(block
.getElementName(&len
), application16
.string()) == 0) { 
 975                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 976                                  classIdentChars
, false) != ATTR_OKAY
) { 
 979                 if (validateAttr(manifestPath
, block
, 
 980                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
 981                                  packageIdentChars
, false) != ATTR_OKAY
) { 
 984                 if (validateAttr(manifestPath
, block
, 
 985                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
 986                                  processIdentChars
, false) != ATTR_OKAY
) { 
 989                 if (validateAttr(manifestPath
, block
, 
 990                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
 991                                  processIdentChars
, false) != ATTR_OKAY
) { 
 994             } else if (strcmp16(block
.getElementName(&len
), provider16
.string()) == 0) { 
 995                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 996                                  classIdentChars
, true) != ATTR_OKAY
) { 
 999                 if (validateAttr(manifestPath
, block
, 
1000                                  RESOURCES_ANDROID_NAMESPACE
, "authorities", 
1001                                  authoritiesIdentChars
, true) != ATTR_OKAY
) { 
1004                 if (validateAttr(manifestPath
, block
, 
1005                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1006                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1009                 if (validateAttr(manifestPath
, block
, 
1010                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1011                                  processIdentChars
, false) != ATTR_OKAY
) { 
1014             } else if (strcmp16(block
.getElementName(&len
), service16
.string()) == 0 
1015                        || strcmp16(block
.getElementName(&len
), receiver16
.string()) == 0 
1016                        || strcmp16(block
.getElementName(&len
), activity16
.string()) == 0) { 
1017                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
1018                                  classIdentChars
, true) != ATTR_OKAY
) { 
1021                 if (validateAttr(manifestPath
, block
, 
1022                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1023                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1026                 if (validateAttr(manifestPath
, block
, 
1027                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1028                                  processIdentChars
, false) != ATTR_OKAY
) { 
1031                 if (validateAttr(manifestPath
, block
, 
1032                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1033                                  processIdentChars
, false) != ATTR_OKAY
) { 
1036             } else if (strcmp16(block
.getElementName(&len
), action16
.string()) == 0 
1037                        || strcmp16(block
.getElementName(&len
), category16
.string()) == 0) { 
1038                 if (validateAttr(manifestPath
, block
, 
1039                                  RESOURCES_ANDROID_NAMESPACE
, "name", 
1040                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1043             } else if (strcmp16(block
.getElementName(&len
), data16
.string()) == 0) { 
1044                 if (validateAttr(manifestPath
, block
, 
1045                                  RESOURCES_ANDROID_NAMESPACE
, "mimeType", 
1046                                  typeIdentChars
, true) != ATTR_OKAY
) { 
1049                 if (validateAttr(manifestPath
, block
, 
1050                                  RESOURCES_ANDROID_NAMESPACE
, "scheme", 
1051                                  schemeIdentChars
, true) != ATTR_OKAY
) { 
1058     if (table
.validateLocalizations()) { 
1063         return UNKNOWN_ERROR
; 
1066     // Generate final compiled manifest file. 
1067     manifestFile
->clearData(); 
1068     sp
<XMLNode
> manifestTree 
= XMLNode::parse(manifestFile
); 
1069     if (manifestTree 
== NULL
) { 
1070         return UNKNOWN_ERROR
; 
1072     err 
= massageManifest(bundle
, manifestTree
); 
1073     if (err 
< NO_ERROR
) { 
1076     err 
= compileXmlFile(assets
, manifestTree
, manifestFile
, &table
); 
1077     if (err 
< NO_ERROR
) { 
1082     //printXMLBlock(&block); 
1084     // -------------------------------------------------------------- 
1085     // Generate the final resource table. 
1086     // Re-flatten because we may have added new resource IDs 
1087     // -------------------------------------------------------------- 
1089     if (table
.hasResources()) { 
1090         sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
1091         err 
= table
.addSymbols(symbols
); 
1092         if (err 
< NO_ERROR
) { 
1096         sp
<AaptFile
> resFile(getResourceFile(assets
)); 
1097         if (resFile 
== NULL
) { 
1098             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
1099             return UNKNOWN_ERROR
; 
1102         err 
= table
.flatten(bundle
, resFile
); 
1103         if (err 
< NO_ERROR
) { 
1107         if (bundle
->getPublicOutputFile()) { 
1108             FILE* fp 
= fopen(bundle
->getPublicOutputFile(), "w+"); 
1110                 fprintf(stderr
, "ERROR: Unable to open public definitions output file %s: %s\n", 
1111                         (const char*)bundle
->getPublicOutputFile(), strerror(errno
)); 
1112                 return UNKNOWN_ERROR
; 
1114             if (bundle
->getVerbose()) { 
1115                 printf("  Writing public definitions to %s.\n", bundle
->getPublicOutputFile()); 
1117             table
.writePublicDefinitions(String16(assets
->getPackage()), fp
); 
1122               rt
.add(resFile
->getData(), resFile
->getSize(), NULL
); 
1123               printf("Generated resources:\n"); 
1127         // These resources are now considered to be a part of the included 
1128         // resources, for others to reference. 
1129         err 
= assets
->addIncludedResources(resFile
); 
1130         if (err 
< NO_ERROR
) { 
1131             fprintf(stderr
, "ERROR: Unable to parse generated resources, aborting.\n"); 
1139 static const char* getIndentSpace(int indent
) 
1141 static const char whitespace
[] = 
1144     return whitespace 
+ sizeof(whitespace
) - 1 - indent
*4; 
1147 static status_t 
fixupSymbol(String16
* inoutSymbol
) 
1149     inoutSymbol
->replaceAll('.', '_'); 
1150     inoutSymbol
->replaceAll(':', '_'); 
1154 static String16 
getAttributeComment(const sp
<AaptAssets
>& assets
, 
1155                                     const String8
& name
, 
1156                                     String16
* outTypeComment 
= NULL
) 
1158     sp
<AaptSymbols
> asym 
= assets
->getSymbolsFor(String8("R")); 
1160         //printf("Got R symbols!\n"); 
1161         asym 
= asym
->getNestedSymbols().valueFor(String8("attr")); 
1163             //printf("Got attrs symbols! comment %s=%s\n", 
1164             //     name.string(), String8(asym->getComment(name)).string()); 
1165             if (outTypeComment 
!= NULL
) { 
1166                 *outTypeComment 
= asym
->getTypeComment(name
); 
1168             return asym
->getComment(name
); 
1174 static status_t 
writeLayoutClasses( 
1175     FILE* fp
, const sp
<AaptAssets
>& assets
, 
1176     const sp
<AaptSymbols
>& symbols
, int indent
, bool includePrivate
) 
1178     const char* indentStr 
= getIndentSpace(indent
); 
1179     if (!includePrivate
) { 
1180         fprintf(fp
, "%s/** @doconly */\n", indentStr
); 
1182     fprintf(fp
, "%spublic static final class styleable {\n", indentStr
); 
1185     String16 
attr16("attr"); 
1186     String16 
package16(assets
->getPackage()); 
1188     indentStr 
= getIndentSpace(indent
); 
1189     bool hasErrors 
= false; 
1192     size_t N 
= symbols
->getNestedSymbols().size(); 
1193     for (i
=0; i
<N
; i
++) { 
1194         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1195         String16 
nclassName16(symbols
->getNestedSymbols().keyAt(i
)); 
1196         String8 
realClassName(nclassName16
); 
1197         if (fixupSymbol(&nclassName16
) != NO_ERROR
) { 
1200         String8 
nclassName(nclassName16
); 
1202         SortedVector
<uint32_t> idents
; 
1203         Vector
<uint32_t> origOrder
; 
1204         Vector
<bool> publicFlags
; 
1207         size_t NA 
= nsymbols
->getSymbols().size(); 
1208         for (a
=0; a
<NA
; a
++) { 
1209             const AaptSymbolEntry
& sym(nsymbols
->getSymbols().valueAt(a
)); 
1210             int32_t code 
= sym
.typeCode 
== AaptSymbolEntry::TYPE_INT32
 
1212             bool isPublic 
= true; 
1214                 String16 
name16(sym
.name
); 
1215                 uint32_t typeSpecFlags
; 
1216                 code 
= assets
->getIncludedResources().identifierForName( 
1217                     name16
.string(), name16
.size(), 
1218                     attr16
.string(), attr16
.size(), 
1219                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1221                     fprintf(stderr
, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n", 
1222                             nclassName
.string(), sym
.name
.string()); 
1225                 isPublic 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1228             origOrder
.add(code
); 
1229             publicFlags
.add(isPublic
); 
1234         String16 comment 
= symbols
->getComment(realClassName
); 
1235         fprintf(fp
, "%s/** ", indentStr
); 
1236         if (comment
.size() > 0) { 
1237             fprintf(fp
, "%s\n", String8(comment
).string()); 
1239             fprintf(fp
, "Attributes that can be used with a %s.\n", nclassName
.string()); 
1241         bool hasTable 
= false; 
1242         for (a
=0; a
<NA
; a
++) { 
1243             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1248                             "%s   <p>Includes the following attributes:</p>\n" 
1249                             "%s   <table border=\"2\" width=\"85%%\" align=\"center\" frame=\"hsides\" rules=\"all\" cellpadding=\"5\">\n" 
1250                             "%s   <colgroup align=\"left\" />\n" 
1251                             "%s   <colgroup align=\"left\" />\n" 
1252                             "%s   <tr><th>Attribute<th>Summary</tr>\n", 
1259                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1260                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1263                 String8 
name8(sym
.name
); 
1264                 String16 
comment(sym
.comment
); 
1265                 if (comment
.size() <= 0) { 
1266                     comment 
= getAttributeComment(assets
, name8
); 
1268                 if (comment
.size() > 0) { 
1269                     const char16_t* p 
= comment
.string(); 
1270                     while (*p 
!= 0 && *p 
!= '.') { 
1272                             while (*p 
!= 0 && *p 
!= '}') { 
1282                     comment 
= String16(comment
.string(), p
-comment
.string()); 
1284                 String16 
name(name8
); 
1286                 fprintf(fp
, "%s   <tr><th><code>{@link #%s_%s %s:%s}</code><td>%s</tr>\n", 
1287                         indentStr
, nclassName
.string(), 
1288                         String8(name
).string(), 
1289                         assets
->getPackage().string(), 
1290                         String8(name
).string(), 
1291                         String8(comment
).string()); 
1295             fprintf(fp
, "%s   </table>\n", indentStr
); 
1297         for (a
=0; a
<NA
; a
++) { 
1298             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1300                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1301                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1304                 String16 
name(sym
.name
); 
1306                 fprintf(fp
, "%s   @see #%s_%s\n", 
1307                         indentStr
, nclassName
.string(), 
1308                         String8(name
).string()); 
1311         fprintf(fp
, "%s */\n", getIndentSpace(indent
)); 
1314                 "%spublic static final int[] %s = {\n" 
1316                 indentStr
, nclassName
.string(), 
1317                 getIndentSpace(indent
+1)); 
1319         for (a
=0; a
<NA
; a
++) { 
1322                     fprintf(fp
, ",\n%s", getIndentSpace(indent
+1)); 
1327             fprintf(fp
, "0x%08x", idents
[a
]); 
1330         fprintf(fp
, "\n%s};\n", indentStr
); 
1332         for (a
=0; a
<NA
; a
++) { 
1333             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1335                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1336                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1339                 String8 
name8(sym
.name
); 
1340                 String16 
comment(sym
.comment
); 
1341                 String16 typeComment
; 
1342                 if (comment
.size() <= 0) { 
1343                     comment 
= getAttributeComment(assets
, name8
, &typeComment
); 
1345                     getAttributeComment(assets
, name8
, &typeComment
); 
1347                 String16 
name(name8
); 
1348                 if (fixupSymbol(&name
) != NO_ERROR
) { 
1352                 uint32_t typeSpecFlags 
= 0; 
1353                 String16 
name16(sym
.name
); 
1354                 assets
->getIncludedResources().identifierForName( 
1355                     name16
.string(), name16
.size(), 
1356                     attr16
.string(), attr16
.size(), 
1357                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1358                 //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), 
1359                 //    String8(attr16).string(), String8(name16).string(), typeSpecFlags); 
1360                 const bool pub 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1362                 fprintf(fp
, "%s/**\n", indentStr
); 
1363                 if (comment
.size() > 0) { 
1364                     fprintf(fp
, "%s  <p>\n%s  @attr description\n", indentStr
, indentStr
); 
1365                     fprintf(fp
, "%s  %s\n", indentStr
, String8(comment
).string()); 
1368                             "%s  <p>This symbol is the offset where the {@link %s.R.attr#%s}\n" 
1369                             "%s  attribute's value can be found in the {@link #%s} array.\n", 
1371                             pub 
? assets
->getPackage().string() 
1372                                 : assets
->getSymbolsPrivatePackage().string(), 
1373                             String8(name
).string(), 
1374                             indentStr
, nclassName
.string()); 
1376                 if (typeComment
.size() > 0) { 
1377                     fprintf(fp
, "\n\n%s  %s\n", indentStr
, String8(typeComment
).string()); 
1379                 if (comment
.size() > 0) { 
1382                                 "%s  <p>This corresponds to the global attribute" 
1383                                 "%s  resource symbol {@link %s.R.attr#%s}.\n", 
1384                                 indentStr
, indentStr
, 
1385                                 assets
->getPackage().string(), 
1386                                 String8(name
).string()); 
1389                                 "%s  <p>This is a private symbol.\n", indentStr
); 
1392                 fprintf(fp
, "%s  @attr name %s:%s\n", indentStr
, 
1393                         "android", String8(name
).string()); 
1394                 fprintf(fp
, "%s*/\n", indentStr
); 
1396                         "%spublic static final int %s_%s = %d;\n", 
1397                         indentStr
, nclassName
.string(), 
1398                         String8(name
).string(), (int)pos
); 
1404     fprintf(fp
, "%s};\n", getIndentSpace(indent
)); 
1405     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
1408 static status_t 
writeSymbolClass( 
1409     FILE* fp
, const sp
<AaptAssets
>& assets
, bool includePrivate
, 
1410     const sp
<AaptSymbols
>& symbols
, const String8
& className
, int indent
) 
1412     fprintf(fp
, "%spublic %sfinal class %s {\n", 
1413             getIndentSpace(indent
), 
1414             indent 
!= 0 ? "static " : "", className
.string()); 
1418     status_t err 
= NO_ERROR
; 
1420     size_t N 
= symbols
->getSymbols().size(); 
1421     for (i
=0; i
<N
; i
++) { 
1422         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1423         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_INT32
) { 
1426         if (!includePrivate 
&& !sym
.isPublic
) { 
1429         String16 
name(sym
.name
); 
1430         String8 
realName(name
); 
1431         if (fixupSymbol(&name
) != NO_ERROR
) { 
1432             return UNKNOWN_ERROR
; 
1434         String16 
comment(sym
.comment
); 
1435         bool haveComment 
= false; 
1436         if (comment
.size() > 0) { 
1440                     getIndentSpace(indent
), String8(comment
).string()); 
1441         } else if (sym
.isPublic 
&& !includePrivate
) { 
1442             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1443                 assets
->getPackage().string(), className
.string(), 
1444                 String8(sym
.name
).string()); 
1446         String16 
typeComment(sym
.typeComment
); 
1447         if (typeComment
.size() > 0) { 
1452                         getIndentSpace(indent
), String8(typeComment
).string()); 
1456                         getIndentSpace(indent
), String8(typeComment
).string()); 
1460             fprintf(fp
,"%s */\n", getIndentSpace(indent
)); 
1462         fprintf(fp
, "%spublic static final int %s=0x%08x;\n", 
1463                 getIndentSpace(indent
), 
1464                 String8(name
).string(), (int)sym
.int32Val
); 
1467     for (i
=0; i
<N
; i
++) { 
1468         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1469         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_STRING
) { 
1472         if (!includePrivate 
&& !sym
.isPublic
) { 
1475         String16 
name(sym
.name
); 
1476         if (fixupSymbol(&name
) != NO_ERROR
) { 
1477             return UNKNOWN_ERROR
; 
1479         String16 
comment(sym
.comment
); 
1480         if (comment
.size() > 0) { 
1484                     getIndentSpace(indent
), String8(comment
).string(), 
1485                     getIndentSpace(indent
)); 
1486         } else if (sym
.isPublic 
&& !includePrivate
) { 
1487             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1488                 assets
->getPackage().string(), className
.string(), 
1489                 String8(sym
.name
).string()); 
1491         fprintf(fp
, "%spublic static final String %s=\"%s\";\n", 
1492                 getIndentSpace(indent
), 
1493                 String8(name
).string(), sym
.stringVal
.string()); 
1496     sp
<AaptSymbols
> styleableSymbols
; 
1498     N 
= symbols
->getNestedSymbols().size(); 
1499     for (i
=0; i
<N
; i
++) { 
1500         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1501         String8 
nclassName(symbols
->getNestedSymbols().keyAt(i
)); 
1502         if (nclassName 
== "styleable") { 
1503             styleableSymbols 
= nsymbols
; 
1505             err 
= writeSymbolClass(fp
, assets
, includePrivate
, nsymbols
, nclassName
, indent
); 
1507         if (err 
!= NO_ERROR
) { 
1512     if (styleableSymbols 
!= NULL
) { 
1513         err 
= writeLayoutClasses(fp
, assets
, styleableSymbols
, indent
, includePrivate
); 
1514         if (err 
!= NO_ERROR
) { 
1520     fprintf(fp
, "%s}\n", getIndentSpace(indent
)); 
1524 status_t 
writeResourceSymbols(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
1525     const String8
& package
, bool includePrivate
) 
1527     if (!bundle
->getRClassDir()) { 
1531     const size_t N 
= assets
->getSymbols().size(); 
1532     for (size_t i
=0; i
<N
; i
++) { 
1533         sp
<AaptSymbols
> symbols 
= assets
->getSymbols().valueAt(i
); 
1534         String8 
className(assets
->getSymbols().keyAt(i
)); 
1535         String8 
dest(bundle
->getRClassDir()); 
1536         if (bundle
->getMakePackageDirs()) { 
1537             String8 
pkg(package
); 
1538             const char* last 
= pkg
.string(); 
1539             const char* s 
= last
-1; 
1542                 if (s 
> last 
&& (*s 
== '.' || *s 
== 0)) { 
1543                     String8 
part(last
, s
-last
); 
1544                     dest
.appendPath(part
); 
1545 #ifdef HAVE_MS_C_RUNTIME 
1546                     _mkdir(dest
.string()); 
1548                     mkdir(dest
.string(), S_IRUSR
|S_IWUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
); 
1554         dest
.appendPath(className
); 
1555         dest
.append(".java"); 
1556         FILE* fp 
= fopen(dest
.string(), "w+"); 
1558             fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
1559                     dest
.string(), strerror(errno
)); 
1560             return UNKNOWN_ERROR
; 
1562         if (bundle
->getVerbose()) { 
1563             printf("  Writing symbols for class %s.\n", className
.string()); 
1567         "/* AUTO-GENERATED FILE.  DO NOT MODIFY.\n" 
1569         " * This class was automatically generated by the\n" 
1570         " * aapt tool from the resource data it found.  It\n" 
1571         " * should not be modified by hand.\n" 
1574         "package %s;\n\n", package
.string()); 
1576         status_t err 
= writeSymbolClass(fp
, assets
, includePrivate
, symbols
, className
, 0); 
1577         if (err 
!= NO_ERROR
) {