serialization.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. //
  2. // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BHO_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
  8. #define BHO_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
  9. #include <asio2/bho/mysql/client_errc.hpp>
  10. #include <asio2/bho/mysql/error_code.hpp>
  11. #include <asio2/bho/mysql/field_view.hpp>
  12. #include <asio2/bho/mysql/string_view.hpp>
  13. #include <asio2/bho/mysql/impl/internal/protocol/basic_types.hpp>
  14. #include <asio2/bho/mysql/impl/internal/protocol/capabilities.hpp>
  15. #include <asio2/bho/mysql/impl/internal/protocol/protocol_field_type.hpp>
  16. #include <asio2/bho/assert.hpp>
  17. #include <asio2/bho/core/span.hpp>
  18. #include <asio2/bho/endian/conversion.hpp>
  19. #include <asio2/bho/endian/detail/endian_load.hpp>
  20. #include <asio2/bho/endian/detail/endian_store.hpp>
  21. #include <cstddef>
  22. #include <cstdint>
  23. #include <cstring>
  24. #include <type_traits>
  25. namespace bho {
  26. namespace mysql {
  27. namespace detail {
  28. // We operate with this enum directly in the deserialization routines for efficiency, then transform it to an
  29. // actual error code
  30. enum class deserialize_errc
  31. {
  32. ok = 0,
  33. incomplete_message = 1,
  34. protocol_value_error,
  35. server_unsupported
  36. };
  37. inline error_code to_error_code(deserialize_errc v) noexcept
  38. {
  39. switch (v)
  40. {
  41. case deserialize_errc::ok: return error_code();
  42. case deserialize_errc::incomplete_message: return error_code(client_errc::incomplete_message);
  43. case deserialize_errc::protocol_value_error: return error_code(client_errc::protocol_value_error);
  44. case deserialize_errc::server_unsupported: return error_code(client_errc::server_unsupported);
  45. default: BHO_ASSERT(false); return error_code(); // avoid warnings
  46. }
  47. }
  48. class serialization_context
  49. {
  50. std::uint8_t* first_;
  51. public:
  52. explicit serialization_context(std::uint8_t* first) noexcept : first_(first) {}
  53. std::uint8_t* first() const noexcept { return first_; }
  54. void advance(std::size_t size) noexcept { first_ += size; }
  55. void write(const void* buffer, std::size_t size) noexcept
  56. {
  57. if (size)
  58. {
  59. BHO_ASSERT(buffer != nullptr);
  60. std::memcpy(first_, buffer, size);
  61. advance(size);
  62. }
  63. }
  64. void write(std::uint8_t elm) noexcept
  65. {
  66. *first_ = elm;
  67. ++first_;
  68. }
  69. };
  70. class deserialization_context
  71. {
  72. const std::uint8_t* first_;
  73. const std::uint8_t* last_;
  74. public:
  75. deserialization_context(span<const std::uint8_t> data) noexcept
  76. : deserialization_context(data.data(), data.size())
  77. {
  78. }
  79. deserialization_context(const std::uint8_t* first, std::size_t size) noexcept
  80. : first_(first), last_(first + size){};
  81. const std::uint8_t* first() const noexcept { return first_; }
  82. const std::uint8_t* last() const noexcept { return last_; }
  83. void advance(std::size_t sz) noexcept
  84. {
  85. first_ += sz;
  86. BHO_ASSERT(last_ >= first_);
  87. }
  88. void rewind(std::size_t sz) noexcept { first_ -= sz; }
  89. std::size_t size() const noexcept { return last_ - first_; }
  90. bool empty() const noexcept { return last_ == first_; }
  91. bool enough_size(std::size_t required_size) const noexcept { return size() >= required_size; }
  92. deserialize_errc copy(void* to, std::size_t sz) noexcept
  93. {
  94. if (!enough_size(sz))
  95. return deserialize_errc::incomplete_message;
  96. memcpy(to, first_, sz);
  97. advance(sz);
  98. return deserialize_errc::ok;
  99. }
  100. string_view get_string(std::size_t sz) const noexcept
  101. {
  102. return string_view(reinterpret_cast<const char*>(first_), sz);
  103. }
  104. error_code check_extra_bytes() const noexcept
  105. {
  106. return empty() ? error_code() : error_code(client_errc::extra_bytes);
  107. }
  108. span<const std::uint8_t> to_span() const noexcept { return span<const std::uint8_t>(first_, size()); }
  109. };
  110. // integers
  111. template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
  112. deserialize_errc deserialize(deserialization_context& ctx, T& output) noexcept
  113. {
  114. constexpr std::size_t sz = sizeof(T);
  115. if (!ctx.enough_size(sz))
  116. {
  117. return deserialize_errc::incomplete_message;
  118. }
  119. output = endian::endian_load<T, sz, bho::endian::order::little>(ctx.first());
  120. ctx.advance(sz);
  121. return deserialize_errc::ok;
  122. }
  123. template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
  124. void serialize(serialization_context& ctx, T input) noexcept
  125. {
  126. endian::endian_store<T, sizeof(T), endian::order::little>(ctx.first(), input);
  127. ctx.advance(sizeof(T));
  128. }
  129. template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
  130. constexpr std::size_t get_size(T) noexcept
  131. {
  132. return sizeof(T);
  133. }
  134. // int3
  135. inline deserialize_errc deserialize(deserialization_context& ctx, int3& output) noexcept
  136. {
  137. if (!ctx.enough_size(3))
  138. return deserialize_errc::incomplete_message;
  139. output.value = endian::load_little_u24(ctx.first());
  140. ctx.advance(3);
  141. return deserialize_errc::ok;
  142. }
  143. inline void serialize(serialization_context& ctx, int3 input) noexcept
  144. {
  145. endian::store_little_u24(ctx.first(), input.value);
  146. ctx.advance(3);
  147. }
  148. constexpr std::size_t get_size(int3) noexcept { return 3; }
  149. // int_lenenc
  150. inline deserialize_errc deserialize(deserialization_context& ctx, int_lenenc& output) noexcept
  151. {
  152. std::uint8_t first_byte = 0;
  153. auto err = deserialize(ctx, first_byte);
  154. if (err != deserialize_errc::ok)
  155. {
  156. return err;
  157. }
  158. if (first_byte == 0xFC)
  159. {
  160. std::uint16_t value = 0;
  161. err = deserialize(ctx, value);
  162. output.value = value;
  163. }
  164. else if (first_byte == 0xFD)
  165. {
  166. int3 value{};
  167. err = deserialize(ctx, value);
  168. output.value = value.value;
  169. }
  170. else if (first_byte == 0xFE)
  171. {
  172. std::uint64_t value = 0;
  173. err = deserialize(ctx, value);
  174. output.value = value;
  175. }
  176. else
  177. {
  178. err = deserialize_errc::ok;
  179. output.value = first_byte;
  180. }
  181. return err;
  182. }
  183. inline void serialize(serialization_context& ctx, int_lenenc input) noexcept
  184. {
  185. if (input.value < 251)
  186. {
  187. serialize(ctx, static_cast<std::uint8_t>(input.value));
  188. }
  189. else if (input.value < 0x10000)
  190. {
  191. ctx.write(0xfc);
  192. serialize(ctx, static_cast<std::uint16_t>(input.value));
  193. }
  194. else if (input.value < 0x1000000)
  195. {
  196. ctx.write(0xfd);
  197. serialize(ctx, int3{static_cast<std::uint32_t>(input.value)});
  198. }
  199. else
  200. {
  201. ctx.write(0xfe);
  202. serialize(ctx, static_cast<std::uint64_t>(input.value));
  203. }
  204. }
  205. inline std::size_t get_size(int_lenenc input) noexcept
  206. {
  207. if (input.value < 251)
  208. return 1;
  209. else if (input.value < 0x10000)
  210. return 3;
  211. else if (input.value < 0x1000000)
  212. return 4;
  213. else
  214. return 9;
  215. }
  216. // protocol_field_type
  217. inline deserialize_errc deserialize(deserialization_context& ctx, protocol_field_type& output) noexcept
  218. {
  219. std::underlying_type<protocol_field_type>::type value = 0;
  220. auto err = deserialize(ctx, value);
  221. output = static_cast<protocol_field_type>(value);
  222. return err;
  223. }
  224. inline void serialize(serialization_context& ctx, protocol_field_type input) noexcept
  225. {
  226. serialize(ctx, static_cast<std::underlying_type<protocol_field_type>::type>(input));
  227. }
  228. constexpr std::size_t get_size(protocol_field_type) noexcept { return sizeof(protocol_field_type); }
  229. // string_fixed
  230. template <std::size_t N>
  231. deserialize_errc deserialize(deserialization_context& ctx, string_fixed<N>& output) noexcept
  232. {
  233. if (!ctx.enough_size(N))
  234. return deserialize_errc::incomplete_message;
  235. memcpy(output.value.data(), ctx.first(), N);
  236. ctx.advance(N);
  237. return deserialize_errc::ok;
  238. }
  239. template <std::size_t N>
  240. void serialize(serialization_context& ctx, const string_fixed<N>& input) noexcept
  241. {
  242. ctx.write(input.value.data(), N);
  243. }
  244. template <std::size_t N>
  245. constexpr std::size_t get_size(const string_fixed<N>&) noexcept
  246. {
  247. return N;
  248. }
  249. // string_null
  250. inline deserialize_errc deserialize(deserialization_context& ctx, string_null& output) noexcept
  251. {
  252. auto string_end = std::find(ctx.first(), ctx.last(), 0);
  253. if (string_end == ctx.last())
  254. {
  255. return deserialize_errc::incomplete_message;
  256. }
  257. std::size_t length = string_end - ctx.first();
  258. output.value = ctx.get_string(length);
  259. ctx.advance(length + 1); // skip the null terminator
  260. return deserialize_errc::ok;
  261. }
  262. inline void serialize(serialization_context& ctx, string_null input) noexcept
  263. {
  264. ctx.write(input.value.data(), input.value.size());
  265. ctx.write(0); // null terminator
  266. }
  267. inline std::size_t get_size(string_null input) noexcept { return input.value.size() + 1; }
  268. // string_eof
  269. inline deserialize_errc deserialize(deserialization_context& ctx, string_eof& output) noexcept
  270. {
  271. std::size_t size = ctx.size();
  272. output.value = ctx.get_string(size);
  273. ctx.advance(size);
  274. return deserialize_errc::ok;
  275. }
  276. inline void serialize(serialization_context& ctx, string_eof input) noexcept
  277. {
  278. ctx.write(input.value.data(), input.value.size());
  279. }
  280. inline std::size_t get_size(string_eof input) noexcept { return input.value.size(); }
  281. // string_lenenc
  282. inline deserialize_errc deserialize(deserialization_context& ctx, string_lenenc& output) noexcept
  283. {
  284. int_lenenc length;
  285. auto err = deserialize(ctx, length);
  286. if (err != deserialize_errc::ok)
  287. {
  288. return err;
  289. }
  290. if (length.value > (std::numeric_limits<std::size_t>::max)())
  291. {
  292. return deserialize_errc::protocol_value_error;
  293. }
  294. auto len = static_cast<std::size_t>(length.value);
  295. if (!ctx.enough_size(len))
  296. {
  297. return deserialize_errc::incomplete_message;
  298. }
  299. output.value = ctx.get_string(len);
  300. ctx.advance(len);
  301. return deserialize_errc::ok;
  302. }
  303. inline void serialize(serialization_context& ctx, string_lenenc input) noexcept
  304. {
  305. serialize(ctx, int_lenenc{input.value.size()});
  306. ctx.write(input.value.data(), input.value.size());
  307. }
  308. inline std::size_t get_size(string_lenenc input) noexcept
  309. {
  310. return get_size(int_lenenc{input.value.size()}) + input.value.size();
  311. }
  312. // serialize, deserialize, and get size of multiple fields at the same time
  313. template <class FirstType, class SecondType, class... Rest>
  314. deserialize_errc deserialize(
  315. deserialization_context& ctx,
  316. FirstType& first,
  317. SecondType& second,
  318. Rest&... tail
  319. ) noexcept
  320. {
  321. deserialize_errc err = deserialize(ctx, first);
  322. if (err == deserialize_errc::ok)
  323. {
  324. err = deserialize(ctx, second, tail...);
  325. }
  326. return err;
  327. }
  328. template <class FirstType, class SecondType, class... Rest>
  329. void serialize(
  330. serialization_context& ctx,
  331. const FirstType& first,
  332. const SecondType& second,
  333. const Rest&... rest
  334. ) noexcept
  335. {
  336. serialize(ctx, first);
  337. serialize(ctx, second, rest...);
  338. }
  339. template <class FirstType, class SecondType, class... Rest>
  340. std::size_t get_size(const FirstType& first, const SecondType& second, const Rest&... rest) noexcept
  341. {
  342. return get_size(first) + get_size(second, rest...);
  343. }
  344. // helpers
  345. inline string_view to_string(span<const std::uint8_t> v) noexcept
  346. {
  347. return string_view(reinterpret_cast<const char*>(v.data()), v.size());
  348. }
  349. inline span<const std::uint8_t> to_span(string_view v) noexcept
  350. {
  351. return span<const std::uint8_t>(reinterpret_cast<const std::uint8_t*>(v.data()), v.size());
  352. }
  353. } // namespace detail
  354. } // namespace mysql
  355. } // namespace bho
  356. #endif