X-Git-Url: https://git.saurik.com/android/aapt.git/blobdiff_plain/dfc6828a06b23282f39d4c45e613d33f7e8e646e..18dbbc2491a39719dbd0731a2b6b4861babac4f4:/ResourceTable.cpp diff --git a/ResourceTable.cpp b/ResourceTable.cpp index ef11a83..b3cf7ea 100644 --- a/ResourceTable.cpp +++ b/ResourceTable.cpp @@ -23,6 +23,16 @@ status_t compileXmlFile(const sp& assets, if (root == NULL) { return UNKNOWN_ERROR; } + + return compileXmlFile(assets, root, target, table, options); +} + +status_t compileXmlFile(const sp& assets, + const sp& root, + const sp& target, + ResourceTable* table, + int options) +{ if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) { root->removeWhitespace(true, NULL); } else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) { @@ -470,22 +480,22 @@ static status_t compileAttribute(const sp& 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("

\n\n" + enumOrFlagsComment.append(String16("

\n
\n" "\n" "\n" "\n" - "")); + "")); } - enumOrFlagsComment.append(String16("\n")); + enumOrFlagsComment.append(String16("")); err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()), myPackage, @@ -651,7 +661,9 @@ 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 add_resource16("add-resource"); const String16 skip16("skip"); const String16 eat_comment16("eat-comment"); @@ -685,7 +697,7 @@ status_t compileResourceFile(Bundle* bundle, bool hasErrors = false; - uint32_t nextPublicId = 0; + DefaultKeyedVector nextPublicId(0); ResXMLTree::event_code_t code; do { @@ -718,6 +730,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 +787,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 ," " 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 +829,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 \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 \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 ," + " 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 \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 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"); @@ -838,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 \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 \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()); @@ -1050,6 +1203,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 +1222,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 +1264,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 +1464,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp e = getEntry(package, type, name, sourcePos, params, doSetIndex); + + sp e = getEntry(package, type, name, sourcePos, overwrite, + params, doSetIndex); if (e == NULL) { return UNKNOWN_ERROR; } @@ -1408,6 +1566,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 +1587,24 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos, sourcePos.file.striing(), sourcePos.line, String8(type).string()); } #endif - - sp e = getEntry(package, type, name, sourcePos, params); + if (overlay && !mBundle->getAutoAddOverlay() && !hasBagOrEntry(package, type, name)) { + bool canAdd = false; + sp p = mPackages.valueFor(package); + if (p != NULL) { + sp 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 to add.\n", + String8(name).string()); + return UNKNOWN_ERROR; + } + } + sp e = getEntry(package, type, name, sourcePos, overlay, params); if (e == NULL) { return UNKNOWN_ERROR; } @@ -1450,7 +1625,7 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos, return result; } - if (replace) { + if (overlay && replace) { return e->emptyBag(sourcePos); } return result; @@ -1483,8 +1658,7 @@ status_t ResourceTable::addBag(const SourcePos& sourcePos, sourcePos.file.striing(), sourcePos.line, String8(type).string()); } #endif - - sp e = getEntry(package, type, name, sourcePos, params); + sp e = getEntry(package, type, name, sourcePos, replace, params); if (e == NULL) { return UNKNOWN_ERROR; } @@ -1593,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 t = getType(package, type, pos); + if (t != NULL) { + t->canAddEntry(name); + } +} + size_t ResourceTable::size() const { return mPackages.size(); } @@ -2181,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; } } } @@ -2767,7 +2949,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; @@ -3084,14 +3266,27 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos, return NO_ERROR; } +void ResourceTable::Type::canAddEntry(const String16& name) +{ + mCanAddEntries.add(name); +} + sp ResourceTable::Type::getEntry(const String16& entry, const SourcePos& sourcePos, const ResTable_config* config, - bool doSetIndex) + bool doSetIndex, + bool overlay, + bool autoAddOverlay) { int pos = -1; sp c = mConfigs.valueFor(entry); if (c == NULL) { + if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) { + sourcePos.error("Resource at %s appears in overlay but not" + " in the base package; use to add.\n", + String8(entry).string()); + return NULL; + } c = new ConfigList(entry, sourcePos); mConfigs.add(entry, c); pos = (int)mOrderedConfigs.size(); @@ -3390,6 +3585,7 @@ sp ResourceTable::getEntry(const String16& package, const String16& type, const String16& name, const SourcePos& sourcePos, + bool overlay, const ResTable_config* config, bool doSetIndex) { @@ -3397,7 +3593,7 @@ sp 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, mBundle->getAutoAddOverlay()); } sp ResourceTable::getEntry(uint32_t resID, @@ -3416,26 +3612,26 @@ sp ResourceTable::getEntry(uint32_t resID, } if (p == NULL) { - fprintf(stderr, "WARNING: Package not found for resource #%08x\n", resID); + fprintf(stderr, "warning: Package not found for resource #%08x\n", resID); return NULL; } int tid = Res_GETTYPE(resID); if (tid < 0 || tid >= (int)p->getOrderedTypes().size()) { - fprintf(stderr, "WARNING: Type not found for resource #%08x\n", resID); + fprintf(stderr, "warning: Type not found for resource #%08x\n", resID); return NULL; } sp t = p->getOrderedTypes()[tid]; int eid = Res_GETENTRY(resID); if (eid < 0 || eid >= (int)t->getOrderedConfigs().size()) { - fprintf(stderr, "WARNING: Entry not found for resource #%08x\n", resID); + fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID); return NULL; } sp c = t->getOrderedConfigs()[eid]; if (c == NULL) { - fprintf(stderr, "WARNING: Entry not found for resource #%08x\n", resID); + fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID); return NULL; } @@ -3443,7 +3639,7 @@ sp ResourceTable::getEntry(uint32_t resID, if (config) cdesc = *config; sp e = c->getEntries().valueFor(cdesc); if (c == NULL) { - fprintf(stderr, "WARNING: Entry configuration not found for resource #%08x\n", resID); + fprintf(stderr, "warning: Entry configuration not found for resource #%08x\n", resID); return NULL; } @@ -3461,7 +3657,7 @@ const ResourceTable::Item* ResourceTable::getItem(uint32_t resID, uint32_t attrI for (size_t i=0; igetBag().valueAt(i); if (it.bagKeyId == 0) { - fprintf(stderr, "WARNING: ID not yet assigned to '%s' in bag '%s'\n", + fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n", String8(e->getName()).string(), String8(e->getBag().keyAt(i)).string()); } @@ -3489,7 +3685,7 @@ bool ResourceTable::getItemValue( break; } } - fprintf(stderr, "WARNING: Circular reference detected in key '%s' of bag '%s'\n", + fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n", String8(e->getName()).string(), String8(e->getBag().keyAt(i)).string()); return false;
ConstantValueDescription
ConstantValueDescription
")); + enumOrFlagsComment.append(String16("\n
")); enumOrFlagsComment.append(itemIdent); - enumOrFlagsComment.append(String16("")); + enumOrFlagsComment.append(String16("")); enumOrFlagsComment.append(value); - enumOrFlagsComment.append(String16("")); + enumOrFlagsComment.append(String16("")); if (block.getComment(&len)) { enumOrFlagsComment.append(String16(block.getComment(&len))); } - enumOrFlagsComment.append(String16("