// Copyright (c) 2014, The Monero Project // // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Parts of this file are originally copyright (c) 2006-2013, Andrey N. Sabelnikov #pragma once #include "misc_language.h" #include "portable_storage_base.h" namespace epee { namespace serialization { template size_t pack_varint_t(t_stream& strm, uint8_t type_or, size_t& pv) { pack_value v = (*((pack_value*)&pv)) << 2; v |= type_or; strm.write((const char*)&v, sizeof(pack_value)); return sizeof(pack_value); } PRAGMA_WARNING_PUSH PRAGMA_GCC("GCC diagnostic ignored \"-Wstrict-aliasing\"") template size_t pack_varint(t_stream& strm, size_t val) { //the first two bits always reserved for size information if(val <= 63) {//mean enough one byte return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_BYTE, val); } else if(val <= 16383) {//mean need word return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_WORD, val); }else if(val <= 1073741823) {//mean need dword return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_DWORD, val); }else { CHECK_AND_ASSERT_THROW_MES(val <= 4611686018427387903, "failed to pack varint - too big amount = " << val); return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_INT64, val); } } PRAGMA_WARNING_POP template bool put_string(t_stream& strm, const std::string& v) { pack_varint(strm, v.size()); if(v.size()) strm.write((const char*)v.data(), v.size()); return true; } template struct array_entry_store_visitor: public boost::static_visitor { t_stream& m_strm; template bool pack_pod_array_type(uint8_t contained_type, const array_entry_t& arr_pod) { uint8_t type = contained_type|SERIALIZE_FLAG_ARRAY; m_strm.write((const char*)&type, 1); pack_varint(m_strm, arr_pod.m_array.size()); for(const t_pod_type& x: arr_pod.m_array) m_strm.write((const char*)&x, sizeof(t_pod_type)); return true; } array_entry_store_visitor(t_stream& strm):m_strm(strm){} bool operator()(const array_entry_t& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT64, v);} bool operator()(const array_entry_t& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT32, v);} bool operator()(const array_entry_t& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT16, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_UINT8, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT64, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT32, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT16, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT8, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_DUOBLE, v);} bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_BOOL, v);} bool operator()(const array_entry_t& arr_str) { uint8_t type = SERIALIZE_TYPE_STRING|SERIALIZE_FLAG_ARRAY; m_strm.write((const char*)&type, 1); pack_varint(m_strm, arr_str.m_array.size()); for(const std::string& s: arr_str.m_array) put_string(m_strm, s); return true; } bool operator()(const array_entry_t
& arr_sec) { uint8_t type = SERIALIZE_TYPE_OBJECT|SERIALIZE_FLAG_ARRAY; m_strm.write((const char*)&type, 1); pack_varint(m_strm, arr_sec.m_array.size()); for(const section& s: arr_sec.m_array) pack_entry_to_buff(m_strm, s); return true; } bool operator()(const array_entry_t& arra_ar) { uint8_t type = SERIALIZE_TYPE_ARRAY|SERIALIZE_FLAG_ARRAY; m_strm.write((const char*)&type, 1); pack_varint(m_strm, arra_ar.m_array.size()); for(const array_entry& s: arra_ar.m_array) pack_entry_to_buff(m_strm, s); return true; } }; template struct storage_entry_store_visitor: public boost::static_visitor { t_stream& m_strm; storage_entry_store_visitor(t_stream& strm):m_strm(strm){} template bool pack_pod_type(uint8_t type, const pod_type& v) { m_strm.write((const char*)&type, 1); m_strm.write((const char*)&v, sizeof(pod_type)); return true; } //section, array_entry bool operator()(const uint64_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT64, v);} bool operator()(const uint32_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT32, v);} bool operator()(const uint16_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT16, v);} bool operator()(const uint8_t& v) { return pack_pod_type(SERIALIZE_TYPE_UINT8, v);} bool operator()(const int64_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT64, v);} bool operator()(const int32_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT32, v);} bool operator()(const int16_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT16, v);} bool operator()(const int8_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT8, v);} bool operator()(const double& v) { return pack_pod_type(SERIALIZE_TYPE_DUOBLE, v);} bool operator()(const bool& v) { return pack_pod_type(SERIALIZE_TYPE_BOOL, v);} bool operator()(const std::string& v) { uint8_t type = SERIALIZE_TYPE_STRING; m_strm.write((const char*)&type, 1); put_string(m_strm, v); return true; } bool operator()(const section& v) { uint8_t type = SERIALIZE_TYPE_OBJECT; m_strm.write((const char*)&type, 1); return pack_entry_to_buff(m_strm, v); } bool operator()(const array_entry& v) { //uint8_t type = SERIALIZE_TYPE_ARRAY; //m_strm.write((const char*)&type, 1); return pack_entry_to_buff(m_strm, v); } }; template bool pack_entry_to_buff(t_stream& strm, const array_entry& ae) { array_entry_store_visitor aesv(strm); return boost::apply_visitor(aesv, ae); } template bool pack_entry_to_buff(t_stream& strm, const storage_entry& se) { storage_entry_store_visitor sv(strm); return boost::apply_visitor(sv, se); } template bool pack_entry_to_buff(t_stream& strm, const section& sec) { typedef std::map::value_type section_pair; pack_varint(strm, sec.m_entries.size()); for(const section_pair& se: sec.m_entries) { CHECK_AND_ASSERT_THROW_MES(se.first.size() < std::numeric_limits::max(), "storage_entry_name is too long: " << se.first.size() << ", val: " << se.first); uint8_t len = static_cast(se.first.size()); strm.write((const char*)&len, sizeof(len)); strm.write(se.first.data(), size_t(len)); pack_entry_to_buff(strm, se.second); } return true; } } }