Merge "AAPT2: Be more strict parsing references"
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index d3c3c10..b1a4c7d 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -23,22 +23,28 @@
namespace aapt {
namespace ResourceUtils {
-void extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
+bool extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
StringPiece16* outType, StringPiece16* outEntry) {
+ bool hasPackageSeparator = false;
+ bool hasTypeSeparator = false;
const char16_t* start = str.data();
const char16_t* end = start + str.size();
const char16_t* current = start;
while (current != end) {
if (outType->size() == 0 && *current == u'/') {
+ hasTypeSeparator = true;
outType->assign(start, current - start);
start = current + 1;
} else if (outPackage->size() == 0 && *current == u':') {
+ hasPackageSeparator = true;
outPackage->assign(start, current - start);
start = current + 1;
}
current++;
}
outEntry->assign(start, end - start);
+
+ return !(hasPackageSeparator && outPackage->empty()) && !(hasTypeSeparator && outType->empty());
}
bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool* outCreate,
@@ -62,26 +68,34 @@
StringPiece16 package;
StringPiece16 type;
StringPiece16 entry;
- extractResourceName(trimmedStr.substr(offset, trimmedStr.size() - offset), &package, &type,
- &entry);
+ if (!extractResourceName(trimmedStr.substr(offset, trimmedStr.size() - offset),
+ &package, &type, &entry)) {
+ return false;
+ }
const ResourceType* parsedType = parseResourceType(type);
if (!parsedType) {
return false;
}
+ if (entry.empty()) {
+ return false;
+ }
+
if (create && *parsedType != ResourceType::kId) {
return false;
}
- if (outRef != nullptr) {
+ if (outRef) {
outRef->package = package;
outRef->type = *parsedType;
outRef->entry = entry;
}
+
if (outCreate) {
*outCreate = create;
}
+
if (outPrivate) {
*outPrivate = priv;
}
@@ -104,20 +118,33 @@
StringPiece16 package;
StringPiece16 type;
StringPiece16 entry;
- extractResourceName(trimmedStr.substr(1, trimmedStr.size() - 1), &package, &type, &entry);
+ if (!extractResourceName(trimmedStr.substr(1, trimmedStr.size() - 1),
+ &package, &type, &entry)) {
+ return false;
+ }
if (!type.empty() && type != u"attr") {
return false;
}
- outRef->package = package;
- outRef->type = ResourceType::kAttr;
- outRef->entry = entry;
+ if (entry.empty()) {
+ return false;
+ }
+
+ if (outRef) {
+ outRef->package = package;
+ outRef->type = ResourceType::kAttr;
+ outRef->entry = entry;
+ }
return true;
}
return false;
}
+bool isAttributeReference(const StringPiece16& str) {
+ return tryParseAttributeReference(str, nullptr);
+}
+
/*
* Style parent's are a bit different. We accept the following formats:
*
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 851edc8..34daa66 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -34,8 +34,9 @@
*
* where the package can be empty. Validation must be performed on each
* individual extracted piece to verify that the pieces are valid.
+ * Returns false if there was no package but a ':' was present.
*/
-void extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
+bool extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
StringPiece16* outType, StringPiece16* outEntry);
/*
@@ -54,12 +55,17 @@
bool isReference(const StringPiece16& str);
/*
- * Returns true if the string was parsed as an attribute reference (?[package:]type/name),
+ * Returns true if the string was parsed as an attribute reference (?[package:][type/]name),
* with `outReference` set to the parsed reference.
*/
bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outReference);
/**
+ * Returns true if the string is in the form of an attribute reference(?[package:][type/]name).
+ */
+bool isAttributeReference(const StringPiece16& str);
+
+/**
* Returns true if the value is a boolean, putting the result in `outValue`.
*/
bool tryParseBool(const StringPiece16& str, bool* outValue);
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 7de8f41..3d2a6e1 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -90,6 +90,26 @@
&privateRef));
}
+TEST(ResourceUtilsTest, ParseAttributeReferences) {
+ EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?android"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?android:foo"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?attr/foo"));
+ EXPECT_TRUE(ResourceUtils::isAttributeReference(u"?android:attr/foo"));
+}
+
+TEST(ResourceUtilsTest, FailParseIncompleteReference) {
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?style/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?android:style/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?android:"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?android:attr/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:attr/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:attr/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?:/foo"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?attr/"));
+ EXPECT_FALSE(ResourceUtils::isAttributeReference(u"?/foo"));
+}
+
TEST(ResourceUtilsTest, ParseStyleParentReference) {
const ResourceName kAndroidStyleFooName = { u"android", ResourceType::kStyle, u"foo" };
const ResourceName kStyleFooName = { {}, ResourceType::kStyle, u"foo" };