xref: /aosp_15_r20/art/libdexfile/dex/utf-inl.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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