]> git.saurik.com Git - android/aapt.git/commitdiff
donut snapshot
authorJean-Baptiste Queru <jbq@google.com>
Tue, 21 Jul 2009 18:16:54 +0000 (11:16 -0700)
committerJean-Baptiste Queru <jbq@google.com>
Tue, 21 Jul 2009 18:16:54 +0000 (11:16 -0700)
AaptAssets.cpp
AaptAssets.h
Bundle.h
Command.cpp
Main.cpp
Resource.cpp
ResourceTable.cpp
ResourceTable.h
XMLNode.cpp
XMLNode.h

index 6bc1ee6cbfbc5bd67197fefbec19deeca3b4d6e3..67af116d372dc5e67dff6bc01cba8e13d053fb2e 100644 (file)
@@ -187,6 +187,13 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
         return 0;
     }
 
+    // screen layout
+    if (getScreenLayoutName(part.string(), &config)) {
+        *axis = AXIS_SCREENLAYOUT;
+        *value = config.screenLayout;
+        return 0;
+    }
+
     // version
     if (getVersionName(part.string(), &config)) {
         *axis = AXIS_VERSION;
@@ -202,7 +209,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
 {
     Vector<String8> parts;
 
-    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, vers;
+    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers;
 
     const char *p = dir;
     const char *q;
@@ -378,6 +385,18 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
         //printf("not screen size: %s\n", part.string());
     }
 
+    if (getScreenLayoutName(part.string())) {
+        layout = part;
+
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index];
+    } else {
+        //printf("not screen layout: %s\n", part.string());
+    }
+
     if (getVersionName(part.string())) {
         vers = part;
 
@@ -404,6 +423,7 @@ success:
     this->keyboard = key;
     this->navigation = nav;
     this->screenSize = size;
+    this->screenLayout = layout;
     this->version = vers;
 
     // what is this anyway?
@@ -435,6 +455,8 @@ AaptGroupEntry::toString() const
     s += ",";
     s += screenSize;
     s += ",";
+    s += screenLayout;
+    s += ",";
     s += version;
     return s;
 }
@@ -483,6 +505,10 @@ AaptGroupEntry::toDirName(const String8& resType) const
         s += "-";
         s += screenSize;
     }
+    if (this->screenLayout != "") {
+        s += "-";
+        s += screenLayout;
+    }
     if (this->version != "") {
         s += "-";
         s += version;
@@ -786,6 +812,26 @@ bool AaptGroupEntry::getScreenSizeName(const char* name,
     return true;
 }
 
+bool AaptGroupEntry::getScreenLayoutName(const char* name,
+                                     ResTable_config* out)
+{
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_ANY;
+        return true;
+    } else if (strcmp(name, "smallscreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_SMALL;
+        return true;
+    } else if (strcmp(name, "normalscreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL;
+        return true;
+    } else if (strcmp(name, "largescreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_LARGE;
+        return true;
+    }
+
+    return false;
+}
+
 bool AaptGroupEntry::getVersionName(const char* name,
                                     ResTable_config* out)
 {
@@ -828,6 +874,7 @@ int AaptGroupEntry::compare(const AaptGroupEntry& o) const
     if (v == 0) v = keyboard.compare(o.keyboard);
     if (v == 0) v = navigation.compare(o.navigation);
     if (v == 0) v = screenSize.compare(o.screenSize);
+    if (v == 0) v = screenLayout.compare(o.screenLayout);
     if (v == 0) v = version.compare(o.version);
     return v;
 }
@@ -846,6 +893,7 @@ ResTable_config AaptGroupEntry::toParams() const
     getKeyboardName(keyboard.string(), &params);
     getNavigationName(navigation.string(), &params);
     getScreenSizeName(screenSize.string(), &params);
+    getScreenLayoutName(screenLayout.string(), &params);
     getVersionName(version.string(), &params);
     return params;
 }
index 01c8140b25ce09683d917df04e61ab3efc290fc7..3b96412c7c54a7ed8b33f63c3a9a40f46b7b7540 100644 (file)
@@ -37,6 +37,7 @@ enum {
     AXIS_KEYBOARD,
     AXIS_NAVIGATION,
     AXIS_SCREENSIZE,
+    AXIS_SCREENLAYOUT,
     AXIS_VERSION
 };
 
@@ -62,6 +63,7 @@ public:
     String8 keyboard;
     String8 navigation;
     String8 screenSize;
+    String8 screenLayout;
     String8 version;
 
     bool initFromDirName(const char* dir, String8* resType);
@@ -78,6 +80,7 @@ public:
     static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
     static bool getNavigationName(const char* name, ResTable_config* out = NULL);
     static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
+    static bool getScreenLayoutName(const char* name, ResTable_config* out = NULL);
     static bool getVersionName(const char* name, ResTable_config* out = NULL);
 
     int compare(const AaptGroupEntry& o) const;
index 2d8471bb5cc64f686594983c0cd06f327c218657..a6fedf3d34bd5b1b5526a16fa96044fa4c1a185d 100644 (file)
--- a/Bundle.h
+++ b/Bundle.h
@@ -34,10 +34,13 @@ public:
           mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
           mUpdate(false), mExtending(false),
           mRequireLocalization(false), mPseudolocalize(false),
+          mValues(false),
           mCompressionMethod(0), mOutputAPKFile(NULL),
           mAssetSourceDir(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL),
+          mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
+          mVersionCode(NULL), mVersionName(NULL),
           mArgc(0), mArgv(NULL)
         {}
     ~Bundle(void) {}
@@ -70,6 +73,8 @@ public:
     void setRequireLocalization(bool val) { mRequireLocalization = val; }
     bool getPseudolocalize(void) const { return mPseudolocalize; }
     void setPseudolocalize(bool val) { mPseudolocalize = val; }
+    bool getValues(void) const { return mValues; }
+    void setValues(bool val) { mValues = val; }
     int getCompressionMethod(void) const { return mCompressionMethod; }
     void setCompressionMethod(int val) { mCompressionMethod = val; }
     const char* getOutputAPKFile() const { return mOutputAPKFile; }
@@ -99,6 +104,17 @@ public:
     const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; }
     void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); }
 
+    const char*  getMinSdkVersion() const { return mMinSdkVersion; }
+    void setMinSdkVersion(const char*  val) { mMinSdkVersion = val; }
+    const char*  getTargetSdkVersion() const { return mTargetSdkVersion; }
+    void setTargetSdkVersion(const char*  val) { mTargetSdkVersion = val; }
+    const char*  getMaxSdkVersion() const { return mMaxSdkVersion; }
+    void setMaxSdkVersion(const char*  val) { mMaxSdkVersion = val; }
+    const char*  getVersionCode() const { return mVersionCode; }
+    void setVersionCode(const char*  val) { mVersionCode = val; }
+    const char* getVersionName() const { return mVersionName; }
+    void setVersionName(const char* val) { mVersionName = val; }
+    
     /*
      * Set and get the file specification.
      *
@@ -138,6 +154,7 @@ private:
     bool        mExtending;
     bool        mRequireLocalization;
     bool        mPseudolocalize;
+    bool        mValues;
     int         mCompressionMethod;
     const char* mOutputAPKFile;
     const char* mAssetSourceDir;
@@ -151,6 +168,12 @@ private:
     android::Vector<const char*> mNoCompressExtensions;
     android::Vector<const char*> mResourceSourceDirs;
     
+    const char* mMinSdkVersion;
+    const char* mTargetSdkVersion;
+    const char* mMaxSdkVersion;
+    const char* mVersionCode;
+    const char* mVersionName;
+    
     /* file specification */
     int         mArgc;
     char* const* mArgv;
index 6f3461df15eb1b4fd76d00597b79d454e8c4accc..e04491d93b863c3949a238bb2049faf5cef3ae42 100644 (file)
@@ -196,7 +196,7 @@ int doList(Bundle* bundle)
             printf("\nNo resource table found.\n");
         } else {
             printf("\nResource table:\n");
-            res.print();
+            res.print(false);
         }
 
         Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -268,17 +268,19 @@ static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* o
     return str ? String8(str, len) : String8();
 }
 
-static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
+static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
+        String8* outError, int32_t defValue = -1)
 {
     ssize_t idx = indexOfAttribute(tree, attrRes);
     if (idx < 0) {
-        return -1;
+        return defValue;
     }
     Res_value value;
     if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
-        if (value.dataType != Res_value::TYPE_INT_DEC) {
+        if (value.dataType < Res_value::TYPE_FIRST_INT
+                || value.dataType > Res_value::TYPE_LAST_INT) {
             if (outError != NULL) *outError = "attribute is not an integer value";
-            return -1;
+            return defValue;
         }
     }
     return value.data;
@@ -318,7 +320,18 @@ enum {
     VERSION_NAME_ATTR = 0x0101021c,
     LABEL_ATTR = 0x01010001,
     ICON_ATTR = 0x01010002,
-    MIN_SDK_VERSION_ATTR = 0x0101020c
+    MIN_SDK_VERSION_ATTR = 0x0101020c,
+    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
+    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
+    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
+    REQ_NAVIGATION_ATTR = 0x0101022a,
+    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
+    TARGET_SDK_VERSION_ATTR = 0x01010270,
+    TEST_ONLY_ATTR = 0x01010272,
+    DENSITY_ATTR = 0x0101026c,
+    SMALL_SCREEN_ATTR = 0x01010284,
+    NORMAL_SCREEN_ATTR = 0x01010285,
+    LARGE_SCREEN_ATTR = 0x01010286,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -357,7 +370,8 @@ int doDump(Bundle* bundle)
     const char* filename = bundle->getFileSpecEntry(1);
 
     AssetManager assets;
-    if (!assets.addAssetPath(String8(filename), NULL)) {
+    void* assetsCookie;
+    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
         fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
         return 1;
     }
@@ -369,7 +383,7 @@ int doDump(Bundle* bundle)
     }
 
     if (strcmp("resources", option) == 0) {
-        res.print();
+        res.print(bundle->getValues());
 
     } else if (strcmp("xmltree", option) == 0) {
         if (bundle->getFileSpecCount() < 3) {
@@ -488,6 +502,10 @@ int doDump(Bundle* bundle)
             bool isLauncherActivity = false;
             bool withinApplication = false;
             bool withinReceiver = false;
+            int targetSdk = 0;
+            int smallScreen = 1;
+            int normalScreen = 1;
+            int largeScreen = 1;
             String8 pkg;
             String8 activityName;
             String8 activityLabel;
@@ -543,15 +561,90 @@ int doDump(Bundle* bundle)
                             goto bail;
                         }
                         printf("icon='%s'\n", icon.string());
-                    } else if (tag == "uses-sdk") {
-                        int32_t sdkVersion = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
                         if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", error.string());
+                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
                             goto bail;
                         }
-                        if (sdkVersion != -1) {
-                            printf("sdkVersion:'%d'\n", sdkVersion);
+                        if (testOnly != 0) {
+                            printf("testOnly='%d'\n", testOnly);
+                        }
+                    } else if (tag == "uses-sdk") {
+                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+                        if (error != "") {
+                            error = "";
+                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
+                            if (name == "Donut") targetSdk = 4;
+                            printf("sdkVersion:'%s'\n", name.string());
+                        } else if (code != -1) {
+                            targetSdk = code;
+                            printf("sdkVersion:'%d'\n", code);
+                        }
+                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
+                        if (error != "") {
+                            error = "";
+                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
+                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
+                            printf("targetSdkVersion:'%s'\n", name.string());
+                        } else if (code != -1) {
+                            if (targetSdk < code) {
+                                targetSdk = code;
+                            }
+                            printf("targetSdkVersion:'%d'\n", code);
+                        }
+                    } else if (tag == "uses-configuration") {
+                        int32_t reqTouchScreen = getIntegerAttribute(tree,
+                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
+                        int32_t reqKeyboardType = getIntegerAttribute(tree,
+                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
+                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
+                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
+                        int32_t reqNavigation = getIntegerAttribute(tree,
+                                REQ_NAVIGATION_ATTR, NULL, 0);
+                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
+                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
+                        printf("uses-configuation:");
+                        if (reqTouchScreen != 0) {
+                            printf(" reqTouchScreen='%d'", reqTouchScreen);
+                        }
+                        if (reqKeyboardType != 0) {
+                            printf(" reqKeyboardType='%d'", reqKeyboardType);
+                        }
+                        if (reqHardKeyboard != 0) {
+                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
+                        }
+                        if (reqNavigation != 0) {
+                            printf(" reqNavigation='%d'", reqNavigation);
+                        }
+                        if (reqFiveWayNav != 0) {
+                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
+                        }
+                        printf("\n");
+                    } else if (tag == "supports-density") {
+                        int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n",
+                                    error.string());
+                            goto bail;
                         }
+                        printf("supports-density:'%d'\n", dens);
+                    } else if (tag == "supports-screens") {
+                        smallScreen = getIntegerAttribute(tree,
+                                SMALL_SCREEN_ATTR, NULL, 1);
+                        normalScreen = getIntegerAttribute(tree,
+                                NORMAL_SCREEN_ATTR, NULL, 1);
+                        largeScreen = getIntegerAttribute(tree,
+                                LARGE_SCREEN_ATTR, NULL, 1);
                     }
                 } else if (depth == 3 && withinApplication) {
                     withinActivity = false;
@@ -592,18 +685,18 @@ int doDump(Bundle* bundle)
                         }
                     }
                 } else if (depth == 5) {
-                        if (withinActivity) {
-                            if (tag == "action") {
-                                //printf("LOG: action tag\n");
-                                String8 action = getAttribute(tree, NAME_ATTR, &error);
-                                if (error != "") {
-                                    fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
-                                    goto bail;
-                                }
-                                if (action == "android.intent.action.MAIN") {
-                                    isMainActivity = true;
-                                    //printf("LOG: isMainActivity==true\n");
-                                }
+                    if (withinActivity) {
+                        if (tag == "action") {
+                            //printf("LOG: action tag\n");
+                            String8 action = getAttribute(tree, NAME_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
+                                goto bail;
+                            }
+                            if (action == "android.intent.action.MAIN") {
+                                isMainActivity = true;
+                                //printf("LOG: isMainActivity==true\n");
+                            }
                         } else if (tag == "category") {
                             String8 category = getAttribute(tree, NAME_ATTR, &error);
                             if (error != "") {
@@ -659,11 +752,31 @@ int doDump(Bundle* bundle)
                            activityIcon.string());
                 }
             }
+            
+            // Determine default values for any unspecified screen sizes,
+            // based on the target SDK of the package.  As of 4 (donut)
+            // the screen size support was introduced, so all default to
+            // enabled.
+            if (smallScreen > 0) {
+                smallScreen = targetSdk >= 4 ? -1 : 0;
+            }
+            if (normalScreen > 0) {
+                normalScreen = -1;
+            }
+            if (largeScreen > 0) {
+                largeScreen = targetSdk >= 4 ? -1 : 0;
+            }
+            printf("supports-screens:");
+            if (smallScreen != 0) printf(" 'small'");
+            if (normalScreen != 0) printf(" 'normal'");
+            if (largeScreen != 0) printf(" 'large'");
+            printf("\n");
+            
             printf("locales:");
             Vector<String8> locales;
             res.getLocales(&locales);
-            const size_t N = locales.size();
-            for (size_t i=0; i<N; i++) {
+            const size_t NL = locales.size();
+            for (size_t i=0; i<NL; i++) {
                 const char* localeStr =  locales[i].string();
                 if (localeStr == NULL || strlen(localeStr) == 0) {
                     localeStr = "--_--";
@@ -671,6 +784,35 @@ int doDump(Bundle* bundle)
                 printf(" '%s'", localeStr);
             }
             printf("\n");
+            
+            Vector<ResTable_config> configs;
+            res.getConfigurations(&configs);
+            SortedVector<int> densities;
+            const size_t NC = configs.size();
+            for (size_t i=0; i<NC; i++) {
+                int dens = configs[i].density;
+                if (dens == 0) dens = 160;
+                densities.add(dens);
+            }
+            
+            printf("densities:");
+            const size_t ND = densities.size();
+            for (size_t i=0; i<ND; i++) {
+                printf(" '%d'", densities[i]);
+            }
+            printf("\n");
+            
+            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
+            if (dir != NULL) {
+                if (dir->getFileCount() > 0) {
+                    printf("native-code:");
+                    for (size_t i=0; i<dir->getFileCount(); i++) {
+                        printf(" '%s'", dir->getFileName(i).string());
+                    }
+                    printf("\n");
+                }
+                delete dir;
+            }
         } else if (strcmp("configurations", option) == 0) {
             Vector<ResTable_config> configs;
             res.getConfigurations(&configs);
index 71b1a3c86317f6366f45e2dc8a071c029cbbbdfd..12a04454cb54fb7e52d2c165b69756a49d08570f 100644 (file)
--- a/Main.cpp
+++ b/Main.cpp
@@ -45,7 +45,7 @@ void usage(void)
         " %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
         "   List contents of Zip-compatible archive.\n\n", gProgName);
     fprintf(stderr,
-        " %s d[ump] WHAT file.{apk} [asset [asset ...]]\n"
+        " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
         "   badging          Print the label and icon for the app declared in APK.\n"
         "   permissions      Print the permissions from the APK.\n"
         "   resources        Print the resource table from the APK.\n"
@@ -54,9 +54,10 @@ void usage(void)
         "   xmlstrings       Print the strings of the given compiled xml assets.\n\n", gProgName);
     fprintf(stderr,
         " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
-        "        [-0 extension [-0 extension ...]] \\\n"
-        "        [-g tolerance] \\\n"
-        "        [-j jarfile] \\\n"
+        "        [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
+        "        [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
+        "        [--max-sdk-version VAL] [--app-version VAL] \\\n"
+        "        [--app-version-name TEXT] \\\n"
         "        [-I base-package [-I base-package ...]] \\\n"
         "        [-A asset-source-dir] [-P public-definitions-file] \\\n"
         "        [-S resource-sources [-S resource-sources ...]] "
@@ -115,7 +116,19 @@ void usage(void)
         "       and the first match found (left to right) will take precedence."
         "   -0  specifies an additional extension for which such files will not\n"
         "       be stored compressed in the .apk.  An empty string means to not\n"
-        "       compress any files at all.\n");
+        "       compress any files at all.\n"
+        "   --min-sdk-version\n"
+        "       inserts android:minSdkVersion in to manifest.\n"
+        "   --target-sdk-version\n"
+        "       inserts android:targetSdkVersion in to manifest.\n"
+        "   --max-sdk-version\n"
+        "       inserts android:maxSdkVersion in to manifest.\n"
+        "   --values\n"
+        "       when used with \"dump resources\" also includes resource values.\n"
+        "   --version-code\n"
+        "       inserts android:versionCode in to manifest.\n"
+        "   --version-name\n"
+        "       inserts android:versionName in to manifest.\n");
 }
 
 /*
@@ -339,6 +352,61 @@ int main(int argc, char* const argv[])
                     bundle.setCompressionMethod(ZipEntry::kCompressStored);
                 }
                 break;
+            case '-':
+                if (strcmp(cp, "-min-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setMinSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-target-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setTargetSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-max-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setMaxSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-version-code") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setVersionCode(argv[0]);
+                } else if (strcmp(cp, "-version-name") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setVersionName(argv[0]);
+                } else if (strcmp(cp, "-values") == 0) {
+                    bundle.setValues(true);
+                } else {
+                    fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
+                    wantUsage = true;
+                    goto bail;
+                }
+                cp += strlen(cp) - 1;
+                break;
             default:
                 fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp);
                 wantUsage = true;
index b2bd9ffc35eca9628acec0b2919766908a735e88..027e3ab3883d6601b43f94158085125981601343 100644 (file)
@@ -433,7 +433,7 @@ static void checkForIds(const String8& path, ResXMLParser& parser)
     }
 }
 
-static void applyFileOverlay(const sp<AaptAssets>& assets, 
+static bool applyFileOverlay(const sp<AaptAssets>& assets,
                              const sp<ResourceTypeSet>& baseSet,
                              const char *resType)
 {
@@ -441,7 +441,7 @@ static void applyFileOverlay(const sp<AaptAssets>& assets,
     // Also add any found only in the overlay.
     sp<AaptAssets> overlay = assets->getOverlay();
     String8 resTypeString(resType);
-    
+
     // work through the linked list of overlays
     while (overlay.get()) {
         KeyedVector<String8, sp<ResourceTypeSet> >* overlayRes = overlay->getResources();
@@ -456,7 +456,7 @@ static void applyFileOverlay(const sp<AaptAssets>& assets,
             size_t overlayCount = overlaySet->size();
             for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) {
                 size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex));
-                if (baseIndex != UNKNOWN_ERROR) {
+                if (baseIndex < UNKNOWN_ERROR) {
                     // look for same flavor.  For a given file (strings.xml, for example)
                     // there may be a locale specific or other flavors - we want to match
                     // the same flavor.
@@ -482,9 +482,10 @@ static void applyFileOverlay(const sp<AaptAssets>& assets,
                     }
                 } else {
                     // this group doesn't exist (a file that's only in the overlay)
-                    // add it
-                    baseSet->add(overlaySet->keyAt(overlayIndex),
-                                 overlaySet->valueAt(overlayIndex));
+                    fprintf(stderr, "aapt: error: "
+                            "*** Resource file '%s' exists only in an overlay\n",
+                            overlaySet->keyAt(overlayIndex).string());
+                    return false;
                 }
             }
             // this overlay didn't have resources for this type
@@ -492,7 +493,59 @@ static void applyFileOverlay(const sp<AaptAssets>& assets,
         // try next overlay
         overlay = overlay->getOverlay();
     }
-    return;
+    return true;
+}
+
+void addTagAttribute(const sp<XMLNode>& node, const char* ns8,
+        const char* attr8, const char* value)
+{
+    if (value == NULL) {
+        return;
+    }
+    
+    const String16 ns(ns8);
+    const String16 attr(attr8);
+    
+    if (node->getAttribute(ns, attr) != NULL) {
+        fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n",
+                String8(attr).string(), String8(ns).string());
+        return;
+    }
+    
+    node->addAttribute(ns, attr, String16(value));
+}
+
+status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
+{
+    root = root->searchElement(String16(), String16("manifest"));
+    if (root == NULL) {
+        fprintf(stderr, "No <manifest> tag.\n");
+        return UNKNOWN_ERROR;
+    }
+    
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
+            bundle->getVersionCode());
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
+            bundle->getVersionName());
+    
+    if (bundle->getMinSdkVersion() != NULL
+            || bundle->getTargetSdkVersion() != NULL
+            || bundle->getMaxSdkVersion() != NULL) {
+        sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
+        if (vers == NULL) {
+            vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
+            root->insertChildAt(vers, 0);
+        }
+        
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion",
+                bundle->getMinSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion",
+                bundle->getTargetSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion",
+                bundle->getMaxSdkVersion());
+    }
+    
+    return NO_ERROR;
 }
 
 #define ASSIGN_IT(n) \
@@ -566,13 +619,15 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
         current = current->getOverlay();
     }
     // apply the overlay files to the base set
-    applyFileOverlay(assets, drawables, "drawable");
-    applyFileOverlay(assets, layouts, "layout");
-    applyFileOverlay(assets, anims, "anim");
-    applyFileOverlay(assets, xmls, "xml");
-    applyFileOverlay(assets, raws, "raw");
-    applyFileOverlay(assets, colors, "color");
-    applyFileOverlay(assets, menus, "menu");
+    if (!applyFileOverlay(assets, drawables, "drawable") ||
+            !applyFileOverlay(assets, layouts, "layout") ||
+            !applyFileOverlay(assets, anims, "anim") ||
+            !applyFileOverlay(assets, xmls, "xml") ||
+            !applyFileOverlay(assets, raws, "raw") ||
+            !applyFileOverlay(assets, colors, "color") ||
+            !applyFileOverlay(assets, menus, "menu")) {
+        return UNKNOWN_ERROR;
+    }
 
     bool hasErrors = false;
 
@@ -1013,7 +1068,15 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
 
     // Generate final compiled manifest file.
     manifestFile->clearData();
-    err = compileXmlFile(assets, manifestFile, &table);
+    sp<XMLNode> manifestTree = XMLNode::parse(manifestFile);
+    if (manifestTree == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    err = massageManifest(bundle, manifestTree);
+    if (err < NO_ERROR) {
+        return err;
+    }
+    err = compileXmlFile(assets, manifestTree, manifestFile, &table);
     if (err < NO_ERROR) {
         return err;
     }
index ef11a83c83875f4236bc16bbbd9c4d78ee53c52f..b004664af5ce740d3d973ddbdecbb904bf7e2805 100644 (file)
@@ -23,6 +23,16 @@ status_t compileXmlFile(const sp<AaptAssets>& assets,
     if (root == NULL) {
         return UNKNOWN_ERROR;
     }
+    
+    return compileXmlFile(assets, root, target, table, options);
+}
+
+status_t compileXmlFile(const sp<AaptAssets>& assets,
+                        const sp<XMLNode>& root,
+                        const sp<AaptFile>& target,
+                        ResourceTable* table,
+                        int options)
+{
     if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
         root->removeWhitespace(true, NULL);
     } else  if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
@@ -651,6 +661,7 @@ status_t compileResourceFile(Bundle* bundle,
     const String16 string_array16("string-array");
     const String16 integer_array16("integer-array");
     const String16 public16("public");
+    const String16 public_padding16("public-padding");
     const String16 private_symbols16("private-symbols");
     const String16 skip16("skip");
     const String16 eat_comment16("eat-comment");
@@ -685,7 +696,7 @@ status_t compileResourceFile(Bundle* bundle,
 
     bool hasErrors = false;
     
-    uint32_t nextPublicId = 0;
+    DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
 
     ResXMLTree::event_code_t code;
     do {
@@ -718,6 +729,7 @@ status_t compileResourceFile(Bundle* bundle,
             String16 curType;
             int32_t curFormat = ResTable_map::TYPE_ANY;
             bool curIsBag = false;
+            bool curIsBagReplaceOnOverwrite = false;
             bool curIsStyled = false;
             bool curIsPseudolocalizable = false;
             bool localHasErrors = false;
@@ -774,15 +786,15 @@ status_t compileResourceFile(Bundle* bundle,
                         hasErrors = localHasErrors = true;
                     } else {
                         ident = identValue.data;
-                        nextPublicId = ident+1;
+                        nextPublicId.replaceValueFor(type, ident+1);
                     }
-                } else if (nextPublicId == 0) {
+                } else if (nextPublicId.indexOfKey(type) < 0) {
                     srcPos.error("No 'id' attribute supplied <public>,"
                             " and no previous id defined in this file.\n");
                     hasErrors = localHasErrors = true;
                 } else if (!localHasErrors) {
-                    ident = nextPublicId;
-                    nextPublicId++;
+                    ident = nextPublicId.valueFor(type);
+                    nextPublicId.replaceValueFor(type, ident+1);
                 }
 
                 if (!localHasErrors) {
@@ -816,6 +828,116 @@ status_t compileResourceFile(Bundle* bundle,
                 }
                 continue;
 
+            } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
+            
+                String16 type;
+                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
+                if (typeIdx < 0) {
+                    srcPos.error("A 'type' attribute is required for <public-padding>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                type = String16(block.getAttributeStringValue(typeIdx, &len));
+
+                String16 name;
+                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
+                if (nameIdx < 0) {
+                    srcPos.error("A 'name' attribute is required for <public-padding>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                name = String16(block.getAttributeStringValue(nameIdx, &len));
+
+                uint32_t start = 0;
+                ssize_t startIdx = block.indexOfAttribute(NULL, "start");
+                if (startIdx >= 0) {
+                    const char16_t* startStr = block.getAttributeStringValue(startIdx, &len);
+                    Res_value startValue;
+                    if (!ResTable::stringToInt(startStr, len, &startValue)) {
+                        srcPos.error("Given 'start' attribute is not an integer: %s\n",
+                                String8(block.getAttributeStringValue(startIdx, &len)).string());
+                        hasErrors = localHasErrors = true;
+                    } else {
+                        start = startValue.data;
+                    }
+                } else if (nextPublicId.indexOfKey(type) < 0) {
+                    srcPos.error("No 'start' attribute supplied <public-padding>,"
+                            " and no previous id defined in this file.\n");
+                    hasErrors = localHasErrors = true;
+                } else if (!localHasErrors) {
+                    start = nextPublicId.valueFor(type);
+                }
+
+                uint32_t end = 0;
+                ssize_t endIdx = block.indexOfAttribute(NULL, "end");
+                if (endIdx >= 0) {
+                    const char16_t* endStr = block.getAttributeStringValue(endIdx, &len);
+                    Res_value endValue;
+                    if (!ResTable::stringToInt(endStr, len, &endValue)) {
+                        srcPos.error("Given 'end' attribute is not an integer: %s\n",
+                                String8(block.getAttributeStringValue(endIdx, &len)).string());
+                        hasErrors = localHasErrors = true;
+                    } else {
+                        end = endValue.data;
+                    }
+                } else {
+                    srcPos.error("No 'end' attribute supplied <public-padding>\n");
+                    hasErrors = localHasErrors = true;
+                }
+
+                if (end >= start) {
+                    nextPublicId.replaceValueFor(type, end+1);
+                } else {
+                    srcPos.error("Padding start '%ul' is after end '%ul'\n",
+                            start, end);
+                    hasErrors = localHasErrors = true;
+                }
+                
+                String16 comment(
+                    block.getComment(&len) ? block.getComment(&len) : nulStr);
+                for (uint32_t curIdent=start; curIdent<=end; curIdent++) {
+                    if (localHasErrors) {
+                        break;
+                    }
+                    String16 curName(name);
+                    char buf[64];
+                    sprintf(buf, "%d", (int)(end-curIdent+1));
+                    curName.append(String16(buf));
+                    
+                    err = outTable->addEntry(srcPos, myPackage, type, curName,
+                                             String16("padding"), NULL, &curParams, false,
+                                             ResTable_map::TYPE_STRING, overwrite);
+                    if (err < NO_ERROR) {
+                        hasErrors = localHasErrors = true;
+                        break;
+                    }
+                    err = outTable->addPublic(srcPos, myPackage, type,
+                            curName, curIdent);
+                    if (err < NO_ERROR) {
+                        hasErrors = localHasErrors = true;
+                        break;
+                    }
+                    sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
+                    if (symbols != NULL) {
+                        symbols = symbols->addNestedSymbol(String8(type), srcPos);
+                    }
+                    if (symbols != NULL) {
+                        symbols->makeSymbolPublic(String8(curName), srcPos);
+                        symbols->appendComment(String8(curName), comment, srcPos);
+                    } else {
+                        srcPos.error("Unable to create symbols!\n");
+                        hasErrors = localHasErrors = true;
+                    }
+                }
+
+                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+                    if (code == ResXMLTree::END_TAG) {
+                        if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+                            break;
+                        }
+                    }
+                }
+                continue;
+
             } else if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
                 String16 pkg;
                 ssize_t pkgIdx = block.indexOfAttribute(NULL, "package");
@@ -1050,6 +1172,7 @@ status_t compileResourceFile(Bundle* bundle,
                 curTag = &array16;
                 curType = array16;
                 curIsBag = true;
+                curIsBagReplaceOnOverwrite = true;
                 ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
                 if (formatIdx >= 0) {
                     String16 formatStr = String16(block.getAttributeStringValue(
@@ -1068,12 +1191,14 @@ status_t compileResourceFile(Bundle* bundle,
                 curType = array16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
                 curIsBag = true;
+                curIsBagReplaceOnOverwrite = true;
                 curIsPseudolocalizable = true;
             } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) {
                 curTag = &integer_array16;
                 curType = array16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
                 curIsBag = true;
+                curIsBagReplaceOnOverwrite = true;
             } else {
                 SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                         "Found tag %s where item is expected\n",
@@ -1108,9 +1233,10 @@ status_t compileResourceFile(Bundle* bundle,
                 }
 
                 if (!localHasErrors) {
-                    err = outTable->startBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
-                                             myPackage, curType, ident, parentIdent, &curParams, 
-                                             overwrite);
+                    err = outTable->startBag(SourcePos(in->getPrintableSource(),
+                            block.getLineNumber()), myPackage, curType, ident,
+                            parentIdent, &curParams,
+                            overwrite, curIsBagReplaceOnOverwrite);
                     if (err != NO_ERROR) {
                         hasErrors = localHasErrors = true;
                     }
@@ -1307,7 +1433,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets
             } else if (id != 0) {
                 if (id == 127) {
                     if (mHaveAppPackage) {
-                        fprintf(stderr, "Included resource have two application packages!\n");
+                        fprintf(stderr, "Included resources have two application packages!\n");
                         return UNKNOWN_ERROR;
                     }
                     mHaveAppPackage = true;
@@ -1390,8 +1516,9 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos,
                String8(value).string());
     }
 #endif
-    
-    sp<Entry> e = getEntry(package, type, name, sourcePos, params, doSetIndex);
+
+    sp<Entry> e = getEntry(package, type, name, sourcePos, overwrite,
+                           params, doSetIndex);
     if (e == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -1408,6 +1535,7 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
                                  const String16& name,
                                  const String16& bagParent,
                                  const ResTable_config* params,
+                                 bool overlay,
                                  bool replace, bool isId)
 {
     status_t result = NO_ERROR;
@@ -1428,8 +1556,12 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
                sourcePos.file.striing(), sourcePos.line, String8(type).string());
     }
 #endif
-    
-    sp<Entry> e = getEntry(package, type, name, sourcePos, params);
+    if (overlay && !hasBagOrEntry(package, type, name)) {
+        sourcePos.error("Can't add new bags in an overlay.  See '%s'\n",
+                        String8(name).string());
+        return UNKNOWN_ERROR;
+    }
+    sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
     if (e == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -1450,7 +1582,7 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
         return result;
     }
 
-    if (replace) { 
+    if (overlay && replace) { 
         return e->emptyBag(sourcePos);
     }
     return result;
@@ -1483,8 +1615,7 @@ status_t ResourceTable::addBag(const SourcePos& sourcePos,
                sourcePos.file.striing(), sourcePos.line, String8(type).string());
     }
 #endif
-    
-    sp<Entry> e = getEntry(package, type, name, sourcePos, params);
+    sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params);
     if (e == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -2767,7 +2898,7 @@ status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos,
                         mItem.sourcePos.file.string(), mItem.sourcePos.line);
         return UNKNOWN_ERROR;
     }
-    
+
     mType = TYPE_ITEM;
     mItem = item;
     mItemFormat = format;
@@ -3087,11 +3218,17 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
 sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
                                                        const SourcePos& sourcePos,
                                                        const ResTable_config* config,
-                                                       bool doSetIndex)
+                                                       bool doSetIndex,
+                                                       bool overlay)
 {
     int pos = -1;
     sp<ConfigList> c = mConfigs.valueFor(entry);
     if (c == NULL) {
+        if (overlay == true) {
+            sourcePos.error("Resource %s appears in overlay but not"
+                            " in the base package.\n", String8(entry).string());
+            return NULL;
+        }
         c = new ConfigList(entry, sourcePos);
         mConfigs.add(entry, c);
         pos = (int)mOrderedConfigs.size();
@@ -3390,6 +3527,7 @@ sp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package,
                                                  const String16& type,
                                                  const String16& name,
                                                  const SourcePos& sourcePos,
+                                                 bool overlay,
                                                  const ResTable_config* config,
                                                  bool doSetIndex)
 {
@@ -3397,7 +3535,7 @@ sp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package,
     if (t == NULL) {
         return NULL;
     }
-    return t->getEntry(name, sourcePos, config, doSetIndex);
+    return t->getEntry(name, sourcePos, config, doSetIndex, overlay);
 }
 
 sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
index 74ba326c2bf3c6969f29c705c6407f6ca93860cc..ec4331aa35579b600151fbfc0acce0d6c86e667c 100644 (file)
@@ -15,6 +15,7 @@
 
 using namespace std;
 
+class XMLNode;
 class ResourceTable;
 
 enum {
@@ -34,6 +35,12 @@ status_t compileXmlFile(const sp<AaptAssets>& assets,
                         ResourceTable* table,
                         int options = XML_COMPILE_STANDARD_RESOURCE);
 
+status_t compileXmlFile(const sp<AaptAssets>& assets,
+                        const sp<XMLNode>& xmlTree,
+                        const sp<AaptFile>& target,
+                        ResourceTable* table,
+                        int options = XML_COMPILE_STANDARD_RESOURCE);
+
 status_t compileResourceFile(Bundle* bundle,
                              const sp<AaptAssets>& assets,
                              const sp<AaptFile>& in,
@@ -89,6 +96,7 @@ public:
                     const String16& name,
                     const String16& bagParent,
                     const ResTable_config* params = NULL,
+                    bool overlay = false,
                     bool replace = false,
                     bool isId = false);
     
@@ -410,7 +418,8 @@ public:
         sp<Entry> getEntry(const String16& entry,
                            const SourcePos& pos,
                            const ResTable_config* config = NULL,
-                           bool doSetIndex = false);
+                           bool doSetIndex = false,
+                           bool overlay = false);
 
         const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
 
@@ -494,6 +503,7 @@ private:
                        const String16& type,
                        const String16& name,
                        const SourcePos& pos,
+                       bool overlay,
                        const ResTable_config* config = NULL,
                        bool doSetIndex = false);
     sp<const Entry> getEntry(uint32_t resID,
index d4765672274e90574a83ed554bf0039cb87b2a00..2a85bc7e8b6d55be36a6512a7f5e1de7620bff23 100644 (file)
@@ -524,12 +524,30 @@ const Vector<sp<XMLNode> >& XMLNode::getChildren() const
     return mChildren;
 }
 
+const String8& XMLNode::getFilename() const
+{
+    return mFilename;
+}
+    
 const Vector<XMLNode::attribute_entry>&
     XMLNode::getAttributes() const
 {
     return mAttributes;
 }
 
+const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns,
+        const String16& name) const
+{
+    for (size_t i=0; i<mAttributes.size(); i++) {
+        const attribute_entry& ae(mAttributes.itemAt(i));
+        if (ae.ns == ns && ae.name == name) {
+            return &ae;
+        }
+    }
+    
+    return NULL;
+}
+
 const String16& XMLNode::getCData() const
 {
     return mChars;
@@ -550,6 +568,38 @@ int32_t XMLNode::getEndLineNumber() const
     return mEndLineNumber;
 }
 
+sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName)
+{
+    if (getType() == XMLNode::TYPE_ELEMENT
+            && mNamespaceUri == tagNamespace
+            && mElementName == tagName) {
+        return this;
+    }
+    
+    for (size_t i=0; i<mChildren.size(); i++) {
+        sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName);
+        if (found != NULL) {
+            return found;
+        }
+    }
+    
+    return NULL;
+}
+
+sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName)
+{
+    for (size_t i=0; i<mChildren.size(); i++) {
+        sp<XMLNode> child = mChildren.itemAt(i);
+        if (child->getType() == XMLNode::TYPE_ELEMENT
+                && child->mNamespaceUri == tagNamespace
+                && child->mElementName == tagName) {
+            return child;
+        }
+    }
+    
+    return NULL;
+}
+
 status_t XMLNode::addChild(const sp<XMLNode>& child)
 {
     if (getType() == TYPE_CDATA) {
@@ -561,6 +611,17 @@ status_t XMLNode::addChild(const sp<XMLNode>& child)
     return NO_ERROR;
 }
 
+status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index)
+{
+    if (getType() == TYPE_CDATA) {
+        SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node.");
+        return UNKNOWN_ERROR;
+    }
+    //printf("Adding child %p to parent %p\n", child.get(), this);
+    mChildren.insertAt(child, index);
+    return NO_ERROR;
+}
+
 status_t XMLNode::addAttribute(const String16& ns, const String16& name,
                                const String16& value)
 {
index 86548a22c85805f8819a1b9e1980a6fd8b1d22b9..a9bea4312eccd0bd2e30bb0c3c562fb743bb8cb6 100644 (file)
--- a/XMLNode.h
+++ b/XMLNode.h
@@ -68,6 +68,8 @@ public:
     const String16& getElementName() const;
     const Vector<sp<XMLNode> >& getChildren() const;
 
+    const String8& getFilename() const;
+    
     struct attribute_entry {
         attribute_entry() : index(~(uint32_t)0), nameResId(0)
         {
@@ -91,6 +93,8 @@ public:
 
     const Vector<attribute_entry>& getAttributes() const;
 
+    const attribute_entry* getAttribute(const String16& ns, const String16& name) const;
+    
     const String16& getCData() const;
 
     const String16& getComment() const;
@@ -98,8 +102,14 @@ public:
     int32_t getStartLineNumber() const;
     int32_t getEndLineNumber() const;
 
+    sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName);
+    
+    sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName);
+    
     status_t addChild(const sp<XMLNode>& child);
 
+    status_t insertChildAt(const sp<XMLNode>& child, size_t index);
+
     status_t addAttribute(const String16& ns, const String16& name,
                           const String16& value);