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
176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "BigBuffer.h"
186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Maybe.h"
196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "StringPiece.h"
206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "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
3124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskiconstexpr const char16_t* kSchemaAuto = u"http://schemas.android.com/apk/res-auto";
3224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskiconstexpr const char16_t* kSchemaPrefix = u"http://schemas.android.com/apk/res/";
3324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic std::vector<std::string> splitAndTransform(const StringPiece& str, char sep,
356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        const std::function<char(char)>& f) {
366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    std::vector<std::string> parts;
376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const StringPiece::const_iterator end = std::end(str);
386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    StringPiece::const_iterator start = std::begin(str);
396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    StringPiece::const_iterator current;
406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    do {
416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        current = std::find(start, end, sep);
426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        parts.emplace_back(str.substr(start, current).toString());
436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (f) {
446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            std::string& part = parts.back();
456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            std::transform(part.begin(), part.end(), part.begin(), f);
466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        start = current + 1;
486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    } while (current != end);
496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return parts;
506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::vector<std::string> split(const StringPiece& str, char sep) {
536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return splitAndTransform(str, sep, nullptr);
546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::vector<std::string> splitAndLowercase(const StringPiece& str, char sep) {
576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return splitAndTransform(str, sep, ::tolower);
586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPiece16 trimWhitespace(const StringPiece16& str) {
616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (str.size() == 0 || str.data() == nullptr) {
626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return str;
636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const char16_t* start = str.data();
666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const char16_t* end = str.data() + str.length();
676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    while (start != end && util::isspace16(*start)) {
696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        start++;
706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    while (end != start && util::isspace16(*(end - 1))) {
736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        end--;
746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return StringPiece16(start, end - start);
776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str,
806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        const StringPiece16& allowedChars) {
816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const auto endIter = str.end();
826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    for (auto iter = str.begin(); iter != endIter; ++iter) {
836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        char16_t c = *iter;
846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if ((c >= u'a' && c <= u'z') ||
856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                (c >= u'A' && c <= u'Z') ||
866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                (c >= u'0' && c <= u'9')) {
876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            continue;
886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        bool match = false;
916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        for (char16_t i : allowedChars) {
926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            if (c == i) {
936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                match = true;
946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                break;
956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            }
966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (!match) {
996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return iter;
1006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
1026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return endIter;
1036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
105a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskibool isJavaClassName(const StringPiece16& str) {
106a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    size_t pieces = 0;
107a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    for (const StringPiece16& piece : tokenize(str, u'.')) {
108a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        pieces++;
109a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (piece.empty()) {
110a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            return false;
111a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
112a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
113a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        // Can't have starting or trailing $ character.
114a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (piece.data()[0] == u'$' || piece.data()[piece.size() - 1] == u'$') {
115a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            return false;
116a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
117a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
118a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (findNonAlphaNumericAndNotInSet(piece, u"$_") != piece.end()) {
119a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            return false;
120a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
121a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
122a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    return pieces >= 2;
123a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski}
124a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
125a1ad4a812a87642ad259ff4478159e8cc8194680Adam LesinskiMaybe<std::u16string> getFullyQualifiedClassName(const StringPiece16& package,
126a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                                                 const StringPiece16& className) {
127a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    if (className.empty()) {
128a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        return {};
129a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
130a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
131a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    if (util::isJavaClassName(className)) {
132a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        return className.toString();
133a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
134a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
135a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    if (package.empty()) {
136a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        return {};
137a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
138a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
139a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    std::u16string result(package.data(), package.size());
140a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    if (className.data()[0] != u'.') {
141a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        result += u'.';
142a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
143a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    result.append(className.data(), className.size());
144a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    if (!isJavaClassName(result)) {
145a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        return {};
146a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
147a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    return result;
148a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski}
149a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
1506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistatic Maybe<char16_t> parseUnicodeCodepoint(const char16_t** start, const char16_t* end) {
1516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    char16_t code = 0;
1526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    for (size_t i = 0; i < 4 && *start != end; i++, (*start)++) {
1536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        char16_t c = **start;
1546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        int a;
1556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (c >= '0' && c <= '9') {
1566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            a = c - '0';
1576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (c >= 'a' && c <= 'f') {
1586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            a = c - 'a' + 10;
1596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (c >= 'A' && c <= 'F') {
1606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            a = c - 'A' + 10;
1616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else {
1626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return make_nothing<char16_t>();
1636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
1646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        code = (code << 4) | a;
1656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
1666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return make_value(code);
1676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiStringBuilder& StringBuilder::append(const StringPiece16& str) {
1706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (!mError.empty()) {
1716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return *this;
1726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
1736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const char16_t* const end = str.end();
1756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const char16_t* start = str.begin();
1766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    const char16_t* current = start;
1776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    while (current != end) {
1786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (*current == u'"') {
1796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            if (!mQuote && mTrailingSpace) {
1806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // We found an opening quote, and we have
1816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // trailing space, so we should append that
1826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // space now.
1836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                if (mTrailingSpace) {
1846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    // We had trailing whitespace, so
1856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    // replace with a single space.
1866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    if (!mStr.empty()) {
1876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u' ';
1886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    }
1896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    mTrailingSpace = false;
1906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                }
1916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            }
1926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            mQuote = !mQuote;
1936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            mStr.append(start, current - start);
1946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            start = current + 1;
1956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (*current == u'\'' && !mQuote) {
1966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // This should be escaped.
1976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            mError = "unescaped apostrophe";
1986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return *this;
1996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (*current == u'\\') {
2006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // This is an escape sequence, convert to the real value.
2016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            if (!mQuote && mTrailingSpace) {
2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // We had trailing whitespace, so
2036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // replace with a single space.
2046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                if (!mStr.empty()) {
2056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    mStr += u' ';
2066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                }
2076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                mTrailingSpace = false;
2086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            }
2096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            mStr.append(start, current - start);
2106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            start = current + 1;
2116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            current++;
2136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            if (current != end) {
2146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                switch (*current) {
2156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u't':
2166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'\t';
2176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'n':
2196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'\n';
2206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'#':
2226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'#';
2236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'@':
2256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'@';
2266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'?':
2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'?';
2296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'"':
2316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'"';
2326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'\'':
2346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'\'';
2356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'\\':
2376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += u'\\';
2386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    case u'u': {
2406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        current++;
2416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        Maybe<char16_t> c = parseUnicodeCodepoint(&current, end);
2426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        if (!c) {
2436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                            mError = "invalid unicode escape sequence";
2446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                            return *this;
2456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        }
2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        mStr += c.value();
2476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        current -= 1;
2486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    }
2506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    default:
2526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        // Ignore.
2536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                        break;
2546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                }
2556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                start = current + 1;
2566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            }
2576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        } else if (!mQuote) {
2586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            // This is not quoted text, so look for whitespace.
2596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            if (isspace16(*current)) {
2606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // We found whitespace, see if we have seen some
2616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // before.
2626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                if (!mTrailingSpace) {
2636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    // We didn't see a previous adjacent space,
2646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    // so mark that we did.
2656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    mTrailingSpace = true;
2666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    mStr.append(start, current - start);
2676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                }
2686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // Keep skipping whitespace.
2706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                start = current + 1;
2716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            } else if (mTrailingSpace) {
2726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // We saw trailing space before, so replace all
2736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                // that trailing space with one space.
2746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                if (!mStr.empty()) {
2756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                    mStr += u' ';
2766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                }
2776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski                mTrailingSpace = false;
2786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            }
2796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
2806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        current++;
2816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    mStr.append(start, end - start);
2836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return *this;
2846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::u16string utf8ToUtf16(const StringPiece& utf8) {
2876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    ssize_t utf16Length = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(utf8.data()),
2886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            utf8.length());
2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (utf16Length <= 0) {
2906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return {};
2916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
2926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    std::u16string utf16;
2946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    utf16.resize(utf16Length);
2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length(), &*utf16.begin());
2966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return utf16;
2976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::string utf16ToUtf8(const StringPiece16& utf16) {
3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    ssize_t utf8Length = utf16_to_utf8_length(utf16.data(), utf16.length());
3016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    if (utf8Length <= 0) {
3026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        return {};
3036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    std::string utf8;
3066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    utf8.resize(utf8Length);
3076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin());
3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return utf8;
3096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskibool writeAll(std::ostream& out, const BigBuffer& buffer) {
3126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    for (const auto& b : buffer) {
3136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        if (!out.write(reinterpret_cast<const char*>(b.buffer.get()), b.size)) {
3146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski            return false;
3156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        }
3166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return true;
3186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistd::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer) {
3216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
3226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    uint8_t* p = data.get();
3236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    for (const auto& block : buffer) {
3246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        memcpy(p, block.buffer.get(), block.size);
3256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski        p += block.size;
3266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    return data;
3286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
33024aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<std::u16string> extractPackageFromNamespace(const std::u16string& namespaceUri) {
33124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski    if (stringStartsWith<char16_t>(namespaceUri, kSchemaPrefix)) {
33224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski        StringPiece16 schemaPrefix = kSchemaPrefix;
33324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski        StringPiece16 package = namespaceUri;
33424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski        return package.substr(schemaPrefix.size(), package.size() - schemaPrefix.size())
33524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski                .toString();
33624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski    } else if (namespaceUri == kSchemaAuto) {
33724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski        return std::u16string();
33824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski    }
33924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski    return {};
34024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
34124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
3426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace util
3436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt
344