blob: 077e193e091e286948c592dab222a1649be06e3d [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 */
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059inline bool isspace16(char16_t c) { return c < 0x0080 && isspace(c); }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080060
61/**
62 * Returns an iterator to the first character that is not alpha-numeric and that
63 * is not in the allowedChars set.
64 */
Adam Lesinskicacb28f2016-10-19 12:18:14 -070065StringPiece::const_iterator findNonAlphaNumericAndNotInSet(
66 const StringPiece& str, const StringPiece& allowedChars);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080067
68/**
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070069 * Tests that the string is a valid Java class name.
70 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070071bool isJavaClassName(const StringPiece& str);
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070072
73/**
Adam Lesinski1ab598f2015-08-14 14:26:04 -070074 * Tests that the string is a valid Java package name.
75 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070076bool isJavaPackageName(const StringPiece& str);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070077
78/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 * Converts the class name to a fully qualified class name from the given
80 * `package`. Ex:
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070081 *
82 * asdf --> package.asdf
83 * .asdf --> package.asdf
84 * .a.b --> package.a.b
85 * asdf.adsf --> asdf.adsf
86 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -070087Maybe<std::string> getFullyQualifiedClassName(const StringPiece& package,
88 const StringPiece& className);
Adam Lesinskia1ad4a82015-06-08 11:41:09 -070089
90/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 * Makes a std::unique_ptr<> with the template parameter inferred by the
92 * compiler.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080093 * 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) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080098}
99
100/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700101 * Writes a set of items to the std::ostream, joining the times with the
102 * provided
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800103 * separator.
104 */
Adam Lesinski36c73a52016-08-11 13:39:24 -0700105template <typename Container>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700106::std::function<::std::ostream&(::std::ostream&)> joiner(
107 const Container& container, const char* sep) {
108 using std::begin;
109 using std::end;
110 const auto beginIter = begin(container);
111 const auto endIter = end(container);
112 return [beginIter, endIter, sep](::std::ostream& out) -> ::std::ostream& {
113 for (auto iter = beginIter; iter != endIter; ++iter) {
114 if (iter != beginIter) {
115 out << sep;
116 }
117 out << *iter;
118 }
119 return out;
120 };
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800121}
122
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700123inline ::std::function<::std::ostream&(::std::ostream&)> formatSize(
124 size_t size) {
125 return [size](::std::ostream& out) -> ::std::ostream& {
126 constexpr size_t K = 1024u;
127 constexpr size_t M = K * K;
128 constexpr size_t G = M * K;
129 if (size < K) {
130 out << size << "B";
131 } else if (size < M) {
132 out << (double(size) / K) << " KiB";
133 } else if (size < G) {
134 out << (double(size) / M) << " MiB";
135 } else {
136 out << (double(size) / G) << " GiB";
137 }
138 return out;
139 };
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800140}
141
142/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 * Helper method to extract a UTF-16 string from a StringPool. If the string is
144 * stored as UTF-8,
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700145 * the conversion to UTF-16 happens within ResStringPool.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800146 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700147StringPiece16 getString16(const android::ResStringPool& pool, size_t idx);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800148
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700149/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 * Helper method to extract a UTF-8 string from a StringPool. If the string is
151 * stored as UTF-16,
152 * the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is
153 * done by this method,
154 * which maintains no state or cache. This means we must return an std::string
155 * copy.
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700156 */
157std::string getString(const android::ResStringPool& pool, size_t idx);
Adam Lesinski28cacf02015-11-23 14:22:47 -0800158
Adam Lesinskib23f1e02015-11-03 12:24:17 -0800159/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 * Checks that the Java string format contains no non-positional arguments
161 * (arguments without
162 * explicitly specifying an index) when there are more than one argument. This
163 * is an error
164 * because translations may rearrange the order of the arguments in the string,
165 * which will
Adam Lesinskib23f1e02015-11-03 12:24:17 -0800166 * break the string interpolation.
167 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700168bool verifyJavaStringFormat(const StringPiece& str);
Adam Lesinskib23f1e02015-11-03 12:24:17 -0800169
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800170class StringBuilder {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700171 public:
172 StringBuilder& append(const StringPiece& str);
173 const std::string& str() const;
174 const std::string& error() const;
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700175
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 // When building StyledStrings, we need UTF-16 indices into the string,
177 // which is what the Java layer expects when dealing with java
178 // String.charAt().
179 size_t utf16Len() const;
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700180
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 operator bool() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800182
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 private:
184 std::string mStr;
185 size_t mUtf16Len = 0;
186 bool mQuote = false;
187 bool mTrailingSpace = false;
188 bool mLastCharWasEscape = false;
189 std::string mError;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800190};
191
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192inline const std::string& StringBuilder::str() const { return mStr; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800193
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194inline const std::string& StringBuilder::error() const { return mError; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800195
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196inline size_t StringBuilder::utf16Len() const { return mUtf16Len; }
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700197
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700198inline StringBuilder::operator bool() const { return mError.empty(); }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800199
200/**
201 * Converts a UTF8 string to a UTF16 string.
202 */
203std::u16string utf8ToUtf16(const StringPiece& utf8);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700204std::string utf16ToUtf8(const StringPiece16& utf16);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800205
206/**
207 * Writes the entire BigBuffer to the output stream.
208 */
209bool writeAll(std::ostream& out, const BigBuffer& buffer);
210
211/*
212 * Copies the entire BigBuffer into a single buffer.
213 */
214std::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer);
215
216/**
217 * A Tokenizer implemented as an iterable collection. It does not allocate
218 * any memory on the heap nor use standard containers.
219 */
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800220class Tokenizer {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 public:
222 class iterator {
223 public:
224 iterator(const iterator&) = default;
225 iterator& operator=(const iterator&) = default;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800226
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700227 iterator& operator++();
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700228
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700229 StringPiece operator*() { return mToken; }
230 bool operator==(const iterator& rhs) const;
231 bool operator!=(const iterator& rhs) const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800232
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 private:
234 friend class Tokenizer;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800235
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 iterator(StringPiece s, char sep, StringPiece tok, bool end);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800237
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700238 StringPiece mStr;
239 char mSeparator;
240 StringPiece mToken;
241 bool mEnd;
242 };
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800243
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700244 Tokenizer(StringPiece str, char sep);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700245
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700246 iterator begin() { return mBegin; }
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700247
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 iterator end() { return mEnd; }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800249
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700250 private:
251 const iterator mBegin;
252 const iterator mEnd;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800253};
254
Chih-Hung Hsieh470f8fc2016-08-15 12:32:51 -0700255inline Tokenizer tokenize(const StringPiece& str, char sep) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700256 return Tokenizer(str, sep);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800257}
258
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259inline uint16_t hostToDevice16(uint16_t value) { return htods(value); }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700260
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700261inline uint32_t hostToDevice32(uint32_t value) { return htodl(value); }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700262
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700263inline uint16_t deviceToHost16(uint16_t value) { return dtohs(value); }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700264
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700265inline uint32_t deviceToHost32(uint32_t value) { return dtohl(value); }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700266
Adam Lesinski24aad162015-04-24 19:19:30 -0700267/**
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700268 * Given a path like: res/xml-sw600dp/foo.xml
269 *
270 * Extracts "res/xml-sw600dp/" into outPrefix.
271 * Extracts "foo" into outEntry.
272 * Extracts ".xml" into outSuffix.
273 *
274 * Returns true if successful.
275 */
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700276bool extractResFilePathParts(const StringPiece& path, StringPiece* outPrefix,
277 StringPiece* outEntry, StringPiece* outSuffix);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700278
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700279} // namespace util
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800280
281/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 * Stream operator for functions. Calls the function with the stream as an
283 * argument.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800284 * In the aapt namespace for lookup.
285 */
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700286inline ::std::ostream& operator<<(
287 ::std::ostream& out,
288 const ::std::function<::std::ostream&(::std::ostream&)>& f) {
289 return f(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800290}
291
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292} // namespace aapt
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800293
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700294#endif // AAPT_UTIL_H