Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:42

0001 //
0002 // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
0010 
0011 #include <boost/mysql/client_errc.hpp>
0012 #include <boost/mysql/error_code.hpp>
0013 #include <boost/mysql/field_view.hpp>
0014 #include <boost/mysql/string_view.hpp>
0015 
0016 #include <boost/mysql/impl/internal/protocol/basic_types.hpp>
0017 #include <boost/mysql/impl/internal/protocol/capabilities.hpp>
0018 #include <boost/mysql/impl/internal/protocol/protocol_field_type.hpp>
0019 
0020 #include <boost/assert.hpp>
0021 #include <boost/core/span.hpp>
0022 #include <boost/endian/conversion.hpp>
0023 #include <boost/endian/detail/endian_load.hpp>
0024 #include <boost/endian/detail/endian_store.hpp>
0025 
0026 #include <cstddef>
0027 #include <cstdint>
0028 #include <cstring>
0029 #include <type_traits>
0030 
0031 namespace boost {
0032 namespace mysql {
0033 namespace detail {
0034 
0035 // We operate with this enum directly in the deserialization routines for efficiency, then transform it to an
0036 // actual error code
0037 enum class deserialize_errc
0038 {
0039     ok = 0,
0040     incomplete_message = 1,
0041     protocol_value_error,
0042     server_unsupported
0043 };
0044 inline error_code to_error_code(deserialize_errc v) noexcept
0045 {
0046     switch (v)
0047     {
0048     case deserialize_errc::ok: return error_code();
0049     case deserialize_errc::incomplete_message: return error_code(client_errc::incomplete_message);
0050     case deserialize_errc::protocol_value_error: return error_code(client_errc::protocol_value_error);
0051     case deserialize_errc::server_unsupported: return error_code(client_errc::server_unsupported);
0052     default: BOOST_ASSERT(false); return error_code();  // avoid warnings
0053     }
0054 }
0055 
0056 class serialization_context
0057 {
0058     std::uint8_t* first_;
0059 
0060 public:
0061     explicit serialization_context(std::uint8_t* first) noexcept : first_(first) {}
0062     std::uint8_t* first() const noexcept { return first_; }
0063     void advance(std::size_t size) noexcept { first_ += size; }
0064     void write(const void* buffer, std::size_t size) noexcept
0065     {
0066         if (size)
0067         {
0068             BOOST_ASSERT(buffer != nullptr);
0069             std::memcpy(first_, buffer, size);
0070             advance(size);
0071         }
0072     }
0073     void write(std::uint8_t elm) noexcept
0074     {
0075         *first_ = elm;
0076         ++first_;
0077     }
0078 };
0079 
0080 class deserialization_context
0081 {
0082     const std::uint8_t* first_;
0083     const std::uint8_t* last_;
0084 
0085 public:
0086     deserialization_context(span<const std::uint8_t> data) noexcept
0087         : deserialization_context(data.data(), data.size())
0088     {
0089     }
0090     deserialization_context(const std::uint8_t* first, std::size_t size) noexcept
0091         : first_(first), last_(first + size){};
0092     const std::uint8_t* first() const noexcept { return first_; }
0093     const std::uint8_t* last() const noexcept { return last_; }
0094     void advance(std::size_t sz) noexcept
0095     {
0096         first_ += sz;
0097         BOOST_ASSERT(last_ >= first_);
0098     }
0099     void rewind(std::size_t sz) noexcept { first_ -= sz; }
0100     std::size_t size() const noexcept { return last_ - first_; }
0101     bool empty() const noexcept { return last_ == first_; }
0102     bool enough_size(std::size_t required_size) const noexcept { return size() >= required_size; }
0103     deserialize_errc copy(void* to, std::size_t sz) noexcept
0104     {
0105         if (!enough_size(sz))
0106             return deserialize_errc::incomplete_message;
0107         memcpy(to, first_, sz);
0108         advance(sz);
0109         return deserialize_errc::ok;
0110     }
0111     string_view get_string(std::size_t sz) const noexcept
0112     {
0113         return string_view(reinterpret_cast<const char*>(first_), sz);
0114     }
0115     error_code check_extra_bytes() const noexcept
0116     {
0117         return empty() ? error_code() : error_code(client_errc::extra_bytes);
0118     }
0119     span<const std::uint8_t> to_span() const noexcept { return span<const std::uint8_t>(first_, size()); }
0120 };
0121 
0122 // integers
0123 template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
0124 deserialize_errc deserialize(deserialization_context& ctx, T& output) noexcept
0125 {
0126     constexpr std::size_t sz = sizeof(T);
0127     if (!ctx.enough_size(sz))
0128     {
0129         return deserialize_errc::incomplete_message;
0130     }
0131     output = endian::endian_load<T, sz, boost::endian::order::little>(ctx.first());
0132     ctx.advance(sz);
0133     return deserialize_errc::ok;
0134 }
0135 
0136 template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
0137 void serialize(serialization_context& ctx, T input) noexcept
0138 {
0139     endian::endian_store<T, sizeof(T), endian::order::little>(ctx.first(), input);
0140     ctx.advance(sizeof(T));
0141 }
0142 
0143 template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
0144 constexpr std::size_t get_size(T) noexcept
0145 {
0146     return sizeof(T);
0147 }
0148 
0149 // int3
0150 inline deserialize_errc deserialize(deserialization_context& ctx, int3& output) noexcept
0151 {
0152     if (!ctx.enough_size(3))
0153         return deserialize_errc::incomplete_message;
0154     output.value = endian::load_little_u24(ctx.first());
0155     ctx.advance(3);
0156     return deserialize_errc::ok;
0157 }
0158 inline void serialize(serialization_context& ctx, int3 input) noexcept
0159 {
0160     endian::store_little_u24(ctx.first(), input.value);
0161     ctx.advance(3);
0162 }
0163 constexpr std::size_t get_size(int3) noexcept { return 3; }
0164 
0165 // int_lenenc
0166 inline deserialize_errc deserialize(deserialization_context& ctx, int_lenenc& output) noexcept
0167 {
0168     std::uint8_t first_byte = 0;
0169     auto err = deserialize(ctx, first_byte);
0170     if (err != deserialize_errc::ok)
0171     {
0172         return err;
0173     }
0174 
0175     if (first_byte == 0xFC)
0176     {
0177         std::uint16_t value = 0;
0178         err = deserialize(ctx, value);
0179         output.value = value;
0180     }
0181     else if (first_byte == 0xFD)
0182     {
0183         int3 value{};
0184         err = deserialize(ctx, value);
0185         output.value = value.value;
0186     }
0187     else if (first_byte == 0xFE)
0188     {
0189         std::uint64_t value = 0;
0190         err = deserialize(ctx, value);
0191         output.value = value;
0192     }
0193     else
0194     {
0195         err = deserialize_errc::ok;
0196         output.value = first_byte;
0197     }
0198     return err;
0199 }
0200 inline void serialize(serialization_context& ctx, int_lenenc input) noexcept
0201 {
0202     if (input.value < 251)
0203     {
0204         serialize(ctx, static_cast<std::uint8_t>(input.value));
0205     }
0206     else if (input.value < 0x10000)
0207     {
0208         ctx.write(0xfc);
0209         serialize(ctx, static_cast<std::uint16_t>(input.value));
0210     }
0211     else if (input.value < 0x1000000)
0212     {
0213         ctx.write(0xfd);
0214         serialize(ctx, int3{static_cast<std::uint32_t>(input.value)});
0215     }
0216     else
0217     {
0218         ctx.write(0xfe);
0219         serialize(ctx, static_cast<std::uint64_t>(input.value));
0220     }
0221 }
0222 inline std::size_t get_size(int_lenenc input) noexcept
0223 {
0224     if (input.value < 251)
0225         return 1;
0226     else if (input.value < 0x10000)
0227         return 3;
0228     else if (input.value < 0x1000000)
0229         return 4;
0230     else
0231         return 9;
0232 }
0233 
0234 // protocol_field_type
0235 inline deserialize_errc deserialize(deserialization_context& ctx, protocol_field_type& output) noexcept
0236 {
0237     std::underlying_type<protocol_field_type>::type value = 0;
0238     auto err = deserialize(ctx, value);
0239     output = static_cast<protocol_field_type>(value);
0240     return err;
0241 }
0242 inline void serialize(serialization_context& ctx, protocol_field_type input) noexcept
0243 {
0244     serialize(ctx, static_cast<std::underlying_type<protocol_field_type>::type>(input));
0245 }
0246 constexpr std::size_t get_size(protocol_field_type) noexcept { return sizeof(protocol_field_type); }
0247 
0248 // string_fixed
0249 template <std::size_t N>
0250 deserialize_errc deserialize(deserialization_context& ctx, string_fixed<N>& output) noexcept
0251 {
0252     if (!ctx.enough_size(N))
0253         return deserialize_errc::incomplete_message;
0254     memcpy(output.value.data(), ctx.first(), N);
0255     ctx.advance(N);
0256     return deserialize_errc::ok;
0257 }
0258 
0259 template <std::size_t N>
0260 void serialize(serialization_context& ctx, const string_fixed<N>& input) noexcept
0261 {
0262     ctx.write(input.value.data(), N);
0263 }
0264 
0265 template <std::size_t N>
0266 constexpr std::size_t get_size(const string_fixed<N>&) noexcept
0267 {
0268     return N;
0269 }
0270 
0271 // string_null
0272 inline deserialize_errc deserialize(deserialization_context& ctx, string_null& output) noexcept
0273 {
0274     auto string_end = std::find(ctx.first(), ctx.last(), 0);
0275     if (string_end == ctx.last())
0276     {
0277         return deserialize_errc::incomplete_message;
0278     }
0279     std::size_t length = string_end - ctx.first();
0280     output.value = ctx.get_string(length);
0281     ctx.advance(length + 1);  // skip the null terminator
0282     return deserialize_errc::ok;
0283 }
0284 inline void serialize(serialization_context& ctx, string_null input) noexcept
0285 {
0286     ctx.write(input.value.data(), input.value.size());
0287     ctx.write(0);  // null terminator
0288 }
0289 inline std::size_t get_size(string_null input) noexcept { return input.value.size() + 1; }
0290 
0291 // string_eof
0292 inline deserialize_errc deserialize(deserialization_context& ctx, string_eof& output) noexcept
0293 {
0294     std::size_t size = ctx.size();
0295     output.value = ctx.get_string(size);
0296     ctx.advance(size);
0297     return deserialize_errc::ok;
0298 }
0299 inline void serialize(serialization_context& ctx, string_eof input) noexcept
0300 {
0301     ctx.write(input.value.data(), input.value.size());
0302 }
0303 inline std::size_t get_size(string_eof input) noexcept { return input.value.size(); }
0304 
0305 // string_lenenc
0306 inline deserialize_errc deserialize(deserialization_context& ctx, string_lenenc& output) noexcept
0307 {
0308     int_lenenc length;
0309     auto err = deserialize(ctx, length);
0310     if (err != deserialize_errc::ok)
0311     {
0312         return err;
0313     }
0314     if (length.value > (std::numeric_limits<std::size_t>::max)())
0315     {
0316         return deserialize_errc::protocol_value_error;
0317     }
0318     auto len = static_cast<std::size_t>(length.value);
0319     if (!ctx.enough_size(len))
0320     {
0321         return deserialize_errc::incomplete_message;
0322     }
0323 
0324     output.value = ctx.get_string(len);
0325     ctx.advance(len);
0326     return deserialize_errc::ok;
0327 }
0328 inline void serialize(serialization_context& ctx, string_lenenc input) noexcept
0329 {
0330     serialize(ctx, int_lenenc{input.value.size()});
0331     ctx.write(input.value.data(), input.value.size());
0332 }
0333 inline std::size_t get_size(string_lenenc input) noexcept
0334 {
0335     return get_size(int_lenenc{input.value.size()}) + input.value.size();
0336 }
0337 
0338 // serialize, deserialize, and get size of multiple fields at the same time
0339 template <class FirstType, class SecondType, class... Rest>
0340 deserialize_errc deserialize(
0341     deserialization_context& ctx,
0342     FirstType& first,
0343     SecondType& second,
0344     Rest&... tail
0345 ) noexcept
0346 {
0347     deserialize_errc err = deserialize(ctx, first);
0348     if (err == deserialize_errc::ok)
0349     {
0350         err = deserialize(ctx, second, tail...);
0351     }
0352     return err;
0353 }
0354 
0355 template <class FirstType, class SecondType, class... Rest>
0356 void serialize(
0357     serialization_context& ctx,
0358     const FirstType& first,
0359     const SecondType& second,
0360     const Rest&... rest
0361 ) noexcept
0362 {
0363     serialize(ctx, first);
0364     serialize(ctx, second, rest...);
0365 }
0366 
0367 template <class FirstType, class SecondType, class... Rest>
0368 std::size_t get_size(const FirstType& first, const SecondType& second, const Rest&... rest) noexcept
0369 {
0370     return get_size(first) + get_size(second, rest...);
0371 }
0372 
0373 // helpers
0374 inline string_view to_string(span<const std::uint8_t> v) noexcept
0375 {
0376     return string_view(reinterpret_cast<const char*>(v.data()), v.size());
0377 }
0378 inline span<const std::uint8_t> to_span(string_view v) noexcept
0379 {
0380     return span<const std::uint8_t>(reinterpret_cast<const std::uint8_t*>(v.data()), v.size());
0381 }
0382 
0383 }  // namespace detail
0384 }  // namespace mysql
0385 }  // namespace boost
0386 
0387 #endif