diff options
-rw-r--r-- | tools/aapt/AaptAssets.h | 3 | ||||
-rw-r--r-- | tools/aapt/Images.cpp | 5 | ||||
-rw-r--r-- | tools/aapt/Images.h | 2 | ||||
-rw-r--r-- | tools/aapt/Main.h | 3 | ||||
-rw-r--r-- | tools/aapt/Resource.cpp | 50 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 183 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.h | 43 | ||||
-rw-r--r-- | tools/aapt/XMLNode.cpp | 56 | ||||
-rw-r--r-- | tools/aapt/XMLNode.h | 7 |
9 files changed, 316 insertions, 36 deletions
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 3fc9f81..d809c5b 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -104,6 +104,9 @@ private: struct AaptGroupEntry { public: + AaptGroupEntry() {} + AaptGroupEntry(const ConfigDescription& config) : mParams(config) {} + bool initFromDirName(const char* dir, String8* resType); inline const ConfigDescription& toParams() const { return mParams; } diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp index 137c85c..56d1650 100644 --- a/tools/aapt/Images.cpp +++ b/tools/aapt/Images.cpp @@ -1483,7 +1483,7 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con return NO_ERROR; } -status_t postProcessImage(const sp<AaptAssets>& assets, +status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, ResourceTable* table, const sp<AaptFile>& file) { String8 ext(file->getPath().getPathExtension()); @@ -1491,7 +1491,8 @@ status_t postProcessImage(const sp<AaptAssets>& assets, // At this point, now that we have all the resource data, all we need to // do is compile XML files. if (strcmp(ext.string(), ".xml") == 0) { - return compileXmlFile(assets, file, table); + String16 resourceName(parseResourceName(file->getPath().getPathLeaf())); + return compileXmlFile(bundle, assets, resourceName, file, table); } return NO_ERROR; diff --git a/tools/aapt/Images.h b/tools/aapt/Images.h index 91b6554..a0a94f8 100644 --- a/tools/aapt/Images.h +++ b/tools/aapt/Images.h @@ -20,7 +20,7 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, status_t preProcessImageToCache(const Bundle* bundle, const String8& source, const String8& dest); -status_t postProcessImage(const sp<AaptAssets>& assets, +status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets, ResourceTable* table, const sp<AaptFile>& file); #endif diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h index f24a023..089dde5 100644 --- a/tools/aapt/Main.h +++ b/tools/aapt/Main.h @@ -62,4 +62,7 @@ int dumpResources(Bundle* bundle); status_t writeDependencyPreReqs(Bundle* bundle, const sp<AaptAssets>& assets, FILE* fp, bool includeRaw); + +android::String8 parseResourceName(const String8& pathLeaf); + #endif // __MAIN_H diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index d605202..a4c9dab 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -50,7 +50,7 @@ public: // ========================================================================== // ========================================================================== -static String8 parseResourceName(const String8& leaf) +String8 parseResourceName(const String8& leaf) { const char* firstDot = strchr(leaf.string(), '.'); const char* str = leaf.string(); @@ -1088,7 +1088,7 @@ status_t generateAndroidManifestForSplit(Bundle* bundle, const sp<AaptAssets>& a manifest->addChild(app); root->addChild(manifest); - int err = compileXmlFile(assets, root, outFile, table); + int err = compileXmlFile(bundle, assets, String16(), root, outFile, table); if (err < NO_ERROR) { return err; } @@ -1336,7 +1336,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil ResourceDirIterator it(layouts, String8("layout")); while ((err=it.next()) == NO_ERROR) { String8 src = it.getFile()->getPrintableSource(); - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err == NO_ERROR) { ResXMLTree block; block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true); @@ -1355,7 +1356,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (anims != NULL) { ResourceDirIterator it(anims, String8("anim")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1370,7 +1372,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (animators != NULL) { ResourceDirIterator it(animators, String8("animator")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1385,7 +1388,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (interpolators != NULL) { ResourceDirIterator it(interpolators, String8("interpolator")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1400,7 +1404,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (transitions != NULL) { ResourceDirIterator it(transitions, String8("transition")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1415,7 +1420,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (xmls != NULL) { ResourceDirIterator it(xmls, String8("xml")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1430,7 +1436,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (drawables != NULL) { ResourceDirIterator it(drawables, String8("drawable")); while ((err=it.next()) == NO_ERROR) { - err = postProcessImage(assets, &table, it.getFile()); + err = postProcessImage(bundle, assets, &table, it.getFile()); if (err != NO_ERROR) { hasErrors = true; } @@ -1445,7 +1451,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (colors != NULL) { ResourceDirIterator it(colors, String8("color")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1461,7 +1468,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil ResourceDirIterator it(menus, String8("menu")); while ((err=it.next()) == NO_ERROR) { String8 src = it.getFile()->getPrintableSource(); - err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); + err = compileXmlFile(bundle, assets, String16(it.getBaseName()), + it.getFile(), &table, xmlFlags); if (err == NO_ERROR) { ResXMLTree block; block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true); @@ -1477,6 +1485,22 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil err = NO_ERROR; } + // Now compile any generated resources. + std::queue<CompileResourceWorkItem>& workQueue = table.getWorkQueue(); + while (!workQueue.empty()) { + CompileResourceWorkItem& workItem = workQueue.front(); + err = compileXmlFile(bundle, assets, workItem.resourceName, workItem.file, &table, xmlFlags); + if (err == NO_ERROR) { + assets->addResource(workItem.resPath.getPathLeaf(), + workItem.resPath, + workItem.file, + workItem.file->getResourceType()); + } else { + hasErrors = true; + } + workQueue.pop(); + } + if (table.validateLocalizations()) { hasErrors = true; } @@ -1509,7 +1533,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil if (err < NO_ERROR) { return err; } - err = compileXmlFile(assets, manifestTree, manifestFile, &table); + err = compileXmlFile(bundle, assets, String16(), manifestTree, manifestFile, &table); if (err < NO_ERROR) { return err; } @@ -1599,7 +1623,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil sp<AaptFile> outManifestFile = new AaptFile(manifestFile->getSourceFile(), manifestFile->getGroupEntry(), manifestFile->getResourceType()); - err = compileXmlFile(assets, manifestFile, + err = compileXmlFile(bundle, assets, String16(), manifestFile, outManifestFile, &table, XML_COMPILE_ASSIGN_ATTRIBUTE_IDS | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES); diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 8c9efc9..b8c3454 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -17,7 +17,9 @@ #define NOISY(x) //x -status_t compileXmlFile(const sp<AaptAssets>& assets, +status_t compileXmlFile(const Bundle* bundle, + const sp<AaptAssets>& assets, + const String16& resourceName, const sp<AaptFile>& target, ResourceTable* table, int options) @@ -27,10 +29,12 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, return UNKNOWN_ERROR; } - return compileXmlFile(assets, root, target, table, options); + return compileXmlFile(bundle, assets, resourceName, root, target, table, options); } -status_t compileXmlFile(const sp<AaptAssets>& assets, +status_t compileXmlFile(const Bundle* bundle, + const sp<AaptAssets>& assets, + const String16& resourceName, const sp<AaptFile>& target, const sp<AaptFile>& outTarget, ResourceTable* table, @@ -41,10 +45,12 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, return UNKNOWN_ERROR; } - return compileXmlFile(assets, root, outTarget, table, options); + return compileXmlFile(bundle, assets, resourceName, root, outTarget, table, options); } -status_t compileXmlFile(const sp<AaptAssets>& assets, +status_t compileXmlFile(const Bundle* bundle, + const sp<AaptAssets>& assets, + const String16& resourceName, const sp<XMLNode>& root, const sp<AaptFile>& target, ResourceTable* table, @@ -77,6 +83,10 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, if (hasErrors) { return UNKNOWN_ERROR; } + + if (table->modifyForCompat(bundle, resourceName, target, root) != NO_ERROR) { + return UNKNOWN_ERROR; + } NOISY(printf("Input XML Resource:\n")); NOISY(root->print()); @@ -4028,6 +4038,39 @@ sp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package, return t->getEntry(name, sourcePos, config, doSetIndex, overlay, mBundle->getAutoAddOverlay()); } +sp<ResourceTable::ConfigList> ResourceTable::getConfigList(const String16& package, + const String16& type, const String16& name) const +{ + const size_t packageCount = mOrderedPackages.size(); + for (size_t pi = 0; pi < packageCount; pi++) { + const sp<Package>& p = mOrderedPackages[pi]; + if (p == NULL || p->getName() != package) { + continue; + } + + const Vector<sp<Type> >& types = p->getOrderedTypes(); + const size_t typeCount = types.size(); + for (size_t ti = 0; ti < typeCount; ti++) { + const sp<Type>& t = types[ti]; + if (t == NULL || t->getName() != type) { + continue; + } + + const Vector<sp<ConfigList> >& configs = t->getOrderedConfigs(); + const size_t configCount = configs.size(); + for (size_t ci = 0; ci < configCount; ci++) { + const sp<ConfigList>& cl = configs[ci]; + if (cl == NULL || cl->getName() != name) { + continue; + } + + return cl; + } + } + } + return NULL; +} + sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID, const ResTable_config* config) const { @@ -4157,6 +4200,22 @@ bool ResourceTable::isAttributeFromL(uint32_t attrId) { (attrId & 0x0000ffff) >= (baseAttrId & 0x0000ffff); } +static bool isMinSdkVersionLOrAbove(const Bundle* bundle) { + if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) { + const char firstChar = bundle->getMinSdkVersion()[0]; + if (firstChar >= 'L' && firstChar <= 'Z') { + // L is the code-name for the v21 release. + return true; + } + + const int minSdk = atoi(bundle->getMinSdkVersion()); + if (minSdk >= SDK_L) { + return true; + } + } + return false; +} + /** * Modifies the entries in the resource table to account for compatibility * issues with older versions of Android. @@ -4200,19 +4259,10 @@ bool ResourceTable::isAttributeFromL(uint32_t attrId) { * attribute will be respected. */ status_t ResourceTable::modifyForCompat(const Bundle* bundle) { - if (bundle->getMinSdkVersion() != NULL) { + if (isMinSdkVersionLOrAbove(bundle)) { // If this app will only ever run on L+ devices, // we don't need to do any compatibility work. - - if (String8("L") == bundle->getMinSdkVersion()) { - // Code-name for the v21 release. - return NO_ERROR; - } - - const int minSdk = atoi(bundle->getMinSdkVersion()); - if (minSdk >= SDK_L) { - return NO_ERROR; - } + return NO_ERROR; } const String16 attr16("attr"); @@ -4309,3 +4359,104 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) { } return NO_ERROR; } + +status_t ResourceTable::modifyForCompat(const Bundle* bundle, + const String16& resourceName, + const sp<AaptFile>& target, + const sp<XMLNode>& root) { + if (isMinSdkVersionLOrAbove(bundle)) { + return NO_ERROR; + } + + if (target->getResourceType() == "" || target->getGroupEntry().toParams().sdkVersion >= SDK_L) { + // Skip resources that have no type (AndroidManifest.xml) or are already version qualified with v21 + // or higher. + return NO_ERROR; + } + + Vector<key_value_pair_t<sp<XMLNode>, size_t> > attrsToRemove; + + Vector<sp<XMLNode> > nodesToVisit; + nodesToVisit.push(root); + while (!nodesToVisit.isEmpty()) { + sp<XMLNode> node = nodesToVisit.top(); + nodesToVisit.pop(); + + const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes(); + const size_t attrCount = attrs.size(); + for (size_t i = 0; i < attrCount; i++) { + const XMLNode::attribute_entry& attr = attrs[i]; + if (isAttributeFromL(attr.nameResId)) { + attrsToRemove.add(key_value_pair_t<sp<XMLNode>, size_t>(node, i)); + } + } + + // Schedule a visit to the children. + const Vector<sp<XMLNode> >& children = node->getChildren(); + const size_t childCount = children.size(); + for (size_t i = 0; i < childCount; i++) { + nodesToVisit.push(children[i]); + } + } + + if (attrsToRemove.isEmpty()) { + return NO_ERROR; + } + + ConfigDescription newConfig(target->getGroupEntry().toParams()); + newConfig.sdkVersion = SDK_L; + + // Look to see if we already have an overriding v21 configuration. + sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()), + String16(target->getResourceType()), resourceName); + if (cl->getEntries().indexOfKey(newConfig) < 0) { + // We don't have an overriding entry for v21, so we must duplicate this one. + sp<XMLNode> newRoot = root->clone(); + sp<AaptFile> newFile = new AaptFile(target->getSourceFile(), + AaptGroupEntry(newConfig), target->getResourceType()); + String8 resPath = String8::format("res/%s/%s", + newFile->getGroupEntry().toDirName(target->getResourceType()).string(), + target->getPath().getPathLeaf().string()); + resPath.convertToResPath(); + + // Add a resource table entry. + SourcePos(target->getSourceFile(), -1).printf( + "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.", + SDK_L, + mAssets->getPackage().string(), + newFile->getResourceType().string(), + String8(resourceName).string(), + newConfig.toString().string()); + + addEntry(SourcePos(), + String16(mAssets->getPackage()), + String16(target->getResourceType()), + resourceName, + String16(resPath), + NULL, + &newConfig); + + // Schedule this to be compiled. + CompileResourceWorkItem item; + item.resourceName = resourceName; + item.resPath = resPath; + item.file = newFile; + mWorkQueue.push(item); + } + + const size_t removeCount = attrsToRemove.size(); + for (size_t i = 0; i < removeCount; i++) { + sp<XMLNode> node = attrsToRemove[i].key; + size_t attrIndex = attrsToRemove[i].value; + const XMLNode::attribute_entry& ae = node->getAttributes()[attrIndex]; + SourcePos(node->getFilename(), node->getStartLineNumber()).printf( + "removing attribute %s%s%s from <%s>", + String8(ae.ns).string(), + (ae.ns.size() == 0 ? "" : ":"), + String8(ae.name).string(), + String8(node->getElementName()).string()); + node->removeAttribute(attrIndex); + } + + return NO_ERROR; +} diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index 025a868..c548a85 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -12,8 +12,9 @@ #include "SourcePos.h" #include "ResourceFilter.h" -#include <set> #include <map> +#include <queue> +#include <set> using namespace std; @@ -33,18 +34,24 @@ enum { | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES }; -status_t compileXmlFile(const sp<AaptAssets>& assets, +status_t compileXmlFile(const Bundle* bundle, + const sp<AaptAssets>& assets, + const String16& resourceName, const sp<AaptFile>& target, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); -status_t compileXmlFile(const sp<AaptAssets>& assets, +status_t compileXmlFile(const Bundle* bundle, + const sp<AaptAssets>& assets, + const String16& resourceName, const sp<AaptFile>& target, const sp<AaptFile>& outTarget, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); -status_t compileXmlFile(const sp<AaptAssets>& assets, +status_t compileXmlFile(const Bundle* bundle, + const sp<AaptAssets>& assets, + const String16& resourceName, const sp<XMLNode>& xmlTree, const sp<AaptFile>& target, ResourceTable* table, @@ -71,6 +78,14 @@ struct AccessorCookie } }; +// Holds the necessary information to compile the +// resource. +struct CompileResourceWorkItem { + String16 resourceName; + String8 resPath; + sp<AaptFile> file; +}; + class ResourceTable : public ResTable::Accessor { public: @@ -92,6 +107,18 @@ public: return mAssetsPackage; } + /** + * Returns the queue of resources that need to be compiled. + * This is only used for resources that have been generated + * during the compilation phase. If they were just added + * to the AaptAssets, then they may be skipped over + * and would mess up iteration order for the existing + * resources. + */ + queue<CompileResourceWorkItem>& getWorkQueue() { + return mWorkQueue; + } + status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets); status_t addPublic(const SourcePos& pos, @@ -166,6 +193,10 @@ public: bool hasResources() const; status_t modifyForCompat(const Bundle* bundle); + status_t modifyForCompat(const Bundle* bundle, + const String16& resourceName, + const sp<AaptFile>& file, + const sp<XMLNode>& root); sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const bool isBase); @@ -527,6 +558,9 @@ private: bool doSetIndex = false); sp<const Entry> getEntry(uint32_t resID, const ResTable_config* config = NULL) const; + sp<ConfigList> getConfigList(const String16& package, + const String16& type, + const String16& name) const; const Item* getItem(uint32_t resID, uint32_t attrID) const; bool getItemValue(uint32_t resID, uint32_t attrID, Res_value* outValue); @@ -545,6 +579,7 @@ private: // key = string resource name, value = set of locales in which that name is defined map<String16, map<String8, SourcePos> > mLocalizations; + queue<CompileResourceWorkItem> mWorkQueue; }; #endif diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index 607d419..51a4154 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -621,6 +621,12 @@ sp<XMLNode> XMLNode::parse(const sp<AaptFile>& file) return state.root; } +XMLNode::XMLNode() + : mNextAttributeIndex(0x80000000) + , mStartLineNumber(0) + , mEndLineNumber(0) + , mUTF8(false) {} + XMLNode::XMLNode(const String8& filename, const String16& s1, const String16& s2, bool isNamespace) : mNextAttributeIndex(0x80000000) , mFilename(filename) @@ -810,6 +816,32 @@ status_t XMLNode::addAttribute(const String16& ns, const String16& name, return NO_ERROR; } +status_t XMLNode::removeAttribute(size_t index) +{ + if (getType() == TYPE_CDATA) { + return UNKNOWN_ERROR; + } + + if (index >= mAttributes.size()) { + return UNKNOWN_ERROR; + } + + const attribute_entry& e = mAttributes[index]; + const uint32_t key = e.nameResId ? e.nameResId : e.index; + mAttributeOrder.removeItem(key); + mAttributes.removeAt(index); + + // Shift all the indices. + const size_t attrCount = mAttributeOrder.size(); + for (size_t i = 0; i < attrCount; i++) { + size_t attrIdx = mAttributeOrder[i]; + if (attrIdx > index) { + mAttributeOrder.replaceValueAt(i, attrIdx - 1); + } + } + return NO_ERROR; +} + void XMLNode::setAttributeResID(size_t attrIdx, uint32_t resId) { attribute_entry& e = mAttributes.editItemAt(attrIdx); @@ -999,6 +1031,30 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets, return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } +sp<XMLNode> XMLNode::clone() const { + sp<XMLNode> copy = new XMLNode(); + copy->mNamespacePrefix = mNamespacePrefix; + copy->mNamespaceUri = mNamespaceUri; + copy->mElementName = mElementName; + + const size_t childCount = mChildren.size(); + for (size_t i = 0; i < childCount; i++) { + copy->mChildren.add(mChildren[i]->clone()); + } + + copy->mAttributes = mAttributes; + copy->mAttributeOrder = mAttributeOrder; + copy->mNextAttributeIndex = mNextAttributeIndex; + copy->mChars = mChars; + memcpy(©->mCharsValue, &mCharsValue, sizeof(mCharsValue)); + copy->mComment = mComment; + copy->mFilename = mFilename; + copy->mStartLineNumber = mStartLineNumber; + copy->mEndLineNumber = mEndLineNumber; + copy->mUTF8 = mUTF8; + return copy; +} + status_t XMLNode::flatten(const sp<AaptFile>& dest, bool stripComments, bool stripRawValues) const { diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h index ccbf9f4..3161f65 100644 --- a/tools/aapt/XMLNode.h +++ b/tools/aapt/XMLNode.h @@ -116,6 +116,8 @@ public: status_t addAttribute(const String16& ns, const String16& name, const String16& value); + status_t removeAttribute(size_t index); + void setAttributeResID(size_t attrIdx, uint32_t resId); status_t appendChars(const String16& chars); @@ -137,6 +139,8 @@ public: status_t flatten(const sp<AaptFile>& dest, bool stripComments, bool stripRawValues) const; + sp<XMLNode> clone() const; + void print(int indent=0); private: @@ -163,6 +167,9 @@ private: static void XMLCALL commentData(void *userData, const char *comment); + // For cloning + XMLNode(); + // Creating an element node. XMLNode(const String8& filename, const String16& s1, const String16& s2, bool isNamespace); |