* commit 'ea4e07518cd1844b1654175ef27cf9501e0dd7eb': AAPT emits error for res with no 'default' product
This commit is contained in:
@@ -636,6 +636,30 @@ bool isInProductList(const String16& needle, const String16& haystack) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A simple container that holds a resource type and name. It is ordered first by type then
|
||||||
|
* by name.
|
||||||
|
*/
|
||||||
|
struct type_ident_pair_t {
|
||||||
|
String16 type;
|
||||||
|
String16 ident;
|
||||||
|
|
||||||
|
type_ident_pair_t() { };
|
||||||
|
type_ident_pair_t(const String16& t, const String16& i) : type(t), ident(i) { }
|
||||||
|
type_ident_pair_t(const type_ident_pair_t& o) : type(o.type), ident(o.ident) { }
|
||||||
|
inline bool operator < (const type_ident_pair_t& o) const {
|
||||||
|
int cmp = compare_type(type, o.type);
|
||||||
|
if (cmp < 0) {
|
||||||
|
return true;
|
||||||
|
} else if (cmp > 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return strictly_order_type(ident, o.ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
status_t parseAndAddEntry(Bundle* bundle,
|
status_t parseAndAddEntry(Bundle* bundle,
|
||||||
const sp<AaptFile>& in,
|
const sp<AaptFile>& in,
|
||||||
ResXMLTree* block,
|
ResXMLTree* block,
|
||||||
@@ -650,6 +674,7 @@ status_t parseAndAddEntry(Bundle* bundle,
|
|||||||
const String16& product,
|
const String16& product,
|
||||||
bool pseudolocalize,
|
bool pseudolocalize,
|
||||||
const bool overwrite,
|
const bool overwrite,
|
||||||
|
KeyedVector<type_ident_pair_t, bool>* skippedResourceNames,
|
||||||
ResourceTable* outTable)
|
ResourceTable* outTable)
|
||||||
{
|
{
|
||||||
status_t err;
|
status_t err;
|
||||||
@@ -684,6 +709,13 @@ status_t parseAndAddEntry(Bundle* bundle,
|
|||||||
|
|
||||||
if (bundleProduct[0] == '\0') {
|
if (bundleProduct[0] == '\0') {
|
||||||
if (strcmp16(String16("default").string(), product.string()) != 0) {
|
if (strcmp16(String16("default").string(), product.string()) != 0) {
|
||||||
|
/*
|
||||||
|
* This string has a product other than 'default'. Do not add it,
|
||||||
|
* but record it so that if we do not see the same string with
|
||||||
|
* product 'default' or no product, then report an error.
|
||||||
|
*/
|
||||||
|
skippedResourceNames->replaceValueFor(
|
||||||
|
type_ident_pair_t(curType, ident), true);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -797,6 +829,11 @@ status_t compileResourceFile(Bundle* bundle,
|
|||||||
|
|
||||||
DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
|
DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
|
||||||
|
|
||||||
|
// Stores the resource names that were skipped. Typically this happens when
|
||||||
|
// AAPT is invoked without a product specified and a resource has no
|
||||||
|
// 'default' product attribute.
|
||||||
|
KeyedVector<type_ident_pair_t, bool> skippedResourceNames;
|
||||||
|
|
||||||
ResXMLTree::event_code_t code;
|
ResXMLTree::event_code_t code;
|
||||||
do {
|
do {
|
||||||
code = block.next();
|
code = block.next();
|
||||||
@@ -1544,7 +1581,7 @@ status_t compileResourceFile(Bundle* bundle,
|
|||||||
|
|
||||||
err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
|
err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
|
||||||
*curTag, curIsStyled, curFormat, curIsFormatted,
|
*curTag, curIsStyled, curFormat, curIsFormatted,
|
||||||
product, false, overwrite, outTable);
|
product, false, overwrite, &skippedResourceNames, outTable);
|
||||||
|
|
||||||
if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
|
if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
|
||||||
hasErrors = localHasErrors = true;
|
hasErrors = localHasErrors = true;
|
||||||
@@ -1557,7 +1594,7 @@ status_t compileResourceFile(Bundle* bundle,
|
|||||||
err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
|
err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
|
||||||
ident, *curTag, curIsStyled, curFormat,
|
ident, *curTag, curIsStyled, curFormat,
|
||||||
curIsFormatted, product,
|
curIsFormatted, product,
|
||||||
true, overwrite, outTable);
|
true, overwrite, &skippedResourceNames, outTable);
|
||||||
if (err != NO_ERROR) {
|
if (err != NO_ERROR) {
|
||||||
hasErrors = localHasErrors = true;
|
hasErrors = localHasErrors = true;
|
||||||
}
|
}
|
||||||
@@ -1596,6 +1633,30 @@ status_t compileResourceFile(Bundle* bundle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For every resource defined, there must be exist one variant with a product attribute
|
||||||
|
// set to 'default' (or no product attribute at all).
|
||||||
|
// We check to see that for every resource that was ignored because of a mismatched
|
||||||
|
// product attribute, some product variant of that resource was processed.
|
||||||
|
for (size_t i = 0; i < skippedResourceNames.size(); i++) {
|
||||||
|
if (skippedResourceNames[i]) {
|
||||||
|
const type_ident_pair_t& p = skippedResourceNames.keyAt(i);
|
||||||
|
if (!outTable->hasBagOrEntry(myPackage, p.type, p.ident)) {
|
||||||
|
const char* bundleProduct =
|
||||||
|
(bundle->getProduct() == NULL) ? "" : bundle->getProduct();
|
||||||
|
fprintf(stderr, "In resource file %s: %s\n",
|
||||||
|
in->getPrintableSource().string(),
|
||||||
|
curParams.toString().string());
|
||||||
|
|
||||||
|
fprintf(stderr, "\t%s '%s' does not match product %s.\n"
|
||||||
|
"\tYou may have forgotten to include a 'default' product variant"
|
||||||
|
" of the resource.\n",
|
||||||
|
String8(p.type).string(), String8(p.ident).string(),
|
||||||
|
bundleProduct[0] == 0 ? "default" : bundleProduct);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
|
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2483,8 +2544,8 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) {
|
|||||||
|
|
||||||
String16 comment(c->getComment());
|
String16 comment(c->getComment());
|
||||||
typeSymbols->appendComment(String8(c->getName()), comment, c->getPos());
|
typeSymbols->appendComment(String8(c->getName()), comment, c->getPos());
|
||||||
//printf("Type symbol %s comment: %s\n", String8(e->getName()).string(),
|
//printf("Type symbol [%08x] %s comment: %s\n", rid,
|
||||||
// String8(comment).string());
|
// String8(c->getName()).string(), String8(comment).string());
|
||||||
comment = c->getTypeComment();
|
comment = c->getTypeComment();
|
||||||
typeSymbols->appendTypeComment(String8(c->getName()), comment);
|
typeSymbols->appendTypeComment(String8(c->getName()), comment);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user