Loading tools/aapt2/Diagnostics.h +0 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ #define AAPT_DIAGNOSTICS_H #include "Source.h" #include "util/StringPiece.h" #include "util/Util.h" Loading tools/aapt2/ResourceParser.cpp +47 −0 Original line number Diff line number Diff line Loading @@ -711,6 +711,46 @@ bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* o } } Maybe<int32_t> maybeMin, maybeMax; if (Maybe<StringPiece16> maybeMinStr = xml::findAttribute(parser, u"min")) { StringPiece16 minStr = util::trimWhitespace(maybeMinStr.value()); if (!minStr.empty()) { android::Res_value value; if (android::ResTable::stringToInt(minStr.data(), minStr.size(), &value)) { maybeMin = static_cast<int32_t>(value.data); } } if (!maybeMin) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "invalid 'min' value '" << minStr << "'"); return false; } } if (Maybe<StringPiece16> maybeMaxStr = xml::findAttribute(parser, u"max")) { StringPiece16 maxStr = util::trimWhitespace(maybeMaxStr.value()); if (!maxStr.empty()) { android::Res_value value; if (android::ResTable::stringToInt(maxStr.data(), maxStr.size(), &value)) { maybeMax = static_cast<int32_t>(value.data); } } if (!maybeMax) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "invalid 'max' value '" << maxStr << "'"); return false; } } if ((maybeMin || maybeMax) && (typeMask & android::ResTable_map::TYPE_INTEGER) == 0) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "'min' and 'max' can only be used when format='integer'"); return false; } struct SymbolComparator { bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) { return a.symbol.name.value() < b.symbol.name.value(); Loading Loading @@ -794,6 +834,13 @@ bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* o std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak); attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end()); attr->typeMask = typeMask ? typeMask : uint32_t(android::ResTable_map::TYPE_ANY); if (maybeMin) { attr->minInt = maybeMin.value(); } if (maybeMax) { attr->maxInt = maybeMax.value(); } outResource->value = std::move(attr); return true; } Loading tools/aapt2/ResourceParser_test.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,22 @@ TEST_F(ResourceParserTest, ParseAttr) { EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask); } TEST_F(ResourceParserTest, ParseAttrWithMinMax) { std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>"; ASSERT_TRUE(testParse(input)); Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); ASSERT_NE(nullptr, attr); EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->typeMask); EXPECT_EQ(10, attr->minInt); EXPECT_EQ(23, attr->maxInt); } TEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) { std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>"; ASSERT_FALSE(testParse(input)); } TEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) { std::string input = "<declare-styleable name=\"Styleable\">\n" " <attr name=\"foo\" />\n" Loading tools/aapt2/ResourceValues.cpp +81 −3 Original line number Diff line number Diff line Loading @@ -15,9 +15,9 @@ */ #include "Resource.h" #include "ResourceUtils.h" #include "ResourceValues.h" #include "ValueVisitor.h" #include "util/Util.h" #include "flatten/ResourceTypeExtensions.h" Loading Loading @@ -216,7 +216,7 @@ void BinaryPrimitive::print(std::ostream* out) const { *out << "(null)"; break; case android::Res_value::TYPE_INT_DEC: *out << "(integer) " << value.data; *out << "(integer) " << static_cast<int32_t>(value.data); break; case android::Res_value::TYPE_INT_HEX: *out << "(integer) " << std::hex << value.data << std::dec; Loading @@ -237,7 +237,10 @@ void BinaryPrimitive::print(std::ostream* out) const { } } Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t) { Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t), minInt(std::numeric_limits<int32_t>::min()), maxInt(std::numeric_limits<int32_t>::max()) { } bool Attribute::isWeak() const { Loading Loading @@ -361,6 +364,81 @@ void Attribute::print(std::ostream* out) const { } } static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr, const Item* value) { *msg << "expected"; if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) { *msg << " boolean"; } if (attr->typeMask & android::ResTable_map::TYPE_COLOR) { *msg << " color"; } if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) { *msg << " dimension"; } if (attr->typeMask & android::ResTable_map::TYPE_ENUM) { *msg << " enum"; } if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) { *msg << " flags"; } if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) { *msg << " float"; } if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) { *msg << " fraction"; } if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) { *msg << " integer"; } if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) { *msg << " reference"; } if (attr->typeMask & android::ResTable_map::TYPE_STRING) { *msg << " string"; } *msg << " but got " << *value; } bool Attribute::matches(const Item* item, DiagMessage* outMsg) const { android::Res_value val = {}; item->flatten(&val); // Always allow references. const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE; if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) { if (outMsg) { buildAttributeMismatchMessage(outMsg, this, item); } return false; } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) & android::ResTable_map::TYPE_INTEGER) { if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) { if (outMsg) { *outMsg << *item << " is less than minimum integer " << minInt; } return false; } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) { if (outMsg) { *outMsg << *item << " is greater than maximum integer " << maxInt; } return false; } } return true; } Style* Style::clone(StringPool* newPool) const { Style* style = new Style(); style->parent = parent; Loading tools/aapt2/ResourceValues.h +5 −3 Original line number Diff line number Diff line Loading @@ -17,9 +17,10 @@ #ifndef AAPT_RESOURCE_VALUES_H #define AAPT_RESOURCE_VALUES_H #include "util/Maybe.h" #include "Diagnostics.h" #include "Resource.h" #include "StringPool.h" #include "util/Maybe.h" #include <array> #include <androidfw/ResourceTypes.h> Loading Loading @@ -233,8 +234,8 @@ struct Attribute : public BaseValue<Attribute> { bool weak; uint32_t typeMask; uint32_t minInt; uint32_t maxInt; int32_t minInt; int32_t maxInt; std::vector<Symbol> symbols; Attribute(bool w, uint32_t t = 0u); Loading @@ -243,6 +244,7 @@ struct Attribute : public BaseValue<Attribute> { Attribute* clone(StringPool* newPool) const override; void printMask(std::ostream* out) const; void print(std::ostream* out) const override; bool matches(const Item* item, DiagMessage* outMsg) const; }; struct Style : public BaseValue<Style> { Loading Loading
tools/aapt2/Diagnostics.h +0 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ #define AAPT_DIAGNOSTICS_H #include "Source.h" #include "util/StringPiece.h" #include "util/Util.h" Loading
tools/aapt2/ResourceParser.cpp +47 −0 Original line number Diff line number Diff line Loading @@ -711,6 +711,46 @@ bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* o } } Maybe<int32_t> maybeMin, maybeMax; if (Maybe<StringPiece16> maybeMinStr = xml::findAttribute(parser, u"min")) { StringPiece16 minStr = util::trimWhitespace(maybeMinStr.value()); if (!minStr.empty()) { android::Res_value value; if (android::ResTable::stringToInt(minStr.data(), minStr.size(), &value)) { maybeMin = static_cast<int32_t>(value.data); } } if (!maybeMin) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "invalid 'min' value '" << minStr << "'"); return false; } } if (Maybe<StringPiece16> maybeMaxStr = xml::findAttribute(parser, u"max")) { StringPiece16 maxStr = util::trimWhitespace(maybeMaxStr.value()); if (!maxStr.empty()) { android::Res_value value; if (android::ResTable::stringToInt(maxStr.data(), maxStr.size(), &value)) { maybeMax = static_cast<int32_t>(value.data); } } if (!maybeMax) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "invalid 'max' value '" << maxStr << "'"); return false; } } if ((maybeMin || maybeMax) && (typeMask & android::ResTable_map::TYPE_INTEGER) == 0) { mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) << "'min' and 'max' can only be used when format='integer'"); return false; } struct SymbolComparator { bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) { return a.symbol.name.value() < b.symbol.name.value(); Loading Loading @@ -794,6 +834,13 @@ bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* o std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak); attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end()); attr->typeMask = typeMask ? typeMask : uint32_t(android::ResTable_map::TYPE_ANY); if (maybeMin) { attr->minInt = maybeMin.value(); } if (maybeMax) { attr->maxInt = maybeMax.value(); } outResource->value = std::move(attr); return true; } Loading
tools/aapt2/ResourceParser_test.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,22 @@ TEST_F(ResourceParserTest, ParseAttr) { EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask); } TEST_F(ResourceParserTest, ParseAttrWithMinMax) { std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>"; ASSERT_TRUE(testParse(input)); Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); ASSERT_NE(nullptr, attr); EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->typeMask); EXPECT_EQ(10, attr->minInt); EXPECT_EQ(23, attr->maxInt); } TEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) { std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>"; ASSERT_FALSE(testParse(input)); } TEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) { std::string input = "<declare-styleable name=\"Styleable\">\n" " <attr name=\"foo\" />\n" Loading
tools/aapt2/ResourceValues.cpp +81 −3 Original line number Diff line number Diff line Loading @@ -15,9 +15,9 @@ */ #include "Resource.h" #include "ResourceUtils.h" #include "ResourceValues.h" #include "ValueVisitor.h" #include "util/Util.h" #include "flatten/ResourceTypeExtensions.h" Loading Loading @@ -216,7 +216,7 @@ void BinaryPrimitive::print(std::ostream* out) const { *out << "(null)"; break; case android::Res_value::TYPE_INT_DEC: *out << "(integer) " << value.data; *out << "(integer) " << static_cast<int32_t>(value.data); break; case android::Res_value::TYPE_INT_HEX: *out << "(integer) " << std::hex << value.data << std::dec; Loading @@ -237,7 +237,10 @@ void BinaryPrimitive::print(std::ostream* out) const { } } Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t) { Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t), minInt(std::numeric_limits<int32_t>::min()), maxInt(std::numeric_limits<int32_t>::max()) { } bool Attribute::isWeak() const { Loading Loading @@ -361,6 +364,81 @@ void Attribute::print(std::ostream* out) const { } } static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr, const Item* value) { *msg << "expected"; if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) { *msg << " boolean"; } if (attr->typeMask & android::ResTable_map::TYPE_COLOR) { *msg << " color"; } if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) { *msg << " dimension"; } if (attr->typeMask & android::ResTable_map::TYPE_ENUM) { *msg << " enum"; } if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) { *msg << " flags"; } if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) { *msg << " float"; } if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) { *msg << " fraction"; } if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) { *msg << " integer"; } if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) { *msg << " reference"; } if (attr->typeMask & android::ResTable_map::TYPE_STRING) { *msg << " string"; } *msg << " but got " << *value; } bool Attribute::matches(const Item* item, DiagMessage* outMsg) const { android::Res_value val = {}; item->flatten(&val); // Always allow references. const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE; if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) { if (outMsg) { buildAttributeMismatchMessage(outMsg, this, item); } return false; } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) & android::ResTable_map::TYPE_INTEGER) { if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) { if (outMsg) { *outMsg << *item << " is less than minimum integer " << minInt; } return false; } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) { if (outMsg) { *outMsg << *item << " is greater than maximum integer " << maxInt; } return false; } } return true; } Style* Style::clone(StringPool* newPool) const { Style* style = new Style(); style->parent = parent; Loading
tools/aapt2/ResourceValues.h +5 −3 Original line number Diff line number Diff line Loading @@ -17,9 +17,10 @@ #ifndef AAPT_RESOURCE_VALUES_H #define AAPT_RESOURCE_VALUES_H #include "util/Maybe.h" #include "Diagnostics.h" #include "Resource.h" #include "StringPool.h" #include "util/Maybe.h" #include <array> #include <androidfw/ResourceTypes.h> Loading Loading @@ -233,8 +234,8 @@ struct Attribute : public BaseValue<Attribute> { bool weak; uint32_t typeMask; uint32_t minInt; uint32_t maxInt; int32_t minInt; int32_t maxInt; std::vector<Symbol> symbols; Attribute(bool w, uint32_t t = 0u); Loading @@ -243,6 +244,7 @@ struct Attribute : public BaseValue<Attribute> { Attribute* clone(StringPool* newPool) const override; void printMask(std::ostream* out) const; void print(std::ostream* out) const override; bool matches(const Item* item, DiagMessage* outMsg) const; }; struct Style : public BaseValue<Style> { Loading