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 #include "util/Util.h"
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
20*d57664e9SAndroid Build Coastguard Worker #include <ostream>
21*d57664e9SAndroid Build Coastguard Worker #include <string>
22*d57664e9SAndroid Build Coastguard Worker #include <vector>
23*d57664e9SAndroid Build Coastguard Worker
24*d57664e9SAndroid Build Coastguard Worker #include "android-base/parseint.h"
25*d57664e9SAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
26*d57664e9SAndroid Build Coastguard Worker #include "android-base/strings.h"
27*d57664e9SAndroid Build Coastguard Worker #include "androidfw/BigBuffer.h"
28*d57664e9SAndroid Build Coastguard Worker #include "androidfw/StringPiece.h"
29*d57664e9SAndroid Build Coastguard Worker #include "androidfw/Util.h"
30*d57664e9SAndroid Build Coastguard Worker #include "build/version.h"
31*d57664e9SAndroid Build Coastguard Worker #include "text/Unicode.h"
32*d57664e9SAndroid Build Coastguard Worker #include "text/Utf8Iterator.h"
33*d57664e9SAndroid Build Coastguard Worker #include "utils/Unicode.h"
34*d57664e9SAndroid Build Coastguard Worker
35*d57664e9SAndroid Build Coastguard Worker using ::aapt::text::Utf8Iterator;
36*d57664e9SAndroid Build Coastguard Worker using ::android::StringPiece;
37*d57664e9SAndroid Build Coastguard Worker using ::android::StringPiece16;
38*d57664e9SAndroid Build Coastguard Worker
39*d57664e9SAndroid Build Coastguard Worker namespace aapt {
40*d57664e9SAndroid Build Coastguard Worker namespace util {
41*d57664e9SAndroid Build Coastguard Worker
42*d57664e9SAndroid Build Coastguard Worker // Package name and shared user id would be used as a part of the file name.
43*d57664e9SAndroid Build Coastguard Worker // Limits size to 223 and reserves 32 for the OS.
44*d57664e9SAndroid Build Coastguard Worker // See frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
45*d57664e9SAndroid Build Coastguard Worker constexpr static const size_t kMaxPackageNameSize = 223;
46*d57664e9SAndroid Build Coastguard Worker
SplitAndTransform(StringPiece str,char sep,char (* f)(char))47*d57664e9SAndroid Build Coastguard Worker static std::vector<std::string> SplitAndTransform(StringPiece str, char sep, char (*f)(char)) {
48*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> parts;
49*d57664e9SAndroid Build Coastguard Worker const StringPiece::const_iterator end = std::end(str);
50*d57664e9SAndroid Build Coastguard Worker StringPiece::const_iterator start = std::begin(str);
51*d57664e9SAndroid Build Coastguard Worker StringPiece::const_iterator current;
52*d57664e9SAndroid Build Coastguard Worker do {
53*d57664e9SAndroid Build Coastguard Worker current = std::find(start, end, sep);
54*d57664e9SAndroid Build Coastguard Worker parts.emplace_back(start, current);
55*d57664e9SAndroid Build Coastguard Worker if (f) {
56*d57664e9SAndroid Build Coastguard Worker std::string& part = parts.back();
57*d57664e9SAndroid Build Coastguard Worker std::transform(part.begin(), part.end(), part.begin(), f);
58*d57664e9SAndroid Build Coastguard Worker }
59*d57664e9SAndroid Build Coastguard Worker start = current + 1;
60*d57664e9SAndroid Build Coastguard Worker } while (current != end);
61*d57664e9SAndroid Build Coastguard Worker return parts;
62*d57664e9SAndroid Build Coastguard Worker }
63*d57664e9SAndroid Build Coastguard Worker
Split(StringPiece str,char sep)64*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> Split(StringPiece str, char sep) {
65*d57664e9SAndroid Build Coastguard Worker return SplitAndTransform(str, sep, nullptr);
66*d57664e9SAndroid Build Coastguard Worker }
67*d57664e9SAndroid Build Coastguard Worker
SplitAndLowercase(StringPiece str,char sep)68*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> SplitAndLowercase(StringPiece str, char sep) {
69*d57664e9SAndroid Build Coastguard Worker return SplitAndTransform(str, sep, [](char c) -> char { return ::tolower(c); });
70*d57664e9SAndroid Build Coastguard Worker }
71*d57664e9SAndroid Build Coastguard Worker
StartsWith(StringPiece str,StringPiece prefix)72*d57664e9SAndroid Build Coastguard Worker bool StartsWith(StringPiece str, StringPiece prefix) {
73*d57664e9SAndroid Build Coastguard Worker if (str.size() < prefix.size()) {
74*d57664e9SAndroid Build Coastguard Worker return false;
75*d57664e9SAndroid Build Coastguard Worker }
76*d57664e9SAndroid Build Coastguard Worker return str.substr(0, prefix.size()) == prefix;
77*d57664e9SAndroid Build Coastguard Worker }
78*d57664e9SAndroid Build Coastguard Worker
EndsWith(StringPiece str,StringPiece suffix)79*d57664e9SAndroid Build Coastguard Worker bool EndsWith(StringPiece str, StringPiece suffix) {
80*d57664e9SAndroid Build Coastguard Worker if (str.size() < suffix.size()) {
81*d57664e9SAndroid Build Coastguard Worker return false;
82*d57664e9SAndroid Build Coastguard Worker }
83*d57664e9SAndroid Build Coastguard Worker return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
84*d57664e9SAndroid Build Coastguard Worker }
85*d57664e9SAndroid Build Coastguard Worker
TrimLeadingWhitespace(StringPiece str)86*d57664e9SAndroid Build Coastguard Worker StringPiece TrimLeadingWhitespace(StringPiece str) {
87*d57664e9SAndroid Build Coastguard Worker if (str.size() == 0 || str.data() == nullptr) {
88*d57664e9SAndroid Build Coastguard Worker return str;
89*d57664e9SAndroid Build Coastguard Worker }
90*d57664e9SAndroid Build Coastguard Worker
91*d57664e9SAndroid Build Coastguard Worker const char* start = str.data();
92*d57664e9SAndroid Build Coastguard Worker const char* end = start + str.length();
93*d57664e9SAndroid Build Coastguard Worker
94*d57664e9SAndroid Build Coastguard Worker while (start != end && isspace(*start)) {
95*d57664e9SAndroid Build Coastguard Worker start++;
96*d57664e9SAndroid Build Coastguard Worker }
97*d57664e9SAndroid Build Coastguard Worker return StringPiece(start, end - start);
98*d57664e9SAndroid Build Coastguard Worker }
99*d57664e9SAndroid Build Coastguard Worker
TrimTrailingWhitespace(StringPiece str)100*d57664e9SAndroid Build Coastguard Worker StringPiece TrimTrailingWhitespace(StringPiece str) {
101*d57664e9SAndroid Build Coastguard Worker if (str.size() == 0 || str.data() == nullptr) {
102*d57664e9SAndroid Build Coastguard Worker return str;
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker
105*d57664e9SAndroid Build Coastguard Worker const char* start = str.data();
106*d57664e9SAndroid Build Coastguard Worker const char* end = start + str.length();
107*d57664e9SAndroid Build Coastguard Worker
108*d57664e9SAndroid Build Coastguard Worker while (end != start && isspace(*(end - 1))) {
109*d57664e9SAndroid Build Coastguard Worker end--;
110*d57664e9SAndroid Build Coastguard Worker }
111*d57664e9SAndroid Build Coastguard Worker return StringPiece(start, end - start);
112*d57664e9SAndroid Build Coastguard Worker }
113*d57664e9SAndroid Build Coastguard Worker
TrimWhitespace(StringPiece str)114*d57664e9SAndroid Build Coastguard Worker StringPiece TrimWhitespace(StringPiece str) {
115*d57664e9SAndroid Build Coastguard Worker if (str.size() == 0 || str.data() == nullptr) {
116*d57664e9SAndroid Build Coastguard Worker return str;
117*d57664e9SAndroid Build Coastguard Worker }
118*d57664e9SAndroid Build Coastguard Worker
119*d57664e9SAndroid Build Coastguard Worker const char* start = str.data();
120*d57664e9SAndroid Build Coastguard Worker const char* end = str.data() + str.length();
121*d57664e9SAndroid Build Coastguard Worker
122*d57664e9SAndroid Build Coastguard Worker while (start != end && isspace(*start)) {
123*d57664e9SAndroid Build Coastguard Worker start++;
124*d57664e9SAndroid Build Coastguard Worker }
125*d57664e9SAndroid Build Coastguard Worker
126*d57664e9SAndroid Build Coastguard Worker while (end != start && isspace(*(end - 1))) {
127*d57664e9SAndroid Build Coastguard Worker end--;
128*d57664e9SAndroid Build Coastguard Worker }
129*d57664e9SAndroid Build Coastguard Worker
130*d57664e9SAndroid Build Coastguard Worker return StringPiece(start, end - start);
131*d57664e9SAndroid Build Coastguard Worker }
132*d57664e9SAndroid Build Coastguard Worker
IsJavaNameImpl(StringPiece str)133*d57664e9SAndroid Build Coastguard Worker static int IsJavaNameImpl(StringPiece str) {
134*d57664e9SAndroid Build Coastguard Worker int pieces = 0;
135*d57664e9SAndroid Build Coastguard Worker for (StringPiece piece : Tokenize(str, '.')) {
136*d57664e9SAndroid Build Coastguard Worker pieces++;
137*d57664e9SAndroid Build Coastguard Worker if (!text::IsJavaIdentifier(piece)) {
138*d57664e9SAndroid Build Coastguard Worker return -1;
139*d57664e9SAndroid Build Coastguard Worker }
140*d57664e9SAndroid Build Coastguard Worker }
141*d57664e9SAndroid Build Coastguard Worker return pieces;
142*d57664e9SAndroid Build Coastguard Worker }
143*d57664e9SAndroid Build Coastguard Worker
IsJavaClassName(StringPiece str)144*d57664e9SAndroid Build Coastguard Worker bool IsJavaClassName(StringPiece str) {
145*d57664e9SAndroid Build Coastguard Worker return IsJavaNameImpl(str) >= 2;
146*d57664e9SAndroid Build Coastguard Worker }
147*d57664e9SAndroid Build Coastguard Worker
IsJavaPackageName(StringPiece str)148*d57664e9SAndroid Build Coastguard Worker bool IsJavaPackageName(StringPiece str) {
149*d57664e9SAndroid Build Coastguard Worker return IsJavaNameImpl(str) >= 1;
150*d57664e9SAndroid Build Coastguard Worker }
151*d57664e9SAndroid Build Coastguard Worker
IsAndroidNameImpl(StringPiece str)152*d57664e9SAndroid Build Coastguard Worker static int IsAndroidNameImpl(StringPiece str) {
153*d57664e9SAndroid Build Coastguard Worker int pieces = 0;
154*d57664e9SAndroid Build Coastguard Worker for (StringPiece piece : Tokenize(str, '.')) {
155*d57664e9SAndroid Build Coastguard Worker if (piece.empty()) {
156*d57664e9SAndroid Build Coastguard Worker return -1;
157*d57664e9SAndroid Build Coastguard Worker }
158*d57664e9SAndroid Build Coastguard Worker
159*d57664e9SAndroid Build Coastguard Worker const char first_character = piece.data()[0];
160*d57664e9SAndroid Build Coastguard Worker if (!::isalpha(first_character)) {
161*d57664e9SAndroid Build Coastguard Worker return -1;
162*d57664e9SAndroid Build Coastguard Worker }
163*d57664e9SAndroid Build Coastguard Worker
164*d57664e9SAndroid Build Coastguard Worker bool valid = std::all_of(piece.begin() + 1, piece.end(), [](const char c) -> bool {
165*d57664e9SAndroid Build Coastguard Worker return ::isalnum(c) || c == '_';
166*d57664e9SAndroid Build Coastguard Worker });
167*d57664e9SAndroid Build Coastguard Worker
168*d57664e9SAndroid Build Coastguard Worker if (!valid) {
169*d57664e9SAndroid Build Coastguard Worker return -1;
170*d57664e9SAndroid Build Coastguard Worker }
171*d57664e9SAndroid Build Coastguard Worker pieces++;
172*d57664e9SAndroid Build Coastguard Worker }
173*d57664e9SAndroid Build Coastguard Worker return pieces;
174*d57664e9SAndroid Build Coastguard Worker }
175*d57664e9SAndroid Build Coastguard Worker
IsAndroidPackageName(StringPiece str)176*d57664e9SAndroid Build Coastguard Worker bool IsAndroidPackageName(StringPiece str) {
177*d57664e9SAndroid Build Coastguard Worker if (str.size() > kMaxPackageNameSize) {
178*d57664e9SAndroid Build Coastguard Worker return false;
179*d57664e9SAndroid Build Coastguard Worker }
180*d57664e9SAndroid Build Coastguard Worker return IsAndroidNameImpl(str) > 1 || str == "android";
181*d57664e9SAndroid Build Coastguard Worker }
182*d57664e9SAndroid Build Coastguard Worker
IsAndroidSharedUserId(android::StringPiece package_name,android::StringPiece shared_user_id)183*d57664e9SAndroid Build Coastguard Worker bool IsAndroidSharedUserId(android::StringPiece package_name, android::StringPiece shared_user_id) {
184*d57664e9SAndroid Build Coastguard Worker if (shared_user_id.size() > kMaxPackageNameSize) {
185*d57664e9SAndroid Build Coastguard Worker return false;
186*d57664e9SAndroid Build Coastguard Worker }
187*d57664e9SAndroid Build Coastguard Worker return shared_user_id.empty() || IsAndroidNameImpl(shared_user_id) > 1 ||
188*d57664e9SAndroid Build Coastguard Worker package_name == "android";
189*d57664e9SAndroid Build Coastguard Worker }
190*d57664e9SAndroid Build Coastguard Worker
IsAndroidSplitName(StringPiece str)191*d57664e9SAndroid Build Coastguard Worker bool IsAndroidSplitName(StringPiece str) {
192*d57664e9SAndroid Build Coastguard Worker return IsAndroidNameImpl(str) > 0;
193*d57664e9SAndroid Build Coastguard Worker }
194*d57664e9SAndroid Build Coastguard Worker
GetFullyQualifiedClassName(StringPiece package,StringPiece classname)195*d57664e9SAndroid Build Coastguard Worker std::optional<std::string> GetFullyQualifiedClassName(StringPiece package, StringPiece classname) {
196*d57664e9SAndroid Build Coastguard Worker if (classname.empty()) {
197*d57664e9SAndroid Build Coastguard Worker return {};
198*d57664e9SAndroid Build Coastguard Worker }
199*d57664e9SAndroid Build Coastguard Worker
200*d57664e9SAndroid Build Coastguard Worker if (util::IsJavaClassName(classname)) {
201*d57664e9SAndroid Build Coastguard Worker return std::string(classname);
202*d57664e9SAndroid Build Coastguard Worker }
203*d57664e9SAndroid Build Coastguard Worker
204*d57664e9SAndroid Build Coastguard Worker if (package.empty()) {
205*d57664e9SAndroid Build Coastguard Worker return {};
206*d57664e9SAndroid Build Coastguard Worker }
207*d57664e9SAndroid Build Coastguard Worker
208*d57664e9SAndroid Build Coastguard Worker std::string result{package};
209*d57664e9SAndroid Build Coastguard Worker if (classname.data()[0] != '.') {
210*d57664e9SAndroid Build Coastguard Worker result += '.';
211*d57664e9SAndroid Build Coastguard Worker }
212*d57664e9SAndroid Build Coastguard Worker
213*d57664e9SAndroid Build Coastguard Worker result.append(classname.data(), classname.size());
214*d57664e9SAndroid Build Coastguard Worker if (!IsJavaClassName(result)) {
215*d57664e9SAndroid Build Coastguard Worker return {};
216*d57664e9SAndroid Build Coastguard Worker }
217*d57664e9SAndroid Build Coastguard Worker return result;
218*d57664e9SAndroid Build Coastguard Worker }
219*d57664e9SAndroid Build Coastguard Worker
GetToolName()220*d57664e9SAndroid Build Coastguard Worker const char* GetToolName() {
221*d57664e9SAndroid Build Coastguard Worker static const char* const sToolName = "Android Asset Packaging Tool (aapt)";
222*d57664e9SAndroid Build Coastguard Worker return sToolName;
223*d57664e9SAndroid Build Coastguard Worker }
224*d57664e9SAndroid Build Coastguard Worker
GetToolFingerprint()225*d57664e9SAndroid Build Coastguard Worker std::string GetToolFingerprint() {
226*d57664e9SAndroid Build Coastguard Worker // DO NOT UPDATE, this is more of a marketing version.
227*d57664e9SAndroid Build Coastguard Worker static const char* const sMajorVersion = "2";
228*d57664e9SAndroid Build Coastguard Worker
229*d57664e9SAndroid Build Coastguard Worker // Update minor version whenever a feature or flag is added.
230*d57664e9SAndroid Build Coastguard Worker static const char* const sMinorVersion = "19";
231*d57664e9SAndroid Build Coastguard Worker
232*d57664e9SAndroid Build Coastguard Worker // The build id of aapt2 binary.
233*d57664e9SAndroid Build Coastguard Worker static const std::string sBuildId = [] {
234*d57664e9SAndroid Build Coastguard Worker std::string buildNumber = android::build::GetBuildNumber();
235*d57664e9SAndroid Build Coastguard Worker
236*d57664e9SAndroid Build Coastguard Worker if (android::base::StartsWith(buildNumber, "eng.")) {
237*d57664e9SAndroid Build Coastguard Worker // android::build::GetBuildNumber() returns something like "eng.user.20230725.214219" where
238*d57664e9SAndroid Build Coastguard Worker // the latter two parts are "yyyyMMdd.HHmmss" at build time. Use "yyyyMM" in the fingerprint.
239*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> parts = util::Split(buildNumber, '.');
240*d57664e9SAndroid Build Coastguard Worker int buildYear;
241*d57664e9SAndroid Build Coastguard Worker int buildMonth;
242*d57664e9SAndroid Build Coastguard Worker if (parts.size() < 3 || parts[2].length() < 6 ||
243*d57664e9SAndroid Build Coastguard Worker !android::base::ParseInt(parts[2].substr(0, 4), &buildYear) ||
244*d57664e9SAndroid Build Coastguard Worker !android::base::ParseInt(parts[2].substr(4, 2), &buildMonth)) {
245*d57664e9SAndroid Build Coastguard Worker // Fallback to localtime() if GetBuildNumber() returns an unexpected output.
246*d57664e9SAndroid Build Coastguard Worker time_t now = time(0);
247*d57664e9SAndroid Build Coastguard Worker tm* ltm = localtime(&now);
248*d57664e9SAndroid Build Coastguard Worker buildYear = 1900 + ltm->tm_year;
249*d57664e9SAndroid Build Coastguard Worker buildMonth = 1 + ltm->tm_mon;
250*d57664e9SAndroid Build Coastguard Worker }
251*d57664e9SAndroid Build Coastguard Worker
252*d57664e9SAndroid Build Coastguard Worker buildNumber = android::base::StringPrintf("eng.%04d%02d", buildYear, buildMonth);
253*d57664e9SAndroid Build Coastguard Worker }
254*d57664e9SAndroid Build Coastguard Worker return buildNumber;
255*d57664e9SAndroid Build Coastguard Worker }();
256*d57664e9SAndroid Build Coastguard Worker
257*d57664e9SAndroid Build Coastguard Worker return android::base::StringPrintf("%s.%s-%s", sMajorVersion, sMinorVersion, sBuildId.c_str());
258*d57664e9SAndroid Build Coastguard Worker }
259*d57664e9SAndroid Build Coastguard Worker
ConsumeDigits(const char * start,const char * end)260*d57664e9SAndroid Build Coastguard Worker static size_t ConsumeDigits(const char* start, const char* end) {
261*d57664e9SAndroid Build Coastguard Worker const char* c = start;
262*d57664e9SAndroid Build Coastguard Worker for (; c != end && *c >= '0' && *c <= '9'; c++) {
263*d57664e9SAndroid Build Coastguard Worker }
264*d57664e9SAndroid Build Coastguard Worker return static_cast<size_t>(c - start);
265*d57664e9SAndroid Build Coastguard Worker }
266*d57664e9SAndroid Build Coastguard Worker
VerifyJavaStringFormat(StringPiece str)267*d57664e9SAndroid Build Coastguard Worker bool VerifyJavaStringFormat(StringPiece str) {
268*d57664e9SAndroid Build Coastguard Worker const char* c = str.begin();
269*d57664e9SAndroid Build Coastguard Worker const char* const end = str.end();
270*d57664e9SAndroid Build Coastguard Worker
271*d57664e9SAndroid Build Coastguard Worker size_t arg_count = 0;
272*d57664e9SAndroid Build Coastguard Worker bool nonpositional = false;
273*d57664e9SAndroid Build Coastguard Worker while (c != end) {
274*d57664e9SAndroid Build Coastguard Worker if (*c == '%' && c + 1 < end) {
275*d57664e9SAndroid Build Coastguard Worker c++;
276*d57664e9SAndroid Build Coastguard Worker
277*d57664e9SAndroid Build Coastguard Worker if (*c == '%' || *c == 'n') {
278*d57664e9SAndroid Build Coastguard Worker c++;
279*d57664e9SAndroid Build Coastguard Worker continue;
280*d57664e9SAndroid Build Coastguard Worker }
281*d57664e9SAndroid Build Coastguard Worker
282*d57664e9SAndroid Build Coastguard Worker arg_count++;
283*d57664e9SAndroid Build Coastguard Worker
284*d57664e9SAndroid Build Coastguard Worker size_t num_digits = ConsumeDigits(c, end);
285*d57664e9SAndroid Build Coastguard Worker if (num_digits > 0) {
286*d57664e9SAndroid Build Coastguard Worker c += num_digits;
287*d57664e9SAndroid Build Coastguard Worker if (c != end && *c != '$') {
288*d57664e9SAndroid Build Coastguard Worker // The digits were a size, but not a positional argument.
289*d57664e9SAndroid Build Coastguard Worker nonpositional = true;
290*d57664e9SAndroid Build Coastguard Worker }
291*d57664e9SAndroid Build Coastguard Worker } else if (*c == '<') {
292*d57664e9SAndroid Build Coastguard Worker // Reusing last argument, bad idea since positions can be moved around
293*d57664e9SAndroid Build Coastguard Worker // during translation.
294*d57664e9SAndroid Build Coastguard Worker nonpositional = true;
295*d57664e9SAndroid Build Coastguard Worker
296*d57664e9SAndroid Build Coastguard Worker c++;
297*d57664e9SAndroid Build Coastguard Worker
298*d57664e9SAndroid Build Coastguard Worker // Optionally we can have a $ after
299*d57664e9SAndroid Build Coastguard Worker if (c != end && *c == '$') {
300*d57664e9SAndroid Build Coastguard Worker c++;
301*d57664e9SAndroid Build Coastguard Worker }
302*d57664e9SAndroid Build Coastguard Worker } else {
303*d57664e9SAndroid Build Coastguard Worker nonpositional = true;
304*d57664e9SAndroid Build Coastguard Worker }
305*d57664e9SAndroid Build Coastguard Worker
306*d57664e9SAndroid Build Coastguard Worker // Ignore size, width, flags, etc.
307*d57664e9SAndroid Build Coastguard Worker while (c != end && (*c == '-' || *c == '#' || *c == '+' || *c == ' ' ||
308*d57664e9SAndroid Build Coastguard Worker *c == ',' || *c == '(' || (*c >= '0' && *c <= '9'))) {
309*d57664e9SAndroid Build Coastguard Worker c++;
310*d57664e9SAndroid Build Coastguard Worker }
311*d57664e9SAndroid Build Coastguard Worker
312*d57664e9SAndroid Build Coastguard Worker /*
313*d57664e9SAndroid Build Coastguard Worker * This is a shortcut to detect strings that are going to Time.format()
314*d57664e9SAndroid Build Coastguard Worker * instead of String.format()
315*d57664e9SAndroid Build Coastguard Worker *
316*d57664e9SAndroid Build Coastguard Worker * Comparison of String.format() and Time.format() args:
317*d57664e9SAndroid Build Coastguard Worker *
318*d57664e9SAndroid Build Coastguard Worker * String: ABC E GH ST X abcdefgh nost x
319*d57664e9SAndroid Build Coastguard Worker * Time: DEFGHKMS W Za d hkm s w yz
320*d57664e9SAndroid Build Coastguard Worker *
321*d57664e9SAndroid Build Coastguard Worker * Therefore we know it's definitely Time if we have:
322*d57664e9SAndroid Build Coastguard Worker * DFKMWZkmwyz
323*d57664e9SAndroid Build Coastguard Worker */
324*d57664e9SAndroid Build Coastguard Worker if (c != end) {
325*d57664e9SAndroid Build Coastguard Worker switch (*c) {
326*d57664e9SAndroid Build Coastguard Worker case 'D':
327*d57664e9SAndroid Build Coastguard Worker case 'F':
328*d57664e9SAndroid Build Coastguard Worker case 'K':
329*d57664e9SAndroid Build Coastguard Worker case 'M':
330*d57664e9SAndroid Build Coastguard Worker case 'W':
331*d57664e9SAndroid Build Coastguard Worker case 'Z':
332*d57664e9SAndroid Build Coastguard Worker case 'k':
333*d57664e9SAndroid Build Coastguard Worker case 'm':
334*d57664e9SAndroid Build Coastguard Worker case 'w':
335*d57664e9SAndroid Build Coastguard Worker case 'y':
336*d57664e9SAndroid Build Coastguard Worker case 'z':
337*d57664e9SAndroid Build Coastguard Worker return true;
338*d57664e9SAndroid Build Coastguard Worker }
339*d57664e9SAndroid Build Coastguard Worker }
340*d57664e9SAndroid Build Coastguard Worker }
341*d57664e9SAndroid Build Coastguard Worker
342*d57664e9SAndroid Build Coastguard Worker if (c != end) {
343*d57664e9SAndroid Build Coastguard Worker c++;
344*d57664e9SAndroid Build Coastguard Worker }
345*d57664e9SAndroid Build Coastguard Worker }
346*d57664e9SAndroid Build Coastguard Worker
347*d57664e9SAndroid Build Coastguard Worker if (arg_count > 1 && nonpositional) {
348*d57664e9SAndroid Build Coastguard Worker // Multiple arguments were specified, but some or all were non positional.
349*d57664e9SAndroid Build Coastguard Worker // Translated
350*d57664e9SAndroid Build Coastguard Worker // strings may rearrange the order of the arguments, which will break the
351*d57664e9SAndroid Build Coastguard Worker // string.
352*d57664e9SAndroid Build Coastguard Worker return false;
353*d57664e9SAndroid Build Coastguard Worker }
354*d57664e9SAndroid Build Coastguard Worker return true;
355*d57664e9SAndroid Build Coastguard Worker }
356*d57664e9SAndroid Build Coastguard Worker
Utf8ToUtf16(StringPiece utf8)357*d57664e9SAndroid Build Coastguard Worker std::u16string Utf8ToUtf16(StringPiece utf8) {
358*d57664e9SAndroid Build Coastguard Worker ssize_t utf16_length = utf8_to_utf16_length(
359*d57664e9SAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
360*d57664e9SAndroid Build Coastguard Worker if (utf16_length <= 0) {
361*d57664e9SAndroid Build Coastguard Worker return {};
362*d57664e9SAndroid Build Coastguard Worker }
363*d57664e9SAndroid Build Coastguard Worker
364*d57664e9SAndroid Build Coastguard Worker std::u16string utf16;
365*d57664e9SAndroid Build Coastguard Worker utf16.resize(utf16_length);
366*d57664e9SAndroid Build Coastguard Worker utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length(),
367*d57664e9SAndroid Build Coastguard Worker &*utf16.begin(), utf16_length + 1);
368*d57664e9SAndroid Build Coastguard Worker return utf16;
369*d57664e9SAndroid Build Coastguard Worker }
370*d57664e9SAndroid Build Coastguard Worker
Utf16ToUtf8(const StringPiece16 & utf16)371*d57664e9SAndroid Build Coastguard Worker std::string Utf16ToUtf8(const StringPiece16& utf16) {
372*d57664e9SAndroid Build Coastguard Worker ssize_t utf8_length = utf16_to_utf8_length(utf16.data(), utf16.length());
373*d57664e9SAndroid Build Coastguard Worker if (utf8_length <= 0) {
374*d57664e9SAndroid Build Coastguard Worker return {};
375*d57664e9SAndroid Build Coastguard Worker }
376*d57664e9SAndroid Build Coastguard Worker
377*d57664e9SAndroid Build Coastguard Worker std::string utf8;
378*d57664e9SAndroid Build Coastguard Worker utf8.resize(utf8_length);
379*d57664e9SAndroid Build Coastguard Worker utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin(), utf8_length + 1);
380*d57664e9SAndroid Build Coastguard Worker return utf8;
381*d57664e9SAndroid Build Coastguard Worker }
382*d57664e9SAndroid Build Coastguard Worker
WriteAll(std::ostream & out,const android::BigBuffer & buffer)383*d57664e9SAndroid Build Coastguard Worker bool WriteAll(std::ostream& out, const android::BigBuffer& buffer) {
384*d57664e9SAndroid Build Coastguard Worker for (const auto& b : buffer) {
385*d57664e9SAndroid Build Coastguard Worker if (!out.write(reinterpret_cast<const char*>(b.buffer.get()), b.size)) {
386*d57664e9SAndroid Build Coastguard Worker return false;
387*d57664e9SAndroid Build Coastguard Worker }
388*d57664e9SAndroid Build Coastguard Worker }
389*d57664e9SAndroid Build Coastguard Worker return true;
390*d57664e9SAndroid Build Coastguard Worker }
391*d57664e9SAndroid Build Coastguard Worker
operator ++()392*d57664e9SAndroid Build Coastguard Worker typename Tokenizer::iterator& Tokenizer::iterator::operator++() {
393*d57664e9SAndroid Build Coastguard Worker const char* start = token_.end();
394*d57664e9SAndroid Build Coastguard Worker const char* end = str_.end();
395*d57664e9SAndroid Build Coastguard Worker if (start == end) {
396*d57664e9SAndroid Build Coastguard Worker end_ = true;
397*d57664e9SAndroid Build Coastguard Worker token_ = StringPiece(token_.end(), 0);
398*d57664e9SAndroid Build Coastguard Worker return *this;
399*d57664e9SAndroid Build Coastguard Worker }
400*d57664e9SAndroid Build Coastguard Worker
401*d57664e9SAndroid Build Coastguard Worker start += 1;
402*d57664e9SAndroid Build Coastguard Worker const char* current = start;
403*d57664e9SAndroid Build Coastguard Worker while (current != end) {
404*d57664e9SAndroid Build Coastguard Worker if (*current == separator_) {
405*d57664e9SAndroid Build Coastguard Worker token_ = StringPiece(start, current - start);
406*d57664e9SAndroid Build Coastguard Worker return *this;
407*d57664e9SAndroid Build Coastguard Worker }
408*d57664e9SAndroid Build Coastguard Worker ++current;
409*d57664e9SAndroid Build Coastguard Worker }
410*d57664e9SAndroid Build Coastguard Worker token_ = StringPiece(start, end - start);
411*d57664e9SAndroid Build Coastguard Worker return *this;
412*d57664e9SAndroid Build Coastguard Worker }
413*d57664e9SAndroid Build Coastguard Worker
operator ==(const iterator & rhs) const414*d57664e9SAndroid Build Coastguard Worker bool Tokenizer::iterator::operator==(const iterator& rhs) const {
415*d57664e9SAndroid Build Coastguard Worker // We check equality here a bit differently.
416*d57664e9SAndroid Build Coastguard Worker // We need to know that the addresses are the same.
417*d57664e9SAndroid Build Coastguard Worker return token_.begin() == rhs.token_.begin() &&
418*d57664e9SAndroid Build Coastguard Worker token_.end() == rhs.token_.end() && end_ == rhs.end_;
419*d57664e9SAndroid Build Coastguard Worker }
420*d57664e9SAndroid Build Coastguard Worker
operator !=(const iterator & rhs) const421*d57664e9SAndroid Build Coastguard Worker bool Tokenizer::iterator::operator!=(const iterator& rhs) const {
422*d57664e9SAndroid Build Coastguard Worker return !(*this == rhs);
423*d57664e9SAndroid Build Coastguard Worker }
424*d57664e9SAndroid Build Coastguard Worker
iterator(StringPiece s,char sep,StringPiece tok,bool end)425*d57664e9SAndroid Build Coastguard Worker Tokenizer::iterator::iterator(StringPiece s, char sep, StringPiece tok, bool end)
426*d57664e9SAndroid Build Coastguard Worker : str_(s), separator_(sep), token_(tok), end_(end) {
427*d57664e9SAndroid Build Coastguard Worker }
428*d57664e9SAndroid Build Coastguard Worker
Tokenizer(StringPiece str,char sep)429*d57664e9SAndroid Build Coastguard Worker Tokenizer::Tokenizer(StringPiece str, char sep)
430*d57664e9SAndroid Build Coastguard Worker : begin_(++iterator(str, sep, StringPiece(str.begin() - 1, 0), false)),
431*d57664e9SAndroid Build Coastguard Worker end_(str, sep, StringPiece(str.end(), 0), true) {
432*d57664e9SAndroid Build Coastguard Worker }
433*d57664e9SAndroid Build Coastguard Worker
ExtractResFilePathParts(StringPiece path,StringPiece * out_prefix,StringPiece * out_entry,StringPiece * out_suffix)434*d57664e9SAndroid Build Coastguard Worker bool ExtractResFilePathParts(StringPiece path, StringPiece* out_prefix, StringPiece* out_entry,
435*d57664e9SAndroid Build Coastguard Worker StringPiece* out_suffix) {
436*d57664e9SAndroid Build Coastguard Worker const StringPiece res_prefix("res/");
437*d57664e9SAndroid Build Coastguard Worker if (!StartsWith(path, res_prefix)) {
438*d57664e9SAndroid Build Coastguard Worker return false;
439*d57664e9SAndroid Build Coastguard Worker }
440*d57664e9SAndroid Build Coastguard Worker
441*d57664e9SAndroid Build Coastguard Worker StringPiece::const_iterator last_occurence = path.end();
442*d57664e9SAndroid Build Coastguard Worker for (auto iter = path.begin() + res_prefix.size(); iter != path.end();
443*d57664e9SAndroid Build Coastguard Worker ++iter) {
444*d57664e9SAndroid Build Coastguard Worker if (*iter == '/') {
445*d57664e9SAndroid Build Coastguard Worker last_occurence = iter;
446*d57664e9SAndroid Build Coastguard Worker }
447*d57664e9SAndroid Build Coastguard Worker }
448*d57664e9SAndroid Build Coastguard Worker
449*d57664e9SAndroid Build Coastguard Worker if (last_occurence == path.end()) {
450*d57664e9SAndroid Build Coastguard Worker return false;
451*d57664e9SAndroid Build Coastguard Worker }
452*d57664e9SAndroid Build Coastguard Worker
453*d57664e9SAndroid Build Coastguard Worker auto iter = std::find(last_occurence, path.end(), '.');
454*d57664e9SAndroid Build Coastguard Worker *out_suffix = StringPiece(iter, path.end() - iter);
455*d57664e9SAndroid Build Coastguard Worker *out_entry = StringPiece(last_occurence + 1, iter - last_occurence - 1);
456*d57664e9SAndroid Build Coastguard Worker *out_prefix = StringPiece(path.begin(), last_occurence - path.begin() + 1);
457*d57664e9SAndroid Build Coastguard Worker return true;
458*d57664e9SAndroid Build Coastguard Worker }
459*d57664e9SAndroid Build Coastguard Worker
460*d57664e9SAndroid Build Coastguard Worker } // namespace util
461*d57664e9SAndroid Build Coastguard Worker } // namespace aapt
462