#include "node_string.h" #include "crdtp/json.h" #include "node/inspector/protocol/Protocol.h" #include "simdutf.h" #include "util-inl.h" namespace crdtp { bool ProtocolTypeTraits::Deserialize(DeserializerState* state, std::string* value) { if (state->tokenizer()->TokenTag() == cbor::CBORTokenTag::STRING8) { span cbor_span = state->tokenizer()->GetString8(); value->assign(reinterpret_cast(cbor_span.data()), cbor_span.size()); return true; } CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::STRING16); span utf16le = state->tokenizer()->GetString16WireRep(); value->assign(node::inspector::protocol::StringUtil::fromUTF16LE( reinterpret_cast(utf16le.data()), utf16le.size() / sizeof(uint16_t))); return true; } void ProtocolTypeTraits::Serialize(const std::string& value, std::vector* bytes) { cbor::EncodeString8(SpanFrom(value), bytes); } bool ProtocolTypeTraits::Deserialize( DeserializerState* state, node::inspector::protocol::Binary* value) { CHECK(state->tokenizer()->TokenTag() == cbor::CBORTokenTag::BINARY); span cbor_span = state->tokenizer()->GetBinary(); *value = node::inspector::protocol::Binary::fromSpan(cbor_span); return true; } void ProtocolTypeTraits::Serialize( const node::inspector::protocol::Binary& value, std::vector* bytes) { cbor::EncodeString8(SpanFrom(value.toBase64()), bytes); } } // namespace crdtp namespace node { namespace inspector { namespace protocol { String StringUtil::StringViewToUtf8(v8_inspector::StringView view) { if (view.length() == 0) return ""; if (view.is8Bit()) { return std::string(reinterpret_cast(view.characters8()), view.length()); } return fromUTF16(view.characters16(), view.length()); } String StringUtil::fromUTF16(const uint16_t* data, size_t length) { auto casted_data = reinterpret_cast(data); size_t expected_utf8_length = simdutf::utf8_length_from_utf16(casted_data, length); MaybeStackBuffer buffer(expected_utf8_length); // simdutf::convert_utf16_to_utf8 returns zero in case of error. size_t utf8_length = simdutf::convert_utf16_to_utf8(casted_data, length, buffer.out()); // We have that utf8_length == expected_utf8_length if and only // if the input was a valid UTF-16 string. Otherwise, utf8_length // must be zero. CHECK(utf8_length == 0 || utf8_length == expected_utf8_length); // An invalid UTF-16 input will generate the empty string: return String(buffer.out(), utf8_length); } String StringUtil::fromUTF8(const uint8_t* data, size_t length) { return std::string(reinterpret_cast(data), length); } String StringUtil::fromUTF16LE(const uint16_t* data, size_t length) { auto casted_data = reinterpret_cast(data); size_t expected_utf8_length = simdutf::utf8_length_from_utf16le(casted_data, length); MaybeStackBuffer buffer(expected_utf8_length); // simdutf::convert_utf16le_to_utf8 returns zero in case of error. size_t utf8_length = simdutf::convert_utf16le_to_utf8(casted_data, length, buffer.out()); // We have that utf8_length == expected_utf8_length if and only // if the input was a valid UTF-16 string. Otherwise, utf8_length // must be zero. CHECK(utf8_length == 0 || utf8_length == expected_utf8_length); // An invalid UTF-16 input will generate the empty string: return String(buffer.out(), utf8_length); } const uint8_t* StringUtil::CharactersUTF8(const std::string_view s) { return reinterpret_cast(s.data()); } size_t StringUtil::CharacterCount(const std::string_view s) { // Return the length of underlying representation storage. // E.g. for std::basic_string_view, return its byte length. // If we adopt a variant underlying store string type, like // `v8_inspector::StringView`, for UTF16, return the length of the // underlying uint16_t store. return s.length(); } String Binary::toBase64() const { MaybeStackBuffer buffer; size_t str_len = simdutf::base64_length_from_binary(bytes_->size()); buffer.SetLength(str_len); size_t len = simdutf::binary_to_base64(reinterpret_cast(bytes_->data()), bytes_->size(), buffer.out()); CHECK_EQ(len, str_len); return buffer.ToString(); } // static Binary Binary::concat(const std::vector& binaries) { size_t total_size = 0; for (const auto& binary : binaries) { total_size += binary.size(); } auto bytes = std::make_shared>(total_size); uint8_t* data_ptr = bytes->data(); for (const auto& binary : binaries) { memcpy(data_ptr, binary.data(), binary.size()); data_ptr += binary.size(); } return Binary(bytes); } // static Binary Binary::fromBase64(const String& base64, bool* success) { Binary binary{}; size_t base64_len = simdutf::maximal_binary_length_from_base64( base64.data(), base64.length()); binary.bytes_->resize(base64_len); simdutf::result result; result = simdutf::base64_to_binary(base64.data(), base64.length(), reinterpret_cast(binary.bytes_->data())); CHECK_EQ(result.error, simdutf::error_code::SUCCESS); return binary; } // static Binary Binary::fromUint8Array(v8::Local data) { auto bytes = std::make_shared>(data->ByteLength()); size_t size = data->CopyContents(bytes->data(), data->ByteLength()); CHECK_EQ(size, data->ByteLength()); return Binary(bytes); } } // namespace protocol } // namespace inspector } // namespace node