Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7298bc9c authored by Adam Lesinski's avatar Adam Lesinski
Browse files

AAPT2: Be more strict parsing references

Change-Id: I3d54a519687fff1e66acb8e395ef99ba01a1b845
parent e352b990
Loading
Loading
Loading
Loading
+35 −8
Original line number Diff line number Diff line
@@ -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 @@ bool tryParseReference(const StringPiece16& str, ResourceNameRef* outRef, bool*
        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 @@ bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outRe
        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;
        }

        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:
 *
+8 −2
Original line number Diff line number Diff line
@@ -34,8 +34,9 @@ namespace ResourceUtils {
 *
 * 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,11 +55,16 @@ bool tryParseReference(const StringPiece16& str, ResourceNameRef* outReference,
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`.
 */
+20 −0
Original line number Diff line number Diff line
@@ -90,6 +90,26 @@ TEST(ResourceUtilsTest, FailToParseAutoCreateNonIdReference) {
                                                  &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" };