blob: 998ecf7702bdab3822c5a0eddee634a720c1221a [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;
166 operator bool() const;
167
168private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700169 std::string mStr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800170 bool mQuote = false;
171 bool mTrailingSpace = false;
Adam Lesinski90959882015-07-06 18:09:18 -0700172 bool mLastCharWasEscape = false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800173 std::string mError;
174};
175
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700176inline const std::string& StringBuilder::str() const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800177 return mStr;
178}
179
180inline const std::string& StringBuilder::error() const {
181 return mError;
182}
183
184inline StringBuilder::operator bool() const {
185 return mError.empty();
186}
187
188/**
189 * Converts a UTF8 string to a UTF16 string.
190 */
191std::u16string utf8ToUtf16(const StringPiece& utf8);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700192std::string utf16ToUtf8(const StringPiece16& utf16);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800193
194/**
195 * Writes the entire BigBuffer to the output stream.
196 */
197bool writeAll(std::ostream& out, const BigBuffer& buffer);
198
199/*
200 * Copies the entire BigBuffer into a single buffer.
201 */
202std::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer);
203
204/**
205 * A Tokenizer implemented as an iterable collection. It does not allocate
206 * any memory on the heap nor use standard containers.
207 */
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800208class Tokenizer {
209public:
210 class iterator {
211 public:
212 iterator(const iterator&) = default;
213 iterator& operator=(const iterator&) = default;
214
215 iterator& operator++();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700216
217 StringPiece operator*() {
218 return mToken;
219 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800220 bool operator==(const iterator& rhs) const;
221 bool operator!=(const iterator& rhs) const;
222
223 private:
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700224 friend class Tokenizer;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800225
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700226 iterator(StringPiece s, char sep, StringPiece tok, bool end);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800227
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700228 StringPiece mStr;
229 char mSeparator;
230 StringPiece mToken;
Adam Lesinskicf95a582015-11-16 15:37:30 -0800231 bool mEnd;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800232 };
233
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700234 Tokenizer(StringPiece str, char sep);
235
236 iterator begin() {
237 return mBegin;
238 }
239
240 iterator end() {
241 return mEnd;
242 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800243
244private:
245 const iterator mBegin;
246 const iterator mEnd;
247};
248
Chih-Hung Hsieh470f8fc2016-08-15 12:32:51 -0700249inline Tokenizer tokenize(const StringPiece& str, char sep) {
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700250 return Tokenizer(str, sep);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800251}
252
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700253inline uint16_t hostToDevice16(uint16_t value) {
254 return htods(value);
255}
256
257inline uint32_t hostToDevice32(uint32_t value) {
258 return htodl(value);
259}
260
261inline uint16_t deviceToHost16(uint16_t value) {
262 return dtohs(value);
263}
264
265inline uint32_t deviceToHost32(uint32_t value) {
266 return dtohl(value);
267}
268
Adam Lesinski24aad162015-04-24 19:19:30 -0700269/**
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700270 * Given a path like: res/xml-sw600dp/foo.xml
271 *
272 * Extracts "res/xml-sw600dp/" into outPrefix.
273 * Extracts "foo" into outEntry.
274 * Extracts ".xml" into outSuffix.
275 *
276 * Returns true if successful.
277 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700278bool extractResFilePathParts(const StringPiece& path, StringPiece* outPrefix,
279 StringPiece* outEntry, StringPiece* outSuffix);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700280
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281} // namespace util
282
283/**
284 * Stream operator for functions. Calls the function with the stream as an argument.
285 * In the aapt namespace for lookup.
286 */
287inline ::std::ostream& operator<<(::std::ostream& out,
Chih-Hung Hsieh470f8fc2016-08-15 12:32:51 -0700288 const ::std::function<::std::ostream&(::std::ostream&)>& f) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800289 return f(out);
290}
291
292} // namespace aapt
293
294#endif // AAPT_UTIL_H