blob: 9c88354dfaf119421cfe79810b5c43b10c158be6 [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef AAPT_UTIL_H
18#define AAPT_UTIL_H
19
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "util/BigBuffer.h"
21#include "util/Maybe.h"
22#include "util/StringPiece.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080023
24#include <androidfw/ResourceTypes.h>
25#include <functional>
26#include <memory>
27#include <ostream>
28#include <string>
29#include <vector>
30
31namespace aapt {
32namespace util {
33
34std::vector<std::string> split(const StringPiece& str, char sep);
35std::vector<std::string> splitAndLowercase(const StringPiece& str, char sep);
36
37/**
Adam Lesinski4d3a9872015-04-09 19:53:22 -070038 * Returns true if the string starts with prefix.
39 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070040bool stringStartsWith(const StringPiece& str, const StringPiece& prefix);
Adam Lesinski4d3a9872015-04-09 19:53:22 -070041
42/**
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080043 * Returns true if the string ends with suffix.
44 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070045bool stringEndsWith(const StringPiece& str, const StringPiece& suffix);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080046
47/**
48 * Creates a new StringPiece16 that points to a substring
49 * of the original string without leading or trailing whitespace.
50 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070051StringPiece trimWhitespace(const StringPiece& str);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080052
Adam Lesinski3b4cd942015-10-30 16:31:42 -070053StringPiece trimWhitespace(const StringPiece& str);
54
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080055/**
56 * UTF-16 isspace(). It basically checks for lower range characters that are
57 * whitespace.
58 */
59inline bool isspace16(char16_t c) {
60 return c < 0x0080 && isspace(c);
61}
62
63/**
64 * Returns an iterator to the first character that is not alpha-numeric and that
65 * is not in the allowedChars set.
66 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070067StringPiece::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece& str,
68 const StringPiece& allowedChars);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080069
70/**
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070071 * Tests that the string is a valid Java class name.
72 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070073bool isJavaClassName(const StringPiece& str);
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070074
75/**
Adam Lesinski1ab598f2015-08-14 14:26:04 -070076 * Tests that the string is a valid Java package name.
77 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070078bool isJavaPackageName(const StringPiece& str);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070079
80/**
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070081 * Converts the class name to a fully qualified class name from the given `package`. Ex:
82 *
83 * asdf --> package.asdf
84 * .asdf --> package.asdf
85 * .a.b --> package.a.b
86 * asdf.adsf --> asdf.adsf
87 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070088Maybe<std::string> getFullyQualifiedClassName(const StringPiece& package,
89 const StringPiece& className);
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070090
91/**
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080092 * Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
93 * This will be present in C++14 and can be removed then.
94 */
95template <typename T, class... Args>
96std::unique_ptr<T> make_unique(Args&&... args) {
97 return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
98}
99
100/**
101 * Writes a set of items to the std::ostream, joining the times with the provided
102 * separator.
103 */
Adam Lesinski36c73a52016-08-11 13:39:24 -0700104template <typename Container>
105::std::function<::std::ostream&(::std::ostream&)> joiner(const Container& container,
106 const char* sep) {
107 using std::begin;
108 using std::end;
109 const auto beginIter = begin(container);
110 const auto endIter = end(container);
111 return [beginIter, endIter, sep](::std::ostream& out) -> ::std::ostream& {
112 for (auto iter = beginIter; iter != endIter; ++iter) {
113 if (iter != beginIter) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114 out << sep;
115 }
116 out << *iter;
117 }
118 return out;
119 };
120}
121
122inline ::std::function<::std::ostream&(::std::ostream&)> formatSize(size_t size) {
123 return [size](::std::ostream& out) -> ::std::ostream& {
Adam Lesinskica2fc352015-04-03 12:08:26 -0700124 constexpr size_t K = 1024u;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800125 constexpr size_t M = K * K;
Greg Hackmann1fce4f92015-04-02 20:23:22 -0700126 constexpr size_t G = M * K;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800127 if (size < K) {
128 out << size << "B";
129 } else if (size < M) {
130 out << (double(size) / K) << " KiB";
131 } else if (size < G) {
132 out << (double(size) / M) << " MiB";
133 } else {
134 out << (double(size) / G) << " GiB";
135 }
136 return out;
137 };
138}
139
140/**
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700141 * Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
142 * the conversion to UTF-16 happens within ResStringPool.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800143 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700144StringPiece16 getString16(const android::ResStringPool& pool, size_t idx);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800145
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700146/**
147 * Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
148 * the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
149 * which maintains no state or cache. This means we must return an std::string copy.
150 */
151std::string getString(const android::ResStringPool& pool, size_t idx);
Adam Lesinski28cacf02015-11-23 14:22:47 -0800152
Adam Lesinskib23f1e02015-11-03 12:24:17 -0800153/**
154 * Checks that the Java string format contains no non-positional arguments (arguments without
155 * explicitly specifying an index) when there are more than one argument. This is an error
156 * because translations may rearrange the order of the arguments in the string, which will
157 * break the string interpolation.
158 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700159bool verifyJavaStringFormat(const StringPiece& str);
Adam Lesinskib23f1e02015-11-03 12:24:17 -0800160
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800161class StringBuilder {
162public:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700163 StringBuilder& append(const StringPiece& str);
164 const std::string& str() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800165 const std::string& error() const;
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700166
167 // When building StyledStrings, we need UTF-16 indices into the string,
168 // which is what the Java layer expects when dealing with java String.charAt().
169 size_t utf16Len() const;
170
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800171 operator bool() const;
172
173private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700174 std::string mStr;
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700175 size_t mUtf16Len = 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800176 bool mQuote = false;
177 bool mTrailingSpace = false;
Adam Lesinski90959882015-07-06 18:09:18 -0700178 bool mLastCharWasEscape = false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800179 std::string mError;
180};
181
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700182inline const std::string& StringBuilder::str() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800183 return mStr;
184}
185
186inline const std::string& StringBuilder::error() const {
187 return mError;
188}
189
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700190inline size_t StringBuilder::utf16Len() const {
191 return mUtf16Len;
192}
193
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800194inline StringBuilder::operator bool() const {
195 return mError.empty();
196}
197
198/**
199 * Converts a UTF8 string to a UTF16 string.
200 */
201std::u16string utf8ToUtf16(const StringPiece& utf8);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700202std::string utf16ToUtf8(const StringPiece16& utf16);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800203
204/**
205 * Writes the entire BigBuffer to the output stream.
206 */
207bool writeAll(std::ostream& out, const BigBuffer& buffer);
208
209/*
210 * Copies the entire BigBuffer into a single buffer.
211 */
212std::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer);
213
214/**
215 * A Tokenizer implemented as an iterable collection. It does not allocate
216 * any memory on the heap nor use standard containers.
217 */
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800218class Tokenizer {
219public:
220 class iterator {
221 public:
222 iterator(const iterator&) = default;
223 iterator& operator=(const iterator&) = default;
224
225 iterator& operator++();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700226
227 StringPiece operator*() {
228 return mToken;
229 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800230 bool operator==(const iterator& rhs) const;
231 bool operator!=(const iterator& rhs) const;
232
233 private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700234 friend class Tokenizer;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800235
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700236 iterator(StringPiece s, char sep, StringPiece tok, bool end);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800237
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700238 StringPiece mStr;
239 char mSeparator;
240 StringPiece mToken;
Adam Lesinskicf95a582015-11-16 15:37:30 -0800241 bool mEnd;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800242 };
243
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700244 Tokenizer(StringPiece str, char sep);
245
246 iterator begin() {
247 return mBegin;
248 }
249
250 iterator end() {
251 return mEnd;
252 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800253
254private:
255 const iterator mBegin;
256 const iterator mEnd;
257};
258
Chih-Hung Hsieh470f8fc2016-08-15 12:32:51 -0700259inline Tokenizer tokenize(const StringPiece& str, char sep) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700260 return Tokenizer(str, sep);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800261}
262
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700263inline uint16_t hostToDevice16(uint16_t value) {
264 return htods(value);
265}
266
267inline uint32_t hostToDevice32(uint32_t value) {
268 return htodl(value);
269}
270
271inline uint16_t deviceToHost16(uint16_t value) {
272 return dtohs(value);
273}
274
275inline uint32_t deviceToHost32(uint32_t value) {
276 return dtohl(value);
277}
278
Adam Lesinski24aad162015-04-24 19:19:30 -0700279/**
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700280 * Given a path like: res/xml-sw600dp/foo.xml
281 *
282 * Extracts "res/xml-sw600dp/" into outPrefix.
283 * Extracts "foo" into outEntry.
284 * Extracts ".xml" into outSuffix.
285 *
286 * Returns true if successful.
287 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700288bool extractResFilePathParts(const StringPiece& path, StringPiece* outPrefix,
289 StringPiece* outEntry, StringPiece* outSuffix);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700290
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800291} // namespace util
292
293/**
294 * Stream operator for functions. Calls the function with the stream as an argument.
295 * In the aapt namespace for lookup.
296 */
297inline ::std::ostream& operator<<(::std::ostream& out,
Chih-Hung Hsieh470f8fc2016-08-15 12:32:51 -0700298 const ::std::function<::std::ostream&(::std::ostream&)>& f) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800299 return f(out);
300}
301
302} // namespace aapt
303
304#endif // AAPT_UTIL_H