• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-util.h"
6 
7 #include <cinttypes>
8 #include <cmath>
9 #include <cstddef>
10 
11 #include "src/base/platform/platform.h"
12 #include "src/inspector/protocol/Protocol.h"
13 #include "src/numbers/conversions.h"
14 
15 namespace v8_inspector {
16 
17 namespace protocol {
18 namespace {
SplitByte(uint8_t byte,uint8_t split)19 std::pair<uint8_t, uint8_t> SplitByte(uint8_t byte, uint8_t split) {
20   return {byte >> split, (byte & ((1 << split) - 1)) << (6 - split)};
21 }
22 
DecodeByte(char byte)23 v8::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 
toBase64() const34 String Binary::toBase64() const {
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 */
fromBase64(const String & base64,bool * success)59 Binary Binary::fromBase64(const String& base64, bool* success) {
60   if (base64.isEmpty()) {
61     *success = true;
62     return Binary::fromSpan(nullptr, 0);
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 Binary::fromSpan(nullptr, 0);
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 Binary::fromSpan(nullptr, 0);
78     if (!DecodeByte(base64[i + 1]).To(&b)) return Binary::fromSpan(nullptr, 0);
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 Binary::fromSpan(nullptr, 0);
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 Binary::fromSpan(nullptr, 0);
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 
toV8String(v8::Isolate * isolate,const String16 & string)102 v8::Local<v8::String> toV8String(v8::Isolate* isolate, const String16& string) {
103   if (string.isEmpty()) return v8::String::Empty(isolate);
104   DCHECK_GT(v8::String::kMaxLength, string.length());
105   return v8::String::NewFromTwoByte(
106              isolate, reinterpret_cast<const uint16_t*>(string.characters16()),
107              v8::NewStringType::kNormal, static_cast<int>(string.length()))
108       .ToLocalChecked();
109 }
110 
toV8StringInternalized(v8::Isolate * isolate,const String16 & string)111 v8::Local<v8::String> toV8StringInternalized(v8::Isolate* isolate,
112                                              const String16& string) {
113   if (string.isEmpty()) return v8::String::Empty(isolate);
114   DCHECK_GT(v8::String::kMaxLength, string.length());
115   return v8::String::NewFromTwoByte(
116              isolate, reinterpret_cast<const uint16_t*>(string.characters16()),
117              v8::NewStringType::kInternalized,
118              static_cast<int>(string.length()))
119       .ToLocalChecked();
120 }
121 
toV8StringInternalized(v8::Isolate * isolate,const char * str)122 v8::Local<v8::String> toV8StringInternalized(v8::Isolate* isolate,
123                                              const char* str) {
124   return v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kInternalized)
125       .ToLocalChecked();
126 }
127 
toV8String(v8::Isolate * isolate,const StringView & string)128 v8::Local<v8::String> toV8String(v8::Isolate* isolate,
129                                  const StringView& string) {
130   if (!string.length()) return v8::String::Empty(isolate);
131   DCHECK_GT(v8::String::kMaxLength, string.length());
132   if (string.is8Bit())
133     return v8::String::NewFromOneByte(
134                isolate, reinterpret_cast<const uint8_t*>(string.characters8()),
135                v8::NewStringType::kNormal, static_cast<int>(string.length()))
136         .ToLocalChecked();
137   return v8::String::NewFromTwoByte(
138              isolate, reinterpret_cast<const uint16_t*>(string.characters16()),
139              v8::NewStringType::kNormal, static_cast<int>(string.length()))
140       .ToLocalChecked();
141 }
142 
toProtocolString(v8::Isolate * isolate,v8::Local<v8::String> value)143 String16 toProtocolString(v8::Isolate* isolate, v8::Local<v8::String> value) {
144   if (value.IsEmpty() || value->IsNullOrUndefined()) return String16();
145   std::unique_ptr<UChar[]> buffer(new UChar[value->Length()]);
146   value->Write(isolate, reinterpret_cast<uint16_t*>(buffer.get()), 0,
147                value->Length());
148   return String16(buffer.get(), value->Length());
149 }
150 
toProtocolStringWithTypeCheck(v8::Isolate * isolate,v8::Local<v8::Value> value)151 String16 toProtocolStringWithTypeCheck(v8::Isolate* isolate,
152                                        v8::Local<v8::Value> value) {
153   if (value.IsEmpty() || !value->IsString()) return String16();
154   return toProtocolString(isolate, value.As<v8::String>());
155 }
156 
toString16(const StringView & string)157 String16 toString16(const StringView& string) {
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 
toStringView(const String16 & string)165 StringView toStringView(const String16& string) {
166   if (string.isEmpty()) return StringView();
167   return StringView(string.characters16(), string.length());
168 }
169 
stringViewStartsWith(const StringView & string,const char * prefix)170 bool 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 
184 namespace {
185 // An empty string buffer doesn't own any string data; its ::string() returns a
186 // default-constructed StringView instance.
187 class EmptyStringBuffer : public StringBuffer {
188  public:
string() const189   StringView string() const override { return StringView(); }
190 };
191 
192 // Contains LATIN1 text data or CBOR encoded binary data in a vector.
193 class StringBuffer8 : public StringBuffer {
194  public:
StringBuffer8(std::vector<uint8_t> data)195   explicit StringBuffer8(std::vector<uint8_t> data) : data_(std::move(data)) {}
196 
string() const197   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).
206 class StringBuffer16 : public StringBuffer {
207  public:
StringBuffer16(String16 data)208   explicit StringBuffer16(String16 data) : data_(std::move(data)) {}
209 
string() const210   StringView string() const override {
211     return StringView(data_.characters16(), data_.length());
212   }
213 
214  private:
215   String16 data_;
216 };
217 }  // namespace
218 
219 // static
create(StringView string)220 std::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 
StringBufferFrom(String16 str)230 std::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 
StringBufferFrom(std::vector<uint8_t> str)235 std::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 
stackTraceIdToString(uintptr_t id)240 String16 stackTraceIdToString(uintptr_t id) {
241   String16Builder builder;
242   builder.appendNumber(static_cast<size_t>(id));
243   return builder.toString();
244 }
245 
246 }  // namespace v8_inspector
247 
248 namespace v8_crdtp {
249 
250 using v8_inspector::String16;
251 using v8_inspector::protocol::Binary;
252 using v8_inspector::protocol::StringUtil;
253 
254 // static
Deserialize(DeserializerState * state,String16 * value)255 bool 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();
265     *value = StringUtil::fromUTF16LE(
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
Serialize(const String16 & value,std::vector<uint8_t> * bytes)274 void 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
Deserialize(DeserializerState * state,Binary * value)283 bool ProtocolTypeTraits<Binary>::Deserialize(DeserializerState* state,
284                                              Binary* value) {
285   auto* tokenizer = state->tokenizer();
286   if (tokenizer->TokenTag() == cbor::CBORTokenTag::BINARY) {
287     const span<uint8_t> bin = tokenizer->GetBinary();
288     *value = Binary::fromSpan(bin.data(), bin.size());
289     return true;
290   }
291   if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING8) {
292     const auto str_span = tokenizer->GetString8();
293     auto str = StringUtil::fromUTF8(str_span.data(), str_span.size());
294     bool success = false;
295     *value = Binary::fromBase64(str, &success);
296     return success;
297   }
298   state->RegisterError(Error::BINDINGS_BINARY_VALUE_EXPECTED);
299   return false;
300 }
301 
302 // static
Serialize(const Binary & value,std::vector<uint8_t> * bytes)303 void ProtocolTypeTraits<Binary>::Serialize(const Binary& value,
304                                            std::vector<uint8_t>* bytes) {
305   cbor::EncodeBinary(span<uint8_t>(value.data(), value.size()), bytes);
306 }
307 
Serialize(const v8_inspector::protocol::Binary & binary,std::vector<uint8_t> * out)308 void SerializerTraits<Binary>::Serialize(
309     const v8_inspector::protocol::Binary& binary, std::vector<uint8_t>* out) {
310   cbor::EncodeBinary(span<uint8_t>(binary.data(), binary.size()), out);
311 }
312 }  // namespace v8_crdtp
313