1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/inspector/string-16.h"
6
7 #include <algorithm>
8 #include <cctype>
9 #include <cinttypes>
10 #include <cstdlib>
11 #include <cstring>
12 #include <limits>
13 #include <string>
14
15 #include "../../third_party/inspector_protocol/crdtp/cbor.h"
16 #include "src/base/platform/platform.h"
17 #include "src/inspector/v8-string-conversions.h"
18 #include "src/numbers/conversions.h"
19
20 namespace v8_inspector {
21
22 namespace {
23
isASCII(UChar c)24 bool isASCII(UChar c) { return !(c & ~0x7F); }
25
isSpaceOrNewLine(UChar c)26 bool isSpaceOrNewLine(UChar c) {
27 return isASCII(c) && c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
28 }
29
charactersToInteger(const UChar * characters,size_t length,bool * ok=nullptr)30 int64_t charactersToInteger(const UChar* characters, size_t length,
31 bool* ok = nullptr) {
32 std::vector<char> buffer;
33 buffer.reserve(length + 1);
34 for (size_t i = 0; i < length; ++i) {
35 if (!isASCII(characters[i])) {
36 if (ok) *ok = false;
37 return 0;
38 }
39 buffer.push_back(static_cast<char>(characters[i]));
40 }
41 buffer.push_back('\0');
42
43 char* endptr;
44 int64_t result =
45 static_cast<int64_t>(std::strtoll(buffer.data(), &endptr, 10));
46 if (ok) *ok = !(*endptr);
47 return result;
48 }
49 } // namespace
50
String16(const UChar * characters,size_t size)51 String16::String16(const UChar* characters, size_t size)
52 : m_impl(characters, size) {}
53
String16(const UChar * characters)54 String16::String16(const UChar* characters) : m_impl(characters) {}
55
String16(const char * characters)56 String16::String16(const char* characters)
57 : String16(characters, std::strlen(characters)) {}
58
String16(const char * characters,size_t size)59 String16::String16(const char* characters, size_t size) {
60 m_impl.resize(size);
61 for (size_t i = 0; i < size; ++i) m_impl[i] = characters[i];
62 }
63
String16(const std::basic_string<UChar> & impl)64 String16::String16(const std::basic_string<UChar>& impl) : m_impl(impl) {}
65
String16(std::basic_string<UChar> && impl)66 String16::String16(std::basic_string<UChar>&& impl) : m_impl(impl) {}
67
68 // static
fromInteger(int number)69 String16 String16::fromInteger(int number) {
70 char arr[50];
71 v8::internal::Vector<char> buffer(arr, arraysize(arr));
72 return String16(IntToCString(number, buffer));
73 }
74
75 // static
fromInteger(size_t number)76 String16 String16::fromInteger(size_t number) {
77 const size_t kBufferSize = 50;
78 char buffer[kBufferSize];
79 #if !defined(_WIN32) && !defined(_WIN64)
80 v8::base::OS::SNPrintF(buffer, kBufferSize, "%zu", number);
81 #else
82 v8::base::OS::SNPrintF(buffer, kBufferSize, "%Iu", number);
83 #endif
84 return String16(buffer);
85 }
86
87 // static
fromInteger64(int64_t number)88 String16 String16::fromInteger64(int64_t number) {
89 char buffer[50];
90 v8::base::OS::SNPrintF(buffer, arraysize(buffer), "%" PRId64 "", number);
91 return String16(buffer);
92 }
93
94 // static
fromDouble(double number)95 String16 String16::fromDouble(double number) {
96 char arr[50];
97 v8::internal::Vector<char> buffer(arr, arraysize(arr));
98 return String16(DoubleToCString(number, buffer));
99 }
100
101 // static
fromDouble(double number,int precision)102 String16 String16::fromDouble(double number, int precision) {
103 std::unique_ptr<char[]> str(
104 v8::internal::DoubleToPrecisionCString(number, precision));
105 return String16(str.get());
106 }
107
toInteger64(bool * ok) const108 int64_t String16::toInteger64(bool* ok) const {
109 return charactersToInteger(characters16(), length(), ok);
110 }
111
toInteger(bool * ok) const112 int String16::toInteger(bool* ok) const {
113 int64_t result = toInteger64(ok);
114 if (ok && *ok) {
115 *ok = result <= std::numeric_limits<int>::max() &&
116 result >= std::numeric_limits<int>::min();
117 }
118 return static_cast<int>(result);
119 }
120
stripWhiteSpace() const121 String16 String16::stripWhiteSpace() const {
122 if (!length()) return String16();
123
124 size_t start = 0;
125 size_t end = length() - 1;
126
127 // skip white space from start
128 while (start <= end && isSpaceOrNewLine(characters16()[start])) ++start;
129
130 // only white space
131 if (start > end) return String16();
132
133 // skip white space from end
134 while (end && isSpaceOrNewLine(characters16()[end])) --end;
135
136 if (!start && end == length() - 1) return *this;
137 return String16(characters16() + start, end + 1 - start);
138 }
139
140 String16Builder::String16Builder() = default;
141
append(const String16 & s)142 void String16Builder::append(const String16& s) {
143 m_buffer.insert(m_buffer.end(), s.characters16(),
144 s.characters16() + s.length());
145 }
146
append(UChar c)147 void String16Builder::append(UChar c) { m_buffer.push_back(c); }
148
append(char c)149 void String16Builder::append(char c) {
150 UChar u = c;
151 m_buffer.push_back(u);
152 }
153
append(const UChar * characters,size_t length)154 void String16Builder::append(const UChar* characters, size_t length) {
155 m_buffer.insert(m_buffer.end(), characters, characters + length);
156 }
157
append(const char * characters,size_t length)158 void String16Builder::append(const char* characters, size_t length) {
159 m_buffer.insert(m_buffer.end(), characters, characters + length);
160 }
161
appendNumber(int number)162 void String16Builder::appendNumber(int number) {
163 constexpr int kBufferSize = 11;
164 char buffer[kBufferSize];
165 int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%d", number);
166 DCHECK_LE(0, chars);
167 m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
168 }
169
appendNumber(size_t number)170 void String16Builder::appendNumber(size_t number) {
171 constexpr int kBufferSize = 20;
172 char buffer[kBufferSize];
173 #if !defined(_WIN32) && !defined(_WIN64)
174 int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%zu", number);
175 #else
176 int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%Iu", number);
177 #endif
178 DCHECK_LE(0, chars);
179 m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
180 }
181
appendUnsignedAsHex(uint64_t number)182 void String16Builder::appendUnsignedAsHex(uint64_t number) {
183 constexpr int kBufferSize = 17;
184 char buffer[kBufferSize];
185 int chars =
186 v8::base::OS::SNPrintF(buffer, kBufferSize, "%016" PRIx64, number);
187 DCHECK_LE(0, chars);
188 m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
189 }
190
appendUnsignedAsHex(uint32_t number)191 void String16Builder::appendUnsignedAsHex(uint32_t number) {
192 constexpr int kBufferSize = 9;
193 char buffer[kBufferSize];
194 int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%08" PRIx32, number);
195 DCHECK_LE(0, chars);
196 m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
197 }
198
appendUnsignedAsHex(uint8_t number)199 void String16Builder::appendUnsignedAsHex(uint8_t number) {
200 constexpr int kBufferSize = 3;
201 char buffer[kBufferSize];
202 int chars = v8::base::OS::SNPrintF(buffer, kBufferSize, "%02" PRIx8, number);
203 DCHECK_LE(0, chars);
204 m_buffer.insert(m_buffer.end(), buffer, buffer + chars);
205 }
206
toString()207 String16 String16Builder::toString() {
208 return String16(m_buffer.data(), m_buffer.size());
209 }
210
reserveCapacity(size_t capacity)211 void String16Builder::reserveCapacity(size_t capacity) {
212 m_buffer.reserve(capacity);
213 }
214
fromUTF8(const char * stringStart,size_t length)215 String16 String16::fromUTF8(const char* stringStart, size_t length) {
216 return String16(UTF8ToUTF16(stringStart, length));
217 }
218
fromUTF16LE(const UChar * stringStart,size_t length)219 String16 String16::fromUTF16LE(const UChar* stringStart, size_t length) {
220 #ifdef V8_TARGET_BIG_ENDIAN
221 // Need to flip the byte order on big endian machines.
222 String16Builder builder;
223 builder.reserveCapacity(length);
224 for (size_t i = 0; i < length; i++) {
225 const UChar utf16be_char =
226 stringStart[i] << 8 | (stringStart[i] >> 8 & 0x00FF);
227 builder.append(utf16be_char);
228 }
229 return builder.toString();
230 #else
231 // No need to do anything on little endian machines.
232 return String16(stringStart, length);
233 #endif // V8_TARGET_BIG_ENDIAN
234 }
235
utf8() const236 std::string String16::utf8() const {
237 return UTF16ToUTF8(m_impl.data(), m_impl.size());
238 }
239
240 } // namespace v8_inspector
241
242 namespace v8_crdtp {
Serialize(const v8_inspector::String16 & str,std::vector<uint8_t> * out)243 void SerializerTraits<v8_inspector::String16>::Serialize(
244 const v8_inspector::String16& str, std::vector<uint8_t>* out) {
245 cbor::EncodeFromUTF16(
246 span<uint16_t>(reinterpret_cast<const uint16_t*>(str.characters16()),
247 str.length()),
248 out);
249 }
250 } // namespace v8_crdtp
251