xref: /aosp_15_r20/frameworks/base/tools/aapt2/util/Util.h (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #ifndef AAPT_UTIL_H
18*d57664e9SAndroid Build Coastguard Worker #define AAPT_UTIL_H
19*d57664e9SAndroid Build Coastguard Worker 
20*d57664e9SAndroid Build Coastguard Worker #include <functional>
21*d57664e9SAndroid Build Coastguard Worker #include <memory>
22*d57664e9SAndroid Build Coastguard Worker #include <ostream>
23*d57664e9SAndroid Build Coastguard Worker #include <string>
24*d57664e9SAndroid Build Coastguard Worker #include <vector>
25*d57664e9SAndroid Build Coastguard Worker 
26*d57664e9SAndroid Build Coastguard Worker #include "androidfw/BigBuffer.h"
27*d57664e9SAndroid Build Coastguard Worker #include "androidfw/ResourceTypes.h"
28*d57664e9SAndroid Build Coastguard Worker #include "androidfw/StringPiece.h"
29*d57664e9SAndroid Build Coastguard Worker #include "utils/ByteOrder.h"
30*d57664e9SAndroid Build Coastguard Worker 
31*d57664e9SAndroid Build Coastguard Worker #ifdef _WIN32
32*d57664e9SAndroid Build Coastguard Worker // TODO(adamlesinski): remove once http://b/32447322 is resolved.
33*d57664e9SAndroid Build Coastguard Worker // utils/ByteOrder.h includes winsock2.h on WIN32,
34*d57664e9SAndroid Build Coastguard Worker // which will pull in the ERROR definition. This conflicts
35*d57664e9SAndroid Build Coastguard Worker // with android-base/logging.h, which takes care of undefining
36*d57664e9SAndroid Build Coastguard Worker // ERROR, but it gets included too early (before winsock2.h).
37*d57664e9SAndroid Build Coastguard Worker #ifdef ERROR
38*d57664e9SAndroid Build Coastguard Worker #undef ERROR
39*d57664e9SAndroid Build Coastguard Worker #endif
40*d57664e9SAndroid Build Coastguard Worker #endif
41*d57664e9SAndroid Build Coastguard Worker 
42*d57664e9SAndroid Build Coastguard Worker namespace aapt {
43*d57664e9SAndroid Build Coastguard Worker namespace util {
44*d57664e9SAndroid Build Coastguard Worker 
45*d57664e9SAndroid Build Coastguard Worker template <typename T>
46*d57664e9SAndroid Build Coastguard Worker struct Range {
47*d57664e9SAndroid Build Coastguard Worker   T start;
48*d57664e9SAndroid Build Coastguard Worker   T end;
49*d57664e9SAndroid Build Coastguard Worker };
50*d57664e9SAndroid Build Coastguard Worker 
51*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> Split(android::StringPiece str, char sep);
52*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> SplitAndLowercase(android::StringPiece str, char sep);
53*d57664e9SAndroid Build Coastguard Worker 
54*d57664e9SAndroid Build Coastguard Worker // Returns true if the string starts with prefix.
55*d57664e9SAndroid Build Coastguard Worker bool StartsWith(android::StringPiece str, android::StringPiece prefix);
56*d57664e9SAndroid Build Coastguard Worker 
57*d57664e9SAndroid Build Coastguard Worker // Returns true if the string ends with suffix.
58*d57664e9SAndroid Build Coastguard Worker bool EndsWith(android::StringPiece str, android::StringPiece suffix);
59*d57664e9SAndroid Build Coastguard Worker 
60*d57664e9SAndroid Build Coastguard Worker // Creates a new StringPiece that points to a substring of the original string without leading
61*d57664e9SAndroid Build Coastguard Worker // whitespace.
62*d57664e9SAndroid Build Coastguard Worker android::StringPiece TrimLeadingWhitespace(android::StringPiece str);
63*d57664e9SAndroid Build Coastguard Worker 
64*d57664e9SAndroid Build Coastguard Worker // Creates a new StringPiece that points to a substring of the original string without trailing
65*d57664e9SAndroid Build Coastguard Worker // whitespace.
66*d57664e9SAndroid Build Coastguard Worker android::StringPiece TrimTrailingWhitespace(android::StringPiece str);
67*d57664e9SAndroid Build Coastguard Worker 
68*d57664e9SAndroid Build Coastguard Worker // Creates a new StringPiece that points to a substring of the original string without leading or
69*d57664e9SAndroid Build Coastguard Worker // trailing whitespace.
70*d57664e9SAndroid Build Coastguard Worker android::StringPiece TrimWhitespace(android::StringPiece str);
71*d57664e9SAndroid Build Coastguard Worker 
72*d57664e9SAndroid Build Coastguard Worker // Tests that the string is a valid Java class name.
73*d57664e9SAndroid Build Coastguard Worker bool IsJavaClassName(android::StringPiece str);
74*d57664e9SAndroid Build Coastguard Worker 
75*d57664e9SAndroid Build Coastguard Worker // Tests that the string is a valid Java package name.
76*d57664e9SAndroid Build Coastguard Worker bool IsJavaPackageName(android::StringPiece str);
77*d57664e9SAndroid Build Coastguard Worker 
78*d57664e9SAndroid Build Coastguard Worker // Tests that the string is a valid Android package name. More strict than a Java package name.
79*d57664e9SAndroid Build Coastguard Worker // - First character of each component (separated by '.') must be an ASCII letter.
80*d57664e9SAndroid Build Coastguard Worker // - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
81*d57664e9SAndroid Build Coastguard Worker // - Package must contain at least two components, unless it is 'android'.
82*d57664e9SAndroid Build Coastguard Worker // - The maximum package name length is 223.
83*d57664e9SAndroid Build Coastguard Worker bool IsAndroidPackageName(android::StringPiece str);
84*d57664e9SAndroid Build Coastguard Worker 
85*d57664e9SAndroid Build Coastguard Worker // Tests that the string is a valid Android split name.
86*d57664e9SAndroid Build Coastguard Worker // - First character of each component (separated by '.') must be an ASCII letter.
87*d57664e9SAndroid Build Coastguard Worker // - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
88*d57664e9SAndroid Build Coastguard Worker bool IsAndroidSplitName(android::StringPiece str);
89*d57664e9SAndroid Build Coastguard Worker 
90*d57664e9SAndroid Build Coastguard Worker // Tests that the string is a valid Android shared user id.
91*d57664e9SAndroid Build Coastguard Worker // - First character of each component (separated by '.') must be an ASCII letter.
92*d57664e9SAndroid Build Coastguard Worker // - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
93*d57664e9SAndroid Build Coastguard Worker // - Must contain at least two components, unless package name is 'android'.
94*d57664e9SAndroid Build Coastguard Worker // - The maximum shared user id length is 223.
95*d57664e9SAndroid Build Coastguard Worker // - Treat empty string as valid, it's the case of no shared user id.
96*d57664e9SAndroid Build Coastguard Worker bool IsAndroidSharedUserId(android::StringPiece package_name, android::StringPiece shared_user_id);
97*d57664e9SAndroid Build Coastguard Worker 
98*d57664e9SAndroid Build Coastguard Worker // Converts the class name to a fully qualified class name from the given
99*d57664e9SAndroid Build Coastguard Worker // `package`. Ex:
100*d57664e9SAndroid Build Coastguard Worker //
101*d57664e9SAndroid Build Coastguard Worker // asdf         --> package.asdf
102*d57664e9SAndroid Build Coastguard Worker // .asdf        --> package.asdf
103*d57664e9SAndroid Build Coastguard Worker // .a.b         --> package.a.b
104*d57664e9SAndroid Build Coastguard Worker // asdf.adsf    --> asdf.adsf
105*d57664e9SAndroid Build Coastguard Worker std::optional<std::string> GetFullyQualifiedClassName(android::StringPiece package,
106*d57664e9SAndroid Build Coastguard Worker                                                       android::StringPiece class_name);
107*d57664e9SAndroid Build Coastguard Worker 
108*d57664e9SAndroid Build Coastguard Worker // Retrieves the formatted name of aapt2.
109*d57664e9SAndroid Build Coastguard Worker const char* GetToolName();
110*d57664e9SAndroid Build Coastguard Worker 
111*d57664e9SAndroid Build Coastguard Worker // Retrieves the build fingerprint of aapt2.
112*d57664e9SAndroid Build Coastguard Worker std::string GetToolFingerprint();
113*d57664e9SAndroid Build Coastguard Worker 
114*d57664e9SAndroid Build Coastguard Worker template <std::integral T>
compare(T a,T b)115*d57664e9SAndroid Build Coastguard Worker int compare(T a, T b) {
116*d57664e9SAndroid Build Coastguard Worker   if (a < b) {
117*d57664e9SAndroid Build Coastguard Worker     return -1;
118*d57664e9SAndroid Build Coastguard Worker   } else if (a > b) {
119*d57664e9SAndroid Build Coastguard Worker     return 1;
120*d57664e9SAndroid Build Coastguard Worker   }
121*d57664e9SAndroid Build Coastguard Worker   return 0;
122*d57664e9SAndroid Build Coastguard Worker }
123*d57664e9SAndroid Build Coastguard Worker 
124*d57664e9SAndroid Build Coastguard Worker // Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
125*d57664e9SAndroid Build Coastguard Worker // This will be present in C++14 and can be removed then.
126*d57664e9SAndroid Build Coastguard Worker using std::make_unique;
127*d57664e9SAndroid Build Coastguard Worker 
128*d57664e9SAndroid Build Coastguard Worker // Writes a set of items to the std::ostream, joining the times with the provided separator.
129*d57664e9SAndroid Build Coastguard Worker template <typename Container>
Joiner(const Container & container,const char * sep)130*d57664e9SAndroid Build Coastguard Worker ::std::function<::std::ostream&(::std::ostream&)> Joiner(const Container& container,
131*d57664e9SAndroid Build Coastguard Worker                                                          const char* sep) {
132*d57664e9SAndroid Build Coastguard Worker   using std::begin;
133*d57664e9SAndroid Build Coastguard Worker   using std::end;
134*d57664e9SAndroid Build Coastguard Worker   const auto begin_iter = begin(container);
135*d57664e9SAndroid Build Coastguard Worker   const auto end_iter = end(container);
136*d57664e9SAndroid Build Coastguard Worker   return [begin_iter, end_iter, sep](::std::ostream& out) -> ::std::ostream& {
137*d57664e9SAndroid Build Coastguard Worker     for (auto iter = begin_iter; iter != end_iter; ++iter) {
138*d57664e9SAndroid Build Coastguard Worker       if (iter != begin_iter) {
139*d57664e9SAndroid Build Coastguard Worker         out << sep;
140*d57664e9SAndroid Build Coastguard Worker       }
141*d57664e9SAndroid Build Coastguard Worker       out << *iter;
142*d57664e9SAndroid Build Coastguard Worker     }
143*d57664e9SAndroid Build Coastguard Worker     return out;
144*d57664e9SAndroid Build Coastguard Worker   };
145*d57664e9SAndroid Build Coastguard Worker }
146*d57664e9SAndroid Build Coastguard Worker 
147*d57664e9SAndroid Build Coastguard Worker // Checks that the Java string format contains no non-positional arguments (arguments without
148*d57664e9SAndroid Build Coastguard Worker // explicitly specifying an index) when there are more than one argument. This is an error
149*d57664e9SAndroid Build Coastguard Worker // because translations may rearrange the order of the arguments in the string, which will
150*d57664e9SAndroid Build Coastguard Worker // break the string interpolation.
151*d57664e9SAndroid Build Coastguard Worker bool VerifyJavaStringFormat(android::StringPiece str);
152*d57664e9SAndroid Build Coastguard Worker 
153*d57664e9SAndroid Build Coastguard Worker bool AppendStyledString(android::StringPiece input, bool preserve_spaces, std::string* out_str,
154*d57664e9SAndroid Build Coastguard Worker                         std::string* out_error);
155*d57664e9SAndroid Build Coastguard Worker 
156*d57664e9SAndroid Build Coastguard Worker class StringBuilder {
157*d57664e9SAndroid Build Coastguard Worker  public:
158*d57664e9SAndroid Build Coastguard Worker   StringBuilder() = default;
159*d57664e9SAndroid Build Coastguard Worker 
160*d57664e9SAndroid Build Coastguard Worker   StringBuilder& Append(android::StringPiece str);
161*d57664e9SAndroid Build Coastguard Worker   const std::string& ToString() const;
162*d57664e9SAndroid Build Coastguard Worker   const std::string& Error() const;
163*d57664e9SAndroid Build Coastguard Worker   bool IsEmpty() const;
164*d57664e9SAndroid Build Coastguard Worker 
165*d57664e9SAndroid Build Coastguard Worker   // When building StyledStrings, we need UTF-16 indices into the string,
166*d57664e9SAndroid Build Coastguard Worker   // which is what the Java layer expects when dealing with java
167*d57664e9SAndroid Build Coastguard Worker   // String.charAt().
168*d57664e9SAndroid Build Coastguard Worker   size_t Utf16Len() const;
169*d57664e9SAndroid Build Coastguard Worker 
170*d57664e9SAndroid Build Coastguard Worker   explicit operator bool() const;
171*d57664e9SAndroid Build Coastguard Worker 
172*d57664e9SAndroid Build Coastguard Worker  private:
173*d57664e9SAndroid Build Coastguard Worker   std::string str_;
174*d57664e9SAndroid Build Coastguard Worker   size_t utf16_len_ = 0;
175*d57664e9SAndroid Build Coastguard Worker   bool quote_ = false;
176*d57664e9SAndroid Build Coastguard Worker   bool trailing_space_ = false;
177*d57664e9SAndroid Build Coastguard Worker   bool last_char_was_escape_ = false;
178*d57664e9SAndroid Build Coastguard Worker   std::string error_;
179*d57664e9SAndroid Build Coastguard Worker };
180*d57664e9SAndroid Build Coastguard Worker 
ToString()181*d57664e9SAndroid Build Coastguard Worker inline const std::string& StringBuilder::ToString() const {
182*d57664e9SAndroid Build Coastguard Worker   return str_;
183*d57664e9SAndroid Build Coastguard Worker }
184*d57664e9SAndroid Build Coastguard Worker 
Error()185*d57664e9SAndroid Build Coastguard Worker inline const std::string& StringBuilder::Error() const {
186*d57664e9SAndroid Build Coastguard Worker   return error_;
187*d57664e9SAndroid Build Coastguard Worker }
188*d57664e9SAndroid Build Coastguard Worker 
IsEmpty()189*d57664e9SAndroid Build Coastguard Worker inline bool StringBuilder::IsEmpty() const {
190*d57664e9SAndroid Build Coastguard Worker   return str_.empty();
191*d57664e9SAndroid Build Coastguard Worker }
192*d57664e9SAndroid Build Coastguard Worker 
Utf16Len()193*d57664e9SAndroid Build Coastguard Worker inline size_t StringBuilder::Utf16Len() const {
194*d57664e9SAndroid Build Coastguard Worker   return utf16_len_;
195*d57664e9SAndroid Build Coastguard Worker }
196*d57664e9SAndroid Build Coastguard Worker 
197*d57664e9SAndroid Build Coastguard Worker inline StringBuilder::operator bool() const {
198*d57664e9SAndroid Build Coastguard Worker   return error_.empty();
199*d57664e9SAndroid Build Coastguard Worker }
200*d57664e9SAndroid Build Coastguard Worker 
201*d57664e9SAndroid Build Coastguard Worker // Writes the entire BigBuffer to the output stream.
202*d57664e9SAndroid Build Coastguard Worker bool WriteAll(std::ostream& out, const android::BigBuffer& buffer);
203*d57664e9SAndroid Build Coastguard Worker 
204*d57664e9SAndroid Build Coastguard Worker // A Tokenizer implemented as an iterable collection. It does not allocate any memory on the heap
205*d57664e9SAndroid Build Coastguard Worker // nor use standard containers.
206*d57664e9SAndroid Build Coastguard Worker class Tokenizer {
207*d57664e9SAndroid Build Coastguard Worker  public:
208*d57664e9SAndroid Build Coastguard Worker   class iterator {
209*d57664e9SAndroid Build Coastguard Worker    public:
210*d57664e9SAndroid Build Coastguard Worker     using reference = android::StringPiece&;
211*d57664e9SAndroid Build Coastguard Worker     using value_type = android::StringPiece;
212*d57664e9SAndroid Build Coastguard Worker     using difference_type = size_t;
213*d57664e9SAndroid Build Coastguard Worker     using pointer = android::StringPiece*;
214*d57664e9SAndroid Build Coastguard Worker     using iterator_category = std::forward_iterator_tag;
215*d57664e9SAndroid Build Coastguard Worker 
216*d57664e9SAndroid Build Coastguard Worker     iterator(const iterator&) = default;
217*d57664e9SAndroid Build Coastguard Worker     iterator& operator=(const iterator&) = default;
218*d57664e9SAndroid Build Coastguard Worker 
219*d57664e9SAndroid Build Coastguard Worker     iterator& operator++();
220*d57664e9SAndroid Build Coastguard Worker 
221*d57664e9SAndroid Build Coastguard Worker     android::StringPiece operator*() { return token_; }
222*d57664e9SAndroid Build Coastguard Worker     bool operator==(const iterator& rhs) const;
223*d57664e9SAndroid Build Coastguard Worker     bool operator!=(const iterator& rhs) const;
224*d57664e9SAndroid Build Coastguard Worker 
225*d57664e9SAndroid Build Coastguard Worker    private:
226*d57664e9SAndroid Build Coastguard Worker     friend class Tokenizer;
227*d57664e9SAndroid Build Coastguard Worker 
228*d57664e9SAndroid Build Coastguard Worker     iterator(android::StringPiece s, char sep, android::StringPiece tok, bool end);
229*d57664e9SAndroid Build Coastguard Worker 
230*d57664e9SAndroid Build Coastguard Worker     android::StringPiece str_;
231*d57664e9SAndroid Build Coastguard Worker     char separator_;
232*d57664e9SAndroid Build Coastguard Worker     android::StringPiece token_;
233*d57664e9SAndroid Build Coastguard Worker     bool end_;
234*d57664e9SAndroid Build Coastguard Worker   };
235*d57664e9SAndroid Build Coastguard Worker 
236*d57664e9SAndroid Build Coastguard Worker   Tokenizer(android::StringPiece str, char sep);
237*d57664e9SAndroid Build Coastguard Worker 
begin()238*d57664e9SAndroid Build Coastguard Worker   iterator begin() const {
239*d57664e9SAndroid Build Coastguard Worker     return begin_;
240*d57664e9SAndroid Build Coastguard Worker   }
241*d57664e9SAndroid Build Coastguard Worker 
end()242*d57664e9SAndroid Build Coastguard Worker   iterator end() const {
243*d57664e9SAndroid Build Coastguard Worker     return end_;
244*d57664e9SAndroid Build Coastguard Worker   }
245*d57664e9SAndroid Build Coastguard Worker 
246*d57664e9SAndroid Build Coastguard Worker  private:
247*d57664e9SAndroid Build Coastguard Worker   const iterator begin_;
248*d57664e9SAndroid Build Coastguard Worker   const iterator end_;
249*d57664e9SAndroid Build Coastguard Worker };
250*d57664e9SAndroid Build Coastguard Worker 
Tokenize(android::StringPiece str,char sep)251*d57664e9SAndroid Build Coastguard Worker inline Tokenizer Tokenize(android::StringPiece str, char sep) {
252*d57664e9SAndroid Build Coastguard Worker   return Tokenizer(str, sep);
253*d57664e9SAndroid Build Coastguard Worker }
254*d57664e9SAndroid Build Coastguard Worker 
255*d57664e9SAndroid Build Coastguard Worker // Given a path like: res/xml-sw600dp/foo.xml
256*d57664e9SAndroid Build Coastguard Worker //
257*d57664e9SAndroid Build Coastguard Worker // Extracts "res/xml-sw600dp/" into outPrefix.
258*d57664e9SAndroid Build Coastguard Worker // Extracts "foo" into outEntry.
259*d57664e9SAndroid Build Coastguard Worker // Extracts ".xml" into outSuffix.
260*d57664e9SAndroid Build Coastguard Worker //
261*d57664e9SAndroid Build Coastguard Worker // Returns true if successful.
262*d57664e9SAndroid Build Coastguard Worker bool ExtractResFilePathParts(android::StringPiece path, android::StringPiece* out_prefix,
263*d57664e9SAndroid Build Coastguard Worker                              android::StringPiece* out_entry, android::StringPiece* out_suffix);
264*d57664e9SAndroid Build Coastguard Worker 
265*d57664e9SAndroid Build Coastguard Worker }  // namespace util
266*d57664e9SAndroid Build Coastguard Worker 
267*d57664e9SAndroid Build Coastguard Worker }  // namespace aapt
268*d57664e9SAndroid Build Coastguard Worker 
269*d57664e9SAndroid Build Coastguard Worker namespace std {
270*d57664e9SAndroid Build Coastguard Worker // Stream operator for functions. Calls the function with the stream as an argument.
271*d57664e9SAndroid Build Coastguard Worker // In the aapt namespace for lookup.
272*d57664e9SAndroid Build Coastguard Worker inline ::std::ostream& operator<<(::std::ostream& out,
273*d57664e9SAndroid Build Coastguard Worker                                   const ::std::function<::std::ostream&(::std::ostream&)>& f) {
274*d57664e9SAndroid Build Coastguard Worker   return f(out);
275*d57664e9SAndroid Build Coastguard Worker }
276*d57664e9SAndroid Build Coastguard Worker }  // namespace std
277*d57664e9SAndroid Build Coastguard Worker 
278*d57664e9SAndroid Build Coastguard Worker #endif  // AAPT_UTIL_H
279