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

Commit ef506c73 authored by Adam Lesinski's avatar Adam Lesinski Committed by Colin Cross
Browse files

AAPT2: Differentiate between Android and Java package names

Android package names are more strict (ASCII only) than Java package names.
Also fixed an issue where trailing underscores were disallowed in Android
package names.

(cherry picked from commit 96ea08f1)

Also includes part of I357fb84941bfbb3892a8c46feb47f55b865b6649 to remove
usage of FindNonAlphaNumericAndNotInSet.

Bug: 79481102
Test: make aapt2_tests
Change-Id: I1052e9e82b6617db6065ce448d9bf7972bb68d59
Merged-In: I1052e9e82b6617db6065ce448d9bf7972bb68d59
parent 1e0a5d39
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -22,9 +22,11 @@
#include "java/AnnotationProcessor.h"
#include "java/ClassDefinition.h"
#include "util/Maybe.h"
#include "text/Unicode.h"
#include "xml/XmlDom.h"

using android::StringPiece;
using ::android::StringPiece;
using ::aapt::text::IsJavaIdentifier;

namespace aapt {

@@ -46,11 +48,8 @@ static Maybe<StringPiece> ExtractJavaIdentifier(IDiagnostics* diag,
    return {};
  }

  iter = util::FindNonAlphaNumericAndNotInSet(result, "_");
  if (iter != result.end()) {
    diag->Error(DiagMessage(source) << "invalid character '"
                                    << StringPiece(iter, 1) << "' in '"
                                    << result << "'");
  if (!IsJavaIdentifier(result)) {
    diag->Error(DiagMessage(source) << "invalid Java identifier '" << result << "'");
    return {};
  }

+2 −2
Original line number Diff line number Diff line
@@ -127,9 +127,9 @@ static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
    diag->Error(DiagMessage(el->line_number)
                << "attribute 'package' in <manifest> tag must not be a reference");
    return false;
  } else if (!util::IsJavaPackageName(attr->value)) {
  } else if (!util::IsAndroidPackageName(attr->value)) {
    diag->Error(DiagMessage(el->line_number)
                << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
                << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
                << attr->value << "'");
    return false;
  }
+2 −1
Original line number Diff line number Diff line
@@ -85,7 +85,8 @@ bool IsJavaIdentifier(const StringPiece& str) {
    return false;
  }

  if (!IsXidStart(iter.Next())) {
  const char32_t first_codepoint = iter.Next();
  if (!IsXidStart(first_codepoint) && first_codepoint != U'_' && first_codepoint != U'$') {
    return false;
  }

+3 −2
Original line number Diff line number Diff line
@@ -44,10 +44,11 @@ TEST(UnicodeTest, IsXidContinue) {
TEST(UnicodeTest, IsJavaIdentifier) {
  EXPECT_TRUE(IsJavaIdentifier("FøøBar_12"));
  EXPECT_TRUE(IsJavaIdentifier("Føø$Bar"));
  EXPECT_TRUE(IsJavaIdentifier("_FøøBar"));
  EXPECT_TRUE(IsJavaIdentifier("$Føø$Bar"));

  EXPECT_FALSE(IsJavaIdentifier("12FøøBar"));
  EXPECT_FALSE(IsJavaIdentifier("_FøøBar"));
  EXPECT_FALSE(IsJavaIdentifier("$Føø$Bar"));
  EXPECT_FALSE(IsJavaIdentifier(".Hello"));
}

TEST(UnicodeTest, IsValidResourceEntryName) {
+34 −50
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include "androidfw/StringPiece.h"
#include "utils/Unicode.h"

#include "text/Unicode.h"
#include "text/Utf8Iterator.h"
#include "util/BigBuffer.h"
#include "util/Maybe.h"
@@ -94,72 +95,55 @@ StringPiece TrimWhitespace(const StringPiece& str) {
  return StringPiece(start, end - start);
}

StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
    const StringPiece& str, const StringPiece& allowed_chars) {
  const auto end_iter = str.end();
  for (auto iter = str.begin(); iter != end_iter; ++iter) {
    char c = *iter;
    if ((c >= u'a' && c <= u'z') || (c >= u'A' && c <= u'Z') ||
        (c >= u'0' && c <= u'9')) {
      continue;
static int IsJavaNameImpl(const StringPiece& str) {
  int pieces = 0;
  for (const StringPiece& piece : Tokenize(str, '.')) {
    pieces++;
    if (!text::IsJavaIdentifier(piece)) {
      return -1;
    }

    bool match = false;
    for (char i : allowed_chars) {
      if (c == i) {
        match = true;
        break;
  }
  return pieces;
}

    if (!match) {
      return iter;
    }
bool IsJavaClassName(const StringPiece& str) {
  return IsJavaNameImpl(str) >= 2;
}
  return end_iter;

bool IsJavaPackageName(const StringPiece& str) {
  return IsJavaNameImpl(str) >= 1;
}

bool IsJavaClassName(const StringPiece& str) {
  size_t pieces = 0;
static int IsAndroidNameImpl(const StringPiece& str) {
  int pieces = 0;
  for (const StringPiece& piece : Tokenize(str, '.')) {
    pieces++;
    if (piece.empty()) {
      return false;
      return -1;
    }

    // Can't have starting or trailing $ character.
    if (piece.data()[0] == '$' || piece.data()[piece.size() - 1] == '$') {
      return false;
    const char first_character = piece.data()[0];
    if (!::isalpha(first_character)) {
      return -1;
    }

    if (FindNonAlphaNumericAndNotInSet(piece, "$_") != piece.end()) {
      return false;
    }
  }
  return pieces >= 2;
}
    bool valid = std::all_of(piece.begin() + 1, piece.end(), [](const char c) -> bool {
      return ::isalnum(c) || c == '_';
    });

bool IsJavaPackageName(const StringPiece& str) {
  if (str.empty()) {
    return false;
    if (!valid) {
      return -1;
    }

  size_t pieces = 0;
  for (const StringPiece& piece : Tokenize(str, '.')) {
    pieces++;
    if (piece.empty()) {
      return false;
  }

    if (piece.data()[0] == '_' || piece.data()[piece.size() - 1] == '_') {
      return false;
  return pieces;
}

    if (FindNonAlphaNumericAndNotInSet(piece, "_") != piece.end()) {
      return false;
    }
bool IsAndroidPackageName(const StringPiece& str) {
  return IsAndroidNameImpl(str) > 1 || str == "android";
}
  return pieces >= 1;

bool IsAndroidSplitName(const StringPiece& str) {
  return IsAndroidNameImpl(str) > 0;
}

Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
@@ -176,7 +160,7 @@ Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
    return {};
  }

  std::string result(package.data(), package.size());
  std::string result = package.to_string();
  if (classname.data()[0] != '.') {
    result += '.';
  }
Loading