/src/serialization/KVBinaryOutputStreamSerializer.cpp

https://github.com/AlbertWerner/cryptonotecoin · C++ · 239 lines · 180 code · 56 blank · 3 comment · 21 complexity · 7b3449b4e2683cfbece565241b1db992 MD5 · raw file

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