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
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
34String 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 */
59Binary 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
102v8::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
111v8::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
122v8::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
128v8::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
143String16 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
151String16 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
157String16 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
165StringView toStringView(const String16& string) {
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
240String16 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
248namespace v8_crdtp {
249
250using v8_inspector::String16;
251using v8_inspector::protocol::Binary;
252using v8_inspector::protocol::StringUtil;
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();
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
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    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
303void 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
308}  // namespace v8_crdtp
309