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 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] : '-', 
 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(const sp
<AaptAssets
>& assets
, const sp
<AaptGroup
>& grp
) 
 176     if (grp
->getFiles().size() != 1) { 
 177         fprintf(stderr
, "warning: Multiple AndroidManifest.xml files found, using %s\n", 
 178                 grp
->getFiles().valueAt(0)->getPrintableSource().string()); 
 181     sp
<AaptFile
> file 
= grp
->getFiles().valueAt(0); 
 184     status_t err 
= parseXMLResource(file
, &block
); 
 185     if (err 
!= NO_ERROR
) { 
 188     //printXMLBlock(&block); 
 190     ResXMLTree::event_code_t code
; 
 191     while ((code
=block
.next()) != ResXMLTree::START_TAG
 
 192            && code 
!= ResXMLTree::END_DOCUMENT
 
 193            && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 197     if (code 
!= ResXMLTree::START_TAG
) { 
 198         fprintf(stderr
, "%s:%d: No start tag found\n", 
 199                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 200         return UNKNOWN_ERROR
; 
 202     if (strcmp16(block
.getElementName(&len
), String16("manifest").string()) != 0) { 
 203         fprintf(stderr
, "%s:%d: Invalid start tag %s, expected <manifest>\n", 
 204                 file
->getPrintableSource().string(), block
.getLineNumber(), 
 205                 String8(block
.getElementName(&len
)).string()); 
 206         return UNKNOWN_ERROR
; 
 209     ssize_t nameIndex 
= block
.indexOfAttribute(NULL
, "package"); 
 211         fprintf(stderr
, "%s:%d: <manifest> does not have package attribute.\n", 
 212                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 213         return UNKNOWN_ERROR
; 
 216     assets
->setPackage(String8(block
.getAttributeStringValue(nameIndex
, &len
))); 
 221 // ========================================================================== 
 222 // ========================================================================== 
 223 // ========================================================================== 
 225 static status_t 
makeFileResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 226                                   ResourceTable
* table
, 
 227                                   const sp
<ResourceTypeSet
>& set
, 
 230     String8 
type8(resType
); 
 231     String16 
type16(resType
); 
 233     bool hasErrors 
= false; 
 235     ResourceDirIterator 
it(set
, String8(resType
)); 
 237     while ((res
=it
.next()) == NO_ERROR
) { 
 238         if (bundle
->getVerbose()) { 
 239             printf("    (new resource id %s from %s)\n", 
 240                    it
.getBaseName().string(), it
.getFile()->getPrintableSource().string()); 
 242         String16 
baseName(it
.getBaseName()); 
 243         const char16_t* str 
= baseName
.string(); 
 244         const char16_t* const end 
= str 
+ baseName
.size(); 
 246             if (!((*str 
>= 'a' && *str 
<= 'z') 
 247                     || (*str 
>= '0' && *str 
<= '9') 
 248                     || *str 
== '_' || *str 
== '.')) { 
 249                 fprintf(stderr
, "%s: Invalid file name: must contain only [a-z0-9_.]\n", 
 250                         it
.getPath().string()); 
 255         String8 resPath 
= it
.getPath(); 
 256         resPath
.convertToResPath(); 
 257         table
->addEntry(SourcePos(it
.getPath(), 0), String16(assets
->getPackage()), 
 263         assets
->addResource(it
.getLeafName(), resPath
, it
.getFile(), type8
); 
 266     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
 269 static status_t 
preProcessImages(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 270                           const sp
<ResourceTypeSet
>& set
) 
 272     ResourceDirIterator 
it(set
, String8("drawable")); 
 273     Vector
<sp
<AaptFile
> > newNameFiles
; 
 274     Vector
<String8
> newNamePaths
; 
 275     bool hasErrors 
= false; 
 277     while ((res
=it
.next()) == NO_ERROR
) { 
 278         res 
= preProcessImage(bundle
, assets
, it
.getFile(), NULL
); 
 279         if (res 
< NO_ERROR
) { 
 284     return (hasErrors 
|| (res 
< NO_ERROR
)) ? UNKNOWN_ERROR 
: NO_ERROR
; 
 287 status_t 
postProcessImages(const sp
<AaptAssets
>& assets
, 
 288                            ResourceTable
* table
, 
 289                            const sp
<ResourceTypeSet
>& set
) 
 291     ResourceDirIterator 
it(set
, String8("drawable")); 
 292     bool hasErrors 
= false; 
 294     while ((res
=it
.next()) == NO_ERROR
) { 
 295         res 
= postProcessImage(assets
, table
, it
.getFile()); 
 296         if (res 
< NO_ERROR
) { 
 301     return (hasErrors 
|| (res 
< NO_ERROR
)) ? UNKNOWN_ERROR 
: NO_ERROR
; 
 304 static void collect_files(const sp
<AaptDir
>& dir
, 
 305         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 307     const DefaultKeyedVector
<String8
, sp
<AaptGroup
> >& groups 
= dir
->getFiles(); 
 308     int N 
= groups
.size(); 
 309     for (int i
=0; i
<N
; i
++) { 
 310         String8 leafName 
= groups
.keyAt(i
); 
 311         const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
 313         const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files
 
 316         if (files
.size() == 0) { 
 320         String8 resType 
= files
.valueAt(0)->getResourceType(); 
 322         ssize_t index 
= resources
->indexOfKey(resType
); 
 325             sp
<ResourceTypeSet
> set 
= new ResourceTypeSet(); 
 326             set
->add(leafName
, group
); 
 327             resources
->add(resType
, set
); 
 329             sp
<ResourceTypeSet
> set 
= resources
->valueAt(index
); 
 330             index 
= set
->indexOfKey(leafName
); 
 332                 set
->add(leafName
, group
); 
 334                 sp
<AaptGroup
> existingGroup 
= set
->valueAt(index
); 
 335                 int M 
= files
.size(); 
 336                 for (int j
=0; j
<M
; j
++) { 
 337                     existingGroup
->addFile(files
.valueAt(j
)); 
 344 static void collect_files(const sp
<AaptAssets
>& ass
, 
 345         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 347     const Vector
<sp
<AaptDir
> >& dirs 
= ass
->resDirs(); 
 350     for (int i
=0; i
<N
; i
++) { 
 351         sp
<AaptDir
> d 
= dirs
.itemAt(i
); 
 352         collect_files(d
, resources
); 
 354         // don't try to include the res dir 
 355         ass
->removeDir(d
->getLeaf()); 
 362     ATTR_LEADING_SPACES 
= -3, 
 363     ATTR_TRAILING_SPACES 
= -4 
 365 static int validateAttr(const String8
& path
, const ResXMLParser
& parser
, 
 366         const char* ns
, const char* attr
, const char* validChars
, bool required
) 
 370     ssize_t index 
= parser
.indexOfAttribute(ns
, attr
); 
 372     if (index 
>= 0 && (str
=parser
.getAttributeStringValue(index
, &len
)) != NULL
) { 
 374             for (size_t i
=0; i
<len
; i
++) { 
 376                 const char* p 
= validChars
; 
 386                     fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n", 
 387                             path
.string(), parser
.getLineNumber(), 
 388                             String8(parser
.getElementName(&len
)).string(), attr
, (char)str
[i
]); 
 394             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not start with a space.\n", 
 395                     path
.string(), parser
.getLineNumber(), 
 396                     String8(parser
.getElementName(&len
)).string(), attr
); 
 397             return ATTR_LEADING_SPACES
; 
 399         if (str
[len
-1] == ' ') { 
 400             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not end with a space.\n", 
 401                     path
.string(), parser
.getLineNumber(), 
 402                     String8(parser
.getElementName(&len
)).string(), attr
); 
 403             return ATTR_TRAILING_SPACES
; 
 408         fprintf(stderr
, "%s:%d: Tag <%s> missing required attribute %s.\n", 
 409                 path
.string(), parser
.getLineNumber(), 
 410                 String8(parser
.getElementName(&len
)).string(), attr
); 
 411         return ATTR_NOT_FOUND
; 
 416 static void checkForIds(const String8
& path
, ResXMLParser
& parser
) 
 418     ResXMLTree::event_code_t code
; 
 419     while ((code
=parser
.next()) != ResXMLTree::END_DOCUMENT
 
 420            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
 421         if (code 
== ResXMLTree::START_TAG
) { 
 422             ssize_t index 
= parser
.indexOfAttribute(NULL
, "id"); 
 424                 fprintf(stderr
, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n", 
 425                         path
.string(), parser
.getLineNumber()); 
 431 static bool applyFileOverlay(Bundle 
*bundle
, 
 432                              const sp
<AaptAssets
>& assets
, 
 433                              const sp
<ResourceTypeSet
>& baseSet
, 
 436     if (bundle
->getVerbose()) { 
 437         printf("applyFileOverlay for %s\n", resType
); 
 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                 if (bundle
->getVerbose()) { 
 459                     printf("trying overlaySet Key=%s\n",overlaySet
->keyAt(overlayIndex
).string()); 
 461                 size_t baseIndex 
= baseSet
->indexOfKey(overlaySet
->keyAt(overlayIndex
)); 
 462                 if (baseIndex 
< UNKNOWN_ERROR
) { 
 463                     // look for same flavor.  For a given file (strings.xml, for example) 
 464                     // there may be a locale specific or other flavors - we want to match 
 466                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 467                     sp
<AaptGroup
> baseGroup 
= baseSet
->valueAt(baseIndex
); 
 469                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
= 
 470                             overlayGroup
->getFiles(); 
 471                     if (bundle
->getVerbose()) { 
 472                         DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > baseFiles 
= 
 473                                 baseGroup
->getFiles(); 
 474                         for (size_t i
=0; i 
< baseFiles
.size(); i
++) { 
 475                             printf("baseFile %d has flavor %s\n", i
, 
 476                                     baseFiles
.keyAt(i
).toString().string()); 
 478                         for (size_t i
=0; i 
< overlayFiles
.size(); i
++) { 
 479                             printf("overlayFile %d has flavor %s\n", i
, 
 480                                     overlayFiles
.keyAt(i
).toString().string()); 
 484                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 485                     for (size_t overlayGroupIndex 
= 0; 
 486                             overlayGroupIndex
<overlayGroupSize
; 
 487                             overlayGroupIndex
++) { 
 488                         size_t baseFileIndex 
= 
 489                                 baseGroup
->getFiles().indexOfKey(overlayFiles
. 
 490                                 keyAt(overlayGroupIndex
)); 
 491                         if(baseFileIndex 
< UNKNOWN_ERROR
) { 
 492                             if (bundle
->getVerbose()) { 
 493                                 printf("found a match (%d) for overlay file %s, for flavor %s\n", 
 495                                         overlayGroup
->getLeaf().string(), 
 496                                         overlayFiles
.keyAt(overlayGroupIndex
).toString().string()); 
 498                             baseGroup
->removeFile(baseFileIndex
); 
 500                             // didn't find a match fall through and add it.. 
 502                         baseGroup
->addFile(overlayFiles
.valueAt(overlayGroupIndex
)); 
 503                         assets
->addGroupEntry(overlayFiles
.keyAt(overlayGroupIndex
)); 
 506                     // this group doesn't exist (a file that's only in the overlay) 
 507                     baseSet
->add(overlaySet
->keyAt(overlayIndex
), 
 508                             overlaySet
->valueAt(overlayIndex
)); 
 509                     // make sure all flavors are defined in the resources. 
 510                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 511                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
= 
 512                             overlayGroup
->getFiles(); 
 513                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 514                     for (size_t overlayGroupIndex 
= 0; 
 515                             overlayGroupIndex
<overlayGroupSize
; 
 516                             overlayGroupIndex
++) { 
 517                         assets
->addGroupEntry(overlayFiles
.keyAt(overlayGroupIndex
)); 
 521             // this overlay didn't have resources for this type 
 524         overlay 
= overlay
->getOverlay(); 
 529 void addTagAttribute(const sp
<XMLNode
>& node
, const char* ns8
, 
 530         const char* attr8
, const char* value
) 
 536     const String16 
ns(ns8
); 
 537     const String16 
attr(attr8
); 
 539     if (node
->getAttribute(ns
, attr
) != NULL
) { 
 540         fprintf(stderr
, "Warning: AndroidManifest.xml already defines %s (in %s)\n", 
 541                 String8(attr
).string(), String8(ns
).string()); 
 545     node
->addAttribute(ns
, attr
, String16(value
)); 
 548 status_t 
massageManifest(Bundle
* bundle
, sp
<XMLNode
> root
) 
 550     root 
= root
->searchElement(String16(), String16("manifest")); 
 552         fprintf(stderr
, "No <manifest> tag.\n"); 
 553         return UNKNOWN_ERROR
; 
 556     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionCode", 
 557             bundle
->getVersionCode()); 
 558     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionName", 
 559             bundle
->getVersionName()); 
 561     if (bundle
->getMinSdkVersion() != NULL
 
 562             || bundle
->getTargetSdkVersion() != NULL
 
 563             || bundle
->getMaxSdkVersion() != NULL
) { 
 564         sp
<XMLNode
> vers 
= root
->getChildElement(String16(), String16("uses-sdk")); 
 566             vers 
= XMLNode::newElement(root
->getFilename(), String16(), String16("uses-sdk")); 
 567             root
->insertChildAt(vers
, 0); 
 570         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "minSdkVersion", 
 571                 bundle
->getMinSdkVersion()); 
 572         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "targetSdkVersion", 
 573                 bundle
->getTargetSdkVersion()); 
 574         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "maxSdkVersion", 
 575                 bundle
->getMaxSdkVersion()); 
 581 #define ASSIGN_IT(n) \ 
 583             ssize_t index = resources->indexOfKey(String8(#n)); \ 
 585                 n ## s = resources->valueAt(index); \ 
 589 status_t 
buildResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
 591     // First, look for a package file to parse.  This is required to 
 592     // be able to generate the resource information. 
 593     sp
<AaptGroup
> androidManifestFile 
= 
 594             assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
 595     if (androidManifestFile 
== NULL
) { 
 596         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
 597         return UNKNOWN_ERROR
; 
 600     status_t err 
= parsePackage(assets
, androidManifestFile
); 
 601     if (err 
!= NO_ERROR
) { 
 605     NOISY(printf("Creating resources for package %s\n", 
 606                  assets
->getPackage().string())); 
 608     ResourceTable 
table(bundle
, String16(assets
->getPackage())); 
 609     err 
= table
.addIncludedResources(bundle
, assets
); 
 610     if (err 
!= NO_ERROR
) { 
 614     NOISY(printf("Found %d included resource packages\n", (int)table
.size())); 
 616     // -------------------------------------------------------------- 
 617     // First, gather all resource information. 
 618     // -------------------------------------------------------------- 
 620     // resType -> leafName -> group 
 621     KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 622             new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 623     collect_files(assets
, resources
); 
 625     sp
<ResourceTypeSet
> drawables
; 
 626     sp
<ResourceTypeSet
> layouts
; 
 627     sp
<ResourceTypeSet
> anims
; 
 628     sp
<ResourceTypeSet
> xmls
; 
 629     sp
<ResourceTypeSet
> raws
; 
 630     sp
<ResourceTypeSet
> colors
; 
 631     sp
<ResourceTypeSet
> menus
; 
 641     assets
->setResources(resources
); 
 642     // now go through any resource overlays and collect their files 
 643     sp
<AaptAssets
> current 
= assets
->getOverlay(); 
 644     while(current
.get()) { 
 645         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 646                 new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 647         current
->setResources(resources
); 
 648         collect_files(current
, resources
); 
 649         current 
= current
->getOverlay(); 
 651     // apply the overlay files to the base set 
 652     if (!applyFileOverlay(bundle
, assets
, drawables
, "drawable") || 
 653             !applyFileOverlay(bundle
, assets
, layouts
, "layout") || 
 654             !applyFileOverlay(bundle
, assets
, anims
, "anim") || 
 655             !applyFileOverlay(bundle
, assets
, xmls
, "xml") || 
 656             !applyFileOverlay(bundle
, assets
, raws
, "raw") || 
 657             !applyFileOverlay(bundle
, assets
, colors
, "color") || 
 658             !applyFileOverlay(bundle
, assets
, menus
, "menu")) { 
 659         return UNKNOWN_ERROR
; 
 662     bool hasErrors 
= false; 
 664     if (drawables 
!= NULL
) { 
 665         err 
= preProcessImages(bundle
, assets
, drawables
); 
 666         if (err 
== NO_ERROR
) { 
 667             err 
= makeFileResources(bundle
, assets
, &table
, drawables
, "drawable"); 
 668             if (err 
!= NO_ERROR
) { 
 676     if (layouts 
!= NULL
) { 
 677         err 
= makeFileResources(bundle
, assets
, &table
, layouts
, "layout"); 
 678         if (err 
!= NO_ERROR
) { 
 684         err 
= makeFileResources(bundle
, assets
, &table
, anims
, "anim"); 
 685         if (err 
!= NO_ERROR
) { 
 691         err 
= makeFileResources(bundle
, assets
, &table
, xmls
, "xml"); 
 692         if (err 
!= NO_ERROR
) { 
 698         err 
= makeFileResources(bundle
, assets
, &table
, raws
, "raw"); 
 699         if (err 
!= NO_ERROR
) { 
 706     while(current
.get()) { 
 707         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 708                 current
->getResources(); 
 710         ssize_t index 
= resources
->indexOfKey(String8("values")); 
 712             ResourceDirIterator 
it(resources
->valueAt(index
), String8("values")); 
 714             while ((res
=it
.next()) == NO_ERROR
) { 
 715                 sp
<AaptFile
> file 
= it
.getFile(); 
 716                 res 
= compileResourceFile(bundle
, assets
, file
, it
.getParams(),  
 717                                           (current
!=assets
), &table
); 
 718                 if (res 
!= NO_ERROR
) { 
 723         current 
= current
->getOverlay(); 
 726     if (colors 
!= NULL
) { 
 727         err 
= makeFileResources(bundle
, assets
, &table
, colors
, "color"); 
 728         if (err 
!= NO_ERROR
) { 
 734         err 
= makeFileResources(bundle
, assets
, &table
, menus
, "menu"); 
 735         if (err 
!= NO_ERROR
) { 
 740     // -------------------------------------------------------------------- 
 741     // Assignment of resource IDs and initial generation of resource table. 
 742     // -------------------------------------------------------------------- 
 744     if (table
.hasResources()) { 
 745         sp
<AaptFile
> resFile(getResourceFile(assets
)); 
 746         if (resFile 
== NULL
) { 
 747             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
 748             return UNKNOWN_ERROR
; 
 751         err 
= table
.assignResourceIds(); 
 752         if (err 
< NO_ERROR
) { 
 757     // -------------------------------------------------------------- 
 758     // Finally, we can now we can compile XML files, which may reference 
 760     // -------------------------------------------------------------- 
 762     if (layouts 
!= NULL
) { 
 763         ResourceDirIterator 
it(layouts
, String8("layout")); 
 764         while ((err
=it
.next()) == NO_ERROR
) { 
 765             String8 src 
= it
.getFile()->getPrintableSource(); 
 766             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 767             if (err 
== NO_ERROR
) { 
 769                 block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
 770                 checkForIds(src
, block
); 
 776         if (err 
< NO_ERROR
) { 
 783         ResourceDirIterator 
it(anims
, String8("anim")); 
 784         while ((err
=it
.next()) == NO_ERROR
) { 
 785             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 786             if (err 
!= NO_ERROR
) { 
 791         if (err 
< NO_ERROR
) { 
 798         ResourceDirIterator 
it(xmls
, String8("xml")); 
 799         while ((err
=it
.next()) == NO_ERROR
) { 
 800             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 801             if (err 
!= NO_ERROR
) { 
 806         if (err 
< NO_ERROR
) { 
 812     if (drawables 
!= NULL
) { 
 813         err 
= postProcessImages(assets
, &table
, drawables
); 
 814         if (err 
!= NO_ERROR
) { 
 819     if (colors 
!= NULL
) { 
 820         ResourceDirIterator 
it(colors
, String8("color")); 
 821         while ((err
=it
.next()) == NO_ERROR
) { 
 822           err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 823             if (err 
!= NO_ERROR
) { 
 828         if (err 
< NO_ERROR
) { 
 835         ResourceDirIterator 
it(menus
, String8("menu")); 
 836         while ((err
=it
.next()) == NO_ERROR
) { 
 837             String8 src 
= it
.getFile()->getPrintableSource(); 
 838             err 
= compileXmlFile(assets
, it
.getFile(), &table
); 
 839             if (err 
!= NO_ERROR
) { 
 843             block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
 844             checkForIds(src
, block
); 
 847         if (err 
< NO_ERROR
) { 
 853     const sp
<AaptFile
> manifestFile(androidManifestFile
->getFiles().valueAt(0)); 
 854     String8 
manifestPath(manifestFile
->getPrintableSource()); 
 856     // Perform a basic validation of the manifest file.  This time we 
 857     // parse it with the comments intact, so that we can use them to 
 858     // generate java docs...  so we are not going to write this one 
 859     // back out to the final manifest data. 
 860     err 
= compileXmlFile(assets
, manifestFile
, &table
, 
 861             XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
 
 862             | XML_COMPILE_STRIP_WHITESPACE 
| XML_COMPILE_STRIP_RAW_VALUES
); 
 863     if (err 
< NO_ERROR
) { 
 867     block
.setTo(manifestFile
->getData(), manifestFile
->getSize(), true); 
 868     String16 
manifest16("manifest"); 
 869     String16 
permission16("permission"); 
 870     String16 
permission_group16("permission-group"); 
 871     String16 
uses_permission16("uses-permission"); 
 872     String16 
instrumentation16("instrumentation"); 
 873     String16 
application16("application"); 
 874     String16 
provider16("provider"); 
 875     String16 
service16("service"); 
 876     String16 
receiver16("receiver"); 
 877     String16 
activity16("activity"); 
 878     String16 
action16("action"); 
 879     String16 
category16("category"); 
 880     String16 
data16("scheme"); 
 881     const char* packageIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 882         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789"; 
 883     const char* packageIdentCharsWithTheStupid 
= "abcdefghijklmnopqrstuvwxyz" 
 884         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
 885     const char* classIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 886         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789$"; 
 887     const char* processIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 888         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:"; 
 889     const char* authoritiesIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 890         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-:;"; 
 891     const char* typeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 892         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:-/*+"; 
 893     const char* schemeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
 894         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
 895     ResXMLTree::event_code_t code
; 
 896     sp
<AaptSymbols
> permissionSymbols
; 
 897     sp
<AaptSymbols
> permissionGroupSymbols
; 
 898     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 899            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
 900         if (code 
== ResXMLTree::START_TAG
) { 
 902             if (block
.getElementNamespace(&len
) != NULL
) { 
 905             if (strcmp16(block
.getElementName(&len
), manifest16
.string()) == 0) { 
 906                 if (validateAttr(manifestPath
, block
, NULL
, "package", 
 907                                  packageIdentChars
, true) != ATTR_OKAY
) { 
 910             } else if (strcmp16(block
.getElementName(&len
), permission16
.string()) == 0 
 911                     || strcmp16(block
.getElementName(&len
), permission_group16
.string()) == 0) { 
 912                 const bool isGroup 
= strcmp16(block
.getElementName(&len
), 
 913                         permission_group16
.string()) == 0; 
 914                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 915                                  isGroup 
? packageIdentCharsWithTheStupid
 
 916                                  : packageIdentChars
, true) != ATTR_OKAY
) { 
 919                 SourcePos 
srcPos(manifestPath
, block
.getLineNumber()); 
 920                 sp
<AaptSymbols
> syms
; 
 922                     syms 
= permissionSymbols
; 
 924                         sp
<AaptSymbols
> symbols 
= 
 925                                 assets
->getSymbolsFor(String8("Manifest")); 
 926                         syms 
= permissionSymbols 
= symbols
->addNestedSymbol( 
 927                                 String8("permission"), srcPos
); 
 930                     syms 
= permissionGroupSymbols
; 
 932                         sp
<AaptSymbols
> symbols 
= 
 933                                 assets
->getSymbolsFor(String8("Manifest")); 
 934                         syms 
= permissionGroupSymbols 
= symbols
->addNestedSymbol( 
 935                                 String8("permission_group"), srcPos
); 
 939                 ssize_t index 
= block
.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE
, "name"); 
 940                 const uint16_t* id 
= block
.getAttributeStringValue(index
, &len
); 
 942                     fprintf(stderr
, "%s:%d: missing name attribute in element <%s>.\n",  
 943                             manifestPath
.string(), block
.getLineNumber(), 
 944                             String8(block
.getElementName(&len
)).string()); 
 949                 char* p 
= idStr
.lockBuffer(idStr
.size()); 
 950                 char* e 
= p 
+ idStr
.size(); 
 951                 bool begins_with_digit 
= true;  // init to true so an empty string fails 
 954                     if (*e 
>= '0' && *e 
<= '9') { 
 955                       begins_with_digit 
= true; 
 958                     if ((*e 
>= 'a' && *e 
<= 'z') || 
 959                         (*e 
>= 'A' && *e 
<= 'Z') || 
 961                       begins_with_digit 
= false; 
 964                     if (isGroup 
&& (*e 
== '-')) { 
 966                         begins_with_digit 
= false; 
 972                 idStr
.unlockBuffer(); 
 973                 // verify that we stopped because we hit a period or 
 974                 // the beginning of the string, and that the 
 975                 // identifier didn't begin with a digit. 
 976                 if (begins_with_digit 
|| (e 
!= p 
&& *(e
-1) != '.')) { 
 978                           "%s:%d: Permission name <%s> is not a valid Java symbol\n", 
 979                           manifestPath
.string(), block
.getLineNumber(), idStr
.string()); 
 982                 syms
->addStringSymbol(String8(e
), idStr
, srcPos
); 
 983                 const uint16_t* cmt 
= block
.getComment(&len
); 
 984                 if (cmt 
!= NULL 
&& *cmt 
!= 0) { 
 985                     //printf("Comment of %s: %s\n", String8(e).string(), 
 986                     //        String8(cmt).string()); 
 987                     syms
->appendComment(String8(e
), String16(cmt
), srcPos
); 
 989                     //printf("No comment for %s\n", String8(e).string()); 
 991                 syms
->makeSymbolPublic(String8(e
), srcPos
); 
 992             } else if (strcmp16(block
.getElementName(&len
), uses_permission16
.string()) == 0) { 
 993                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 994                                  packageIdentChars
, true) != ATTR_OKAY
) { 
 997             } else if (strcmp16(block
.getElementName(&len
), instrumentation16
.string()) == 0) { 
 998                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
 999                                  classIdentChars
, true) != ATTR_OKAY
) { 
1002                 if (validateAttr(manifestPath
, block
, 
1003                                  RESOURCES_ANDROID_NAMESPACE
, "targetPackage", 
1004                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1007             } else if (strcmp16(block
.getElementName(&len
), application16
.string()) == 0) { 
1008                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
1009                                  classIdentChars
, false) != ATTR_OKAY
) { 
1012                 if (validateAttr(manifestPath
, block
, 
1013                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1014                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1017                 if (validateAttr(manifestPath
, block
, 
1018                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1019                                  processIdentChars
, false) != ATTR_OKAY
) { 
1022                 if (validateAttr(manifestPath
, block
, 
1023                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1024                                  processIdentChars
, false) != ATTR_OKAY
) { 
1027             } else if (strcmp16(block
.getElementName(&len
), provider16
.string()) == 0) { 
1028                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
1029                                  classIdentChars
, true) != ATTR_OKAY
) { 
1032                 if (validateAttr(manifestPath
, block
, 
1033                                  RESOURCES_ANDROID_NAMESPACE
, "authorities", 
1034                                  authoritiesIdentChars
, true) != ATTR_OKAY
) { 
1037                 if (validateAttr(manifestPath
, block
, 
1038                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1039                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1042                 if (validateAttr(manifestPath
, block
, 
1043                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1044                                  processIdentChars
, false) != ATTR_OKAY
) { 
1047             } else if (strcmp16(block
.getElementName(&len
), service16
.string()) == 0 
1048                        || strcmp16(block
.getElementName(&len
), receiver16
.string()) == 0 
1049                        || strcmp16(block
.getElementName(&len
), activity16
.string()) == 0) { 
1050                 if (validateAttr(manifestPath
, block
, RESOURCES_ANDROID_NAMESPACE
, "name", 
1051                                  classIdentChars
, true) != ATTR_OKAY
) { 
1054                 if (validateAttr(manifestPath
, block
, 
1055                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1056                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1059                 if (validateAttr(manifestPath
, block
, 
1060                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1061                                  processIdentChars
, false) != ATTR_OKAY
) { 
1064                 if (validateAttr(manifestPath
, block
, 
1065                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1066                                  processIdentChars
, false) != ATTR_OKAY
) { 
1069             } else if (strcmp16(block
.getElementName(&len
), action16
.string()) == 0 
1070                        || strcmp16(block
.getElementName(&len
), category16
.string()) == 0) { 
1071                 if (validateAttr(manifestPath
, block
, 
1072                                  RESOURCES_ANDROID_NAMESPACE
, "name", 
1073                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1076             } else if (strcmp16(block
.getElementName(&len
), data16
.string()) == 0) { 
1077                 if (validateAttr(manifestPath
, block
, 
1078                                  RESOURCES_ANDROID_NAMESPACE
, "mimeType", 
1079                                  typeIdentChars
, true) != ATTR_OKAY
) { 
1082                 if (validateAttr(manifestPath
, block
, 
1083                                  RESOURCES_ANDROID_NAMESPACE
, "scheme", 
1084                                  schemeIdentChars
, true) != ATTR_OKAY
) { 
1091     if (table
.validateLocalizations()) { 
1096         return UNKNOWN_ERROR
; 
1099     // Generate final compiled manifest file. 
1100     manifestFile
->clearData(); 
1101     sp
<XMLNode
> manifestTree 
= XMLNode::parse(manifestFile
); 
1102     if (manifestTree 
== NULL
) { 
1103         return UNKNOWN_ERROR
; 
1105     err 
= massageManifest(bundle
, manifestTree
); 
1106     if (err 
< NO_ERROR
) { 
1109     err 
= compileXmlFile(assets
, manifestTree
, manifestFile
, &table
); 
1110     if (err 
< NO_ERROR
) { 
1115     //printXMLBlock(&block); 
1117     // -------------------------------------------------------------- 
1118     // Generate the final resource table. 
1119     // Re-flatten because we may have added new resource IDs 
1120     // -------------------------------------------------------------- 
1122     if (table
.hasResources()) { 
1123         sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
1124         err 
= table
.addSymbols(symbols
); 
1125         if (err 
< NO_ERROR
) { 
1129         sp
<AaptFile
> resFile(getResourceFile(assets
)); 
1130         if (resFile 
== NULL
) { 
1131             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
1132             return UNKNOWN_ERROR
; 
1135         err 
= table
.flatten(bundle
, resFile
); 
1136         if (err 
< NO_ERROR
) { 
1140         if (bundle
->getPublicOutputFile()) { 
1141             FILE* fp 
= fopen(bundle
->getPublicOutputFile(), "w+"); 
1143                 fprintf(stderr
, "ERROR: Unable to open public definitions output file %s: %s\n", 
1144                         (const char*)bundle
->getPublicOutputFile(), strerror(errno
)); 
1145                 return UNKNOWN_ERROR
; 
1147             if (bundle
->getVerbose()) { 
1148                 printf("  Writing public definitions to %s.\n", bundle
->getPublicOutputFile()); 
1150             table
.writePublicDefinitions(String16(assets
->getPackage()), fp
); 
1156               rt
.add(resFile
->getData(), resFile
->getSize(), NULL
); 
1157               printf("Generated resources:\n"); 
1161         // These resources are now considered to be a part of the included 
1162         // resources, for others to reference. 
1163         err 
= assets
->addIncludedResources(resFile
); 
1164         if (err 
< NO_ERROR
) { 
1165             fprintf(stderr
, "ERROR: Unable to parse generated resources, aborting.\n"); 
1172 static const char* getIndentSpace(int indent
) 
1174 static const char whitespace
[] = 
1177     return whitespace 
+ sizeof(whitespace
) - 1 - indent
*4; 
1180 static status_t 
fixupSymbol(String16
* inoutSymbol
) 
1182     inoutSymbol
->replaceAll('.', '_'); 
1183     inoutSymbol
->replaceAll(':', '_'); 
1187 static String16 
getAttributeComment(const sp
<AaptAssets
>& assets
, 
1188                                     const String8
& name
, 
1189                                     String16
* outTypeComment 
= NULL
) 
1191     sp
<AaptSymbols
> asym 
= assets
->getSymbolsFor(String8("R")); 
1193         //printf("Got R symbols!\n"); 
1194         asym 
= asym
->getNestedSymbols().valueFor(String8("attr")); 
1196             //printf("Got attrs symbols! comment %s=%s\n", 
1197             //     name.string(), String8(asym->getComment(name)).string()); 
1198             if (outTypeComment 
!= NULL
) { 
1199                 *outTypeComment 
= asym
->getTypeComment(name
); 
1201             return asym
->getComment(name
); 
1207 static status_t 
writeLayoutClasses( 
1208     FILE* fp
, const sp
<AaptAssets
>& assets
, 
1209     const sp
<AaptSymbols
>& symbols
, int indent
, bool includePrivate
) 
1211     const char* indentStr 
= getIndentSpace(indent
); 
1212     if (!includePrivate
) { 
1213         fprintf(fp
, "%s/** @doconly */\n", indentStr
); 
1215     fprintf(fp
, "%spublic static final class styleable {\n", indentStr
); 
1218     String16 
attr16("attr"); 
1219     String16 
package16(assets
->getPackage()); 
1221     indentStr 
= getIndentSpace(indent
); 
1222     bool hasErrors 
= false; 
1225     size_t N 
= symbols
->getNestedSymbols().size(); 
1226     for (i
=0; i
<N
; i
++) { 
1227         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1228         String16 
nclassName16(symbols
->getNestedSymbols().keyAt(i
)); 
1229         String8 
realClassName(nclassName16
); 
1230         if (fixupSymbol(&nclassName16
) != NO_ERROR
) { 
1233         String8 
nclassName(nclassName16
); 
1235         SortedVector
<uint32_t> idents
; 
1236         Vector
<uint32_t> origOrder
; 
1237         Vector
<bool> publicFlags
; 
1240         size_t NA 
= nsymbols
->getSymbols().size(); 
1241         for (a
=0; a
<NA
; a
++) { 
1242             const AaptSymbolEntry
& sym(nsymbols
->getSymbols().valueAt(a
)); 
1243             int32_t code 
= sym
.typeCode 
== AaptSymbolEntry::TYPE_INT32
 
1245             bool isPublic 
= true; 
1247                 String16 
name16(sym
.name
); 
1248                 uint32_t typeSpecFlags
; 
1249                 code 
= assets
->getIncludedResources().identifierForName( 
1250                     name16
.string(), name16
.size(), 
1251                     attr16
.string(), attr16
.size(), 
1252                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1254                     fprintf(stderr
, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n", 
1255                             nclassName
.string(), sym
.name
.string()); 
1258                 isPublic 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1261             origOrder
.add(code
); 
1262             publicFlags
.add(isPublic
); 
1267         bool deprecated 
= false; 
1269         String16 comment 
= symbols
->getComment(realClassName
); 
1270         fprintf(fp
, "%s/** ", indentStr
); 
1271         if (comment
.size() > 0) { 
1272             String8 
cmt(comment
); 
1273             fprintf(fp
, "%s\n", cmt
.string()); 
1274             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1278             fprintf(fp
, "Attributes that can be used with a %s.\n", nclassName
.string()); 
1280         bool hasTable 
= false; 
1281         for (a
=0; a
<NA
; a
++) { 
1282             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1287                             "%s   <p>Includes the following attributes:</p>\n" 
1288                             "%s   <table border=\"2\" width=\"85%%\" align=\"center\" frame=\"hsides\" rules=\"all\" cellpadding=\"5\">\n" 
1289                             "%s   <colgroup align=\"left\" />\n" 
1290                             "%s   <colgroup align=\"left\" />\n" 
1291                             "%s   <tr><th>Attribute<th>Summary</tr>\n", 
1298                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1299                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1302                 String8 
name8(sym
.name
); 
1303                 String16 
comment(sym
.comment
); 
1304                 if (comment
.size() <= 0) { 
1305                     comment 
= getAttributeComment(assets
, name8
); 
1307                 if (comment
.size() > 0) { 
1308                     const char16_t* p 
= comment
.string(); 
1309                     while (*p 
!= 0 && *p 
!= '.') { 
1311                             while (*p 
!= 0 && *p 
!= '}') { 
1321                     comment 
= String16(comment
.string(), p
-comment
.string()); 
1323                 String16 
name(name8
); 
1325                 fprintf(fp
, "%s   <tr><th><code>{@link #%s_%s %s:%s}</code><td>%s</tr>\n", 
1326                         indentStr
, nclassName
.string(), 
1327                         String8(name
).string(), 
1328                         assets
->getPackage().string(), 
1329                         String8(name
).string(), 
1330                         String8(comment
).string()); 
1334             fprintf(fp
, "%s   </table>\n", indentStr
); 
1336         for (a
=0; a
<NA
; a
++) { 
1337             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1339                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1340                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1343                 String16 
name(sym
.name
); 
1345                 fprintf(fp
, "%s   @see #%s_%s\n", 
1346                         indentStr
, nclassName
.string(), 
1347                         String8(name
).string()); 
1350         fprintf(fp
, "%s */\n", getIndentSpace(indent
)); 
1353             fprintf(fp
, "%s@Deprecated\n", indentStr
); 
1357                 "%spublic static final int[] %s = {\n" 
1359                 indentStr
, nclassName
.string(), 
1360                 getIndentSpace(indent
+1)); 
1362         for (a
=0; a
<NA
; a
++) { 
1365                     fprintf(fp
, ",\n%s", getIndentSpace(indent
+1)); 
1370             fprintf(fp
, "0x%08x", idents
[a
]); 
1373         fprintf(fp
, "\n%s};\n", indentStr
); 
1375         for (a
=0; a
<NA
; a
++) { 
1376             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1378                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1379                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1382                 String8 
name8(sym
.name
); 
1383                 String16 
comment(sym
.comment
); 
1384                 String16 typeComment
; 
1385                 if (comment
.size() <= 0) { 
1386                     comment 
= getAttributeComment(assets
, name8
, &typeComment
); 
1388                     getAttributeComment(assets
, name8
, &typeComment
); 
1390                 String16 
name(name8
); 
1391                 if (fixupSymbol(&name
) != NO_ERROR
) { 
1395                 uint32_t typeSpecFlags 
= 0; 
1396                 String16 
name16(sym
.name
); 
1397                 assets
->getIncludedResources().identifierForName( 
1398                     name16
.string(), name16
.size(), 
1399                     attr16
.string(), attr16
.size(), 
1400                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1401                 //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), 
1402                 //    String8(attr16).string(), String8(name16).string(), typeSpecFlags); 
1403                 const bool pub 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1405                 bool deprecated 
= false; 
1407                 fprintf(fp
, "%s/**\n", indentStr
); 
1408                 if (comment
.size() > 0) { 
1409                     String8 
cmt(comment
); 
1410                     fprintf(fp
, "%s  <p>\n%s  @attr description\n", indentStr
, indentStr
); 
1411                     fprintf(fp
, "%s  %s\n", indentStr
, cmt
.string()); 
1412                     if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1417                             "%s  <p>This symbol is the offset where the {@link %s.R.attr#%s}\n" 
1418                             "%s  attribute's value can be found in the {@link #%s} array.\n", 
1420                             pub 
? assets
->getPackage().string() 
1421                                 : assets
->getSymbolsPrivatePackage().string(), 
1422                             String8(name
).string(), 
1423                             indentStr
, nclassName
.string()); 
1425                 if (typeComment
.size() > 0) { 
1426                     String8 
cmt(typeComment
); 
1427                     fprintf(fp
, "\n\n%s  %s\n", indentStr
, cmt
.string()); 
1428                     if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1432                 if (comment
.size() > 0) { 
1435                                 "%s  <p>This corresponds to the global attribute" 
1436                                 "%s  resource symbol {@link %s.R.attr#%s}.\n", 
1437                                 indentStr
, indentStr
, 
1438                                 assets
->getPackage().string(), 
1439                                 String8(name
).string()); 
1442                                 "%s  <p>This is a private symbol.\n", indentStr
); 
1445                 fprintf(fp
, "%s  @attr name %s:%s\n", indentStr
, 
1446                         "android", String8(name
).string()); 
1447                 fprintf(fp
, "%s*/\n", indentStr
); 
1449                     fprintf(fp
, "%s@Deprecated\n", indentStr
); 
1452                         "%spublic static final int %s_%s = %d;\n", 
1453                         indentStr
, nclassName
.string(), 
1454                         String8(name
).string(), (int)pos
); 
1460     fprintf(fp
, "%s};\n", getIndentSpace(indent
)); 
1461     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
1464 static status_t 
writeSymbolClass( 
1465     FILE* fp
, const sp
<AaptAssets
>& assets
, bool includePrivate
, 
1466     const sp
<AaptSymbols
>& symbols
, const String8
& className
, int indent
) 
1468     fprintf(fp
, "%spublic %sfinal class %s {\n", 
1469             getIndentSpace(indent
), 
1470             indent 
!= 0 ? "static " : "", className
.string()); 
1474     status_t err 
= NO_ERROR
; 
1476     size_t N 
= symbols
->getSymbols().size(); 
1477     for (i
=0; i
<N
; i
++) { 
1478         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1479         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_INT32
) { 
1482         if (!includePrivate 
&& !sym
.isPublic
) { 
1485         String16 
name(sym
.name
); 
1486         String8 
realName(name
); 
1487         if (fixupSymbol(&name
) != NO_ERROR
) { 
1488             return UNKNOWN_ERROR
; 
1490         String16 
comment(sym
.comment
); 
1491         bool haveComment 
= false; 
1492         bool deprecated 
= false; 
1493         if (comment
.size() > 0) { 
1495             String8 
cmt(comment
); 
1498                     getIndentSpace(indent
), cmt
.string()); 
1499             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1502         } else if (sym
.isPublic 
&& !includePrivate
) { 
1503             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1504                 assets
->getPackage().string(), className
.string(), 
1505                 String8(sym
.name
).string()); 
1507         String16 
typeComment(sym
.typeComment
); 
1508         if (typeComment
.size() > 0) { 
1509             String8 
cmt(typeComment
); 
1513                         "%s/** %s\n", getIndentSpace(indent
), cmt
.string()); 
1516                         "%s %s\n", getIndentSpace(indent
), cmt
.string()); 
1518             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1523             fprintf(fp
,"%s */\n", getIndentSpace(indent
)); 
1526             fprintf(fp
, "%s@Deprecated\n", getIndentSpace(indent
)); 
1528         fprintf(fp
, "%spublic static final int %s=0x%08x;\n", 
1529                 getIndentSpace(indent
), 
1530                 String8(name
).string(), (int)sym
.int32Val
); 
1533     for (i
=0; i
<N
; i
++) { 
1534         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1535         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_STRING
) { 
1538         if (!includePrivate 
&& !sym
.isPublic
) { 
1541         String16 
name(sym
.name
); 
1542         if (fixupSymbol(&name
) != NO_ERROR
) { 
1543             return UNKNOWN_ERROR
; 
1545         String16 
comment(sym
.comment
); 
1546         bool deprecated 
= false; 
1547         if (comment
.size() > 0) { 
1548             String8 
cmt(comment
); 
1552                     getIndentSpace(indent
), cmt
.string(), 
1553                     getIndentSpace(indent
)); 
1554             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1557         } else if (sym
.isPublic 
&& !includePrivate
) { 
1558             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1559                 assets
->getPackage().string(), className
.string(), 
1560                 String8(sym
.name
).string()); 
1563             fprintf(fp
, "%s@Deprecated\n", getIndentSpace(indent
)); 
1565         fprintf(fp
, "%spublic static final String %s=\"%s\";\n", 
1566                 getIndentSpace(indent
), 
1567                 String8(name
).string(), sym
.stringVal
.string()); 
1570     sp
<AaptSymbols
> styleableSymbols
; 
1572     N 
= symbols
->getNestedSymbols().size(); 
1573     for (i
=0; i
<N
; i
++) { 
1574         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1575         String8 
nclassName(symbols
->getNestedSymbols().keyAt(i
)); 
1576         if (nclassName 
== "styleable") { 
1577             styleableSymbols 
= nsymbols
; 
1579             err 
= writeSymbolClass(fp
, assets
, includePrivate
, nsymbols
, nclassName
, indent
); 
1581         if (err 
!= NO_ERROR
) { 
1586     if (styleableSymbols 
!= NULL
) { 
1587         err 
= writeLayoutClasses(fp
, assets
, styleableSymbols
, indent
, includePrivate
); 
1588         if (err 
!= NO_ERROR
) { 
1594     fprintf(fp
, "%s}\n", getIndentSpace(indent
)); 
1598 status_t 
writeResourceSymbols(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
1599     const String8
& package
, bool includePrivate
) 
1601     if (!bundle
->getRClassDir()) { 
1605     const size_t N 
= assets
->getSymbols().size(); 
1606     for (size_t i
=0; i
<N
; i
++) { 
1607         sp
<AaptSymbols
> symbols 
= assets
->getSymbols().valueAt(i
); 
1608         String8 
className(assets
->getSymbols().keyAt(i
)); 
1609         String8 
dest(bundle
->getRClassDir()); 
1610         if (bundle
->getMakePackageDirs()) { 
1611             String8 
pkg(package
); 
1612             const char* last 
= pkg
.string(); 
1613             const char* s 
= last
-1; 
1616                 if (s 
> last 
&& (*s 
== '.' || *s 
== 0)) { 
1617                     String8 
part(last
, s
-last
); 
1618                     dest
.appendPath(part
); 
1619 #ifdef HAVE_MS_C_RUNTIME 
1620                     _mkdir(dest
.string()); 
1622                     mkdir(dest
.string(), S_IRUSR
|S_IWUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
); 
1628         dest
.appendPath(className
); 
1629         dest
.append(".java"); 
1630         FILE* fp 
= fopen(dest
.string(), "w+"); 
1632             fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
1633                     dest
.string(), strerror(errno
)); 
1634             return UNKNOWN_ERROR
; 
1636         if (bundle
->getVerbose()) { 
1637             printf("  Writing symbols for class %s.\n", className
.string()); 
1641         "/* AUTO-GENERATED FILE.  DO NOT MODIFY.\n" 
1643         " * This class was automatically generated by the\n" 
1644         " * aapt tool from the resource data it found.  It\n" 
1645         " * should not be modified by hand.\n" 
1648         "package %s;\n\n", package
.string()); 
1650         status_t err 
= writeSymbolClass(fp
, assets
, includePrivate
, symbols
, className
, 0); 
1651         if (err 
!= NO_ERROR
) { 
1662 class ProguardKeepSet
 
1665     // { rule --> { file locations } } 
1666     KeyedVector
<String8
, SortedVector
<String8
> > rules
; 
1668     void add(const String8
& rule
, const String8
& where
); 
1671 void ProguardKeepSet::add(const String8
& rule
, const String8
& where
) 
1673     ssize_t index 
= rules
.indexOfKey(rule
); 
1675         index 
= rules
.add(rule
, SortedVector
<String8
>()); 
1677     rules
.editValueAt(index
).add(where
); 
1681 writeProguardForAndroidManifest(ProguardKeepSet
* keep
, const sp
<AaptAssets
>& assets
) 
1686     ResXMLTree::event_code_t code
; 
1688     bool inApplication 
= false; 
1690     sp
<AaptGroup
> assGroup
; 
1691     sp
<AaptFile
> assFile
; 
1694     // First, look for a package file to parse.  This is required to 
1695     // be able to generate the resource information. 
1696     assGroup 
= assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
1697     if (assGroup 
== NULL
) { 
1698         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
1702     if (assGroup
->getFiles().size() != 1) { 
1703         fprintf(stderr
, "warning: Multiple AndroidManifest.xml files found, using %s\n", 
1704                 assGroup
->getFiles().valueAt(0)->getPrintableSource().string()); 
1707     assFile 
= assGroup
->getFiles().valueAt(0); 
1709     err 
= parseXMLResource(assFile
, &tree
); 
1710     if (err 
!= NO_ERROR
) { 
1716     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
1717         if (code 
== ResXMLTree::END_TAG
) { 
1718             if (/* name == "Application" && */ depth 
== 2) { 
1719                 inApplication 
= false; 
1724         if (code 
!= ResXMLTree::START_TAG
) { 
1728         String8 
tag(tree
.getElementName(&len
)); 
1729         // printf("Depth %d tag %s\n", depth, tag.string()); 
1731             if (tag 
!= "manifest") { 
1732                 fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
1735             pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
1736         } else if (depth 
== 2 && tag 
== "application") { 
1737             inApplication 
= true; 
1739         if (inApplication
) { 
1740             if (tag 
== "application" || tag 
== "activity" || tag 
== "service" || tag 
== "receiver" 
1741                     || tag 
== "provider") { 
1742                 String8 name 
= getAttribute(tree
, "http://schemas.android.com/apk/res/android", 
1745                     fprintf(stderr
, "ERROR: %s\n", error
.string()); 
1748                 // asdf     --> package.asdf 
1749                 // .asdf  .a.b  --> package.asdf package.a.b 
1750                 // asdf.adsf --> asdf.asdf 
1751                 String8 
rule("-keep class "); 
1752                 const char* p 
= name
.string(); 
1753                 const char* q 
= strchr(p
, '.'); 
1757                 } else if (q 
== NULL
) { 
1765                 String8 location 
= tag
; 
1767                 location 
+= assFile
->getSourceFile(); 
1769                 sprintf(lineno
, ":%d", tree
.getLineNumber()); 
1772                 keep
->add(rule
, location
); 
1781 writeProguardForLayout(ProguardKeepSet
* keep
, const sp
<AaptFile
>& layoutFile
) 
1786     ResXMLTree::event_code_t code
; 
1788     err 
= parseXMLResource(layoutFile
, &tree
); 
1789     if (err 
!= NO_ERROR
) { 
1795     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
1796         if (code 
!= ResXMLTree::START_TAG
) { 
1799         String8 
tag(tree
.getElementName(&len
)); 
1801         // If there is no '.', we'll assume that it's one of the built in names. 
1802         if (strchr(tag
.string(), '.')) { 
1803             String8 
rule("-keep class "); 
1805             rule 
+= " { <init>(...); }"; 
1807             String8 
location("view "); 
1808             location 
+= layoutFile
->getSourceFile(); 
1810             sprintf(lineno
, ":%d", tree
.getLineNumber()); 
1813             keep
->add(rule
, location
); 
1821 writeProguardForLayouts(ProguardKeepSet
* keep
, const sp
<AaptAssets
>& assets
) 
1824     sp
<AaptDir
> layout 
= assets
->resDir(String8("layout")); 
1826     if (layout 
!= NULL
) { 
1827         const KeyedVector
<String8
,sp
<AaptGroup
> > groups 
= layout
->getFiles(); 
1828         const size_t N 
= groups
.size(); 
1829         for (size_t i
=0; i
<N
; i
++) { 
1830             const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
1831             const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files 
= group
->getFiles(); 
1832             const size_t M 
= files
.size(); 
1833             for (size_t j
=0; j
<M
; j
++) { 
1834                 err 
= writeProguardForLayout(keep
, files
.valueAt(j
)); 
1845 writeProguardFile(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
1849     if (!bundle
->getProguardFile()) { 
1853     ProguardKeepSet keep
; 
1855     err 
= writeProguardForAndroidManifest(&keep
, assets
); 
1860     err 
= writeProguardForLayouts(&keep
, assets
); 
1865     FILE* fp 
= fopen(bundle
->getProguardFile(), "w+"); 
1867         fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
1868                 bundle
->getProguardFile(), strerror(errno
)); 
1869         return UNKNOWN_ERROR
; 
1872     const KeyedVector
<String8
, SortedVector
<String8
> >& rules 
= keep
.rules
; 
1873     const size_t N 
= rules
.size(); 
1874     for (size_t i
=0; i
<N
; i
++) { 
1875         const SortedVector
<String8
>& locations 
= rules
.valueAt(i
); 
1876         const size_t M 
= locations
.size(); 
1877         for (size_t j
=0; j
<M
; j
++) { 
1878             fprintf(fp
, "# %s\n", locations
.itemAt(j
).string()); 
1880         fprintf(fp
, "%s\n\n", rules
.keyAt(i
).string());