]> git.saurik.com Git - android/aapt.git/blobdiff - ResourceTable.cpp
merge from open-source master
[android/aapt.git] / ResourceTable.cpp
index 8dbc12ec6069a45d3a3b0f3ccc6a2683cd73ec3b..19b9b01070a4a8e828d31d03d8b9b64a84b4bad0 100644 (file)
@@ -480,22 +480,22 @@ static status_t compileAttribute(const sp<AaptFile>& in,
                     enumOrFlagsComment.append((attr.type&ResTable_map::TYPE_ENUM)
                                        ? String16(" be one of the following constant values.")
                                        : String16(" be one or more (separated by '|') of the following constant values."));
-                    enumOrFlagsComment.append(String16("</p>\n<table border=\"2\" width=\"85%\" align=\"center\" frame=\"hsides\" rules=\"all\" cellpadding=\"5\">\n"
+                    enumOrFlagsComment.append(String16("</p>\n<table>\n"
                                                 "<colgroup align=\"left\" />\n"
                                                 "<colgroup align=\"left\" />\n"
                                                 "<colgroup align=\"left\" />\n"
-                                                "<tr><th>Constant<th>Value<th>Description</tr>"));
+                                                "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>"));
                 }
                 
-                enumOrFlagsComment.append(String16("\n<tr><th><code>"));
+                enumOrFlagsComment.append(String16("\n<tr><td><code>"));
                 enumOrFlagsComment.append(itemIdent);
-                enumOrFlagsComment.append(String16("</code><td>"));
+                enumOrFlagsComment.append(String16("</code></td><td>"));
                 enumOrFlagsComment.append(value);
-                enumOrFlagsComment.append(String16("<td>"));
+                enumOrFlagsComment.append(String16("</td><td>"));
                 if (block.getComment(&len)) {
                     enumOrFlagsComment.append(String16(block.getComment(&len)));
                 }
-                enumOrFlagsComment.append(String16("</tr>"));
+                enumOrFlagsComment.append(String16("</td></tr>"));
                 
                 err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
                                        myPackage,
@@ -663,6 +663,7 @@ status_t compileResourceFile(Bundle* bundle,
     const String16 public16("public");
     const String16 public_padding16("public-padding");
     const String16 private_symbols16("private-symbols");
+    const String16 add_resource16("add-resource");
     const String16 skip16("skip");
     const String16 eat_comment16("eat-comment");
 
@@ -960,6 +961,36 @@ status_t compileResourceFile(Bundle* bundle,
                 }
                 continue;
 
+            } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
+            
+                String16 typeName;
+                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
+                if (typeIdx < 0) {
+                    srcPos.error("A 'type' attribute is required for <add-resource>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                typeName = 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 <add-resource>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                name = String16(block.getAttributeStringValue(nameIdx, &len));
+
+                outTable->canAddEntry(srcPos, myPackage, typeName, name);
+
+                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+                    if (code == ResXMLTree::END_TAG) {
+                        if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+                            break;
+                        }
+                    }
+                }
+                continue;
+                
             } else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
                                 
@@ -1557,9 +1588,21 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
     }
 #endif
     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;
+        bool canAdd = false;
+        sp<Package> p = mPackages.valueFor(package);
+        if (p != NULL) {
+            sp<Type> t = p->getTypes().valueFor(type);
+            if (t != NULL) {
+                if (t->getCanAddEntries().indexOf(name) >= 0) {
+                    canAdd = true;
+                }
+            }
+        }
+        if (!canAdd) {
+            sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
+                            String8(name).string());
+            return UNKNOWN_ERROR;
+        }
     }
     sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
     if (e == NULL) {
@@ -1724,6 +1767,15 @@ bool ResourceTable::appendTypeComment(const String16& package,
     return false;
 }
 
+void ResourceTable::canAddEntry(const SourcePos& pos,
+        const String16& package, const String16& type, const String16& name)
+{
+    sp<Type> t = getType(package, type, pos);
+    if (t != NULL) {
+        t->canAddEntry(name);
+    }
+}
+
 size_t ResourceTable::size() const {
     return mPackages.size();
 }
@@ -2312,13 +2364,12 @@ ResourceTable::validateLocalizations(void)
                         String8 region(config.string(), 2);
                         if (configSet.find(region) == configSet.end()) {
                             if (configSet.count(defaultLocale) == 0) {
-                                fprintf(stdout, "aapt: error: "
+                                fprintf(stdout, "aapt: warning: "
                                         "*** string '%s' has no default or required localization "
                                         "for '%s' in %s\n",
                                         String8(nameIter->first).string(),
                                         config.string(),
                                         mBundle->getResourceSourceDirs()[0]);
-                                err = UNKNOWN_ERROR;
                             }
                         }
                     }
@@ -3215,6 +3266,11 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
     return NO_ERROR;
 }
 
+void ResourceTable::Type::canAddEntry(const String16& name)
+{
+    mCanAddEntries.add(name);
+}
+
 sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
                                                        const SourcePos& sourcePos,
                                                        const ResTable_config* config,
@@ -3224,9 +3280,10 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
     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());
+        if (overlay == true && mCanAddEntries.indexOf(entry) < 0) {
+            sourcePos.error("Resource at %s appears in overlay but not"
+                            " in the base package; use <add-resource> to add.\n",
+                            String8(entry).string());
             return NULL;
         }
         c = new ConfigList(entry, sourcePos);