/src/Serialization/KVBinaryOutputStreamSerializer.cpp

https://github.com/ConcealNetwork/conceal-core · C++ · 239 lines · 184 code · 50 blank · 5 comment · 21 complexity · 5e3255c94f4c0fde3f76615f424d8566 MD5 · raw file

  1. // Copyright (c) 2011-2017 The Cryptonote developers
  2. // Copyright (c) 2017-2018 The Circle Foundation & Conceal Devs
  3. // Copyright (c) 2018-2019 Conceal Network & Conceal Devs
  4. // Distributed under the MIT/X11 software license, see the accompanying
  5. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  6. #include "KVBinaryOutputStreamSerializer.h"
  7. #include "KVBinaryCommon.h"
  8. #include <cassert>
  9. #include <stdexcept>
  10. #include <Common/StreamTools.h>
  11. using namespace Common;
  12. using namespace CryptoNote;
  13. namespace {
  14. template <typename T>
  15. void writePod(IOutputStream& s, const T& value) {
  16. write(s, &value, sizeof(T));
  17. }
  18. template<class T>
  19. size_t packVarint(IOutputStream& s, uint8_t type_or, size_t pv) {
  20. T v = static_cast<T>(pv << 2);
  21. v |= type_or;
  22. write(s, &v, sizeof(T));
  23. return sizeof(T);
  24. }
  25. void writeElementName(IOutputStream& s, Common::StringView name) {
  26. if (name.getSize() > std::numeric_limits<uint8_t>::max()) {
  27. throw std::runtime_error("Element name is too long");
  28. }
  29. uint8_t len = static_cast<uint8_t>(name.getSize());
  30. write(s, &len, sizeof(len));
  31. write(s, name.getData(), len);
  32. }
  33. size_t writeArraySize(IOutputStream& s, size_t val) {
  34. if (val <= 63) {
  35. return packVarint<uint8_t>(s, PORTABLE_RAW_SIZE_MARK_BYTE, val);
  36. } else if (val <= 16383) {
  37. return packVarint<uint16_t>(s, PORTABLE_RAW_SIZE_MARK_WORD, val);
  38. } else if (val <= 1073741823) {
  39. return packVarint<uint32_t>(s, PORTABLE_RAW_SIZE_MARK_DWORD, val);
  40. } else {
  41. if (val > 4611686018427387903) {
  42. throw std::runtime_error("failed to pack varint - too big amount");
  43. }
  44. return packVarint<uint64_t>(s, PORTABLE_RAW_SIZE_MARK_INT64, val);
  45. }
  46. }
  47. }
  48. namespace CryptoNote {
  49. KVBinaryOutputStreamSerializer::KVBinaryOutputStreamSerializer() {
  50. beginObject(std::string());
  51. }
  52. void KVBinaryOutputStreamSerializer::dump(IOutputStream& target) {
  53. assert(m_objectsStack.size() == 1);
  54. assert(m_stack.size() == 1);
  55. KVBinaryStorageBlockHeader hdr;
  56. hdr.m_signature_a = PORTABLE_STORAGE_SIGNATUREA;
  57. hdr.m_signature_b = PORTABLE_STORAGE_SIGNATUREB;
  58. hdr.m_ver = PORTABLE_STORAGE_FORMAT_VER;
  59. Common::write(target, &hdr, sizeof(hdr));
  60. writeArraySize(target, m_stack.front().count);
  61. write(target, stream().data(), stream().size());
  62. }
  63. ISerializer::SerializerType KVBinaryOutputStreamSerializer::type() const {
  64. return ISerializer::OUTPUT;
  65. }
  66. bool KVBinaryOutputStreamSerializer::beginObject(Common::StringView name) {
  67. checkArrayPreamble(BIN_KV_SERIALIZE_TYPE_OBJECT);
  68. m_stack.push_back(Level(name));
  69. m_objectsStack.push_back(MemoryStream());
  70. return true;
  71. }
  72. void KVBinaryOutputStreamSerializer::endObject() {
  73. assert(m_objectsStack.size());
  74. auto level = std::move(m_stack.back());
  75. m_stack.pop_back();
  76. auto objStream = std::move(m_objectsStack.back());
  77. m_objectsStack.pop_back();
  78. auto& out = stream();
  79. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_OBJECT, level.name);
  80. writeArraySize(out, level.count);
  81. write(out, objStream.data(), objStream.size());
  82. }
  83. bool KVBinaryOutputStreamSerializer::beginArray(size_t& size, Common::StringView name) {
  84. m_stack.push_back(Level(name, size));
  85. return true;
  86. }
  87. void KVBinaryOutputStreamSerializer::endArray() {
  88. bool validArray = m_stack.back().state == State::Array;
  89. m_stack.pop_back();
  90. if (m_stack.back().state == State::Object && validArray) {
  91. ++m_stack.back().count;
  92. }
  93. }
  94. bool KVBinaryOutputStreamSerializer::operator()(uint8_t& value, Common::StringView name) {
  95. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_UINT8, name);
  96. writePod(stream(), value);
  97. return true;
  98. }
  99. bool KVBinaryOutputStreamSerializer::operator()(uint16_t& value, Common::StringView name) {
  100. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_UINT16, name);
  101. writePod(stream(), value);
  102. return true;
  103. }
  104. bool KVBinaryOutputStreamSerializer::operator()(int16_t& value, Common::StringView name) {
  105. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_INT16, name);
  106. writePod(stream(), value);
  107. return true;
  108. }
  109. bool KVBinaryOutputStreamSerializer::operator()(uint32_t& value, Common::StringView name) {
  110. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_UINT32, name);
  111. writePod(stream(), value);
  112. return true;
  113. }
  114. bool KVBinaryOutputStreamSerializer::operator()(int32_t& value, Common::StringView name) {
  115. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_INT32, name);
  116. writePod(stream(), value);
  117. return true;
  118. }
  119. bool KVBinaryOutputStreamSerializer::operator()(int64_t& value, Common::StringView name) {
  120. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_INT64, name);
  121. writePod(stream(), value);
  122. return true;
  123. }
  124. bool KVBinaryOutputStreamSerializer::operator()(uint64_t& value, Common::StringView name) {
  125. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_UINT64, name);
  126. writePod(stream(), value);
  127. return true;
  128. }
  129. bool KVBinaryOutputStreamSerializer::operator()(bool& value, Common::StringView name) {
  130. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_BOOL, name);
  131. writePod(stream(), value);
  132. return true;
  133. }
  134. bool KVBinaryOutputStreamSerializer::operator()(double& value, Common::StringView name) {
  135. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_DOUBLE, name);
  136. writePod(stream(), value);
  137. return true;
  138. }
  139. bool KVBinaryOutputStreamSerializer::operator()(std::string& value, Common::StringView name) {
  140. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_STRING, name);
  141. auto& out = stream();
  142. writeArraySize(out, value.size());
  143. write(out, value.data(), value.size());
  144. return true;
  145. }
  146. bool KVBinaryOutputStreamSerializer::binary(void* value, size_t size, Common::StringView name) {
  147. if (size > 0) {
  148. writeElementPrefix(BIN_KV_SERIALIZE_TYPE_STRING, name);
  149. auto& out = stream();
  150. writeArraySize(out, size);
  151. write(out, value, size);
  152. }
  153. return true;
  154. }
  155. bool KVBinaryOutputStreamSerializer::binary(std::string& value, Common::StringView name) {
  156. return binary(const_cast<char*>(value.data()), value.size(), name);
  157. }
  158. void KVBinaryOutputStreamSerializer::writeElementPrefix(uint8_t type, Common::StringView name) {
  159. assert(m_stack.size());
  160. checkArrayPreamble(type);
  161. Level& level = m_stack.back();
  162. if (level.state != State::Array) {
  163. if (!name.isEmpty()) {
  164. auto& s = stream();
  165. writeElementName(s, name);
  166. write(s, &type, 1);
  167. }
  168. ++level.count;
  169. }
  170. }
  171. void KVBinaryOutputStreamSerializer::checkArrayPreamble(uint8_t type) {
  172. if (m_stack.empty()) {
  173. return;
  174. }
  175. Level& level = m_stack.back();
  176. if (level.state == State::ArrayPrefix) {
  177. auto& s = stream();
  178. writeElementName(s, level.name);
  179. char c = BIN_KV_SERIALIZE_FLAG_ARRAY | type;
  180. write(s, &c, 1);
  181. writeArraySize(s, level.count);
  182. level.state = State::Array;
  183. }
  184. }
  185. MemoryStream& KVBinaryOutputStreamSerializer::stream() {
  186. assert(m_objectsStack.size());
  187. return m_objectsStack.back();
  188. }
  189. }