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

Commit d5fd76a2 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

AAPT2: Respect format attr in <array> resource

Bug: 38152130
Test: make aapt2_tests
Change-Id: I84f352afb1a8fd2f329354f789aaa36c5ef88e47
parent 4b2cecbb
Loading
Loading
Loading
Loading
+41 −41
Original line number Diff line number Diff line
@@ -34,40 +34,41 @@ using android::StringPiece;

namespace aapt {

constexpr const char* sXliffNamespaceUri =
    "urn:oasis:names:tc:xliff:document:1.2";
constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";

/**
 * Returns true if the element is <skip> or <eat-comment> and can be safely
 * ignored.
 */
static bool ShouldIgnoreElement(const StringPiece& ns,
                                const StringPiece& name) {
// Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) {
  return ns.empty() && (name == "skip" || name == "eat-comment");
}

static uint32_t ParseFormatType(const StringPiece& piece) {
  if (piece == "reference")
static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) {
  if (piece == "reference") {
    return android::ResTable_map::TYPE_REFERENCE;
  else if (piece == "string")
  } else if (piece == "string") {
    return android::ResTable_map::TYPE_STRING;
  else if (piece == "integer")
  } else if (piece == "integer") {
    return android::ResTable_map::TYPE_INTEGER;
  else if (piece == "boolean")
  } else if (piece == "boolean") {
    return android::ResTable_map::TYPE_BOOLEAN;
  else if (piece == "color")
  } else if (piece == "color") {
    return android::ResTable_map::TYPE_COLOR;
  else if (piece == "float")
  } else if (piece == "float") {
    return android::ResTable_map::TYPE_FLOAT;
  else if (piece == "dimension")
  } else if (piece == "dimension") {
    return android::ResTable_map::TYPE_DIMENSION;
  else if (piece == "fraction")
  } else if (piece == "fraction") {
    return android::ResTable_map::TYPE_FRACTION;
  else if (piece == "enum")
  }
  return 0;
}

static uint32_t ParseFormatType(const StringPiece& piece) {
  if (piece == "enum") {
    return android::ResTable_map::TYPE_ENUM;
  else if (piece == "flags")
  } else if (piece == "flags") {
    return android::ResTable_map::TYPE_FLAGS;
  return 0;
  }
  return ParseFormatTypeNoEnumsOrFlags(piece);
}

static uint32_t ParseFormatAttribute(const StringPiece& str) {
@@ -83,9 +84,7 @@ static uint32_t ParseFormatAttribute(const StringPiece& str) {
  return mask;
}

/**
 * A parsed resource ready to be added to the ResourceTable.
 */
// A parsed resource ready to be added to the ResourceTable.
struct ParsedResource {
  ResourceName name;
  ConfigDescription config;
@@ -416,8 +415,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
    can_be_bag = false;

    // Items have their type encoded in the type attribute.
    if (Maybe<StringPiece> maybe_type =
            xml::FindNonEmptyAttribute(parser, "type")) {
    if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
      resource_type = maybe_type.value().to_string();
    } else {
      diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
@@ -425,13 +423,11 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
      return false;
    }

    if (Maybe<StringPiece> maybe_format =
            xml::FindNonEmptyAttribute(parser, "format")) {
    if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) {
      // An explicit format for this resource was specified. The resource will
      // retain
      // its type in its name, but the accepted value for this type is
      // retain its type in its name, but the accepted value for this type is
      // overridden.
      resource_format = ParseFormatType(maybe_format.value());
      resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value());
      if (!resource_format) {
        diag_->Error(DiagMessage(out_resource->source)
                     << "'" << maybe_format.value()
@@ -1157,21 +1153,25 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
  return true;
}

bool ResourceParser::ParseArray(xml::XmlPullParser* parser,
                                ParsedResource* out_resource) {
  return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_ANY);
bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
  uint32_t resource_format = android::ResTable_map::TYPE_ANY;
  if (Maybe<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
    resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value());
    if (resource_format == 0u) {
      diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
                   << "'" << format_attr.value() << "' is an invalid format");
      return false;
    }
  }
  return ParseArrayImpl(parser, out_resource, resource_format);
}

bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser,
                                       ParsedResource* out_resource) {
  return ParseArrayImpl(parser, out_resource,
                        android::ResTable_map::TYPE_INTEGER);
bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
  return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER);
}

bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser,
                                      ParsedResource* out_resource) {
  return ParseArrayImpl(parser, out_resource,
                        android::ResTable_map::TYPE_STRING);
bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
  return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING);
}

bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
+29 −4
Original line number Diff line number Diff line
@@ -571,14 +571,39 @@ TEST_F(ResourceParserTest, ParseArray) {
}

TEST_F(ResourceParserTest, ParseStringArray) {
  std::string input =
      "<string-array name=\"foo\">\n"
      "  <item>\"Werk\"</item>\n"
      "</string-array>\n";
  std::string input = R"EOF(
      <string-array name="foo">
        <item>"Werk"</item>"
      </string-array>)EOF";
  ASSERT_TRUE(TestParse(input));
  EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
}

TEST_F(ResourceParserTest, ParseArrayWithFormat) {
  std::string input = R"EOF(
      <array name="foo" format="string">
        <item>100</item>
      </array>)EOF";
  ASSERT_TRUE(TestParse(input));

  Array* array = test::GetValue<Array>(&table_, "array/foo");
  ASSERT_NE(nullptr, array);

  ASSERT_EQ(1u, array->items.size());

  String* str = ValueCast<String>(array->items[0].get());
  ASSERT_NE(nullptr, str);
  EXPECT_EQ(std::string("100"), *str->value);
}

TEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
  std::string input = R"EOF(
      <array name="foo" format="integer">
        <item>Hi</item>
      </array>)EOF";
  ASSERT_FALSE(TestParse(input));
}

TEST_F(ResourceParserTest, ParsePlural) {
  std::string input =
      "<plurals name=\"foo\">\n"