1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBDEXFILE_DEX_UTF_INL_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBDEXFILE_DEX_UTF_INL_H_
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard Worker #include "utf.h"
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker namespace art {
23*795d594fSAndroid Build Coastguard Worker
GetTrailingUtf16Char(uint32_t maybe_pair)24*795d594fSAndroid Build Coastguard Worker inline uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
25*795d594fSAndroid Build Coastguard Worker return static_cast<uint16_t>(maybe_pair >> 16);
26*795d594fSAndroid Build Coastguard Worker }
27*795d594fSAndroid Build Coastguard Worker
GetLeadingUtf16Char(uint32_t maybe_pair)28*795d594fSAndroid Build Coastguard Worker inline uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
29*795d594fSAndroid Build Coastguard Worker return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
30*795d594fSAndroid Build Coastguard Worker }
31*795d594fSAndroid Build Coastguard Worker
GetUtf16FromUtf8(const char ** utf8_data_in)32*795d594fSAndroid Build Coastguard Worker inline uint32_t GetUtf16FromUtf8(const char** utf8_data_in) {
33*795d594fSAndroid Build Coastguard Worker const uint8_t one = *(*utf8_data_in)++;
34*795d594fSAndroid Build Coastguard Worker if ((one & 0x80) == 0) {
35*795d594fSAndroid Build Coastguard Worker // one-byte encoding
36*795d594fSAndroid Build Coastguard Worker return one;
37*795d594fSAndroid Build Coastguard Worker }
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Worker const uint8_t two = *(*utf8_data_in)++;
40*795d594fSAndroid Build Coastguard Worker if ((one & 0x20) == 0) {
41*795d594fSAndroid Build Coastguard Worker // two-byte encoding
42*795d594fSAndroid Build Coastguard Worker return ((one & 0x1f) << 6) | (two & 0x3f);
43*795d594fSAndroid Build Coastguard Worker }
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker const uint8_t three = *(*utf8_data_in)++;
46*795d594fSAndroid Build Coastguard Worker if ((one & 0x10) == 0) {
47*795d594fSAndroid Build Coastguard Worker return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
48*795d594fSAndroid Build Coastguard Worker }
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker // Four byte encodings need special handling. We'll have
51*795d594fSAndroid Build Coastguard Worker // to convert them into a surrogate pair.
52*795d594fSAndroid Build Coastguard Worker const uint8_t four = *(*utf8_data_in)++;
53*795d594fSAndroid Build Coastguard Worker
54*795d594fSAndroid Build Coastguard Worker // Since this is a 4 byte UTF-8 sequence, it will lie between
55*795d594fSAndroid Build Coastguard Worker // U+10000 and U+1FFFFF.
56*795d594fSAndroid Build Coastguard Worker //
57*795d594fSAndroid Build Coastguard Worker // TODO: What do we do about values in (U+10FFFF, U+1FFFFF) ? The
58*795d594fSAndroid Build Coastguard Worker // spec says they're invalid but nobody appears to check for them.
59*795d594fSAndroid Build Coastguard Worker const uint32_t code_point = ((one & 0x0f) << 18) | ((two & 0x3f) << 12)
60*795d594fSAndroid Build Coastguard Worker | ((three & 0x3f) << 6) | (four & 0x3f);
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard Worker uint32_t surrogate_pair = 0;
63*795d594fSAndroid Build Coastguard Worker // Step two: Write out the high (leading) surrogate to the bottom 16 bits
64*795d594fSAndroid Build Coastguard Worker // of the of the 32 bit type.
65*795d594fSAndroid Build Coastguard Worker surrogate_pair |= ((code_point >> 10) + 0xd7c0) & 0xffff;
66*795d594fSAndroid Build Coastguard Worker // Step three : Write out the low (trailing) surrogate to the top 16 bits.
67*795d594fSAndroid Build Coastguard Worker surrogate_pair |= ((code_point & 0x03ff) + 0xdc00) << 16;
68*795d594fSAndroid Build Coastguard Worker
69*795d594fSAndroid Build Coastguard Worker return surrogate_pair;
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker
CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char * utf8_1,const char * utf8_2)72*795d594fSAndroid Build Coastguard Worker inline int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1,
73*795d594fSAndroid Build Coastguard Worker const char* utf8_2) {
74*795d594fSAndroid Build Coastguard Worker uint32_t c1, c2;
75*795d594fSAndroid Build Coastguard Worker do {
76*795d594fSAndroid Build Coastguard Worker c1 = *utf8_1;
77*795d594fSAndroid Build Coastguard Worker c2 = *utf8_2;
78*795d594fSAndroid Build Coastguard Worker // Did we reach a terminating character?
79*795d594fSAndroid Build Coastguard Worker if (c1 == 0) {
80*795d594fSAndroid Build Coastguard Worker return (c2 == 0) ? 0 : -1;
81*795d594fSAndroid Build Coastguard Worker } else if (c2 == 0) {
82*795d594fSAndroid Build Coastguard Worker return 1;
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker
85*795d594fSAndroid Build Coastguard Worker c1 = GetUtf16FromUtf8(&utf8_1);
86*795d594fSAndroid Build Coastguard Worker c2 = GetUtf16FromUtf8(&utf8_2);
87*795d594fSAndroid Build Coastguard Worker } while (c1 == c2);
88*795d594fSAndroid Build Coastguard Worker
89*795d594fSAndroid Build Coastguard Worker const uint32_t leading_surrogate_diff = GetLeadingUtf16Char(c1) - GetLeadingUtf16Char(c2);
90*795d594fSAndroid Build Coastguard Worker if (leading_surrogate_diff != 0) {
91*795d594fSAndroid Build Coastguard Worker return static_cast<int>(leading_surrogate_diff);
92*795d594fSAndroid Build Coastguard Worker }
93*795d594fSAndroid Build Coastguard Worker
94*795d594fSAndroid Build Coastguard Worker return GetTrailingUtf16Char(c1) - GetTrailingUtf16Char(c2);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker template <bool kUseShortZero, bool kUse4ByteSequence, bool kReplaceBadSurrogates, typename Append>
ConvertUtf16ToUtf8(const uint16_t * utf16,size_t char_count,Append && append)98*795d594fSAndroid Build Coastguard Worker inline void ConvertUtf16ToUtf8(const uint16_t* utf16, size_t char_count, Append&& append) {
99*795d594fSAndroid Build Coastguard Worker static_assert(kUse4ByteSequence || !kReplaceBadSurrogates);
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker // Use local helpers instead of macros from `libicu` to avoid the dependency on `libicu`.
102*795d594fSAndroid Build Coastguard Worker auto is_lead = [](uint16_t ch) ALWAYS_INLINE { return (ch & 0xfc00u) == 0xd800u; };
103*795d594fSAndroid Build Coastguard Worker auto is_trail = [](uint16_t ch) ALWAYS_INLINE { return (ch & 0xfc00u) == 0xdc00u; };
104*795d594fSAndroid Build Coastguard Worker auto is_surrogate = [](uint16_t ch) ALWAYS_INLINE { return (ch & 0xf800u) == 0xd800u; };
105*795d594fSAndroid Build Coastguard Worker auto is_surrogate_lead = [](uint16_t ch) ALWAYS_INLINE { return (ch & 0x0400u) == 0u; };
106*795d594fSAndroid Build Coastguard Worker auto get_supplementary = [](uint16_t lead, uint16_t trail) ALWAYS_INLINE {
107*795d594fSAndroid Build Coastguard Worker constexpr uint32_t offset = (0xd800u << 10) + 0xdc00u - 0x10000u;
108*795d594fSAndroid Build Coastguard Worker return (static_cast<uint32_t>(lead) << 10) + static_cast<uint32_t>(trail) - offset;
109*795d594fSAndroid Build Coastguard Worker };
110*795d594fSAndroid Build Coastguard Worker
111*795d594fSAndroid Build Coastguard Worker for (size_t i = 0u; i < char_count; ++i) {
112*795d594fSAndroid Build Coastguard Worker auto has_trail = [&]() { return i + 1u != char_count && is_trail(utf16[i + 1u]); };
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker uint16_t ch = utf16[i];
115*795d594fSAndroid Build Coastguard Worker if (ch < 0x80u && (kUseShortZero || ch != 0u)) {
116*795d594fSAndroid Build Coastguard Worker // One byte.
117*795d594fSAndroid Build Coastguard Worker append(ch);
118*795d594fSAndroid Build Coastguard Worker } else if (ch < 0x800u) {
119*795d594fSAndroid Build Coastguard Worker // Two bytes.
120*795d594fSAndroid Build Coastguard Worker append((ch >> 6) | 0xc0);
121*795d594fSAndroid Build Coastguard Worker append((ch & 0x3f) | 0x80);
122*795d594fSAndroid Build Coastguard Worker } else if (kReplaceBadSurrogates
123*795d594fSAndroid Build Coastguard Worker ? is_surrogate(ch)
124*795d594fSAndroid Build Coastguard Worker : kUse4ByteSequence && is_lead(ch) && has_trail()) {
125*795d594fSAndroid Build Coastguard Worker if (kReplaceBadSurrogates && (!is_surrogate_lead(ch) || !has_trail())) {
126*795d594fSAndroid Build Coastguard Worker append('?');
127*795d594fSAndroid Build Coastguard Worker } else {
128*795d594fSAndroid Build Coastguard Worker // We have a *valid* surrogate pair.
129*795d594fSAndroid Build Coastguard Worker uint32_t code_point = get_supplementary(ch, utf16[i + 1u]);
130*795d594fSAndroid Build Coastguard Worker ++i; // Consume the leading surrogate.
131*795d594fSAndroid Build Coastguard Worker // Four bytes.
132*795d594fSAndroid Build Coastguard Worker append((code_point >> 18) | 0xf0);
133*795d594fSAndroid Build Coastguard Worker append(((code_point >> 12) & 0x3f) | 0x80);
134*795d594fSAndroid Build Coastguard Worker append(((code_point >> 6) & 0x3f) | 0x80);
135*795d594fSAndroid Build Coastguard Worker append((code_point & 0x3f) | 0x80);
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker } else {
138*795d594fSAndroid Build Coastguard Worker // Three bytes.
139*795d594fSAndroid Build Coastguard Worker append((ch >> 12) | 0xe0);
140*795d594fSAndroid Build Coastguard Worker append(((ch >> 6) & 0x3f) | 0x80);
141*795d594fSAndroid Build Coastguard Worker append((ch & 0x3f) | 0x80);
142*795d594fSAndroid Build Coastguard Worker }
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker }
145*795d594fSAndroid Build Coastguard Worker
146*795d594fSAndroid Build Coastguard Worker } // namespace art
147*795d594fSAndroid Build Coastguard Worker
148*795d594fSAndroid Build Coastguard Worker #endif // ART_LIBDEXFILE_DEX_UTF_INL_H_
149