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" 
  13 #include "CrunchCache.h" 
  14 #include "FileFinder.h" 
  15 #include "CacheUpdater.h" 
  17 #include <utils/WorkQueue.h> 
  21 #  define ZD_TYPE ssize_t 
  29 // Number of threads to use for preprocessing images. 
  30 static const size_t MAX_THREADS 
= 4; 
  32 // ========================================================================== 
  33 // ========================================================================== 
  34 // ========================================================================== 
  46     status_t 
parsePackage(const sp
<AaptGroup
>& grp
); 
  49 // ========================================================================== 
  50 // ========================================================================== 
  51 // ========================================================================== 
  53 static String8 
parseResourceName(const String8
& leaf
) 
  55     const char* firstDot 
= strchr(leaf
.string(), '.'); 
  56     const char* str 
= leaf
.string(); 
  59         return String8(str
, firstDot
-str
); 
  65 ResourceTypeSet::ResourceTypeSet() 
  67      KeyedVector
<String8
,sp
<AaptGroup
> >() 
  71 FilePathStore::FilePathStore() 
  77 class ResourceDirIterator
 
  80     ResourceDirIterator(const sp
<ResourceTypeSet
>& set
, const String8
& resType
) 
  81         : mResType(resType
), mSet(set
), mSetPos(0), mGroupPos(0) 
  85     inline const sp
<AaptGroup
>& getGroup() const { return mGroup
; } 
  86     inline const sp
<AaptFile
>& getFile() const { return mFile
; } 
  88     inline const String8
& getBaseName() const { return mBaseName
; } 
  89     inline const String8
& getLeafName() const { return mLeafName
; } 
  90     inline String8 
getPath() const { return mPath
; } 
  91     inline const ResTable_config
& getParams() const { return mParams
; } 
 103             // Try to get next file in this current group. 
 104             if (mGroup 
!= NULL 
&& mGroupPos 
< mGroup
->getFiles().size()) { 
 106                 file 
= group
->getFiles().valueAt(mGroupPos
++); 
 108             // Try to get the next group/file in this directory 
 109             } else if (mSetPos 
< mSet
->size()) { 
 110                 mGroup 
= group 
= mSet
->valueAt(mSetPos
++); 
 111                 if (group
->getFiles().size() < 1) { 
 114                 file 
= group
->getFiles().valueAt(0); 
 124             String8 
leaf(group
->getLeaf()); 
 125             mLeafName 
= String8(leaf
); 
 126             mParams 
= file
->getGroupEntry().toParams(); 
 127             NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n", 
 128                    group
->getPath().string(), mParams
.mcc
, mParams
.mnc
, 
 129                    mParams
.language
[0] ? mParams
.language
[0] : '-', 
 130                    mParams
.language
[1] ? mParams
.language
[1] : '-', 
 131                    mParams
.country
[0] ? mParams
.country
[0] : '-', 
 132                    mParams
.country
[1] ? mParams
.country
[1] : '-', 
 133                    mParams
.orientation
, mParams
.uiMode
, 
 134                    mParams
.density
, mParams
.touchscreen
, mParams
.keyboard
, 
 135                    mParams
.inputFlags
, mParams
.navigation
)); 
 137             mPath
.appendPath(file
->getGroupEntry().toDirName(mResType
)); 
 138             mPath
.appendPath(leaf
); 
 139             mBaseName 
= parseResourceName(leaf
); 
 140             if (mBaseName 
== "") { 
 141                 fprintf(stderr
, "Error: malformed resource filename %s\n", 
 142                         file
->getPrintableSource().string()); 
 143                 return UNKNOWN_ERROR
; 
 146             NOISY(printf("file name=%s\n", mBaseName
.string())); 
 155     const sp
<ResourceTypeSet
> mSet
; 
 158     sp
<AaptGroup
> mGroup
; 
 165     ResTable_config mParams
; 
 168 // ========================================================================== 
 169 // ========================================================================== 
 170 // ========================================================================== 
 172 bool isValidResourceType(const String8
& type
) 
 174     return type 
== "anim" || type 
== "animator" || type 
== "interpolator" 
 175         || type 
== "drawable" || type 
== "layout" 
 176         || type 
== "values" || type 
== "xml" || type 
== "raw" 
 177         || type 
== "color" || type 
== "menu" || type 
== "mipmap"; 
 180 static sp
<AaptFile
> getResourceFile(const sp
<AaptAssets
>& assets
, bool makeIfNecessary
=true) 
 182     sp
<AaptGroup
> group 
= assets
->getFiles().valueFor(String8("resources.arsc")); 
 185         file 
= group
->getFiles().valueFor(AaptGroupEntry()); 
 191     if (!makeIfNecessary
) { 
 194     return assets
->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(), 
 198 static status_t 
parsePackage(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 199     const sp
<AaptGroup
>& grp
) 
 201     if (grp
->getFiles().size() != 1) { 
 202         fprintf(stderr
, "warning: Multiple AndroidManifest.xml files found, using %s\n", 
 203                 grp
->getFiles().valueAt(0)->getPrintableSource().string()); 
 206     sp
<AaptFile
> file 
= grp
->getFiles().valueAt(0); 
 209     status_t err 
= parseXMLResource(file
, &block
); 
 210     if (err 
!= NO_ERROR
) { 
 213     //printXMLBlock(&block); 
 215     ResXMLTree::event_code_t code
; 
 216     while ((code
=block
.next()) != ResXMLTree::START_TAG
 
 217            && code 
!= ResXMLTree::END_DOCUMENT
 
 218            && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 222     if (code 
!= ResXMLTree::START_TAG
) { 
 223         fprintf(stderr
, "%s:%d: No start tag found\n", 
 224                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 225         return UNKNOWN_ERROR
; 
 227     if (strcmp16(block
.getElementName(&len
), String16("manifest").string()) != 0) { 
 228         fprintf(stderr
, "%s:%d: Invalid start tag %s, expected <manifest>\n", 
 229                 file
->getPrintableSource().string(), block
.getLineNumber(), 
 230                 String8(block
.getElementName(&len
)).string()); 
 231         return UNKNOWN_ERROR
; 
 234     ssize_t nameIndex 
= block
.indexOfAttribute(NULL
, "package"); 
 236         fprintf(stderr
, "%s:%d: <manifest> does not have package attribute.\n", 
 237                 file
->getPrintableSource().string(), block
.getLineNumber()); 
 238         return UNKNOWN_ERROR
; 
 241     assets
->setPackage(String8(block
.getAttributeStringValue(nameIndex
, &len
))); 
 243     String16 
uses_sdk16("uses-sdk"); 
 244     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
 245            && code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 246         if (code 
== ResXMLTree::START_TAG
) { 
 247             if (strcmp16(block
.getElementName(&len
), uses_sdk16
.string()) == 0) { 
 248                 ssize_t minSdkIndex 
= block
.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE
, 
 250                 if (minSdkIndex 
>= 0) { 
 251                     const uint16_t* minSdk16 
= block
.getAttributeStringValue(minSdkIndex
, &len
); 
 252                     const char* minSdk8 
= strdup(String8(minSdk16
).string()); 
 253                     bundle
->setManifestMinSdkVersion(minSdk8
); 
 262 // ========================================================================== 
 263 // ========================================================================== 
 264 // ========================================================================== 
 266 static status_t 
makeFileResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 267                                   ResourceTable
* table
, 
 268                                   const sp
<ResourceTypeSet
>& set
, 
 271     String8 
type8(resType
); 
 272     String16 
type16(resType
); 
 274     bool hasErrors 
= false; 
 276     ResourceDirIterator 
it(set
, String8(resType
)); 
 278     while ((res
=it
.next()) == NO_ERROR
) { 
 279         if (bundle
->getVerbose()) { 
 280             printf("    (new resource id %s from %s)\n", 
 281                    it
.getBaseName().string(), it
.getFile()->getPrintableSource().string()); 
 283         String16 
baseName(it
.getBaseName()); 
 284         const char16_t* str 
= baseName
.string(); 
 285         const char16_t* const end 
= str 
+ baseName
.size(); 
 287             if (!((*str 
>= 'a' && *str 
<= 'z') 
 288                     || (*str 
>= '0' && *str 
<= '9') 
 289                     || *str 
== '_' || *str 
== '.')) { 
 290                 fprintf(stderr
, "%s: Invalid file name: must contain only [a-z0-9_.]\n", 
 291                         it
.getPath().string()); 
 296         String8 resPath 
= it
.getPath(); 
 297         resPath
.convertToResPath(); 
 298         table
->addEntry(SourcePos(it
.getPath(), 0), String16(assets
->getPackage()), 
 304         assets
->addResource(it
.getLeafName(), resPath
, it
.getFile(), type8
); 
 307     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
 310 class PreProcessImageWorkUnit 
: public WorkQueue::WorkUnit 
{ 
 312     PreProcessImageWorkUnit(const Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 313             const sp
<AaptFile
>& file
, volatile bool* hasErrors
) : 
 314             mBundle(bundle
), mAssets(assets
), mFile(file
), mHasErrors(hasErrors
) { 
 318         status_t status 
= preProcessImage(mBundle
, mAssets
, mFile
, NULL
); 
 322         return true; // continue even if there are errors 
 326     const Bundle
* mBundle
; 
 327     sp
<AaptAssets
> mAssets
; 
 329     volatile bool* mHasErrors
; 
 332 static status_t 
preProcessImages(const Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
 333                           const sp
<ResourceTypeSet
>& set
, const char* type
) 
 335     volatile bool hasErrors 
= false; 
 336     ssize_t res 
= NO_ERROR
; 
 337     if (bundle
->getUseCrunchCache() == false) { 
 338         WorkQueue 
wq(MAX_THREADS
, false); 
 339         ResourceDirIterator 
it(set
, String8(type
)); 
 340         while ((res
=it
.next()) == NO_ERROR
) { 
 341             PreProcessImageWorkUnit
* w 
= new PreProcessImageWorkUnit( 
 342                     bundle
, assets
, it
.getFile(), &hasErrors
); 
 343             status_t status 
= wq
.schedule(w
); 
 345                 fprintf(stderr
, "preProcessImages failed: schedule() returned %d\n", status
); 
 351         status_t status 
= wq
.finish(); 
 353             fprintf(stderr
, "preProcessImages failed: finish() returned %d\n", status
); 
 357     return (hasErrors 
|| (res 
< NO_ERROR
)) ? UNKNOWN_ERROR 
: NO_ERROR
; 
 360 status_t 
postProcessImages(const sp
<AaptAssets
>& assets
, 
 361                            ResourceTable
* table
, 
 362                            const sp
<ResourceTypeSet
>& set
) 
 364     ResourceDirIterator 
it(set
, String8("drawable")); 
 365     bool hasErrors 
= false; 
 367     while ((res
=it
.next()) == NO_ERROR
) { 
 368         res 
= postProcessImage(assets
, table
, it
.getFile()); 
 369         if (res 
< NO_ERROR
) { 
 374     return (hasErrors 
|| (res 
< NO_ERROR
)) ? UNKNOWN_ERROR 
: NO_ERROR
; 
 377 static void collect_files(const sp
<AaptDir
>& dir
, 
 378         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 380     const DefaultKeyedVector
<String8
, sp
<AaptGroup
> >& groups 
= dir
->getFiles(); 
 381     int N 
= groups
.size(); 
 382     for (int i
=0; i
<N
; i
++) { 
 383         String8 leafName 
= groups
.keyAt(i
); 
 384         const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
 386         const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files
 
 389         if (files
.size() == 0) { 
 393         String8 resType 
= files
.valueAt(0)->getResourceType(); 
 395         ssize_t index 
= resources
->indexOfKey(resType
); 
 398             sp
<ResourceTypeSet
> set 
= new ResourceTypeSet(); 
 399             NOISY(printf("Creating new resource type set for leaf %s with group %s (%p)\n", 
 400                     leafName
.string(), group
->getPath().string(), group
.get())); 
 401             set
->add(leafName
, group
); 
 402             resources
->add(resType
, set
); 
 404             sp
<ResourceTypeSet
> set 
= resources
->valueAt(index
); 
 405             index 
= set
->indexOfKey(leafName
); 
 407                 NOISY(printf("Adding to resource type set for leaf %s group %s (%p)\n", 
 408                         leafName
.string(), group
->getPath().string(), group
.get())); 
 409                 set
->add(leafName
, group
); 
 411                 sp
<AaptGroup
> existingGroup 
= set
->valueAt(index
); 
 412                 NOISY(printf("Extending to resource type set for leaf %s group %s (%p)\n", 
 413                         leafName
.string(), group
->getPath().string(), group
.get())); 
 414                 for (size_t j
=0; j
<files
.size(); j
++) { 
 415                     NOISY(printf("Adding file %s in group %s resType %s\n", 
 416                         files
.valueAt(j
)->getSourceFile().string(), 
 417                         files
.keyAt(j
).toDirName(String8()).string(), 
 419                     status_t err 
= existingGroup
->addFile(files
.valueAt(j
)); 
 426 static void collect_files(const sp
<AaptAssets
>& ass
, 
 427         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* resources
) 
 429     const Vector
<sp
<AaptDir
> >& dirs 
= ass
->resDirs(); 
 432     for (int i
=0; i
<N
; i
++) { 
 433         sp
<AaptDir
> d 
= dirs
.itemAt(i
); 
 434         NOISY(printf("Collecting dir #%d %p: %s, leaf %s\n", i
, d
.get(), d
->getPath().string(), 
 435                 d
->getLeaf().string())); 
 436         collect_files(d
, resources
); 
 438         // don't try to include the res dir 
 439         NOISY(printf("Removing dir leaf %s\n", d
->getLeaf().string())); 
 440         ass
->removeDir(d
->getLeaf()); 
 447     ATTR_LEADING_SPACES 
= -3, 
 448     ATTR_TRAILING_SPACES 
= -4 
 450 static int validateAttr(const String8
& path
, const ResTable
& table
, 
 451         const ResXMLParser
& parser
, 
 452         const char* ns
, const char* attr
, const char* validChars
, bool required
) 
 456     ssize_t index 
= parser
.indexOfAttribute(ns
, attr
); 
 459     if (index 
>= 0 && parser
.getAttributeValue(index
, &value
) >= 0) { 
 460         const ResStringPool
* pool 
= &parser
.getStrings(); 
 461         if (value
.dataType 
== Res_value::TYPE_REFERENCE
) { 
 462             uint32_t specFlags 
= 0; 
 464             if ((strIdx
=table
.resolveReference(&value
, 0x10000000, NULL
, &specFlags
)) < 0) { 
 465                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s references unknown resid 0x%08x.\n", 
 466                         path
.string(), parser
.getLineNumber(), 
 467                         String8(parser
.getElementName(&len
)).string(), attr
, 
 469                 return ATTR_NOT_FOUND
; 
 472             pool 
= table
.getTableStringBlock(strIdx
); 
 475                 str 
= pool
->stringAt(value
.data
, &len
); 
 477             printf("***** RES ATTR: %s specFlags=0x%x strIdx=%d: %s\n", attr
, 
 478                     specFlags
, strIdx
, str 
!= NULL 
? String8(str
).string() : "???"); 
 480             if ((specFlags
&~ResTable_typeSpec::SPEC_PUBLIC
) != 0 && false) { 
 481                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s varies by configurations 0x%x.\n", 
 482                         path
.string(), parser
.getLineNumber(), 
 483                         String8(parser
.getElementName(&len
)).string(), attr
, 
 485                 return ATTR_NOT_FOUND
; 
 488         if (value
.dataType 
== Res_value::TYPE_STRING
) { 
 490                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has no string block.\n", 
 491                         path
.string(), parser
.getLineNumber(), 
 492                         String8(parser
.getElementName(&len
)).string(), attr
); 
 493                 return ATTR_NOT_FOUND
; 
 495             if ((str
=pool
->stringAt(value
.data
, &len
)) == NULL
) { 
 496                 fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n", 
 497                         path
.string(), parser
.getLineNumber(), 
 498                         String8(parser
.getElementName(&len
)).string(), attr
); 
 499                 return ATTR_NOT_FOUND
; 
 502             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has invalid type %d.\n", 
 503                     path
.string(), parser
.getLineNumber(), 
 504                     String8(parser
.getElementName(&len
)).string(), attr
, 
 506             return ATTR_NOT_FOUND
; 
 509             for (size_t i
=0; i
<len
; i
++) { 
 511                 const char* p 
= validChars
; 
 521                     fprintf(stderr
, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n", 
 522                             path
.string(), parser
.getLineNumber(), 
 523                             String8(parser
.getElementName(&len
)).string(), attr
, (char)str
[i
]); 
 529             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not start with a space.\n", 
 530                     path
.string(), parser
.getLineNumber(), 
 531                     String8(parser
.getElementName(&len
)).string(), attr
); 
 532             return ATTR_LEADING_SPACES
; 
 534         if (str
[len
-1] == ' ') { 
 535             fprintf(stderr
, "%s:%d: Tag <%s> attribute %s can not end with a space.\n", 
 536                     path
.string(), parser
.getLineNumber(), 
 537                     String8(parser
.getElementName(&len
)).string(), attr
); 
 538             return ATTR_TRAILING_SPACES
; 
 543         fprintf(stderr
, "%s:%d: Tag <%s> missing required attribute %s.\n", 
 544                 path
.string(), parser
.getLineNumber(), 
 545                 String8(parser
.getElementName(&len
)).string(), attr
); 
 546         return ATTR_NOT_FOUND
; 
 551 static void checkForIds(const String8
& path
, ResXMLParser
& parser
) 
 553     ResXMLTree::event_code_t code
; 
 554     while ((code
=parser
.next()) != ResXMLTree::END_DOCUMENT
 
 555            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
 556         if (code 
== ResXMLTree::START_TAG
) { 
 557             ssize_t index 
= parser
.indexOfAttribute(NULL
, "id"); 
 559                 fprintf(stderr
, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n", 
 560                         path
.string(), parser
.getLineNumber()); 
 566 static bool applyFileOverlay(Bundle 
*bundle
, 
 567                              const sp
<AaptAssets
>& assets
, 
 568                              sp
<ResourceTypeSet
> *baseSet
, 
 571     if (bundle
->getVerbose()) { 
 572         printf("applyFileOverlay for %s\n", resType
); 
 575     // Replace any base level files in this category with any found from the overlay 
 576     // Also add any found only in the overlay. 
 577     sp
<AaptAssets
> overlay 
= assets
->getOverlay(); 
 578     String8 
resTypeString(resType
); 
 580     // work through the linked list of overlays 
 581     while (overlay
.get()) { 
 582         KeyedVector
<String8
, sp
<ResourceTypeSet
> >* overlayRes 
= overlay
->getResources(); 
 584         // get the overlay resources of the requested type 
 585         ssize_t index 
= overlayRes
->indexOfKey(resTypeString
); 
 587             sp
<ResourceTypeSet
> overlaySet 
= overlayRes
->valueAt(index
); 
 589             // for each of the resources, check for a match in the previously built 
 590             // non-overlay "baseset". 
 591             size_t overlayCount 
= overlaySet
->size(); 
 592             for (size_t overlayIndex
=0; overlayIndex
<overlayCount
; overlayIndex
++) { 
 593                 if (bundle
->getVerbose()) { 
 594                     printf("trying overlaySet Key=%s\n",overlaySet
->keyAt(overlayIndex
).string()); 
 596                 size_t baseIndex 
= UNKNOWN_ERROR
; 
 597                 if (baseSet
->get() != NULL
) { 
 598                     baseIndex 
= (*baseSet
)->indexOfKey(overlaySet
->keyAt(overlayIndex
)); 
 600                 if (baseIndex 
< UNKNOWN_ERROR
) { 
 601                     // look for same flavor.  For a given file (strings.xml, for example) 
 602                     // there may be a locale specific or other flavors - we want to match 
 604                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 605                     sp
<AaptGroup
> baseGroup 
= (*baseSet
)->valueAt(baseIndex
); 
 607                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
= 
 608                             overlayGroup
->getFiles(); 
 609                     if (bundle
->getVerbose()) { 
 610                         DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > baseFiles 
= 
 611                                 baseGroup
->getFiles(); 
 612                         for (size_t i
=0; i 
< baseFiles
.size(); i
++) { 
 613                             printf("baseFile " ZD 
" has flavor %s\n", (ZD_TYPE
) i
, 
 614                                     baseFiles
.keyAt(i
).toString().string()); 
 616                         for (size_t i
=0; i 
< overlayFiles
.size(); i
++) { 
 617                             printf("overlayFile " ZD 
" has flavor %s\n", (ZD_TYPE
) i
, 
 618                                     overlayFiles
.keyAt(i
).toString().string()); 
 622                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 623                     for (size_t overlayGroupIndex 
= 0; 
 624                             overlayGroupIndex
<overlayGroupSize
; 
 625                             overlayGroupIndex
++) { 
 626                         size_t baseFileIndex 
= 
 627                                 baseGroup
->getFiles().indexOfKey(overlayFiles
. 
 628                                 keyAt(overlayGroupIndex
)); 
 629                         if (baseFileIndex 
< UNKNOWN_ERROR
) { 
 630                             if (bundle
->getVerbose()) { 
 631                                 printf("found a match (" ZD 
") for overlay file %s, for flavor %s\n", 
 632                                         (ZD_TYPE
) baseFileIndex
, 
 633                                         overlayGroup
->getLeaf().string(), 
 634                                         overlayFiles
.keyAt(overlayGroupIndex
).toString().string()); 
 636                             baseGroup
->removeFile(baseFileIndex
); 
 638                             // didn't find a match fall through and add it.. 
 639                             if (true || bundle
->getVerbose()) { 
 640                                 printf("nothing matches overlay file %s, for flavor %s\n", 
 641                                         overlayGroup
->getLeaf().string(), 
 642                                         overlayFiles
.keyAt(overlayGroupIndex
).toString().string()); 
 645                         baseGroup
->addFile(overlayFiles
.valueAt(overlayGroupIndex
)); 
 646                         assets
->addGroupEntry(overlayFiles
.keyAt(overlayGroupIndex
)); 
 649                     if (baseSet
->get() == NULL
) { 
 650                         *baseSet 
= new ResourceTypeSet(); 
 651                         assets
->getResources()->add(String8(resType
), *baseSet
); 
 653                     // this group doesn't exist (a file that's only in the overlay) 
 654                     (*baseSet
)->add(overlaySet
->keyAt(overlayIndex
), 
 655                             overlaySet
->valueAt(overlayIndex
)); 
 656                     // make sure all flavors are defined in the resources. 
 657                     sp
<AaptGroup
> overlayGroup 
= overlaySet
->valueAt(overlayIndex
); 
 658                     DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> > overlayFiles 
= 
 659                             overlayGroup
->getFiles(); 
 660                     size_t overlayGroupSize 
= overlayFiles
.size(); 
 661                     for (size_t overlayGroupIndex 
= 0; 
 662                             overlayGroupIndex
<overlayGroupSize
; 
 663                             overlayGroupIndex
++) { 
 664                         assets
->addGroupEntry(overlayFiles
.keyAt(overlayGroupIndex
)); 
 668             // this overlay didn't have resources for this type 
 671         overlay 
= overlay
->getOverlay(); 
 676 void addTagAttribute(const sp
<XMLNode
>& node
, const char* ns8
, 
 677         const char* attr8
, const char* value
) 
 683     const String16 
ns(ns8
); 
 684     const String16 
attr(attr8
); 
 686     if (node
->getAttribute(ns
, attr
) != NULL
) { 
 687         fprintf(stderr
, "Warning: AndroidManifest.xml already defines %s (in %s);" 
 688                         " using existing value in manifest.\n", 
 689                 String8(attr
).string(), String8(ns
).string()); 
 693     node
->addAttribute(ns
, attr
, String16(value
)); 
 696 static void fullyQualifyClassName(const String8
& package
, sp
<XMLNode
> node
, 
 697         const String16
& attrName
) { 
 698     XMLNode::attribute_entry
* attr 
= node
->editAttribute( 
 699             String16("http://schemas.android.com/apk/res/android"), attrName
); 
 701         String8 
name(attr
->string
); 
 703         // asdf     --> package.asdf 
 704         // .asdf  .a.b  --> package.asdf package.a.b 
 705         // asdf.adsf --> asdf.asdf 
 707         const char* p 
= name
.string(); 
 708         const char* q 
= strchr(p
, '.'); 
 710             className 
+= package
; 
 712         } else if (q 
== NULL
) { 
 713             className 
+= package
; 
 719         NOISY(printf("Qualifying class '%s' to '%s'", name
.string(), className
.string())); 
 720         attr
->string
.setTo(String16(className
)); 
 724 status_t 
massageManifest(Bundle
* bundle
, sp
<XMLNode
> root
) 
 726     root 
= root
->searchElement(String16(), String16("manifest")); 
 728         fprintf(stderr
, "No <manifest> tag.\n"); 
 729         return UNKNOWN_ERROR
; 
 732     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionCode", 
 733             bundle
->getVersionCode()); 
 734     addTagAttribute(root
, RESOURCES_ANDROID_NAMESPACE
, "versionName", 
 735             bundle
->getVersionName()); 
 737     if (bundle
->getMinSdkVersion() != NULL
 
 738             || bundle
->getTargetSdkVersion() != NULL
 
 739             || bundle
->getMaxSdkVersion() != NULL
) { 
 740         sp
<XMLNode
> vers 
= root
->getChildElement(String16(), String16("uses-sdk")); 
 742             vers 
= XMLNode::newElement(root
->getFilename(), String16(), String16("uses-sdk")); 
 743             root
->insertChildAt(vers
, 0); 
 746         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "minSdkVersion", 
 747                 bundle
->getMinSdkVersion()); 
 748         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "targetSdkVersion", 
 749                 bundle
->getTargetSdkVersion()); 
 750         addTagAttribute(vers
, RESOURCES_ANDROID_NAMESPACE
, "maxSdkVersion", 
 751                 bundle
->getMaxSdkVersion()); 
 754     if (bundle
->getDebugMode()) { 
 755         sp
<XMLNode
> application 
= root
->getChildElement(String16(), String16("application")); 
 756         if (application 
!= NULL
) { 
 757             addTagAttribute(application
, RESOURCES_ANDROID_NAMESPACE
, "debuggable", "true"); 
 761     // Deal with manifest package name overrides 
 762     const char* manifestPackageNameOverride 
= bundle
->getManifestPackageNameOverride(); 
 763     if (manifestPackageNameOverride 
!= NULL
) { 
 764         // Update the actual package name 
 765         XMLNode::attribute_entry
* attr 
= root
->editAttribute(String16(), String16("package")); 
 767             fprintf(stderr
, "package name is required with --rename-manifest-package.\n"); 
 768             return UNKNOWN_ERROR
; 
 770         String8 
origPackage(attr
->string
); 
 771         attr
->string
.setTo(String16(manifestPackageNameOverride
)); 
 772         NOISY(printf("Overriding package '%s' to be '%s'\n", origPackage
.string(), manifestPackageNameOverride
)); 
 774         // Make class names fully qualified 
 775         sp
<XMLNode
> application 
= root
->getChildElement(String16(), String16("application")); 
 776         if (application 
!= NULL
) { 
 777             fullyQualifyClassName(origPackage
, application
, String16("name")); 
 778             fullyQualifyClassName(origPackage
, application
, String16("backupAgent")); 
 780             Vector
<sp
<XMLNode
> >& children 
= const_cast<Vector
<sp
<XMLNode
> >&>(application
->getChildren()); 
 781             for (size_t i 
= 0; i 
< children
.size(); i
++) { 
 782                 sp
<XMLNode
> child 
= children
.editItemAt(i
); 
 783                 String8 
tag(child
->getElementName()); 
 784                 if (tag 
== "activity" || tag 
== "service" || tag 
== "receiver" || tag 
== "provider") { 
 785                     fullyQualifyClassName(origPackage
, child
, String16("name")); 
 786                 } else if (tag 
== "activity-alias") { 
 787                     fullyQualifyClassName(origPackage
, child
, String16("name")); 
 788                     fullyQualifyClassName(origPackage
, child
, String16("targetActivity")); 
 794     // Deal with manifest package name overrides 
 795     const char* instrumentationPackageNameOverride 
= bundle
->getInstrumentationPackageNameOverride(); 
 796     if (instrumentationPackageNameOverride 
!= NULL
) { 
 797         // Fix up instrumentation targets. 
 798         Vector
<sp
<XMLNode
> >& children 
= const_cast<Vector
<sp
<XMLNode
> >&>(root
->getChildren()); 
 799         for (size_t i 
= 0; i 
< children
.size(); i
++) { 
 800             sp
<XMLNode
> child 
= children
.editItemAt(i
); 
 801             String8 
tag(child
->getElementName()); 
 802             if (tag 
== "instrumentation") { 
 803                 XMLNode::attribute_entry
* attr 
= child
->editAttribute( 
 804                         String16("http://schemas.android.com/apk/res/android"), String16("targetPackage")); 
 806                     attr
->string
.setTo(String16(instrumentationPackageNameOverride
)); 
 815 #define ASSIGN_IT(n) \ 
 817             ssize_t index = resources->indexOfKey(String8(#n)); \ 
 819                 n ## s = resources->valueAt(index); \ 
 823 status_t 
updatePreProcessedCache(Bundle
* bundle
) 
 826     fprintf(stdout
, "BENCHMARK: Starting PNG PreProcessing \n"); 
 827     long startPNGTime 
= clock(); 
 828     #endif /* BENCHMARK */ 
 830     String8 
source(bundle
->getResourceSourceDirs()[0]); 
 831     String8 
dest(bundle
->getCrunchedOutputDir()); 
 833     FileFinder
* ff 
= new SystemFileFinder(); 
 834     CrunchCache 
cc(source
,dest
,ff
); 
 836     CacheUpdater
* cu 
= new SystemCacheUpdater(bundle
); 
 837     size_t numFiles 
= cc
.crunch(cu
); 
 839     if (bundle
->getVerbose()) 
 840         fprintf(stdout
, "Crunched %d PNG files to update cache\n", (int)numFiles
); 
 846     fprintf(stdout
, "BENCHMARK: End PNG PreProcessing. Time Elapsed: %f ms \n" 
 847             ,(clock() - startPNGTime
)/1000.0); 
 848     #endif /* BENCHMARK */ 
 852 status_t 
buildResources(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
 854     // First, look for a package file to parse.  This is required to 
 855     // be able to generate the resource information. 
 856     sp
<AaptGroup
> androidManifestFile 
= 
 857             assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
 858     if (androidManifestFile 
== NULL
) { 
 859         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
 860         return UNKNOWN_ERROR
; 
 863     status_t err 
= parsePackage(bundle
, assets
, androidManifestFile
); 
 864     if (err 
!= NO_ERROR
) { 
 868     NOISY(printf("Creating resources for package %s\n", 
 869                  assets
->getPackage().string())); 
 871     ResourceTable 
table(bundle
, String16(assets
->getPackage())); 
 872     err 
= table
.addIncludedResources(bundle
, assets
); 
 873     if (err 
!= NO_ERROR
) { 
 877     NOISY(printf("Found %d included resource packages\n", (int)table
.size())); 
 879     // Standard flags for compiled XML and optional UTF-8 encoding 
 880     int xmlFlags 
= XML_COMPILE_STANDARD_RESOURCE
; 
 882     /* Only enable UTF-8 if the caller of aapt didn't specifically 
 883      * request UTF-16 encoding and the parameters of this package 
 884      * allow UTF-8 to be used. 
 886     if (!bundle
->getUTF16StringsOption()) { 
 887         xmlFlags 
|= XML_COMPILE_UTF8
; 
 890     // -------------------------------------------------------------- 
 891     // First, gather all resource information. 
 892     // -------------------------------------------------------------- 
 894     // resType -> leafName -> group 
 895     KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 896             new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 897     collect_files(assets
, resources
); 
 899     sp
<ResourceTypeSet
> drawables
; 
 900     sp
<ResourceTypeSet
> layouts
; 
 901     sp
<ResourceTypeSet
> anims
; 
 902     sp
<ResourceTypeSet
> animators
; 
 903     sp
<ResourceTypeSet
> interpolators
; 
 904     sp
<ResourceTypeSet
> xmls
; 
 905     sp
<ResourceTypeSet
> raws
; 
 906     sp
<ResourceTypeSet
> colors
; 
 907     sp
<ResourceTypeSet
> menus
; 
 908     sp
<ResourceTypeSet
> mipmaps
; 
 914     ASSIGN_IT(interpolator
); 
 921     assets
->setResources(resources
); 
 922     // now go through any resource overlays and collect their files 
 923     sp
<AaptAssets
> current 
= assets
->getOverlay(); 
 924     while(current
.get()) { 
 925         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
 926                 new KeyedVector
<String8
, sp
<ResourceTypeSet
> >; 
 927         current
->setResources(resources
); 
 928         collect_files(current
, resources
); 
 929         current 
= current
->getOverlay(); 
 931     // apply the overlay files to the base set 
 932     if (!applyFileOverlay(bundle
, assets
, &drawables
, "drawable") || 
 933             !applyFileOverlay(bundle
, assets
, &layouts
, "layout") || 
 934             !applyFileOverlay(bundle
, assets
, &anims
, "anim") || 
 935             !applyFileOverlay(bundle
, assets
, &animators
, "animator") || 
 936             !applyFileOverlay(bundle
, assets
, &interpolators
, "interpolator") || 
 937             !applyFileOverlay(bundle
, assets
, &xmls
, "xml") || 
 938             !applyFileOverlay(bundle
, assets
, &raws
, "raw") || 
 939             !applyFileOverlay(bundle
, assets
, &colors
, "color") || 
 940             !applyFileOverlay(bundle
, assets
, &menus
, "menu") || 
 941             !applyFileOverlay(bundle
, assets
, &mipmaps
, "mipmap")) { 
 942         return UNKNOWN_ERROR
; 
 945     bool hasErrors 
= false; 
 947     if (drawables 
!= NULL
) { 
 948         if (bundle
->getOutputAPKFile() != NULL
) { 
 949             err 
= preProcessImages(bundle
, assets
, drawables
, "drawable"); 
 951         if (err 
== NO_ERROR
) { 
 952             err 
= makeFileResources(bundle
, assets
, &table
, drawables
, "drawable"); 
 953             if (err 
!= NO_ERROR
) { 
 961     if (mipmaps 
!= NULL
) { 
 962         if (bundle
->getOutputAPKFile() != NULL
) { 
 963             err 
= preProcessImages(bundle
, assets
, mipmaps
, "mipmap"); 
 965         if (err 
== NO_ERROR
) { 
 966             err 
= makeFileResources(bundle
, assets
, &table
, mipmaps
, "mipmap"); 
 967             if (err 
!= NO_ERROR
) { 
 975     if (layouts 
!= NULL
) { 
 976         err 
= makeFileResources(bundle
, assets
, &table
, layouts
, "layout"); 
 977         if (err 
!= NO_ERROR
) { 
 983         err 
= makeFileResources(bundle
, assets
, &table
, anims
, "anim"); 
 984         if (err 
!= NO_ERROR
) { 
 989     if (animators 
!= NULL
) { 
 990         err 
= makeFileResources(bundle
, assets
, &table
, animators
, "animator"); 
 991         if (err 
!= NO_ERROR
) { 
 996     if (interpolators 
!= NULL
) { 
 997         err 
= makeFileResources(bundle
, assets
, &table
, interpolators
, "interpolator"); 
 998         if (err 
!= NO_ERROR
) { 
1004         err 
= makeFileResources(bundle
, assets
, &table
, xmls
, "xml"); 
1005         if (err 
!= NO_ERROR
) { 
1011         err 
= makeFileResources(bundle
, assets
, &table
, raws
, "raw"); 
1012         if (err 
!= NO_ERROR
) { 
1017     // compile resources 
1019     while(current
.get()) { 
1020         KeyedVector
<String8
, sp
<ResourceTypeSet
> > *resources 
=  
1021                 current
->getResources(); 
1023         ssize_t index 
= resources
->indexOfKey(String8("values")); 
1025             ResourceDirIterator 
it(resources
->valueAt(index
), String8("values")); 
1027             while ((res
=it
.next()) == NO_ERROR
) { 
1028                 sp
<AaptFile
> file 
= it
.getFile(); 
1029                 res 
= compileResourceFile(bundle
, assets
, file
, it
.getParams(),  
1030                                           (current
!=assets
), &table
); 
1031                 if (res 
!= NO_ERROR
) { 
1036         current 
= current
->getOverlay(); 
1039     if (colors 
!= NULL
) { 
1040         err 
= makeFileResources(bundle
, assets
, &table
, colors
, "color"); 
1041         if (err 
!= NO_ERROR
) { 
1046     if (menus 
!= NULL
) { 
1047         err 
= makeFileResources(bundle
, assets
, &table
, menus
, "menu"); 
1048         if (err 
!= NO_ERROR
) { 
1053     // -------------------------------------------------------------------- 
1054     // Assignment of resource IDs and initial generation of resource table. 
1055     // -------------------------------------------------------------------- 
1057     if (table
.hasResources()) { 
1058         sp
<AaptFile
> resFile(getResourceFile(assets
)); 
1059         if (resFile 
== NULL
) { 
1060             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
1061             return UNKNOWN_ERROR
; 
1064         err 
= table
.assignResourceIds(); 
1065         if (err 
< NO_ERROR
) { 
1070     // -------------------------------------------------------------- 
1071     // Finally, we can now we can compile XML files, which may reference 
1073     // -------------------------------------------------------------- 
1075     if (layouts 
!= NULL
) { 
1076         ResourceDirIterator 
it(layouts
, String8("layout")); 
1077         while ((err
=it
.next()) == NO_ERROR
) { 
1078             String8 src 
= it
.getFile()->getPrintableSource(); 
1079             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1080             if (err 
== NO_ERROR
) { 
1082                 block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
1083                 checkForIds(src
, block
); 
1089         if (err 
< NO_ERROR
) { 
1095     if (anims 
!= NULL
) { 
1096         ResourceDirIterator 
it(anims
, String8("anim")); 
1097         while ((err
=it
.next()) == NO_ERROR
) { 
1098             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1099             if (err 
!= NO_ERROR
) { 
1104         if (err 
< NO_ERROR
) { 
1110     if (animators 
!= NULL
) { 
1111         ResourceDirIterator 
it(animators
, String8("animator")); 
1112         while ((err
=it
.next()) == NO_ERROR
) { 
1113             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1114             if (err 
!= NO_ERROR
) { 
1119         if (err 
< NO_ERROR
) { 
1125     if (interpolators 
!= NULL
) { 
1126         ResourceDirIterator 
it(interpolators
, String8("interpolator")); 
1127         while ((err
=it
.next()) == NO_ERROR
) { 
1128             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1129             if (err 
!= NO_ERROR
) { 
1134         if (err 
< NO_ERROR
) { 
1141         ResourceDirIterator 
it(xmls
, String8("xml")); 
1142         while ((err
=it
.next()) == NO_ERROR
) { 
1143             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1144             if (err 
!= NO_ERROR
) { 
1149         if (err 
< NO_ERROR
) { 
1155     if (drawables 
!= NULL
) { 
1156         err 
= postProcessImages(assets
, &table
, drawables
); 
1157         if (err 
!= NO_ERROR
) { 
1162     if (colors 
!= NULL
) { 
1163         ResourceDirIterator 
it(colors
, String8("color")); 
1164         while ((err
=it
.next()) == NO_ERROR
) { 
1165           err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1166             if (err 
!= NO_ERROR
) { 
1171         if (err 
< NO_ERROR
) { 
1177     if (menus 
!= NULL
) { 
1178         ResourceDirIterator 
it(menus
, String8("menu")); 
1179         while ((err
=it
.next()) == NO_ERROR
) { 
1180             String8 src 
= it
.getFile()->getPrintableSource(); 
1181             err 
= compileXmlFile(assets
, it
.getFile(), &table
, xmlFlags
); 
1182             if (err 
!= NO_ERROR
) { 
1186             block
.setTo(it
.getFile()->getData(), it
.getFile()->getSize(), true); 
1187             checkForIds(src
, block
); 
1190         if (err 
< NO_ERROR
) { 
1196     if (table
.validateLocalizations()) { 
1201         return UNKNOWN_ERROR
; 
1204     const sp
<AaptFile
> manifestFile(androidManifestFile
->getFiles().valueAt(0)); 
1205     String8 
manifestPath(manifestFile
->getPrintableSource()); 
1207     // Generate final compiled manifest file. 
1208     manifestFile
->clearData(); 
1209     sp
<XMLNode
> manifestTree 
= XMLNode::parse(manifestFile
); 
1210     if (manifestTree 
== NULL
) { 
1211         return UNKNOWN_ERROR
; 
1213     err 
= massageManifest(bundle
, manifestTree
); 
1214     if (err 
< NO_ERROR
) { 
1217     err 
= compileXmlFile(assets
, manifestTree
, manifestFile
, &table
); 
1218     if (err 
< NO_ERROR
) { 
1223     //printXMLBlock(&block); 
1225     // -------------------------------------------------------------- 
1226     // Generate the final resource table. 
1227     // Re-flatten because we may have added new resource IDs 
1228     // -------------------------------------------------------------- 
1230     ResTable finalResTable
; 
1231     sp
<AaptFile
> resFile
; 
1233     if (table
.hasResources()) { 
1234         sp
<AaptSymbols
> symbols 
= assets
->getSymbolsFor(String8("R")); 
1235         err 
= table
.addSymbols(symbols
); 
1236         if (err 
< NO_ERROR
) { 
1240         resFile 
= getResourceFile(assets
); 
1241         if (resFile 
== NULL
) { 
1242             fprintf(stderr
, "Error: unable to generate entry for resource data\n"); 
1243             return UNKNOWN_ERROR
; 
1246         err 
= table
.flatten(bundle
, resFile
); 
1247         if (err 
< NO_ERROR
) { 
1251         if (bundle
->getPublicOutputFile()) { 
1252             FILE* fp 
= fopen(bundle
->getPublicOutputFile(), "w+"); 
1254                 fprintf(stderr
, "ERROR: Unable to open public definitions output file %s: %s\n", 
1255                         (const char*)bundle
->getPublicOutputFile(), strerror(errno
)); 
1256                 return UNKNOWN_ERROR
; 
1258             if (bundle
->getVerbose()) { 
1259                 printf("  Writing public definitions to %s.\n", bundle
->getPublicOutputFile()); 
1261             table
.writePublicDefinitions(String16(assets
->getPackage()), fp
); 
1265         // Read resources back in, 
1266         finalResTable
.add(resFile
->getData(), resFile
->getSize(), NULL
); 
1270               printf("Generated resources:\n"); 
1271               finalResTable
.print(); 
1276     // Perform a basic validation of the manifest file.  This time we 
1277     // parse it with the comments intact, so that we can use them to 
1278     // generate java docs...  so we are not going to write this one 
1279     // back out to the final manifest data. 
1280     sp
<AaptFile
> outManifestFile 
= new AaptFile(manifestFile
->getSourceFile(), 
1281             manifestFile
->getGroupEntry(), 
1282             manifestFile
->getResourceType()); 
1283     err 
= compileXmlFile(assets
, manifestFile
, 
1284             outManifestFile
, &table
, 
1285             XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
 
1286             | XML_COMPILE_STRIP_WHITESPACE 
| XML_COMPILE_STRIP_RAW_VALUES
); 
1287     if (err 
< NO_ERROR
) { 
1291     block
.setTo(outManifestFile
->getData(), outManifestFile
->getSize(), true); 
1292     String16 
manifest16("manifest"); 
1293     String16 
permission16("permission"); 
1294     String16 
permission_group16("permission-group"); 
1295     String16 
uses_permission16("uses-permission"); 
1296     String16 
instrumentation16("instrumentation"); 
1297     String16 
application16("application"); 
1298     String16 
provider16("provider"); 
1299     String16 
service16("service"); 
1300     String16 
receiver16("receiver"); 
1301     String16 
activity16("activity"); 
1302     String16 
action16("action"); 
1303     String16 
category16("category"); 
1304     String16 
data16("scheme"); 
1305     const char* packageIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1306         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789"; 
1307     const char* packageIdentCharsWithTheStupid 
= "abcdefghijklmnopqrstuvwxyz" 
1308         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
1309     const char* classIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1310         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789$"; 
1311     const char* processIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1312         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:"; 
1313     const char* authoritiesIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1314         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-:;"; 
1315     const char* typeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1316         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789:-/*+"; 
1317     const char* schemeIdentChars 
= "abcdefghijklmnopqrstuvwxyz" 
1318         "ABCDEFGHIJKLMNOPQRSTUVWXYZ._0123456789-"; 
1319     ResXMLTree::event_code_t code
; 
1320     sp
<AaptSymbols
> permissionSymbols
; 
1321     sp
<AaptSymbols
> permissionGroupSymbols
; 
1322     while ((code
=block
.next()) != ResXMLTree::END_DOCUMENT
 
1323            && code 
> ResXMLTree::BAD_DOCUMENT
) { 
1324         if (code 
== ResXMLTree::START_TAG
) { 
1326             if (block
.getElementNamespace(&len
) != NULL
) { 
1329             if (strcmp16(block
.getElementName(&len
), manifest16
.string()) == 0) { 
1330                 if (validateAttr(manifestPath
, finalResTable
, block
, NULL
, "package", 
1331                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1334                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1335                                  "sharedUserId", packageIdentChars
, false) != ATTR_OKAY
) { 
1338             } else if (strcmp16(block
.getElementName(&len
), permission16
.string()) == 0 
1339                     || strcmp16(block
.getElementName(&len
), permission_group16
.string()) == 0) { 
1340                 const bool isGroup 
= strcmp16(block
.getElementName(&len
), 
1341                         permission_group16
.string()) == 0; 
1342                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1343                                  "name", isGroup 
? packageIdentCharsWithTheStupid
 
1344                                  : packageIdentChars
, true) != ATTR_OKAY
) { 
1347                 SourcePos 
srcPos(manifestPath
, block
.getLineNumber()); 
1348                 sp
<AaptSymbols
> syms
; 
1350                     syms 
= permissionSymbols
; 
1352                         sp
<AaptSymbols
> symbols 
= 
1353                                 assets
->getSymbolsFor(String8("Manifest")); 
1354                         syms 
= permissionSymbols 
= symbols
->addNestedSymbol( 
1355                                 String8("permission"), srcPos
); 
1358                     syms 
= permissionGroupSymbols
; 
1360                         sp
<AaptSymbols
> symbols 
= 
1361                                 assets
->getSymbolsFor(String8("Manifest")); 
1362                         syms 
= permissionGroupSymbols 
= symbols
->addNestedSymbol( 
1363                                 String8("permission_group"), srcPos
); 
1367                 ssize_t index 
= block
.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE
, "name"); 
1368                 const uint16_t* id 
= block
.getAttributeStringValue(index
, &len
); 
1370                     fprintf(stderr
, "%s:%d: missing name attribute in element <%s>.\n",  
1371                             manifestPath
.string(), block
.getLineNumber(), 
1372                             String8(block
.getElementName(&len
)).string()); 
1377                 char* p 
= idStr
.lockBuffer(idStr
.size()); 
1378                 char* e 
= p 
+ idStr
.size(); 
1379                 bool begins_with_digit 
= true;  // init to true so an empty string fails 
1382                     if (*e 
>= '0' && *e 
<= '9') { 
1383                       begins_with_digit 
= true; 
1386                     if ((*e 
>= 'a' && *e 
<= 'z') || 
1387                         (*e 
>= 'A' && *e 
<= 'Z') || 
1389                       begins_with_digit 
= false; 
1392                     if (isGroup 
&& (*e 
== '-')) { 
1394                         begins_with_digit 
= false; 
1400                 idStr
.unlockBuffer(); 
1401                 // verify that we stopped because we hit a period or 
1402                 // the beginning of the string, and that the 
1403                 // identifier didn't begin with a digit. 
1404                 if (begins_with_digit 
|| (e 
!= p 
&& *(e
-1) != '.')) { 
1406                           "%s:%d: Permission name <%s> is not a valid Java symbol\n", 
1407                           manifestPath
.string(), block
.getLineNumber(), idStr
.string()); 
1410                 syms
->addStringSymbol(String8(e
), idStr
, srcPos
); 
1411                 const uint16_t* cmt 
= block
.getComment(&len
); 
1412                 if (cmt 
!= NULL 
&& *cmt 
!= 0) { 
1413                     //printf("Comment of %s: %s\n", String8(e).string(), 
1414                     //        String8(cmt).string()); 
1415                     syms
->appendComment(String8(e
), String16(cmt
), srcPos
); 
1417                     //printf("No comment for %s\n", String8(e).string()); 
1419                 syms
->makeSymbolPublic(String8(e
), srcPos
); 
1420             } else if (strcmp16(block
.getElementName(&len
), uses_permission16
.string()) == 0) { 
1421                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1422                                  "name", packageIdentChars
, true) != ATTR_OKAY
) { 
1425             } else if (strcmp16(block
.getElementName(&len
), instrumentation16
.string()) == 0) { 
1426                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1427                                  "name", classIdentChars
, true) != ATTR_OKAY
) { 
1430                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1431                                  RESOURCES_ANDROID_NAMESPACE
, "targetPackage", 
1432                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1435             } else if (strcmp16(block
.getElementName(&len
), application16
.string()) == 0) { 
1436                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1437                                  "name", classIdentChars
, false) != ATTR_OKAY
) { 
1440                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1441                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1442                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1445                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1446                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1447                                  processIdentChars
, false) != ATTR_OKAY
) { 
1450                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1451                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1452                                  processIdentChars
, false) != ATTR_OKAY
) { 
1455             } else if (strcmp16(block
.getElementName(&len
), provider16
.string()) == 0) { 
1456                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1457                                  "name", classIdentChars
, true) != ATTR_OKAY
) { 
1460                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1461                                  RESOURCES_ANDROID_NAMESPACE
, "authorities", 
1462                                  authoritiesIdentChars
, true) != ATTR_OKAY
) { 
1465                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1466                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1467                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1470                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1471                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1472                                  processIdentChars
, false) != ATTR_OKAY
) { 
1475             } else if (strcmp16(block
.getElementName(&len
), service16
.string()) == 0 
1476                        || strcmp16(block
.getElementName(&len
), receiver16
.string()) == 0 
1477                        || strcmp16(block
.getElementName(&len
), activity16
.string()) == 0) { 
1478                 if (validateAttr(manifestPath
, finalResTable
, block
, RESOURCES_ANDROID_NAMESPACE
, 
1479                                  "name", classIdentChars
, true) != ATTR_OKAY
) { 
1482                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1483                                  RESOURCES_ANDROID_NAMESPACE
, "permission", 
1484                                  packageIdentChars
, false) != ATTR_OKAY
) { 
1487                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1488                                  RESOURCES_ANDROID_NAMESPACE
, "process", 
1489                                  processIdentChars
, false) != ATTR_OKAY
) { 
1492                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1493                                  RESOURCES_ANDROID_NAMESPACE
, "taskAffinity", 
1494                                  processIdentChars
, false) != ATTR_OKAY
) { 
1497             } else if (strcmp16(block
.getElementName(&len
), action16
.string()) == 0 
1498                        || strcmp16(block
.getElementName(&len
), category16
.string()) == 0) { 
1499                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1500                                  RESOURCES_ANDROID_NAMESPACE
, "name", 
1501                                  packageIdentChars
, true) != ATTR_OKAY
) { 
1504             } else if (strcmp16(block
.getElementName(&len
), data16
.string()) == 0) { 
1505                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1506                                  RESOURCES_ANDROID_NAMESPACE
, "mimeType", 
1507                                  typeIdentChars
, true) != ATTR_OKAY
) { 
1510                 if (validateAttr(manifestPath
, finalResTable
, block
, 
1511                                  RESOURCES_ANDROID_NAMESPACE
, "scheme", 
1512                                  schemeIdentChars
, true) != ATTR_OKAY
) { 
1519     if (resFile 
!= NULL
) { 
1520         // These resources are now considered to be a part of the included 
1521         // resources, for others to reference. 
1522         err 
= assets
->addIncludedResources(resFile
); 
1523         if (err 
< NO_ERROR
) { 
1524             fprintf(stderr
, "ERROR: Unable to parse generated resources, aborting.\n"); 
1532 static const char* getIndentSpace(int indent
) 
1534 static const char whitespace
[] = 
1537     return whitespace 
+ sizeof(whitespace
) - 1 - indent
*4; 
1540 static status_t 
fixupSymbol(String16
* inoutSymbol
) 
1542     inoutSymbol
->replaceAll('.', '_'); 
1543     inoutSymbol
->replaceAll(':', '_'); 
1547 static String16 
getAttributeComment(const sp
<AaptAssets
>& assets
, 
1548                                     const String8
& name
, 
1549                                     String16
* outTypeComment 
= NULL
) 
1551     sp
<AaptSymbols
> asym 
= assets
->getSymbolsFor(String8("R")); 
1553         //printf("Got R symbols!\n"); 
1554         asym 
= asym
->getNestedSymbols().valueFor(String8("attr")); 
1556             //printf("Got attrs symbols! comment %s=%s\n", 
1557             //     name.string(), String8(asym->getComment(name)).string()); 
1558             if (outTypeComment 
!= NULL
) { 
1559                 *outTypeComment 
= asym
->getTypeComment(name
); 
1561             return asym
->getComment(name
); 
1567 static status_t 
writeLayoutClasses( 
1568     FILE* fp
, const sp
<AaptAssets
>& assets
, 
1569     const sp
<AaptSymbols
>& symbols
, int indent
, bool includePrivate
) 
1571     const char* indentStr 
= getIndentSpace(indent
); 
1572     if (!includePrivate
) { 
1573         fprintf(fp
, "%s/** @doconly */\n", indentStr
); 
1575     fprintf(fp
, "%spublic static final class styleable {\n", indentStr
); 
1578     String16 
attr16("attr"); 
1579     String16 
package16(assets
->getPackage()); 
1581     indentStr 
= getIndentSpace(indent
); 
1582     bool hasErrors 
= false; 
1585     size_t N 
= symbols
->getNestedSymbols().size(); 
1586     for (i
=0; i
<N
; i
++) { 
1587         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1588         String16 
nclassName16(symbols
->getNestedSymbols().keyAt(i
)); 
1589         String8 
realClassName(nclassName16
); 
1590         if (fixupSymbol(&nclassName16
) != NO_ERROR
) { 
1593         String8 
nclassName(nclassName16
); 
1595         SortedVector
<uint32_t> idents
; 
1596         Vector
<uint32_t> origOrder
; 
1597         Vector
<bool> publicFlags
; 
1600         size_t NA 
= nsymbols
->getSymbols().size(); 
1601         for (a
=0; a
<NA
; a
++) { 
1602             const AaptSymbolEntry
& sym(nsymbols
->getSymbols().valueAt(a
)); 
1603             int32_t code 
= sym
.typeCode 
== AaptSymbolEntry::TYPE_INT32
 
1605             bool isPublic 
= true; 
1607                 String16 
name16(sym
.name
); 
1608                 uint32_t typeSpecFlags
; 
1609                 code 
= assets
->getIncludedResources().identifierForName( 
1610                     name16
.string(), name16
.size(), 
1611                     attr16
.string(), attr16
.size(), 
1612                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1614                     fprintf(stderr
, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n", 
1615                             nclassName
.string(), sym
.name
.string()); 
1618                 isPublic 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1621             origOrder
.add(code
); 
1622             publicFlags
.add(isPublic
); 
1627         bool deprecated 
= false; 
1629         String16 comment 
= symbols
->getComment(realClassName
); 
1630         fprintf(fp
, "%s/** ", indentStr
); 
1631         if (comment
.size() > 0) { 
1632             String8 
cmt(comment
); 
1633             fprintf(fp
, "%s\n", cmt
.string()); 
1634             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1638             fprintf(fp
, "Attributes that can be used with a %s.\n", nclassName
.string()); 
1640         bool hasTable 
= false; 
1641         for (a
=0; a
<NA
; a
++) { 
1642             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1647                             "%s   <p>Includes the following attributes:</p>\n" 
1649                             "%s   <colgroup align=\"left\" />\n" 
1650                             "%s   <colgroup align=\"left\" />\n" 
1651                             "%s   <tr><th>Attribute</th><th>Description</th></tr>\n", 
1658                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1659                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1662                 String8 
name8(sym
.name
); 
1663                 String16 
comment(sym
.comment
); 
1664                 if (comment
.size() <= 0) { 
1665                     comment 
= getAttributeComment(assets
, name8
); 
1667                 if (comment
.size() > 0) { 
1668                     const char16_t* p 
= comment
.string(); 
1669                     while (*p 
!= 0 && *p 
!= '.') { 
1671                             while (*p 
!= 0 && *p 
!= '}') { 
1681                     comment 
= String16(comment
.string(), p
-comment
.string()); 
1683                 String16 
name(name8
); 
1685                 fprintf(fp
, "%s   <tr><td><code>{@link #%s_%s %s:%s}</code></td><td>%s</td></tr>\n", 
1686                         indentStr
, nclassName
.string(), 
1687                         String8(name
).string(), 
1688                         assets
->getPackage().string(), 
1689                         String8(name
).string(), 
1690                         String8(comment
).string()); 
1694             fprintf(fp
, "%s   </table>\n", indentStr
); 
1696         for (a
=0; a
<NA
; a
++) { 
1697             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1699                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1700                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1703                 String16 
name(sym
.name
); 
1705                 fprintf(fp
, "%s   @see #%s_%s\n", 
1706                         indentStr
, nclassName
.string(), 
1707                         String8(name
).string()); 
1710         fprintf(fp
, "%s */\n", getIndentSpace(indent
)); 
1713             fprintf(fp
, "%s@Deprecated\n", indentStr
); 
1717                 "%spublic static final int[] %s = {\n" 
1719                 indentStr
, nclassName
.string(), 
1720                 getIndentSpace(indent
+1)); 
1722         for (a
=0; a
<NA
; a
++) { 
1725                     fprintf(fp
, ",\n%s", getIndentSpace(indent
+1)); 
1730             fprintf(fp
, "0x%08x", idents
[a
]); 
1733         fprintf(fp
, "\n%s};\n", indentStr
); 
1735         for (a
=0; a
<NA
; a
++) { 
1736             ssize_t pos 
= idents
.indexOf(origOrder
.itemAt(a
)); 
1738                 const AaptSymbolEntry
& sym 
= nsymbols
->getSymbols().valueAt(a
); 
1739                 if (!publicFlags
.itemAt(a
) && !includePrivate
) { 
1742                 String8 
name8(sym
.name
); 
1743                 String16 
comment(sym
.comment
); 
1744                 String16 typeComment
; 
1745                 if (comment
.size() <= 0) { 
1746                     comment 
= getAttributeComment(assets
, name8
, &typeComment
); 
1748                     getAttributeComment(assets
, name8
, &typeComment
); 
1750                 String16 
name(name8
); 
1751                 if (fixupSymbol(&name
) != NO_ERROR
) { 
1755                 uint32_t typeSpecFlags 
= 0; 
1756                 String16 
name16(sym
.name
); 
1757                 assets
->getIncludedResources().identifierForName( 
1758                     name16
.string(), name16
.size(), 
1759                     attr16
.string(), attr16
.size(), 
1760                     package16
.string(), package16
.size(), &typeSpecFlags
); 
1761                 //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), 
1762                 //    String8(attr16).string(), String8(name16).string(), typeSpecFlags); 
1763                 const bool pub 
= (typeSpecFlags
&ResTable_typeSpec::SPEC_PUBLIC
) != 0; 
1765                 bool deprecated 
= false; 
1767                 fprintf(fp
, "%s/**\n", indentStr
); 
1768                 if (comment
.size() > 0) { 
1769                     String8 
cmt(comment
); 
1770                     fprintf(fp
, "%s  <p>\n%s  @attr description\n", indentStr
, indentStr
); 
1771                     fprintf(fp
, "%s  %s\n", indentStr
, cmt
.string()); 
1772                     if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1777                             "%s  <p>This symbol is the offset where the {@link %s.R.attr#%s}\n" 
1778                             "%s  attribute's value can be found in the {@link #%s} array.\n", 
1780                             pub 
? assets
->getPackage().string() 
1781                                 : assets
->getSymbolsPrivatePackage().string(), 
1782                             String8(name
).string(), 
1783                             indentStr
, nclassName
.string()); 
1785                 if (typeComment
.size() > 0) { 
1786                     String8 
cmt(typeComment
); 
1787                     fprintf(fp
, "\n\n%s  %s\n", indentStr
, cmt
.string()); 
1788                     if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1792                 if (comment
.size() > 0) { 
1795                                 "%s  <p>This corresponds to the global attribute" 
1796                                 "%s  resource symbol {@link %s.R.attr#%s}.\n", 
1797                                 indentStr
, indentStr
, 
1798                                 assets
->getPackage().string(), 
1799                                 String8(name
).string()); 
1802                                 "%s  <p>This is a private symbol.\n", indentStr
); 
1805                 fprintf(fp
, "%s  @attr name %s:%s\n", indentStr
, 
1806                         "android", String8(name
).string()); 
1807                 fprintf(fp
, "%s*/\n", indentStr
); 
1809                     fprintf(fp
, "%s@Deprecated\n", indentStr
); 
1812                         "%spublic static final int %s_%s = %d;\n", 
1813                         indentStr
, nclassName
.string(), 
1814                         String8(name
).string(), (int)pos
); 
1820     fprintf(fp
, "%s};\n", getIndentSpace(indent
)); 
1821     return hasErrors 
? UNKNOWN_ERROR 
: NO_ERROR
; 
1824 static status_t 
writeSymbolClass( 
1825     FILE* fp
, const sp
<AaptAssets
>& assets
, bool includePrivate
, 
1826     const sp
<AaptSymbols
>& symbols
, const String8
& className
, int indent
, 
1829     fprintf(fp
, "%spublic %sfinal class %s {\n", 
1830             getIndentSpace(indent
), 
1831             indent 
!= 0 ? "static " : "", className
.string()); 
1835     status_t err 
= NO_ERROR
; 
1837     const char * id_format 
= nonConstantId 
? 
1838             "%spublic static int %s=0x%08x;\n" : 
1839             "%spublic static final int %s=0x%08x;\n"; 
1841     size_t N 
= symbols
->getSymbols().size(); 
1842     for (i
=0; i
<N
; i
++) { 
1843         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1844         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_INT32
) { 
1847         if (!assets
->isJavaSymbol(sym
, includePrivate
)) { 
1850         String16 
name(sym
.name
); 
1851         String8 
realName(name
); 
1852         if (fixupSymbol(&name
) != NO_ERROR
) { 
1853             return UNKNOWN_ERROR
; 
1855         String16 
comment(sym
.comment
); 
1856         bool haveComment 
= false; 
1857         bool deprecated 
= false; 
1858         if (comment
.size() > 0) { 
1860             String8 
cmt(comment
); 
1863                     getIndentSpace(indent
), cmt
.string()); 
1864             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1867         } else if (sym
.isPublic 
&& !includePrivate
) { 
1868             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1869                 assets
->getPackage().string(), className
.string(), 
1870                 String8(sym
.name
).string()); 
1872         String16 
typeComment(sym
.typeComment
); 
1873         if (typeComment
.size() > 0) { 
1874             String8 
cmt(typeComment
); 
1878                         "%s/** %s\n", getIndentSpace(indent
), cmt
.string()); 
1881                         "%s %s\n", getIndentSpace(indent
), cmt
.string()); 
1883             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1888             fprintf(fp
,"%s */\n", getIndentSpace(indent
)); 
1891             fprintf(fp
, "%s@Deprecated\n", getIndentSpace(indent
)); 
1893         fprintf(fp
, id_format
, 
1894                 getIndentSpace(indent
), 
1895                 String8(name
).string(), (int)sym
.int32Val
); 
1898     for (i
=0; i
<N
; i
++) { 
1899         const AaptSymbolEntry
& sym 
= symbols
->getSymbols().valueAt(i
); 
1900         if (sym
.typeCode 
!= AaptSymbolEntry::TYPE_STRING
) { 
1903         if (!assets
->isJavaSymbol(sym
, includePrivate
)) { 
1906         String16 
name(sym
.name
); 
1907         if (fixupSymbol(&name
) != NO_ERROR
) { 
1908             return UNKNOWN_ERROR
; 
1910         String16 
comment(sym
.comment
); 
1911         bool deprecated 
= false; 
1912         if (comment
.size() > 0) { 
1913             String8 
cmt(comment
); 
1917                     getIndentSpace(indent
), cmt
.string(), 
1918                     getIndentSpace(indent
)); 
1919             if (strstr(cmt
.string(), "@deprecated") != NULL
) { 
1922         } else if (sym
.isPublic 
&& !includePrivate
) { 
1923             sym
.sourcePos
.warning("No comment for public symbol %s:%s/%s", 
1924                 assets
->getPackage().string(), className
.string(), 
1925                 String8(sym
.name
).string()); 
1928             fprintf(fp
, "%s@Deprecated\n", getIndentSpace(indent
)); 
1930         fprintf(fp
, "%spublic static final String %s=\"%s\";\n", 
1931                 getIndentSpace(indent
), 
1932                 String8(name
).string(), sym
.stringVal
.string()); 
1935     sp
<AaptSymbols
> styleableSymbols
; 
1937     N 
= symbols
->getNestedSymbols().size(); 
1938     for (i
=0; i
<N
; i
++) { 
1939         sp
<AaptSymbols
> nsymbols 
= symbols
->getNestedSymbols().valueAt(i
); 
1940         String8 
nclassName(symbols
->getNestedSymbols().keyAt(i
)); 
1941         if (nclassName 
== "styleable") { 
1942             styleableSymbols 
= nsymbols
; 
1944             err 
= writeSymbolClass(fp
, assets
, includePrivate
, nsymbols
, nclassName
, indent
, nonConstantId
); 
1946         if (err 
!= NO_ERROR
) { 
1951     if (styleableSymbols 
!= NULL
) { 
1952         err 
= writeLayoutClasses(fp
, assets
, styleableSymbols
, indent
, includePrivate
); 
1953         if (err 
!= NO_ERROR
) { 
1959     fprintf(fp
, "%s}\n", getIndentSpace(indent
)); 
1963 status_t 
writeResourceSymbols(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, 
1964     const String8
& package
, bool includePrivate
) 
1966     if (!bundle
->getRClassDir()) { 
1970     const size_t N 
= assets
->getSymbols().size(); 
1971     for (size_t i
=0; i
<N
; i
++) { 
1972         sp
<AaptSymbols
> symbols 
= assets
->getSymbols().valueAt(i
); 
1973         String8 
className(assets
->getSymbols().keyAt(i
)); 
1974         String8 
dest(bundle
->getRClassDir()); 
1975         if (bundle
->getMakePackageDirs()) { 
1976             String8 
pkg(package
); 
1977             const char* last 
= pkg
.string(); 
1978             const char* s 
= last
-1; 
1981                 if (s 
> last 
&& (*s 
== '.' || *s 
== 0)) { 
1982                     String8 
part(last
, s
-last
); 
1983                     dest
.appendPath(part
); 
1984 #ifdef HAVE_MS_C_RUNTIME 
1985                     _mkdir(dest
.string()); 
1987                     mkdir(dest
.string(), S_IRUSR
|S_IWUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
); 
1993         dest
.appendPath(className
); 
1994         dest
.append(".java"); 
1995         FILE* fp 
= fopen(dest
.string(), "w+"); 
1997             fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
1998                     dest
.string(), strerror(errno
)); 
1999             return UNKNOWN_ERROR
; 
2001         if (bundle
->getVerbose()) { 
2002             printf("  Writing symbols for class %s.\n", className
.string()); 
2006         "/* AUTO-GENERATED FILE.  DO NOT MODIFY.\n" 
2008         " * This class was automatically generated by the\n" 
2009         " * aapt tool from the resource data it found.  It\n" 
2010         " * should not be modified by hand.\n" 
2013         "package %s;\n\n", package
.string()); 
2015         status_t err 
= writeSymbolClass(fp
, assets
, includePrivate
, symbols
, 
2016                 className
, 0, bundle
->getNonConstantId()); 
2017         if (err 
!= NO_ERROR
) { 
2022         // If we were asked to generate a dependency file, we'll go ahead and add this R.java 
2023         // as a target in the dependency file right next to it. 
2024         if (bundle
->getGenDependencies()) { 
2025             // Add this R.java to the dependency file 
2026             String8 
dependencyFile(bundle
->getRClassDir()); 
2027             dependencyFile
.appendPath("R.java.d"); 
2029             fp 
= fopen(dependencyFile
.string(), "a"); 
2030             fprintf(fp
,"%s \\\n", dest
.string()); 
2040 class ProguardKeepSet
 
2043     // { rule --> { file locations } } 
2044     KeyedVector
<String8
, SortedVector
<String8
> > rules
; 
2046     void add(const String8
& rule
, const String8
& where
); 
2049 void ProguardKeepSet::add(const String8
& rule
, const String8
& where
) 
2051     ssize_t index 
= rules
.indexOfKey(rule
); 
2053         index 
= rules
.add(rule
, SortedVector
<String8
>()); 
2055     rules
.editValueAt(index
).add(where
); 
2059 addProguardKeepRule(ProguardKeepSet
* keep
, const String8
& inClassName
, 
2060         const char* pkg
, const String8
& srcName
, int line
) 
2062     String8 
className(inClassName
); 
2064         // asdf     --> package.asdf 
2065         // .asdf  .a.b  --> package.asdf package.a.b 
2066         // asdf.adsf --> asdf.asdf 
2067         const char* p 
= className
.string(); 
2068         const char* q 
= strchr(p
, '.'); 
2071             className
.append(inClassName
); 
2072         } else if (q 
== NULL
) { 
2074             className
.append("."); 
2075             className
.append(inClassName
); 
2079     String8 
rule("-keep class "); 
2081     rule 
+= " { <init>(...); }"; 
2083     String8 
location("view "); 
2084     location 
+= srcName
; 
2086     sprintf(lineno
, ":%d", line
); 
2089     keep
->add(rule
, location
); 
2093 writeProguardForAndroidManifest(ProguardKeepSet
* keep
, const sp
<AaptAssets
>& assets
) 
2098     ResXMLTree::event_code_t code
; 
2100     bool inApplication 
= false; 
2102     sp
<AaptGroup
> assGroup
; 
2103     sp
<AaptFile
> assFile
; 
2106     // First, look for a package file to parse.  This is required to 
2107     // be able to generate the resource information. 
2108     assGroup 
= assets
->getFiles().valueFor(String8("AndroidManifest.xml")); 
2109     if (assGroup 
== NULL
) { 
2110         fprintf(stderr
, "ERROR: No AndroidManifest.xml file found.\n"); 
2114     if (assGroup
->getFiles().size() != 1) { 
2115         fprintf(stderr
, "warning: Multiple AndroidManifest.xml files found, using %s\n", 
2116                 assGroup
->getFiles().valueAt(0)->getPrintableSource().string()); 
2119     assFile 
= assGroup
->getFiles().valueAt(0); 
2121     err 
= parseXMLResource(assFile
, &tree
); 
2122     if (err 
!= NO_ERROR
) { 
2128     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
2129         if (code 
== ResXMLTree::END_TAG
) { 
2130             if (/* name == "Application" && */ depth 
== 2) { 
2131                 inApplication 
= false; 
2136         if (code 
!= ResXMLTree::START_TAG
) { 
2140         String8 
tag(tree
.getElementName(&len
)); 
2141         // printf("Depth %d tag %s\n", depth, tag.string()); 
2142         bool keepTag 
= false; 
2144             if (tag 
!= "manifest") { 
2145                 fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
2148             pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
2149         } else if (depth 
== 2) { 
2150             if (tag 
== "application") { 
2151                 inApplication 
= true; 
2154                 String8 agent 
= getAttribute(tree
, "http://schemas.android.com/apk/res/android", 
2155                         "backupAgent", &error
); 
2156                 if (agent
.length() > 0) { 
2157                     addProguardKeepRule(keep
, agent
, pkg
.string(), 
2158                             assFile
->getPrintableSource(), tree
.getLineNumber()); 
2160             } else if (tag 
== "instrumentation") { 
2164         if (!keepTag 
&& inApplication 
&& depth 
== 3) { 
2165             if (tag 
== "activity" || tag 
== "service" || tag 
== "receiver" || tag 
== "provider") { 
2170             String8 name 
= getAttribute(tree
, "http://schemas.android.com/apk/res/android", 
2173                 fprintf(stderr
, "ERROR: %s\n", error
.string()); 
2176             if (name
.length() > 0) { 
2177                 addProguardKeepRule(keep
, name
, pkg
.string(), 
2178                         assFile
->getPrintableSource(), tree
.getLineNumber()); 
2186 struct NamespaceAttributePair 
{ 
2190     NamespaceAttributePair(const char* n
, const char* a
) : ns(n
), attr(a
) {} 
2191     NamespaceAttributePair() : ns(NULL
), attr(NULL
) {} 
2195 writeProguardForXml(ProguardKeepSet
* keep
, const sp
<AaptFile
>& layoutFile
, 
2196         const char* startTag
, const KeyedVector
<String8
, NamespaceAttributePair
>* tagAttrPairs
) 
2201     ResXMLTree::event_code_t code
; 
2203     err 
= parseXMLResource(layoutFile
, &tree
); 
2204     if (err 
!= NO_ERROR
) { 
2210     if (startTag 
!= NULL
) { 
2211         bool haveStart 
= false; 
2212         while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
2213             if (code 
!= ResXMLTree::START_TAG
) { 
2216             String8 
tag(tree
.getElementName(&len
)); 
2217             if (tag 
== startTag
) { 
2227     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
2228         if (code 
!= ResXMLTree::START_TAG
) { 
2231         String8 
tag(tree
.getElementName(&len
)); 
2233         // If there is no '.', we'll assume that it's one of the built in names. 
2234         if (strchr(tag
.string(), '.')) { 
2235             addProguardKeepRule(keep
, tag
, NULL
, 
2236                     layoutFile
->getPrintableSource(), tree
.getLineNumber()); 
2237         } else if (tagAttrPairs 
!= NULL
) { 
2238             ssize_t tagIndex 
= tagAttrPairs
->indexOfKey(tag
); 
2239             if (tagIndex 
>= 0) { 
2240                 const NamespaceAttributePair
& nsAttr 
= tagAttrPairs
->valueAt(tagIndex
); 
2241                 ssize_t attrIndex 
= tree
.indexOfAttribute(nsAttr
.ns
, nsAttr
.attr
); 
2242                 if (attrIndex 
< 0) { 
2243                     // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n", 
2244                     //        layoutFile->getPrintableSource().string(), tree.getLineNumber(), 
2245                     //        tag.string(), nsAttr.ns, nsAttr.attr); 
2248                     addProguardKeepRule(keep
, 
2249                                         String8(tree
.getAttributeStringValue(attrIndex
, &len
)), NULL
, 
2250                                         layoutFile
->getPrintableSource(), tree
.getLineNumber()); 
2259 static void addTagAttrPair(KeyedVector
<String8
, NamespaceAttributePair
>* dest
, 
2260         const char* tag
, const char* ns
, const char* attr
) { 
2261     dest
->add(String8(tag
), NamespaceAttributePair(ns
, attr
)); 
2265 writeProguardForLayouts(ProguardKeepSet
* keep
, const sp
<AaptAssets
>& assets
) 
2269     // tag:attribute pairs that should be checked in layout files. 
2270     KeyedVector
<String8
, NamespaceAttributePair
> kLayoutTagAttrPairs
; 
2271     addTagAttrPair(&kLayoutTagAttrPairs
, "view", NULL
, "class"); 
2272     addTagAttrPair(&kLayoutTagAttrPairs
, "fragment", NULL
, "class"); 
2273     addTagAttrPair(&kLayoutTagAttrPairs
, "fragment", RESOURCES_ANDROID_NAMESPACE
, "name"); 
2275     // tag:attribute pairs that should be checked in xml files. 
2276     KeyedVector
<String8
, NamespaceAttributePair
> kXmlTagAttrPairs
; 
2277     addTagAttrPair(&kXmlTagAttrPairs
, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE
, "fragment"); 
2278     addTagAttrPair(&kXmlTagAttrPairs
, "header", RESOURCES_ANDROID_NAMESPACE
, "fragment"); 
2280     const Vector
<sp
<AaptDir
> >& dirs 
= assets
->resDirs(); 
2281     const size_t K 
= dirs
.size(); 
2282     for (size_t k
=0; k
<K
; k
++) { 
2283         const sp
<AaptDir
>& d 
= dirs
.itemAt(k
); 
2284         const String8
& dirName 
= d
->getLeaf(); 
2285         const char* startTag 
= NULL
; 
2286         const KeyedVector
<String8
, NamespaceAttributePair
>* tagAttrPairs 
= NULL
; 
2287         if ((dirName 
== String8("layout")) || (strncmp(dirName
.string(), "layout-", 7) == 0)) { 
2288             tagAttrPairs 
= &kLayoutTagAttrPairs
; 
2289         } else if ((dirName 
== String8("xml")) || (strncmp(dirName
.string(), "xml-", 4) == 0)) { 
2290             startTag 
= "PreferenceScreen"; 
2291             tagAttrPairs 
= &kXmlTagAttrPairs
; 
2296         const KeyedVector
<String8
,sp
<AaptGroup
> > groups 
= d
->getFiles(); 
2297         const size_t N 
= groups
.size(); 
2298         for (size_t i
=0; i
<N
; i
++) { 
2299             const sp
<AaptGroup
>& group 
= groups
.valueAt(i
); 
2300             const DefaultKeyedVector
<AaptGroupEntry
, sp
<AaptFile
> >& files 
= group
->getFiles(); 
2301             const size_t M 
= files
.size(); 
2302             for (size_t j
=0; j
<M
; j
++) { 
2303                 err 
= writeProguardForXml(keep
, files
.valueAt(j
), startTag
, tagAttrPairs
); 
2310     // Handle the overlays 
2311     sp
<AaptAssets
> overlay 
= assets
->getOverlay(); 
2312     if (overlay
.get()) { 
2313         return writeProguardForLayouts(keep
, overlay
); 
2319 writeProguardFile(Bundle
* bundle
, const sp
<AaptAssets
>& assets
) 
2323     if (!bundle
->getProguardFile()) { 
2327     ProguardKeepSet keep
; 
2329     err 
= writeProguardForAndroidManifest(&keep
, assets
); 
2334     err 
= writeProguardForLayouts(&keep
, assets
); 
2339     FILE* fp 
= fopen(bundle
->getProguardFile(), "w+"); 
2341         fprintf(stderr
, "ERROR: Unable to open class file %s: %s\n", 
2342                 bundle
->getProguardFile(), strerror(errno
)); 
2343         return UNKNOWN_ERROR
; 
2346     const KeyedVector
<String8
, SortedVector
<String8
> >& rules 
= keep
.rules
; 
2347     const size_t N 
= rules
.size(); 
2348     for (size_t i
=0; i
<N
; i
++) { 
2349         const SortedVector
<String8
>& locations 
= rules
.valueAt(i
); 
2350         const size_t M 
= locations
.size(); 
2351         for (size_t j
=0; j
<M
; j
++) { 
2352             fprintf(fp
, "# %s\n", locations
.itemAt(j
).string()); 
2354         fprintf(fp
, "%s\n\n", rules
.keyAt(i
).string()); 
2361 // Loops through the string paths and writes them to the file pointer 
2362 // Each file path is written on its own line with a terminating backslash. 
2363 status_t 
writePathsToFile(const sp
<FilePathStore
>& files
, FILE* fp
) 
2366     for (size_t file_i 
= 0; file_i 
< files
->size(); ++file_i
) { 
2367         // Add the full file path to the dependency file 
2368         fprintf(fp
, "%s \\\n", files
->itemAt(file_i
).string()); 
2375 writeDependencyPreReqs(Bundle
* bundle
, const sp
<AaptAssets
>& assets
, FILE* fp
, bool includeRaw
) 
2378     deps 
+= writePathsToFile(assets
->getFullResPaths(), fp
); 
2380         deps 
+= writePathsToFile(assets
->getFullAssetPaths(), fp
);