16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/BigBuffer.h" 181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Maybe.h" 191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/StringPiece.h" 201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h" 216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <algorithm> 236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <ostream> 246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string> 256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <utils/Unicode.h> 266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <vector> 276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace util { 306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic std::vector<std::string> splitAndTransform(const StringPiece& str, char sep, 326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const std::function<char(char)>& f) { 336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::vector<std::string> parts; 346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const StringPiece::const_iterator end = std::end(str); 356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StringPiece::const_iterator start = std::begin(str); 366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StringPiece::const_iterator current; 376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski do { 386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski current = std::find(start, end, sep); 396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski parts.emplace_back(str.substr(start, current).toString()); 406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (f) { 416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::string& part = parts.back(); 426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::transform(part.begin(), part.end(), part.begin(), f); 436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski start = current + 1; 456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } while (current != end); 466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return parts; 476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::vector<std::string> split(const StringPiece& str, char sep) { 506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return splitAndTransform(str, sep, nullptr); 516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::vector<std::string> splitAndLowercase(const StringPiece& str, char sep) { 546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return splitAndTransform(str, sep, ::tolower); 556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPiece16 trimWhitespace(const StringPiece16& str) { 586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (str.size() == 0 || str.data() == nullptr) { 596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return str; 606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* start = str.data(); 636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* end = str.data() + str.length(); 646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski while (start != end && util::isspace16(*start)) { 666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski start++; 676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski while (end != start && util::isspace16(*(end - 1))) { 706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski end--; 716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return StringPiece16(start, end - start); 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 763b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam LesinskiStringPiece trimWhitespace(const StringPiece& str) { 773b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski if (str.size() == 0 || str.data() == nullptr) { 783b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski return str; 793b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski } 803b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 813b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski const char* start = str.data(); 823b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski const char* end = str.data() + str.length(); 833b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 843b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski while (start != end && isspace(*start)) { 853b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski start++; 863b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski } 873b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 883b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski while (end != start && isspace(*(end - 1))) { 893b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski end--; 903b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski } 913b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 923b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski return StringPiece(start, end - start); 933b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski} 943b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str, 966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const StringPiece16& allowedChars) { 976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const auto endIter = str.end(); 986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (auto iter = str.begin(); iter != endIter; ++iter) { 996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski char16_t c = *iter; 1006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if ((c >= u'a' && c <= u'z') || 1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski (c >= u'A' && c <= u'Z') || 1026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski (c >= u'0' && c <= u'9')) { 1036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 1046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski bool match = false; 1076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (char16_t i : allowedChars) { 1086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (c == i) { 1096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski match = true; 1106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski break; 1116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!match) { 1156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return iter; 1166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return endIter; 1196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 121a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskibool isJavaClassName(const StringPiece16& str) { 122a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski size_t pieces = 0; 123a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski for (const StringPiece16& piece : tokenize(str, u'.')) { 124a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski pieces++; 125a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (piece.empty()) { 126a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return false; 127a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 128a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 129a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski // Can't have starting or trailing $ character. 130a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (piece.data()[0] == u'$' || piece.data()[piece.size() - 1] == u'$') { 131a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return false; 132a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 133a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 134a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (findNonAlphaNumericAndNotInSet(piece, u"$_") != piece.end()) { 135a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return false; 136a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 137a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 138a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return pieces >= 2; 139a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski} 140a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 1411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool isJavaPackageName(const StringPiece16& str) { 1421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (str.empty()) { 1431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 1441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski size_t pieces = 0; 1471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski for (const StringPiece16& piece : tokenize(str, u'.')) { 1481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski pieces++; 1491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (piece.empty()) { 1501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 1511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (piece.data()[0] == u'_' || piece.data()[piece.size() - 1] == u'_') { 1541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 1551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (findNonAlphaNumericAndNotInSet(piece, u"_") != piece.end()) { 1581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 1591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return pieces >= 1; 1621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 164a1ad4a812a87642ad259ff4478159e8cc8194680Adam LesinskiMaybe<std::u16string> getFullyQualifiedClassName(const StringPiece16& package, 165a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski const StringPiece16& className) { 166a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (className.empty()) { 167a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return {}; 168a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 169a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 170a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (util::isJavaClassName(className)) { 171a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return className.toString(); 172a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 173a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 174a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (package.empty()) { 175a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return {}; 176a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 177a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 178a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (className.data()[0] != u'.') { 17952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski return {}; 180a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 18152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 18252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski std::u16string result(package.data(), package.size()); 183a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski result.append(className.data(), className.size()); 184a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski if (!isJavaClassName(result)) { 185a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return {}; 186a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski } 187a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski return result; 188a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski} 189a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski 190b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinskistatic size_t consumeDigits(const char16_t* start, const char16_t* end) { 191b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski const char16_t* c = start; 192b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski for (; c != end && *c >= u'0' && *c <= u'9'; c++) {} 193b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return static_cast<size_t>(c - start); 194b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski} 195b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 196b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinskibool verifyJavaStringFormat(const StringPiece16& str) { 197b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski const char16_t* c = str.begin(); 198b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski const char16_t* const end = str.end(); 199b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 200b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski size_t argCount = 0; 201b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski bool nonpositional = false; 202b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski while (c != end) { 203b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (*c == u'%' && c + 1 < end) { 204b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c++; 205b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 206b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (*c == u'%') { 207b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c++; 208b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski continue; 209b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 210b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 211b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski argCount++; 212b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 213b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski size_t numDigits = consumeDigits(c, end); 214b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (numDigits > 0) { 215b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c += numDigits; 216b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (c != end && *c != u'$') { 217b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // The digits were a size, but not a positional argument. 218b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski nonpositional = true; 219b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 220b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } else if (*c == u'<') { 221b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // Reusing last argument, bad idea since positions can be moved around 222b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // during translation. 223b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski nonpositional = true; 224b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 225b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c++; 226b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 227b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // Optionally we can have a $ after 228b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (c != end && *c == u'$') { 229b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c++; 230b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 231b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } else { 232b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski nonpositional = true; 233b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 234b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 235b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // Ignore size, width, flags, etc. 236b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski while (c != end && (*c == u'-' || 237b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski *c == u'#' || 238b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski *c == u'+' || 239b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski *c == u' ' || 240b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski *c == u',' || 241b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski *c == u'(' || 242b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski (*c >= u'0' && *c <= '9'))) { 243b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c++; 244b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 245b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 246b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski /* 247b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * This is a shortcut to detect strings that are going to Time.format() 248b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * instead of String.format() 249b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * 250b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * Comparison of String.format() and Time.format() args: 251b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * 252b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * String: ABC E GH ST X abcdefgh nost x 253b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * Time: DEFGHKMS W Za d hkm s w yz 254b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * 255b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * Therefore we know it's definitely Time if we have: 256b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski * DFKMWZkmwyz 257b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski */ 258b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (c != end) { 259b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski switch (*c) { 260b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'D': 261b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'F': 262b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'K': 263b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'M': 264b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'W': 265b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'Z': 266b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'k': 267b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'm': 268b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'w': 269b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'y': 270b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski case 'z': 271b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return true; 272b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 273b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 274b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 275b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 276b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (c != end) { 277b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski c++; 278b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 279b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 280b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 281b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (argCount > 1 && nonpositional) { 282b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // Multiple arguments were specified, but some or all were non positional. Translated 283b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski // strings may rearrange the order of the arguments, which will break the string. 284b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return false; 285b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 286b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return true; 287b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski} 288b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic Maybe<char16_t> parseUnicodeCodepoint(const char16_t** start, const char16_t* end) { 2906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski char16_t code = 0; 2916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (size_t i = 0; i < 4 && *start != end; i++, (*start)++) { 2926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski char16_t c = **start; 2936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski int a; 2946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (c >= '0' && c <= '9') { 2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski a = c - '0'; 2966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else if (c >= 'a' && c <= 'f') { 2976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski a = c - 'a' + 10; 2986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else if (c >= 'A' && c <= 'F') { 2996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski a = c - 'A' + 10; 3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else { 3016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return make_nothing<char16_t>(); 3026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski code = (code << 4) | a; 3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return make_value(code); 3066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringBuilder& StringBuilder::append(const StringPiece16& str) { 3096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mError.empty()) { 3106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return *this; 3116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* const end = str.end(); 3146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* start = str.begin(); 3156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* current = start; 3166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski while (current != end) { 31790959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski if (mLastCharWasEscape) { 31890959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski switch (*current) { 31990959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u't': 32090959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'\t'; 32190959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 32290959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'n': 32390959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'\n'; 32490959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 32590959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'#': 32690959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'#'; 32790959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 32890959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'@': 32990959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'@'; 33090959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 33190959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'?': 33290959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'?'; 33390959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 33490959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'"': 33590959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'"'; 33690959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 33790959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'\'': 33890959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'\''; 33990959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 34090959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'\\': 34190959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += u'\\'; 34290959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 34390959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski case u'u': { 34490959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski current++; 34590959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski Maybe<char16_t> c = parseUnicodeCodepoint(¤t, end); 34690959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski if (!c) { 34790959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mError = "invalid unicode escape sequence"; 34890959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski return *this; 34990959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski } 35090959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mStr += c.value(); 35190959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski current -= 1; 35290959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 35390959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski } 35490959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski 35590959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski default: 35690959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski // Ignore. 35790959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski break; 35890959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski } 35990959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mLastCharWasEscape = false; 36090959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski start = current + 1; 36190959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski } else if (*current == u'"') { 3626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mQuote && mTrailingSpace) { 3636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // We found an opening quote, and we have 3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // trailing space, so we should append that 3656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // space now. 3666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mTrailingSpace) { 3676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // We had trailing whitespace, so 3686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // replace with a single space. 3696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mStr.empty()) { 3706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr += u' '; 3716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTrailingSpace = false; 3736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mQuote = !mQuote; 3766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr.append(start, current - start); 3776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski start = current + 1; 3786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else if (*current == u'\'' && !mQuote) { 3796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // This should be escaped. 3806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mError = "unescaped apostrophe"; 3816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return *this; 3826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else if (*current == u'\\') { 3836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // This is an escape sequence, convert to the real value. 3846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mQuote && mTrailingSpace) { 3856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // We had trailing whitespace, so 3866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // replace with a single space. 3876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mStr.empty()) { 3886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr += u' '; 3896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTrailingSpace = false; 3916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr.append(start, current - start); 3936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski start = current + 1; 39490959887e9a61ff83097b2789f8b3243ad817decAdam Lesinski mLastCharWasEscape = true; 3956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else if (!mQuote) { 3966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // This is not quoted text, so look for whitespace. 3976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (isspace16(*current)) { 3986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // We found whitespace, see if we have seen some 3996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // before. 4006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mTrailingSpace) { 4016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // We didn't see a previous adjacent space, 4026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // so mark that we did. 4036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTrailingSpace = true; 4046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr.append(start, current - start); 4056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Keep skipping whitespace. 4086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski start = current + 1; 4096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else if (mTrailingSpace) { 4106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // We saw trailing space before, so replace all 4116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // that trailing space with one space. 4126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!mStr.empty()) { 4136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr += u' '; 4146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTrailingSpace = false; 4166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski current++; 4196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mStr.append(start, end - start); 4216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return *this; 4226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::u16string utf8ToUtf16(const StringPiece& utf8) { 4256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ssize_t utf16Length = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(utf8.data()), 4266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski utf8.length()); 4276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (utf16Length <= 0) { 4286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return {}; 4296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::u16string utf16; 4326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski utf16.resize(utf16Length); 4336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length(), &*utf16.begin()); 4346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return utf16; 4356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::string utf16ToUtf8(const StringPiece16& utf16) { 4386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ssize_t utf8Length = utf16_to_utf8_length(utf16.data(), utf16.length()); 4396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (utf8Length <= 0) { 4406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return {}; 4416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::string utf8; 4446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski utf8.resize(utf8Length); 4456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin()); 4466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return utf8; 4476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskibool writeAll(std::ostream& out, const BigBuffer& buffer) { 4506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (const auto& b : buffer) { 4516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!out.write(reinterpret_cast<const char*>(b.buffer.get()), b.size)) { 4526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 4536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return true; 4566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer) { 4596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]); 4606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski uint8_t* p = data.get(); 4616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (const auto& block : buffer) { 4626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski memcpy(p, block.buffer.get(), block.size); 4636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski p += block.size; 4646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return data; 4666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool extractResFilePathParts(const StringPiece16& path, StringPiece16* outPrefix, 4691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski StringPiece16* outEntry, StringPiece16* outSuffix) { 4701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!stringStartsWith<char16_t>(path, u"res/")) { 4711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 4721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski StringPiece16::const_iterator lastOccurence = path.end(); 4751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski for (auto iter = path.begin() + StringPiece16(u"res/").size(); iter != path.end(); ++iter) { 4761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (*iter == u'/') { 4771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski lastOccurence = iter; 4781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (lastOccurence == path.end()) { 4821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 4831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski auto iter = std::find(lastOccurence, path.end(), u'.'); 4861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *outSuffix = StringPiece16(iter, path.end() - iter); 4871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *outEntry = StringPiece16(lastOccurence + 1, iter - lastOccurence - 1); 4881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *outPrefix = StringPiece16(path.begin(), lastOccurence - path.begin() + 1); 4891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return true; 4901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 4911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace util 4936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt 494