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

Commit 903ed1b6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Differentiate between Android and Java package names"

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


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


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


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


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


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

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


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

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


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


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


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


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

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

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


    if (FindNonAlphaNumericAndNotInSet(piece, "_") != piece.end()) {
bool IsAndroidPackageName(const StringPiece& str) {
      return false;
  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,
Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
@@ -176,7 +160,7 @@ Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
    return {};
    return {};
  }
  }


  std::string result(package.data(), package.size());
  std::string result = package.to_string();
  if (classname.data()[0] != '.') {
  if (classname.data()[0] != '.') {
    result += '.';
    result += '.';
  }
  }
+84 −105
Original line number Original line Diff line number Diff line
@@ -53,48 +53,40 @@ struct Range {
std::vector<std::string> Split(const android::StringPiece& str, char sep);
std::vector<std::string> Split(const android::StringPiece& str, char sep);
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);


/**
// Returns true if the string starts with prefix.
 * Returns true if the string starts with prefix.
 */
bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);
bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);


/**
// Returns true if the string ends with suffix.
 * Returns true if the string ends with suffix.
 */
bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);


/**
// Creates a new StringPiece16 that points to a substring of the original string without leading or
 * Creates a new StringPiece16 that points to a substring
// trailing whitespace.
 * of the original string without leading or trailing whitespace.
 */
android::StringPiece TrimWhitespace(const android::StringPiece& str);
android::StringPiece TrimWhitespace(const android::StringPiece& str);


/**
// Tests that the string is a valid Java class name.
 * Returns an iterator to the first character that is not alpha-numeric and that
 * is not in the allowedChars set.
 */
android::StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
    const android::StringPiece& str, const android::StringPiece& allowed_chars);

/**
 * Tests that the string is a valid Java class name.
 */
bool IsJavaClassName(const android::StringPiece& str);
bool IsJavaClassName(const android::StringPiece& str);


/**
// Tests that the string is a valid Java package name.
 * Tests that the string is a valid Java package name.
 */
bool IsJavaPackageName(const android::StringPiece& str);
bool IsJavaPackageName(const android::StringPiece& str);


/**
// Tests that the string is a valid Android package name. More strict than a Java package name.
 * Converts the class name to a fully qualified class name from the given
// - First character of each component (separated by '.') must be an ASCII letter.
 * `package`. Ex:
// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
 *
// - Package must contain at least two components, unless it is 'android'.
 * asdf         --> package.asdf
bool IsAndroidPackageName(const android::StringPiece& str);
 * .asdf        --> package.asdf

 * .a.b         --> package.a.b
// Tests that the string is a valid Android split name.
 * asdf.adsf    --> asdf.adsf
// - First character of each component (separated by '.') must be an ASCII letter.
 */
// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
bool IsAndroidSplitName(const android::StringPiece& str);

// Converts the class name to a fully qualified class name from the given
// `package`. Ex:
//
// asdf         --> package.asdf
// .asdf        --> package.asdf
// .a.b         --> package.a.b
// asdf.adsf    --> asdf.adsf
Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
                                              const android::StringPiece& class_name);
                                              const android::StringPiece& class_name);


@@ -108,23 +100,17 @@ typename std::enable_if<std::is_arithmetic<T>::value, int>::type compare(const T
  return 0;
  return 0;
}
}


/**
// Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
 * Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
// This will be present in C++14 and can be removed then.
 * This will be present in C++14 and can be removed then.
 */
template <typename T, class... Args>
template <typename T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
std::unique_ptr<T> make_unique(Args&&... args) {
  return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
  return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
}


/**
// Writes a set of items to the std::ostream, joining the times with the provided separator.
 * Writes a set of items to the std::ostream, joining the times with the
 * provided
 * separator.
 */
template <typename Container>
template <typename Container>
::std::function<::std::ostream&(::std::ostream&)> Joiner(
::std::function<::std::ostream&(::std::ostream&)> Joiner(const Container& container,
    const Container& container, const char* sep) {
                                                         const char* sep) {
  using std::begin;
  using std::begin;
  using std::end;
  using std::end;
  const auto begin_iter = begin(container);
  const auto begin_iter = begin(container);
@@ -140,32 +126,19 @@ template <typename Container>
  };
  };
}
}


/**
// Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
 * Helper method to extract a UTF-16 string from a StringPool. If the string is
// the conversion to UTF-16 happens within ResStringPool.
 * stored as UTF-8,
 * the conversion to UTF-16 happens within ResStringPool.
 */
android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);


/**
// Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
 * Helper method to extract a UTF-8 string from a StringPool. If the string is
// the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
 * stored as UTF-16,
// which maintains no state or cache. This means we must return an std::string copy.
 * the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is
 * done by this method,
 * which maintains no state or cache. This means we must return an std::string
 * copy.
 */
std::string GetString(const android::ResStringPool& pool, size_t idx);
std::string GetString(const android::ResStringPool& pool, size_t idx);


/**
// Checks that the Java string format contains no non-positional arguments (arguments without
 * Checks that the Java string format contains no non-positional arguments
// explicitly specifying an index) when there are more than one argument. This is an error
 * (arguments without
// because translations may rearrange the order of the arguments in the string, which will
 * explicitly specifying an index) when there are more than one argument. This
// break the string interpolation.
 * is an error
 * because translations may rearrange the order of the arguments in the string,
 * which will
 * break the string interpolation.
 */
bool VerifyJavaStringFormat(const android::StringPiece& str);
bool VerifyJavaStringFormat(const android::StringPiece& str);


class StringBuilder {
class StringBuilder {
@@ -194,36 +167,38 @@ class StringBuilder {
  std::string error_;
  std::string error_;
};
};


inline const std::string& StringBuilder::ToString() const { return str_; }
inline const std::string& StringBuilder::ToString() const {
  return str_;
}


inline const std::string& StringBuilder::Error() const { return error_; }
inline const std::string& StringBuilder::Error() const {
  return error_;
}


inline bool StringBuilder::IsEmpty() const { return str_.empty(); }
inline bool StringBuilder::IsEmpty() const {
  return str_.empty();
}


inline size_t StringBuilder::Utf16Len() const { return utf16_len_; }
inline size_t StringBuilder::Utf16Len() const {
  return utf16_len_;
}


inline StringBuilder::operator bool() const { return error_.empty(); }
inline StringBuilder::operator bool() const {
  return error_.empty();
}


/**
// Converts a UTF8 string to a UTF16 string.
 * Converts a UTF8 string to a UTF16 string.
 */
std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
std::string Utf16ToUtf8(const android::StringPiece16& utf16);
std::string Utf16ToUtf8(const android::StringPiece16& utf16);


/**
// Writes the entire BigBuffer to the output stream.
 * Writes the entire BigBuffer to the output stream.
 */
bool WriteAll(std::ostream& out, const BigBuffer& buffer);
bool WriteAll(std::ostream& out, const BigBuffer& buffer);


/*
// Copies the entire BigBuffer into a single buffer.
 * Copies the entire BigBuffer into a single buffer.
 */
std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer);
std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer);


/**
// A Tokenizer implemented as an iterable collection. It does not allocate any memory on the heap
 * A Tokenizer implemented as an iterable collection. It does not allocate
// nor use standard containers.
 * any memory on the heap nor use standard containers.
 */
class Tokenizer {
class Tokenizer {
 public:
 public:
  class iterator {
  class iterator {
@@ -269,37 +244,41 @@ class Tokenizer {
  const iterator end_;
  const iterator end_;
};
};


inline Tokenizer Tokenize(const android::StringPiece& str, char sep) { return Tokenizer(str, sep); }
inline Tokenizer Tokenize(const android::StringPiece& str, char sep) {
  return Tokenizer(str, sep);
}


inline uint16_t HostToDevice16(uint16_t value) { return htods(value); }
inline uint16_t HostToDevice16(uint16_t value) {
  return htods(value);
}


inline uint32_t HostToDevice32(uint32_t value) { return htodl(value); }
inline uint32_t HostToDevice32(uint32_t value) {
  return htodl(value);
}


inline uint16_t DeviceToHost16(uint16_t value) { return dtohs(value); }
inline uint16_t DeviceToHost16(uint16_t value) {
  return dtohs(value);
}


inline uint32_t DeviceToHost32(uint32_t value) { return dtohl(value); }
inline uint32_t DeviceToHost32(uint32_t value) {
  return dtohl(value);
}


/**
// Given a path like: res/xml-sw600dp/foo.xml
 * Given a path like: res/xml-sw600dp/foo.xml
//
 *
// Extracts "res/xml-sw600dp/" into outPrefix.
 * Extracts "res/xml-sw600dp/" into outPrefix.
// Extracts "foo" into outEntry.
 * Extracts "foo" into outEntry.
// Extracts ".xml" into outSuffix.
 * Extracts ".xml" into outSuffix.
//
 *
// Returns true if successful.
 * Returns true if successful.
 */
bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
                             android::StringPiece* out_entry, android::StringPiece* out_suffix);
                             android::StringPiece* out_entry, android::StringPiece* out_suffix);


}  // namespace util
}  // namespace util


/**
// Stream operator for functions. Calls the function with the stream as an argument.
 * Stream operator for functions. Calls the function with the stream as an
// In the aapt namespace for lookup.
 * argument.
inline ::std::ostream& operator<<(::std::ostream& out,
 * In the aapt namespace for lookup.
 */
inline ::std::ostream& operator<<(
    ::std::ostream& out,
                                  const ::std::function<::std::ostream&(::std::ostream&)>& f) {
                                  const ::std::function<::std::ostream&(::std::ostream&)>& f) {
  return f(out);
  return f(out);
}
}
Loading