v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
string-util.cc
Go to the documentation of this file.
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
6
7#include <cinttypes>
8#include <cmath>
9#include <cstddef>
10
12#include "src/inspector/protocol/Protocol.h"
14
15namespace v8_inspector {
16
17namespace protocol {
18namespace {
19std::pair<uint8_t, uint8_t> SplitByte(uint8_t byte, uint8_t split) {
20 return {byte >> split, (byte & ((1 << split) - 1)) << (6 - split)};
21}
22
23v8::Maybe<uint8_t> DecodeByte(char byte) {
24 if ('A' <= byte && byte <= 'Z') return v8::Just<uint8_t>(byte - 'A');
25 if ('a' <= byte && byte <= 'z') return v8::Just<uint8_t>(byte - 'a' + 26);
26 if ('0' <= byte && byte <= '9')
27 return v8::Just<uint8_t>(byte - '0' + 26 + 26);
28 if (byte == '+') return v8::Just<uint8_t>(62);
29 if (byte == '/') return v8::Just<uint8_t>(63);
30 return v8::Nothing<uint8_t>();
31}
32} // namespace
33
35 const char* table =
36 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
37 if (size() == 0) return {};
38 std::basic_string<UChar> result;
39 result.reserve(4 * ((size() + 2) / 3));
40 uint8_t last = 0;
41 for (size_t n = 0; n < size();) {
42 auto split = SplitByte((*bytes_)[n], 2 + 2 * (n % 3));
43 result.push_back(table[split.first | last]);
44
45 ++n;
46 if (n < size() && n % 3 == 0) {
47 result.push_back(table[split.second]);
48 last = 0;
49 } else {
50 last = split.second;
51 }
52 }
53 result.push_back(table[last]);
54 while (result.size() % 4 > 0) result.push_back('=');
55 return String16(std::move(result));
56}
57
58/* static */
59Binary Binary::fromBase64(const String& base64, bool* success) {
60 if (base64.isEmpty()) {
61 *success = true;
62 return {};
63 }
64
65 *success = false;
66 // Fail if the length is invalid or decoding would overflow.
67 if (base64.length() % 4 != 0 || base64.length() + 4 < base64.length()) {
68 return {};
69 }
70
71 std::vector<uint8_t> result;
72 result.reserve(3 * base64.length() / 4);
73 char pad = '=';
74 // Iterate groups of four
75 for (size_t i = 0; i < base64.length(); i += 4) {
76 uint8_t a = 0, b = 0, c = 0, d = 0;
77 if (!DecodeByte(base64[i + 0]).To(&a)) return {};
78 if (!DecodeByte(base64[i + 1]).To(&b)) return {};
79 if (!DecodeByte(base64[i + 2]).To(&c)) {
80 // Padding is allowed only in the group on the last two positions
81 if (i + 4 < base64.length() || base64[i + 2] != pad ||
82 base64[i + 3] != pad) {
83 return {};
84 }
85 }
86 if (!DecodeByte(base64[i + 3]).To(&d)) {
87 // Padding is allowed only in the group on the last two positions
88 if (i + 4 < base64.length() || base64[i + 3] != pad) {
89 return {};
90 }
91 }
92
93 result.push_back((a << 2) | (b >> 4));
94 if (base64[i + 2] != '=') result.push_back((0xFF & (b << 4)) | (c >> 2));
95 if (base64[i + 3] != '=') result.push_back((0xFF & (c << 6)) | d);
96 }
97 *success = true;
98 return Binary(std::make_shared<std::vector<uint8_t>>(std::move(result)));
99}
100} // namespace protocol
101
103 if (string.isEmpty()) return v8::String::Empty(isolate);
106 isolate, reinterpret_cast<const uint16_t*>(string.characters16()),
107 v8::NewStringType::kNormal, static_cast<int>(string.length()))
108 .ToLocalChecked();
109}
110
112 const String16& string) {
113 if (string.isEmpty()) return v8::String::Empty(isolate);
116 isolate, reinterpret_cast<const uint16_t*>(string.characters16()),
118 static_cast<int>(string.length()))
119 .ToLocalChecked();
120}
121
123 const char* str) {
125 .ToLocalChecked();
126}
127
129 const StringView& string) {
130 if (!string.length()) return v8::String::Empty(isolate);
132 if (string.is8Bit())
134 isolate, reinterpret_cast<const uint8_t*>(string.characters8()),
135 v8::NewStringType::kNormal, static_cast<int>(string.length()))
136 .ToLocalChecked();
138 isolate, reinterpret_cast<const uint16_t*>(string.characters16()),
139 v8::NewStringType::kNormal, static_cast<int>(string.length()))
140 .ToLocalChecked();
141}
142
144 if (value.IsEmpty() || value->IsNullOrUndefined()) return String16();
145 uint32_t length = value->Length();
146 std::unique_ptr<UChar[]> buffer(new UChar[length]);
147 value->WriteV2(isolate, 0, length, reinterpret_cast<uint16_t*>(buffer.get()));
148 return String16(buffer.get(), length);
149}
150
152 v8::Local<v8::Value> value) {
153 if (value.IsEmpty() || !value->IsString()) return String16();
154 return toProtocolString(isolate, value.As<v8::String>());
155}
156
158 if (!string.length()) return String16();
159 if (string.is8Bit())
160 return String16(reinterpret_cast<const char*>(string.characters8()),
161 string.length());
162 return String16(string.characters16(), string.length());
163}
164
166 if (string.isEmpty()) return StringView();
167 return StringView(string.characters16(), string.length());
168}
169
170bool stringViewStartsWith(const StringView& string, const char* prefix) {
171 if (!string.length()) return !(*prefix);
172 if (string.is8Bit()) {
173 for (size_t i = 0, j = 0; prefix[j] && i < string.length(); ++i, ++j) {
174 if (string.characters8()[i] != prefix[j]) return false;
175 }
176 } else {
177 for (size_t i = 0, j = 0; prefix[j] && i < string.length(); ++i, ++j) {
178 if (string.characters16()[i] != prefix[j]) return false;
179 }
180 }
181 return true;
182}
183
184namespace {
185// An empty string buffer doesn't own any string data; its ::string() returns a
186// default-constructed StringView instance.
187class EmptyStringBuffer : public StringBuffer {
188 public:
189 StringView string() const override { return StringView(); }
190};
191
192// Contains LATIN1 text data or CBOR encoded binary data in a vector.
193class StringBuffer8 : public StringBuffer {
194 public:
195 explicit StringBuffer8(std::vector<uint8_t> data) : data_(std::move(data)) {}
196
197 StringView string() const override {
198 return StringView(data_.data(), data_.size());
199 }
200
201 private:
202 std::vector<uint8_t> data_;
203};
204
205// Contains a 16 bit string (String16).
206class StringBuffer16 : public StringBuffer {
207 public:
208 explicit StringBuffer16(String16 data) : data_(std::move(data)) {}
209
210 StringView string() const override {
211 return StringView(data_.characters16(), data_.length());
212 }
213
214 private:
215 String16 data_;
216};
217} // namespace
218
219// static
220std::unique_ptr<StringBuffer> StringBuffer::create(StringView string) {
221 if (string.length() == 0) return std::make_unique<EmptyStringBuffer>();
222 if (string.is8Bit()) {
223 return std::make_unique<StringBuffer8>(std::vector<uint8_t>(
224 string.characters8(), string.characters8() + string.length()));
225 }
226 return std::make_unique<StringBuffer16>(
227 String16(string.characters16(), string.length()));
228}
229
230std::unique_ptr<StringBuffer> StringBufferFrom(String16 str) {
231 if (str.isEmpty()) return std::make_unique<EmptyStringBuffer>();
232 return std::make_unique<StringBuffer16>(std::move(str));
233}
234
235std::unique_ptr<StringBuffer> StringBufferFrom(std::vector<uint8_t> str) {
236 if (str.empty()) return std::make_unique<EmptyStringBuffer>();
237 return std::make_unique<StringBuffer8>(std::move(str));
238}
239
241 String16Builder builder;
242 builder.appendNumber(static_cast<size_t>(id));
243 return builder.toString();
244}
245
246} // namespace v8_inspector
247
248namespace v8_crdtp {
249
253
254// static
255bool ProtocolTypeTraits<String16>::Deserialize(DeserializerState* state,
256 String16* value) {
257 auto* tokenizer = state->tokenizer();
258 if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING8) {
259 const auto str = tokenizer->GetString8();
260 *value = StringUtil::fromUTF8(str.data(), str.size());
261 return true;
262 }
263 if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING16) {
264 const auto str = tokenizer->GetString16WireRep();
266 reinterpret_cast<const uint16_t*>(str.data()), str.size() / 2);
267 return true;
268 }
269 state->RegisterError(Error::BINDINGS_STRING_VALUE_EXPECTED);
270 return false;
271}
272
273// static
274void ProtocolTypeTraits<String16>::Serialize(const String16& value,
275 std::vector<uint8_t>* bytes) {
276 cbor::EncodeFromUTF16(
277 span<uint16_t>(reinterpret_cast<const uint16_t*>(value.characters16()),
278 value.length()),
279 bytes);
280}
281
282// static
283bool ProtocolTypeTraits<Binary>::Deserialize(DeserializerState* state,
284 Binary* value) {
285 auto* tokenizer = state->tokenizer();
286 if (tokenizer->TokenTag() == cbor::CBORTokenTag::BINARY) {
287 *value = Binary::fromSpan(tokenizer->GetBinary());
288 return true;
289 }
290 if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING8) {
291 const auto str_span = tokenizer->GetString8();
292 auto str = StringUtil::fromUTF8(str_span.data(), str_span.size());
293 bool success = false;
294 *value = Binary::fromBase64(str, &success);
295 return success;
296 }
297 state->RegisterError(Error::BINDINGS_BINARY_VALUE_EXPECTED);
298 return false;
299}
300
301// static
302void ProtocolTypeTraits<Binary>::Serialize(const Binary& value,
303 std::vector<uint8_t>* bytes) {
304 cbor::EncodeBinary(span<uint8_t>(value.data(), value.size()), bytes);
305}
306
307} // namespace v8_crdtp
uint8_t data_[MAX_STACK_LENGTH]
static constexpr int kMaxLength
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromUtf8(Isolate *isolate, const char *data, NewStringType type=NewStringType::kNormal, int length=-1)
Definition api.cc:7593
static V8_INLINE Local< String > Empty(Isolate *isolate)
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromTwoByte(Isolate *isolate, const uint16_t *data, NewStringType type=NewStringType::kNormal, int length=-1)
Definition api.cc:7606
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromOneByte(Isolate *isolate, const uint8_t *data, NewStringType type=NewStringType::kNormal, int length=-1)
Definition api.cc:7599
size_t length() const
Definition string-16.h:58
bool isEmpty() const
Definition string-16.h:59
static std::unique_ptr< StringBuffer > create(StringView)
static Binary fromBase64(const String &base64, bool *success)
std::shared_ptr< std::vector< uint8_t > > bytes_
Definition string-util.h:64
static Binary fromSpan(v8_crdtp::span< uint8_t > span)
Definition string-util.h:55
static String fromUTF16LE(const uint16_t *data, size_t length)
Definition string-util.h:34
static String fromUTF8(const uint8_t *data, size_t length)
Definition string-util.h:30
ZoneVector< RpoNumber > & result
int n
Definition mul-fft.cc:296
STL namespace.
char16_t UChar
Definition string-16.h:22
bool stringViewStartsWith(const StringView &string, const char *prefix)
String16 toProtocolString(v8::Isolate *isolate, v8::Local< v8::String > value)
String16 stackTraceIdToString(uintptr_t id)
StringView toStringView(const String16 &string)
std::unique_ptr< StringBuffer > StringBufferFrom(String16 str)
v8::Local< v8::String > toV8String(v8::Isolate *isolate, const String16 &string)
String16 toProtocolStringWithTypeCheck(v8::Isolate *isolate, v8::Local< v8::Value > value)
String16 toString16(const StringView &string)
v8::Local< v8::String > toV8StringInternalized(v8::Isolate *isolate, const String16 &string)
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define DCHECK_GT(v1, v2)
Definition logging.h:487