diff --git a/Userland/Libraries/LibIPC/Encoder.cpp b/Userland/Libraries/LibIPC/Encoder.cpp index 28121ef519..c66f857880 100644 --- a/Userland/Libraries/LibIPC/Encoder.cpp +++ b/Userland/Libraries/LibIPC/Encoder.cpp @@ -20,170 +20,81 @@ namespace IPC { -Encoder& Encoder::operator<<(bool value) +template<> +bool encode(Encoder& encoder, float const& value) { - return *this << (u8)value; + return encoder.encode(bit_cast(value)); } -Encoder& Encoder::operator<<(u8 value) +template<> +bool encode(Encoder& encoder, double const& value) { - m_buffer.data.append(value); - return *this; + return encoder.encode(bit_cast(value)); } -Encoder& Encoder::operator<<(u16 value) +template<> +bool encode(Encoder& encoder, StringView const& value) { - m_buffer.data.ensure_capacity(m_buffer.data.size() + 2); - m_buffer.data.unchecked_append((u8)value); - m_buffer.data.unchecked_append((u8)(value >> 8)); - return *this; + auto result = encoder.append(reinterpret_cast(value.characters_without_null_termination()), value.length()); + return !result.is_error(); } -void Encoder::encode_u32(u32 value) -{ - m_buffer.data.ensure_capacity(m_buffer.data.size() + 4); - m_buffer.data.unchecked_append((u8)value); - m_buffer.data.unchecked_append((u8)(value >> 8)); - m_buffer.data.unchecked_append((u8)(value >> 16)); - m_buffer.data.unchecked_append((u8)(value >> 24)); -} - -void Encoder::encode_u64(u64 value) -{ - m_buffer.data.ensure_capacity(m_buffer.data.size() + 8); - m_buffer.data.unchecked_append((u8)value); - m_buffer.data.unchecked_append((u8)(value >> 8)); - m_buffer.data.unchecked_append((u8)(value >> 16)); - m_buffer.data.unchecked_append((u8)(value >> 24)); - m_buffer.data.unchecked_append((u8)(value >> 32)); - m_buffer.data.unchecked_append((u8)(value >> 40)); - m_buffer.data.unchecked_append((u8)(value >> 48)); - m_buffer.data.unchecked_append((u8)(value >> 56)); -} - -Encoder& Encoder::operator<<(unsigned value) -{ - encode_u32(value); - return *this; -} - -Encoder& Encoder::operator<<(unsigned long value) -{ - if constexpr (sizeof(value) == 4) - encode_u32(value); - else - encode_u64(value); - return *this; -} - -Encoder& Encoder::operator<<(unsigned long long value) -{ - if constexpr (sizeof(value) == 4) - encode_u32(value); - else - encode_u64(value); - return *this; -} - -Encoder& Encoder::operator<<(i8 value) -{ - m_buffer.data.append((u8)value); - return *this; -} - -Encoder& Encoder::operator<<(i16 value) -{ - m_buffer.data.ensure_capacity(m_buffer.data.size() + 2); - m_buffer.data.unchecked_append((u8)value); - m_buffer.data.unchecked_append((u8)(value >> 8)); - return *this; -} - -Encoder& Encoder::operator<<(i32 value) -{ - m_buffer.data.ensure_capacity(m_buffer.data.size() + 4); - m_buffer.data.unchecked_append((u8)value); - m_buffer.data.unchecked_append((u8)(value >> 8)); - m_buffer.data.unchecked_append((u8)(value >> 16)); - m_buffer.data.unchecked_append((u8)(value >> 24)); - return *this; -} - -Encoder& Encoder::operator<<(i64 value) -{ - m_buffer.data.ensure_capacity(m_buffer.data.size() + 8); - m_buffer.data.unchecked_append((u8)value); - m_buffer.data.unchecked_append((u8)(value >> 8)); - m_buffer.data.unchecked_append((u8)(value >> 16)); - m_buffer.data.unchecked_append((u8)(value >> 24)); - m_buffer.data.unchecked_append((u8)(value >> 32)); - m_buffer.data.unchecked_append((u8)(value >> 40)); - m_buffer.data.unchecked_append((u8)(value >> 48)); - m_buffer.data.unchecked_append((u8)(value >> 56)); - return *this; -} - -Encoder& Encoder::operator<<(float value) -{ - u32 as_u32 = bit_cast(value); - return *this << as_u32; -} - -Encoder& Encoder::operator<<(double value) -{ - u64 as_u64 = bit_cast(value); - return *this << as_u64; -} - -Encoder& Encoder::operator<<(char const* value) -{ - return *this << StringView { value, strlen(value) }; -} - -Encoder& Encoder::operator<<(StringView value) -{ - m_buffer.data.append((u8 const*)value.characters_without_null_termination(), value.length()); - return *this; -} - -Encoder& Encoder::operator<<(DeprecatedString const& value) +template<> +bool encode(Encoder& encoder, DeprecatedString const& value) { if (value.is_null()) - return *this << (i32)-1; - *this << static_cast(value.length()); - return *this << value.view(); + return encoder.encode(-1); + + if (!encoder.encode(static_cast(value.length()))) + return false; + return encoder.encode(value.view()); } -Encoder& Encoder::operator<<(ByteBuffer const& value) +template<> +bool encode(Encoder& encoder, ByteBuffer const& value) { - *this << static_cast(value.size()); - m_buffer.data.append(value.data(), value.size()); - return *this; + if (!encoder.encode(static_cast(value.size()))) + return false; + + auto result = encoder.append(value.data(), value.size()); + return !result.is_error(); } -Encoder& Encoder::operator<<(JsonValue const& value) +template<> +bool encode(Encoder& encoder, JsonValue const& value) { - *this << value.serialized(); - return *this; + return encoder.encode(value.serialized()); } -Encoder& Encoder::operator<<(URL const& value) +template<> +bool encode(Encoder& encoder, URL const& value) { - return *this << value.to_deprecated_string(); + return encoder.encode(value.to_deprecated_string()); } -Encoder& Encoder::operator<<(Dictionary const& dictionary) +template<> +bool encode(Encoder& encoder, Dictionary const& dictionary) { - *this << (u64)dictionary.size(); - dictionary.for_each_entry([this](auto& key, auto& value) { - *this << key << value; + if (!encoder.encode(static_cast(dictionary.size()))) + return false; + + bool had_error = false; + + dictionary.for_each_entry([&](auto const& key, auto const& value) { + if (had_error) + return; + if (!encoder.encode(key) || !encoder.encode(value)) + had_error = true; }); - return *this; + + return !had_error; } -Encoder& Encoder::operator<<(File const& file) +template<> +bool encode(Encoder& encoder, File const& file) { int fd = file.fd(); + if (fd != -1) { auto result = dup(fd); if (result < 0) { @@ -192,40 +103,49 @@ Encoder& Encoder::operator<<(File const& file) } fd = result; } - m_buffer.fds.append(adopt_ref(*new AutoCloseFileDescriptor(fd))); - return *this; + + if (encoder.append_file_descriptor(fd).is_error()) + return false; + return true; } -// No-op. -Encoder& Encoder::operator<<(AK::Empty const&) +template<> +bool encode(Encoder&, Empty const&) { - return *this; + return true; } template<> bool encode(Encoder& encoder, Core::AnonymousBuffer const& buffer) { - encoder << buffer.is_valid(); + if (!encoder.encode(buffer.is_valid())) + return false; + if (buffer.is_valid()) { - encoder << (u32)buffer.size(); - encoder << IPC::File(buffer.fd()); + if (!encoder.encode(static_cast(buffer.size()))) + return false; + if (!encoder.encode(IPC::File { buffer.fd() })) + return false; } + return true; } template<> bool encode(Encoder& encoder, Core::DateTime const& datetime) { - encoder << static_cast(datetime.timestamp()); - return true; + return encoder.encode(static_cast(datetime.timestamp())); } template<> bool encode(Encoder& encoder, Core::ProxyData const& proxy) { - encoder << to_underlying(proxy.type); - encoder << proxy.host_ipv4; - encoder << proxy.port; + if (!encoder.encode(proxy.type)) + return false; + if (!encoder.encode(proxy.host_ipv4)) + return false; + if (!encoder.encode(proxy.port)) + return false; return true; } diff --git a/Userland/Libraries/LibIPC/Encoder.h b/Userland/Libraries/LibIPC/Encoder.h index e8bc3b0606..e331f9c9c0 100644 --- a/Userland/Libraries/LibIPC/Encoder.h +++ b/Userland/Libraries/LibIPC/Encoder.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -30,80 +31,6 @@ public: { } - Encoder& operator<<(bool); - Encoder& operator<<(u8); - Encoder& operator<<(u16); - Encoder& operator<<(unsigned); - Encoder& operator<<(unsigned long); - Encoder& operator<<(unsigned long long); - Encoder& operator<<(i8); - Encoder& operator<<(i16); - Encoder& operator<<(i32); - Encoder& operator<<(i64); - Encoder& operator<<(float); - Encoder& operator<<(double); - Encoder& operator<<(char const*); - Encoder& operator<<(StringView); - Encoder& operator<<(DeprecatedString const&); - Encoder& operator<<(ByteBuffer const&); - Encoder& operator<<(JsonValue const&); - Encoder& operator<<(URL const&); - Encoder& operator<<(Dictionary const&); - Encoder& operator<<(File const&); - Encoder& operator<<(AK::Empty const&); - template - Encoder& operator<<(HashMap const& hashmap) - { - *this << (u32)hashmap.size(); - for (auto it : hashmap) { - *this << it.key; - *this << it.value; - } - return *this; - } - - template - Encoder& operator<<(OrderedHashMap const& hashmap) - { - *this << (u32)hashmap.size(); - for (auto it : hashmap) { - *this << it.key; - *this << it.value; - } - return *this; - } - - template - Encoder& operator<<(Vector const& vector) - { - *this << (u64)vector.size(); - for (auto& value : vector) - *this << value; - return *this; - } - - template - Encoder& operator<<(Core::SharedSingleProducerCircularQueue const& queue) - { - *this << IPC::File(queue.fd()); - return *this; - } - - template - Encoder& operator<<(AK::Variant const& variant) - { - *this << variant.index(); - variant.visit([this](auto const& underlying_value) { *this << underlying_value; }); - return *this; - } - - template - Encoder& operator<<(T const& enum_value) - { - *this << AK::to_underlying(enum_value); - return *this; - } - template Encoder& operator<<(T const& value) { @@ -112,18 +39,29 @@ public: } template - Encoder& operator<<(Optional const& optional) + bool encode(T const& value); + + ErrorOr extend_capacity(size_t capacity) { - *this << optional.has_value(); - if (optional.has_value()) - *this << optional.value(); - return *this; + return m_buffer.data.try_ensure_capacity(m_buffer.data.size() + capacity); } - template - void encode(T const& value) + void append(u8 value) { - IPC::encode(*this, value); + m_buffer.data.unchecked_append(value); + } + + ErrorOr append(u8 const* values, size_t count) + { + TRY(extend_capacity(count)); + m_buffer.data.unchecked_append(values, count); + return {}; + } + + ErrorOr append_file_descriptor(int fd) + { + auto auto_fd = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AutoCloseFileDescriptor(fd))); + return m_buffer.fds.try_append(move(auto_fd)); } private: @@ -133,4 +71,137 @@ private: MessageBuffer& m_buffer; }; +template +bool encode(Encoder& encoder, T const& value) +{ + if (encoder.extend_capacity(sizeof(T)).is_error()) + return false; + + if constexpr (sizeof(T) == 1) { + encoder.append(static_cast(value)); + } else if constexpr (sizeof(T) == 2) { + encoder.append(static_cast(value)); + encoder.append(static_cast(value >> 8)); + } else if constexpr (sizeof(T) == 4) { + encoder.append(static_cast(value)); + encoder.append(static_cast(value >> 8)); + encoder.append(static_cast(value >> 16)); + encoder.append(static_cast(value >> 24)); + } else if constexpr (sizeof(T) == 8) { + encoder.append(static_cast(value)); + encoder.append(static_cast(value >> 8)); + encoder.append(static_cast(value >> 16)); + encoder.append(static_cast(value >> 24)); + encoder.append(static_cast(value >> 32)); + encoder.append(static_cast(value >> 40)); + encoder.append(static_cast(value >> 48)); + encoder.append(static_cast(value >> 56)); + } else { + static_assert(DependentFalse); + } + + return true; +} + +template +bool encode(Encoder& encoder, T const& value) +{ + return encoder.encode(to_underlying(value)); +} + +template<> +bool encode(Encoder&, float const&); + +template<> +bool encode(Encoder&, double const&); + +template<> +bool encode(Encoder&, StringView const&); + +template<> +bool encode(Encoder&, DeprecatedString const&); + +template<> +bool encode(Encoder&, ByteBuffer const&); + +template<> +bool encode(Encoder&, JsonValue const&); + +template<> +bool encode(Encoder&, URL const&); + +template<> +bool encode(Encoder&, Dictionary const&); + +template<> +bool encode(Encoder&, File const&); + +template<> +bool encode(Encoder&, Empty const&); + +template +bool encode(Encoder& encoder, T const& vector) +{ + if (!encoder.encode(static_cast(vector.size()))) + return false; + + for (auto const& value : vector) { + if (!encoder.encode(value)) + return false; + } + + return true; +} + +template +bool encode(Encoder& encoder, T const& hashmap) +{ + if (!encoder.encode(static_cast(hashmap.size()))) + return false; + + for (auto it : hashmap) { + if (!encoder.encode(it.key)) + return false; + if (!encoder.encode(it.value)) + return false; + } + + return true; +} + +template +bool encode(Encoder& encoder, T const& queue) +{ + return encoder.encode(IPC::File { queue.fd() }); +} + +template +bool encode(Encoder& encoder, T const& optional) +{ + if (!encoder.encode(optional.has_value())) + return false; + + if (optional.has_value()) + return encoder.encode(optional.value()); + return true; +} + +template +bool encode(Encoder& encoder, T const& variant) +{ + if (!encoder.encode(variant.index())) + return false; + + return variant.visit([&](auto const& value) { + return encoder.encode(value); + }); +} + +// This must be last so that it knows about the above specializations. +template +bool Encoder::encode(T const& value) +{ + return IPC::encode(*this, value); +} + }