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

Commit fa837086 authored by Brandon Liu's avatar Brandon Liu Committed by Android (Google) Code Review
Browse files

Merge "Add additional check on float precision after parsing, only compile the...

Merge "Add additional check on float precision after parsing, only compile the value to a float when the difference between float and double parsed from same raw string is smaller than 1."
parents cf1adec6 c674d38c
Loading
Loading
Loading
Loading
+45 −16
Original line number Diff line number Diff line
@@ -5436,37 +5436,66 @@ bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
    return U16StringToInt(s, len, outValue);
}

bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
{
    while (len > 0 && isspace16(*s)) {
        s++;
        len--;
template <typename T>
bool parseFloatingPoint(const char16_t* inBuf, size_t inLen, char* tempBuf,
                                  const char** outEnd, T& out){
    while (inLen > 0 && isspace16(*inBuf)) {
        inBuf++;
        inLen--;
    }

    if (len <= 0) {
    if (inLen <= 0) {
        return false;
    }

    char buf[128];
    int i=0;
    while (len > 0 && *s != 0 && i < 126) {
        if (*s > 255) {
    while (inLen > 0 && *inBuf != 0 && i < 126) {
        if (*inBuf > 255) {
            return false;
        }
        buf[i++] = *s++;
        len--;
        tempBuf[i++] = *inBuf++;
        inLen--;
    }

    if (len > 0) {
    if (inLen > 0) {
        return false;
    }
    if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
    if ((tempBuf[0] < '0' || tempBuf[0] > '9') && tempBuf[0] != '.' && tempBuf[0] != '-' && tempBuf[0] != '+') {
        return false;
    }

    buf[i] = 0;
    const char* end;
    float f = strtof(buf, (char**)&end);
    tempBuf[i] = 0;
    if constexpr(std::is_same_v<T, float>) {
        out = strtof(tempBuf, (char**)outEnd);
    } else {
        out = strtod(tempBuf, (char**)outEnd);
    }
    return true;
}

bool ResTable::stringToDouble(const char16_t* s, size_t len, double& d){
    char buf[128];
    const char* end = nullptr;
    if (!parseFloatingPoint(s, len, buf, &end, d)) {
        return false;
    }

    while (*end != 0 && isspace((unsigned char)*end)) {
        end++;
    }

    return *end == 0;
}

bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
{
    char buf[128];
    const char* end = nullptr;
    float f;

    if (!parseFloatingPoint(s, len, buf, &end, f)) {
        return false;
    }

    if (*end != 0 && !isspace((unsigned char)*end)) {
        // Might be a unit...
+1 −0
Original line number Diff line number Diff line
@@ -2162,6 +2162,7 @@ public:

    static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue);
    static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue);
    static bool stringToDouble(const char16_t* s, size_t len, double& outValue);

    // Used with stringToValue.
    class Accessor
+19 −1
Original line number Diff line number Diff line
@@ -670,10 +670,28 @@ std::unique_ptr<Item> TryParseItemForAttribute(
    // Try parsing this as a float.
    auto floating_point = TryParseFloat(value);
    if (floating_point) {
      // Only check if the parsed result lost precision when the parsed item is
      // android::Res_value::TYPE_FLOAT and there is other possible types saved in type_mask, like
      // ResTable_map::TYPE_INTEGER.
      if (type_mask & AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) {
        const bool mayOnlyBeFloat = (type_mask & ~float_mask) == 0;
        const bool parsedAsFloat = floating_point->value.dataType == android::Res_value::TYPE_FLOAT;
        if (!mayOnlyBeFloat && parsedAsFloat) {
          float f = reinterpret_cast<float&>(floating_point->value.data);
          std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(value));
          double d;
          if (android::ResTable::stringToDouble(str16.data(), str16.size(), d)) {
            // Parse as a float only if the difference between float and double parsed from the
            // same string is smaller than 1, otherwise return as raw string.
            if (fabs(f - d) < 1) {
              return std::move(floating_point);
            }
          }
        } else {
          return std::move(floating_point);
        }
      }
    }
  }
  return {};
}
+20 −0
Original line number Diff line number Diff line
@@ -228,6 +228,26 @@ TEST(ResourceUtilsTest, ItemsWithWhitespaceAreParsedCorrectly) {
              Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
}

TEST(ResourceUtilsTest, FloatAndBigIntegerParsedCorrectly) {
  const float expected_float = 0.125f;
  const uint32_t expected_float_flattened = *(uint32_t*)&expected_float;
  EXPECT_THAT(ResourceUtils::TryParseItemForAttribute("0.125", ResTable_map::TYPE_FLOAT),
              Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));

  const float special_float = 1.0f;
  const uint32_t special_float_flattened = *(uint32_t*)&special_float;
  EXPECT_THAT(ResourceUtils::TryParseItemForAttribute("1.0", ResTable_map::TYPE_FLOAT),
              Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, special_float_flattened))));

  EXPECT_EQ(ResourceUtils::TryParseItemForAttribute("1099511627776", ResTable_map::TYPE_INTEGER),
            std::unique_ptr<Item>(nullptr));

  const float big_float = 1099511627776.0f;
  const uint32_t big_flattened = *(uint32_t*)&big_float;
  EXPECT_THAT(ResourceUtils::TryParseItemForAttribute("1099511627776", ResTable_map::TYPE_FLOAT),
              Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, big_flattened))));
}

TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
  EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(std::optional<int>(10000)));
  EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q.fingerprint"), Eq(std::optional<int>(10000)));
+18 −1
Original line number Diff line number Diff line
@@ -439,6 +439,21 @@ static std::string ComplexToString(uint32_t complex_value, bool fraction) {
  return str;
}

// This function is designed to using different specifier to print different floats,
// which can print more accurate format rather than using %g only.
const char* BinaryPrimitive::DecideFormat(float f) {
  // if the float is either too big or too tiny, print it in scientific notation.
  // eg: "10995116277760000000000" to 1.099512e+22, "0.00000000001" to 1.000000e-11
  if (fabs(f) > std::numeric_limits<int64_t>::max() || fabs(f) < 1e-10) {
    return "%e";
    // Else if the number is an integer exactly, print it without trailing zeros.
    // eg: "1099511627776" to 1099511627776
  } else if (int64_t(f) == f) {
    return "%.0f";
  }
  return "%g";
}

void BinaryPrimitive::PrettyPrint(Printer* printer) const {
  using ::android::Res_value;
  switch (value.dataType) {
@@ -470,7 +485,9 @@ void BinaryPrimitive::PrettyPrint(Printer* printer) const {
      break;

    case Res_value::TYPE_FLOAT:
      printer->Print(StringPrintf("%g", *reinterpret_cast<const float*>(&value.data)));
      float f;
      f = *reinterpret_cast<const float*>(&value.data);
      printer->Print(StringPrintf(DecideFormat(f), f));
      break;

    case Res_value::TYPE_DIMENSION:
Loading