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
20namespace v8_inspector {
21
22namespace {
23
24bool isASCII(UChar c) { return !(c & ~0x7F); }
25
26bool isSpaceOrNewLine(UChar c) {
27  return isASCII(c) && c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
28}
29
30int64_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
51String16::String16(const UChar* characters, size_t size)
52    : m_impl(characters, size) {}
53
54String16::String16(const UChar* characters) : m_impl(characters) {}
55
56String16::String16(const char* characters)
57    : String16(characters, std::strlen(characters)) {}
58
59String16::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
64String16::String16(const std::basic_string<UChar>& impl) : m_impl(impl) {}
65
66String16::String16(std::basic_string<UChar>&& impl) : m_impl(impl) {}
67
68// static
69String16 String16::fromInteger(int number) {
70  char arr[50];
71  v8::base::Vector<char> buffer(arr, arraysize(arr));
72  return String16(v8::internal::IntToCString(number, buffer));
73}
74
75// static
76String16 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
88String16 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
95String16 String16::fromDouble(double number) {
96  char arr[50];
97  v8::base::Vector<char> buffer(arr, arraysize(arr));
98  return String16(v8::internal::DoubleToCString(number, buffer));
99}
100
101// static
102String16 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
108int64_t String16::toInteger64(bool* ok) const {
109  return charactersToInteger(characters16(), length(), ok);
110}
111
112int 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
121String16 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
140String16Builder::String16Builder() = default;
141
142void String16Builder::append(const String16& s) {
143  m_buffer.insert(m_buffer.end(), s.characters16(),
144                  s.characters16() + s.length());
145}
146
147void String16Builder::append(UChar c) { m_buffer.push_back(c); }
148
149void String16Builder::append(char c) {
150  UChar u = c;
151  m_buffer.push_back(u);
152}
153
154void String16Builder::append(const UChar* characters, size_t length) {
155  m_buffer.insert(m_buffer.end(), characters, characters + length);
156}
157
158void String16Builder::append(const char* characters, size_t length) {
159  m_buffer.insert(m_buffer.end(), characters, characters + length);
160}
161
162void 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
170void 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
182void 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
191void 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
199void 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
207String16 String16Builder::toString() {
208  return String16(m_buffer.data(), m_buffer.size());
209}
210
211void String16Builder::reserveCapacity(size_t capacity) {
212  m_buffer.reserve(capacity);
213}
214
215String16 String16::fromUTF8(const char* stringStart, size_t length) {
216  return String16(UTF8ToUTF16(stringStart, length));
217}
218
219String16 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
236std::string String16::utf8() const {
237  return UTF16ToUTF8(m_impl.data(), m_impl.size());
238}
239
240}  // namespace v8_inspector
241