/src/node/src/inspector/node_string.cc
Line | Count | Source |
1 | | #include "node_string.h" |
2 | | #include "crdtp/json.h" |
3 | | #include "node/inspector/protocol/Protocol.h" |
4 | | #include "simdutf.h" |
5 | | #include "util-inl.h" |
6 | | |
7 | | namespace crdtp { |
8 | | |
9 | | bool ProtocolTypeTraits<std::string>::Deserialize(DeserializerState* state, |
10 | 0 | std::string* value) { |
11 | 0 | if (state->tokenizer()->TokenTag() == cbor::CBORTokenTag::STRING8) { |
12 | 0 | span<uint8_t> cbor_span = state->tokenizer()->GetString8(); |
13 | 0 | value->assign(reinterpret_cast<const char*>(cbor_span.data()), |
14 | 0 | cbor_span.size()); |
15 | 0 | return true; |
16 | 0 | } |
17 | 0 | CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::STRING16); |
18 | 0 | span<uint8_t> utf16le = state->tokenizer()->GetString16WireRep(); |
19 | |
|
20 | 0 | value->assign(node::inspector::protocol::StringUtil::fromUTF16LE( |
21 | 0 | reinterpret_cast<const uint16_t*>(utf16le.data()), |
22 | 0 | utf16le.size() / sizeof(uint16_t))); |
23 | 0 | return true; |
24 | 0 | } |
25 | | |
26 | | void ProtocolTypeTraits<std::string>::Serialize(const std::string& value, |
27 | 0 | std::vector<uint8_t>* bytes) { |
28 | 0 | cbor::EncodeString8(SpanFrom(value), bytes); |
29 | 0 | } |
30 | | |
31 | | bool ProtocolTypeTraits<node::inspector::protocol::Binary>::Deserialize( |
32 | 0 | DeserializerState* state, node::inspector::protocol::Binary* value) { |
33 | 0 | CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::BINARY); |
34 | 0 | span<uint8_t> cbor_span = state->tokenizer()->GetBinary(); |
35 | 0 | *value = node::inspector::protocol::Binary::fromSpan(cbor_span); |
36 | 0 | return true; |
37 | 0 | } |
38 | | |
39 | | void ProtocolTypeTraits<node::inspector::protocol::Binary>::Serialize( |
40 | | const node::inspector::protocol::Binary& value, |
41 | 0 | std::vector<uint8_t>* bytes) { |
42 | 0 | cbor::EncodeString8(SpanFrom(value.toBase64()), bytes); |
43 | 0 | } |
44 | | |
45 | | } // namespace crdtp |
46 | | |
47 | | namespace node { |
48 | | namespace inspector { |
49 | | namespace protocol { |
50 | | |
51 | 0 | String StringUtil::StringViewToUtf8(v8_inspector::StringView view) { |
52 | 0 | if (view.length() == 0) |
53 | 0 | return ""; |
54 | 0 | if (view.is8Bit()) { |
55 | 0 | return std::string(reinterpret_cast<const char*>(view.characters8()), |
56 | 0 | view.length()); |
57 | 0 | } |
58 | 0 | return fromUTF16(view.characters16(), view.length()); |
59 | 0 | } |
60 | | |
61 | 0 | String StringUtil::fromUTF16(const uint16_t* data, size_t length) { |
62 | 0 | auto casted_data = reinterpret_cast<const char16_t*>(data); |
63 | 0 | size_t expected_utf8_length = |
64 | 0 | simdutf::utf8_length_from_utf16(casted_data, length); |
65 | 0 | MaybeStackBuffer<char> buffer(expected_utf8_length); |
66 | | // simdutf::convert_utf16_to_utf8 returns zero in case of error. |
67 | 0 | size_t utf8_length = |
68 | 0 | simdutf::convert_utf16_to_utf8(casted_data, length, buffer.out()); |
69 | | // We have that utf8_length == expected_utf8_length if and only |
70 | | // if the input was a valid UTF-16 string. Otherwise, utf8_length |
71 | | // must be zero. |
72 | 0 | CHECK(utf8_length == 0 || utf8_length == expected_utf8_length); |
73 | | // An invalid UTF-16 input will generate the empty string: |
74 | 0 | return String(buffer.out(), utf8_length); |
75 | 0 | } |
76 | | |
77 | 0 | String StringUtil::fromUTF8(const uint8_t* data, size_t length) { |
78 | 0 | return std::string(reinterpret_cast<const char*>(data), length); |
79 | 0 | } |
80 | | |
81 | 0 | String StringUtil::fromUTF16LE(const uint16_t* data, size_t length) { |
82 | 0 | auto casted_data = reinterpret_cast<const char16_t*>(data); |
83 | 0 | size_t expected_utf8_length = |
84 | 0 | simdutf::utf8_length_from_utf16le(casted_data, length); |
85 | 0 | MaybeStackBuffer<char> buffer(expected_utf8_length); |
86 | | // simdutf::convert_utf16le_to_utf8 returns zero in case of error. |
87 | 0 | size_t utf8_length = |
88 | 0 | simdutf::convert_utf16le_to_utf8(casted_data, length, buffer.out()); |
89 | | // We have that utf8_length == expected_utf8_length if and only |
90 | | // if the input was a valid UTF-16 string. Otherwise, utf8_length |
91 | | // must be zero. |
92 | 0 | CHECK(utf8_length == 0 || utf8_length == expected_utf8_length); |
93 | | // An invalid UTF-16 input will generate the empty string: |
94 | 0 | return String(buffer.out(), utf8_length); |
95 | 0 | } |
96 | | |
97 | 0 | const uint8_t* StringUtil::CharactersUTF8(const std::string_view s) { |
98 | 0 | return reinterpret_cast<const uint8_t*>(s.data()); |
99 | 0 | } |
100 | | |
101 | 0 | size_t StringUtil::CharacterCount(const std::string_view s) { |
102 | | // Return the length of underlying representation storage. |
103 | | // E.g. for std::basic_string_view<char>, return its byte length. |
104 | | // If we adopt a variant underlying store string type, like |
105 | | // `v8_inspector::StringView`, for UTF16, return the length of the |
106 | | // underlying uint16_t store. |
107 | 0 | return s.length(); |
108 | 0 | } |
109 | | |
110 | 0 | String Binary::toBase64() const { |
111 | 0 | size_t expected_base64_length = |
112 | 0 | simdutf::base64_length_from_binary(bytes_->size()); |
113 | 0 | MaybeStackBuffer<char> buffer(expected_base64_length); |
114 | |
|
115 | 0 | size_t len = |
116 | 0 | simdutf::binary_to_base64(reinterpret_cast<const char*>(bytes_->data()), |
117 | 0 | bytes_->size(), |
118 | 0 | buffer.out()); |
119 | 0 | CHECK_EQ(len, expected_base64_length); |
120 | 0 | return buffer.ToString(); |
121 | 0 | } |
122 | | |
123 | | // static |
124 | 0 | Binary Binary::concat(const std::vector<Binary>& binaries) { |
125 | 0 | size_t total_size = 0; |
126 | 0 | for (const auto& binary : binaries) { |
127 | 0 | total_size += binary.size(); |
128 | 0 | } |
129 | 0 | auto bytes = std::make_shared<std::vector<uint8_t>>(total_size); |
130 | 0 | uint8_t* data_ptr = bytes->data(); |
131 | 0 | for (const auto& binary : binaries) { |
132 | 0 | memcpy(data_ptr, binary.data(), binary.size()); |
133 | 0 | data_ptr += binary.size(); |
134 | 0 | } |
135 | 0 | return Binary(bytes); |
136 | 0 | } |
137 | | |
138 | | // static |
139 | 0 | Binary Binary::fromBase64(const String& base64, bool* success) { |
140 | 0 | Binary binary{}; |
141 | 0 | size_t base64_len = simdutf::maximal_binary_length_from_base64( |
142 | 0 | base64.data(), base64.length()); |
143 | 0 | binary.bytes_->resize(base64_len); |
144 | |
|
145 | 0 | simdutf::result result; |
146 | 0 | result = |
147 | 0 | simdutf::base64_to_binary(base64.data(), |
148 | 0 | base64.length(), |
149 | 0 | reinterpret_cast<char*>(binary.bytes_->data())); |
150 | 0 | CHECK_EQ(result.error, simdutf::error_code::SUCCESS); |
151 | 0 | return binary; |
152 | 0 | } |
153 | | |
154 | | // static |
155 | 0 | Binary Binary::fromUint8Array(v8::Local<v8::Uint8Array> data) { |
156 | 0 | auto bytes = std::make_shared<std::vector<uint8_t>>(data->ByteLength()); |
157 | 0 | size_t size = data->CopyContents(bytes->data(), data->ByteLength()); |
158 | 0 | CHECK_EQ(size, data->ByteLength()); |
159 | 0 | return Binary(bytes); |
160 | 0 | } |
161 | | |
162 | | } // namespace protocol |
163 | | } // namespace inspector |
164 | | } // namespace node |