Bug fix
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
"sources": [
|
||||
"src/main.cc",
|
||||
"src/cryptonote_core/cryptonote_format_utils.cpp",
|
||||
"src/offshore/pricing_record.cpp",
|
||||
"src/crypto/tree-hash.c",
|
||||
"src/crypto/crypto.cpp",
|
||||
"src/crypto/crypto-ops.c",
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _CRYPTED_STORAGE_H_
|
||||
#define _CRYPTED_STORAGE_H_
|
||||
|
||||
#include "cryptopp_helper.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
template<class t_base_storage, class crypt_provider, class t_key_provider>
|
||||
class crypted_storage: public t_base_storage
|
||||
{
|
||||
public:
|
||||
size_t PackToSolidBuffer(std::string& targetObj)
|
||||
{
|
||||
size_t res = t_base_storage::PackToSolidBuffer(targetObj);
|
||||
if(res <= 0)
|
||||
return res;
|
||||
|
||||
if(!crypt_provider::encrypt(targetObj, t_key_provider::get_storage_default_key()))
|
||||
return 0;
|
||||
|
||||
return targetObj.size();
|
||||
}
|
||||
|
||||
size_t LoadFromSolidBuffer(const std::string& pTargetObj)
|
||||
{
|
||||
std::string buff_to_decrypt = pTargetObj;
|
||||
if(crypt_provider::decrypt(buff_to_decrypt, t_key_provider::get_storage_default_key()))
|
||||
return t_base_storage::LoadFromSolidBuffer(buff_to_decrypt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //_CRYPTED_STORAGE_H_
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _GZIPPED_INMEMSTORAGE_H_
|
||||
#define _GZIPPED_INMEMSTORAGE_H_
|
||||
|
||||
#include "zlib_helper.h"
|
||||
namespace epee
|
||||
{
|
||||
namespace StorageNamed
|
||||
{
|
||||
|
||||
template<class t_base_storage>
|
||||
class gziped_storage: public t_base_storage
|
||||
{
|
||||
public:
|
||||
size_t PackToSolidBuffer(std::string& targetObj)
|
||||
{
|
||||
size_t res = t_base_storage::PackToSolidBuffer(targetObj);
|
||||
if(res <= 0)
|
||||
return res;
|
||||
|
||||
if(!zlib_helper::pack(targetObj))
|
||||
return 0;
|
||||
|
||||
return targetObj.size();
|
||||
}
|
||||
|
||||
size_t LoadFromSolidBuffer(const std::string& pTargetObj)
|
||||
{
|
||||
std::string buff_to_ungzip = pTargetObj;
|
||||
if(zlib_helper::unpack(buff_to_ungzip))
|
||||
return t_base_storage::LoadFromSolidBuffer(buff_to_ungzip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,141 @@
|
||||
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include "portable_storage_template_helper.h"
|
||||
#include "net/http_base.h"
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
|
||||
{
|
||||
std::string req_param;
|
||||
if(!serialization::store_t_to_json(out_struct, req_param))
|
||||
return false;
|
||||
|
||||
http::fields_list additional_params;
|
||||
additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
|
||||
|
||||
const http::http_response_info* pri = NULL;
|
||||
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri), std::move(additional_params)))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return serialization::load_t_from_json(result_struct, pri->m_body);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
|
||||
{
|
||||
std::string req_param;
|
||||
if(!serialization::store_t_to_binary(out_struct, req_param))
|
||||
return false;
|
||||
|
||||
const http::http_response_info* pri = NULL;
|
||||
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri)))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return serialization::load_t_from_binary(result_struct, epee::strspan<uint8_t>(pri->m_body));
|
||||
}
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, epee::json_rpc::error &error_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
|
||||
req_t.jsonrpc = "2.0";
|
||||
req_t.id = req_id;
|
||||
req_t.method = std::move(method_name);
|
||||
req_t.params = out_struct;
|
||||
epee::json_rpc::response<t_response, epee::json_rpc::error> resp_t = AUTO_VAL_INIT(resp_t);
|
||||
if(!epee::net_utils::invoke_http_json(uri, req_t, resp_t, transport, timeout, http_method))
|
||||
{
|
||||
error_struct = {};
|
||||
return false;
|
||||
}
|
||||
if(resp_t.error.code || resp_t.error.message.size())
|
||||
{
|
||||
error_struct = resp_t.error;
|
||||
LOG_ERROR("RPC call of \"" << req_t.method << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message);
|
||||
return false;
|
||||
}
|
||||
result_struct = resp_t.result;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
epee::json_rpc::error error_struct;
|
||||
return invoke_http_json_rpc(uri, method_name, out_struct, result_struct, error_struct, transport, timeout, http_method, req_id);
|
||||
}
|
||||
|
||||
template<class t_command, class t_transport>
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
return invoke_http_json_rpc(uri, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "portable_storage_template_helper.h"
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <functional>
|
||||
#include "span.h"
|
||||
#include "net/levin_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename context_t>
|
||||
void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, const char *category)
|
||||
{
|
||||
MCINFO("net.p2p.traffic", context << bytes << " bytes " << (sent ? "sent" : "received") << (error ? "/corrupt" : "")
|
||||
<< " for category " << category << " initiated by " << (initiator ? "us" : "peer"));
|
||||
}
|
||||
template<typename context_t>
|
||||
void on_levin_traffic(const context_t &context, bool initiator, bool sent, bool error, size_t bytes, int command)
|
||||
{
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "command-%u", command);
|
||||
return on_levin_traffic(context, initiator, sent, error, bytes, buf);
|
||||
}
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
#if 0
|
||||
template<class t_arg, class t_result, class t_transport>
|
||||
bool invoke_remote_command2(int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport)
|
||||
{
|
||||
if(!transport.is_connected())
|
||||
return false;
|
||||
|
||||
serialization::portable_storage stg;
|
||||
out_struct.store(stg);
|
||||
std::string buff_to_send, buff_to_recv;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
|
||||
int res = transport.invoke(command, buff_to_send, buff_to_recv);
|
||||
if( res <=0 )
|
||||
{
|
||||
MERROR("Failed to invoke command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
serialization::portable_storage stg_ret;
|
||||
if(!stg_ret.load_from_binary(buff_to_recv))
|
||||
{
|
||||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
return false;
|
||||
}
|
||||
return result_struct.load(stg_ret);
|
||||
}
|
||||
|
||||
template<class t_arg, class t_transport>
|
||||
bool notify_remote_command2(int command, const t_arg& out_struct, t_transport& transport)
|
||||
{
|
||||
if(!transport.is_connected())
|
||||
return false;
|
||||
|
||||
serialization::portable_storage stg;
|
||||
out_struct.store(&stg);
|
||||
std::string buff_to_send;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
|
||||
int res = transport.notify(command, buff_to_send);
|
||||
if(res <=0 )
|
||||
{
|
||||
LOG_ERROR("Failed to notify command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class t_arg, class t_result, class t_transport>
|
||||
bool invoke_remote_command2(const epee::net_utils::connection_context_base context, int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport)
|
||||
{
|
||||
const boost::uuids::uuid &conn_id = context.m_connection_id;
|
||||
typename serialization::portable_storage stg;
|
||||
out_struct.store(stg);
|
||||
std::string buff_to_send, buff_to_recv;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
|
||||
on_levin_traffic(context, true, true, false, buff_to_send.size(), command);
|
||||
int res = transport.invoke(command, buff_to_send, buff_to_recv, conn_id);
|
||||
if( res <=0 )
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
typename serialization::portable_storage stg_ret;
|
||||
if(!stg_ret.load_from_binary(buff_to_recv))
|
||||
{
|
||||
on_levin_traffic(context, true, false, true, buff_to_recv.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
return false;
|
||||
}
|
||||
on_levin_traffic(context, true, false, false, buff_to_recv.size(), command);
|
||||
return result_struct.load(stg_ret);
|
||||
}
|
||||
|
||||
template<class t_result, class t_arg, class callback_t, class t_transport>
|
||||
bool async_invoke_remote_command2(const epee::net_utils::connection_context_base &context, int command, const t_arg& out_struct, t_transport& transport, const callback_t &cb, size_t inv_timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
{
|
||||
const boost::uuids::uuid &conn_id = context.m_connection_id;
|
||||
typename serialization::portable_storage stg;
|
||||
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
|
||||
std::string buff_to_send;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
on_levin_traffic(context, true, true, false, buff_to_send.size(), command);
|
||||
int res = transport.invoke_async(command, epee::strspan<uint8_t>(buff_to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
|
||||
{
|
||||
t_result result_struct = AUTO_VAL_INIT(result_struct);
|
||||
if( code <=0 )
|
||||
{
|
||||
if (!buff.empty())
|
||||
on_levin_traffic(context, true, false, true, buff.size(), command);
|
||||
LOG_PRINT_L1("Failed to invoke command " << command << " return code " << code);
|
||||
cb(code, result_struct, context);
|
||||
return false;
|
||||
}
|
||||
serialization::portable_storage stg_ret;
|
||||
if(!stg_ret.load_from_binary(buff))
|
||||
{
|
||||
on_levin_traffic(context, true, false, true, buff.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
cb(LEVIN_ERROR_FORMAT, result_struct, context);
|
||||
return false;
|
||||
}
|
||||
if (!result_struct.load(stg_ret))
|
||||
{
|
||||
on_levin_traffic(context, true, false, true, buff.size(), command);
|
||||
LOG_ERROR("Failed to load result struct on command " << command);
|
||||
cb(LEVIN_ERROR_FORMAT, result_struct, context);
|
||||
return false;
|
||||
}
|
||||
on_levin_traffic(context, true, false, false, buff.size(), command);
|
||||
cb(code, result_struct, context);
|
||||
return true;
|
||||
}, inv_timeout);
|
||||
if( res <=0 )
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class t_arg, class t_transport>
|
||||
bool notify_remote_command2(const typename t_transport::connection_context &context, int command, const t_arg& out_struct, t_transport& transport)
|
||||
{
|
||||
const boost::uuids::uuid &conn_id = context.m_connection_id;
|
||||
serialization::portable_storage stg;
|
||||
out_struct.store(stg);
|
||||
std::string buff_to_send;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
|
||||
on_levin_traffic(context, true, true, false, buff_to_send.size(), command);
|
||||
int res = transport.notify(command, epee::strspan<uint8_t>(buff_to_send), conn_id);
|
||||
if(res <=0 )
|
||||
{
|
||||
MERROR("Failed to notify command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t>
|
||||
int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, callback_t cb, t_context& context )
|
||||
{
|
||||
serialization::portable_storage strg;
|
||||
if(!strg.load_from_binary(in_buff))
|
||||
{
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary in command " << command);
|
||||
return -1;
|
||||
}
|
||||
boost::value_initialized<t_in_type> in_struct;
|
||||
boost::value_initialized<t_out_type> out_struct;
|
||||
|
||||
if (!static_cast<t_in_type&>(in_struct).load(strg))
|
||||
{
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), command);
|
||||
LOG_ERROR("Failed to load in_struct in command " << command);
|
||||
return -1;
|
||||
}
|
||||
on_levin_traffic(context, false, false, false, in_buff.size(), command);
|
||||
int res = cb(command, static_cast<t_in_type&>(in_struct), static_cast<t_out_type&>(out_struct), context);
|
||||
serialization::portable_storage strg_out;
|
||||
static_cast<t_out_type&>(out_struct).store(strg_out);
|
||||
|
||||
if(!strg_out.store_to_binary(buff_out))
|
||||
{
|
||||
LOG_ERROR("Failed to store_to_binary in command" << command);
|
||||
return -1;
|
||||
}
|
||||
on_levin_traffic(context, false, true, false, buff_out.size(), command);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class t_owner, class t_in_type, class t_context, class callback_t>
|
||||
int buff_to_t_adapter(t_owner* powner, int command, const epee::span<const uint8_t> in_buff, callback_t cb, t_context& context)
|
||||
{
|
||||
serialization::portable_storage strg;
|
||||
if(!strg.load_from_binary(in_buff))
|
||||
{
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary in notify " << command);
|
||||
return -1;
|
||||
}
|
||||
boost::value_initialized<t_in_type> in_struct;
|
||||
if (!static_cast<t_in_type&>(in_struct).load(strg))
|
||||
{
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), command);
|
||||
LOG_ERROR("Failed to load in_struct in notify " << command);
|
||||
return -1;
|
||||
}
|
||||
on_levin_traffic(context, false, false, false, in_buff.size(), command);
|
||||
return cb(command, in_struct, context);
|
||||
}
|
||||
|
||||
#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \
|
||||
int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, context_type& context) \
|
||||
{ \
|
||||
bool handled = false; \
|
||||
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
|
||||
}
|
||||
|
||||
#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \
|
||||
int notify(int command, const epee::span<const uint8_t> in_buff, context_type& context) \
|
||||
{ \
|
||||
bool handled = false; std::string fake_str;\
|
||||
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
|
||||
}
|
||||
|
||||
|
||||
#define CHAIN_LEVIN_INVOKE_MAP() \
|
||||
int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \
|
||||
{ \
|
||||
bool handled = false; \
|
||||
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
|
||||
}
|
||||
|
||||
#define CHAIN_LEVIN_NOTIFY_MAP() \
|
||||
int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
|
||||
{ \
|
||||
bool handled = false; std::string fake_str;\
|
||||
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
|
||||
}
|
||||
|
||||
#define CHAIN_LEVIN_NOTIFY_STUB() \
|
||||
int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
|
||||
{ \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define BEGIN_INVOKE_MAP2(owner_type) \
|
||||
template <class t_context> int handle_invoke_map(bool is_notify, int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_context& context, bool& handled) \
|
||||
{ \
|
||||
typedef owner_type internal_owner_type_name;
|
||||
|
||||
#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
|
||||
if(!is_notify && command_id == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
|
||||
|
||||
#define HANDLE_INVOKE_T2(COMMAND, func) \
|
||||
if(!is_notify && COMMAND::ID == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
|
||||
|
||||
|
||||
#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
|
||||
if(is_notify && command_id == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
|
||||
|
||||
#define HANDLE_NOTIFY_T2(NOTIFY, func) \
|
||||
if(is_notify && NOTIFY::ID == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
|
||||
|
||||
|
||||
#define CHAIN_INVOKE_MAP2(func) \
|
||||
{ \
|
||||
int res = func(is_notify, command, in_buff, buff_out, context, handled); \
|
||||
if(handled) \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define CHAIN_INVOKE_MAP_TO_OBJ2(obj) \
|
||||
{ \
|
||||
int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, context, handled); \
|
||||
if(handled) \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(obj, context_type) \
|
||||
{ \
|
||||
int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, static_cast<context_type>(context), handled); \
|
||||
if(handled) return res; \
|
||||
}
|
||||
|
||||
|
||||
#define END_INVOKE_MAP2() \
|
||||
LOG_ERROR("Unknown command:" << command); \
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), "invalid-command"); \
|
||||
return LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED; \
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace misc_utils
|
||||
{
|
||||
namespace parse
|
||||
{
|
||||
// 1: digit
|
||||
// 2: .eE (floating point)
|
||||
// 4: alpha
|
||||
// 8: whitespace
|
||||
// 16: allowed in float but doesn't necessarily mean it's a float
|
||||
// 32: \ and " (end of verbatim string)
|
||||
static const constexpr uint8_t lut[256]={
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, // 16
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
|
||||
8, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48
|
||||
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, // 64
|
||||
0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 80
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 32, 0, 0, 0, // 96
|
||||
0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 112
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 128
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const constexpr unsigned char isx[256] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
inline bool isspace(char c)
|
||||
{
|
||||
return lut[(uint8_t)c] & 8;
|
||||
}
|
||||
|
||||
inline bool isdigit(char c)
|
||||
{
|
||||
return lut[(uint8_t)c] & 1;
|
||||
}
|
||||
|
||||
inline std::string transform_to_escape_sequence(const std::string& src)
|
||||
{
|
||||
static const char escaped[] = "\b\f\n\r\t\v\"\\/";
|
||||
std::string::const_iterator it = std::find_first_of(src.begin(), src.end(), escaped, escaped + sizeof(escaped));
|
||||
if (it == src.end())
|
||||
return src;
|
||||
|
||||
std::string res;
|
||||
res.reserve(2 * src.size());
|
||||
res.assign(src.begin(), it);
|
||||
for(; it!=src.end(); ++it)
|
||||
{
|
||||
switch(*it)
|
||||
{
|
||||
case '\b': //Backspace (ascii code 08)
|
||||
res+="\\b"; break;
|
||||
case '\f': //Form feed (ascii code 0C)
|
||||
res+="\\f"; break;
|
||||
case '\n': //New line
|
||||
res+="\\n"; break;
|
||||
case '\r': //Carriage return
|
||||
res+="\\r"; break;
|
||||
case '\t': //Tab
|
||||
res+="\\t"; break;
|
||||
case '\v': //Vertical tab
|
||||
res+="\\v"; break;
|
||||
//case '\'': //Apostrophe or single quote
|
||||
// res+="\\'"; break;
|
||||
case '"': //Double quote
|
||||
res+="\\\""; break;
|
||||
case '\\': //Backslash caracter
|
||||
res+="\\\\"; break;
|
||||
case '/': //Backslash caracter
|
||||
res+="\\/"; break;
|
||||
default:
|
||||
res.push_back(*it);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
|
||||
\b Backspace (ascii code 08)
|
||||
\f Form feed (ascii code 0C)
|
||||
\n New line
|
||||
\r Carriage return
|
||||
\t Tab
|
||||
\v Vertical tab
|
||||
\' Apostrophe or single quote
|
||||
\" Double quote
|
||||
\\ Backslash character
|
||||
|
||||
*/
|
||||
inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
|
||||
{
|
||||
bool escape_mode = false;
|
||||
std::string::const_iterator it = star_end_string;
|
||||
++it;
|
||||
std::string::const_iterator fi = it;
|
||||
while (fi != buf_end && ((lut[(uint8_t)*fi] & 32)) == 0)
|
||||
++fi;
|
||||
val.assign(it, fi);
|
||||
it = fi;
|
||||
for(;it != buf_end;it++)
|
||||
{
|
||||
if(escape_mode/*prev_ch == '\\'*/)
|
||||
{
|
||||
switch(*it)
|
||||
{
|
||||
case 'b': //Backspace (ascii code 08)
|
||||
val.push_back(0x08);break;
|
||||
case 'f': //Form feed (ascii code 0C)
|
||||
val.push_back(0x0C);break;
|
||||
case 'n': //New line
|
||||
val.push_back('\n');break;
|
||||
case 'r': //Carriage return
|
||||
val.push_back('\r');break;
|
||||
case 't': //Tab
|
||||
val.push_back('\t');break;
|
||||
case 'v': //Vertical tab
|
||||
val.push_back('\v');break;
|
||||
case '\'': //Apostrophe or single quote
|
||||
val.push_back('\'');break;
|
||||
case '"': //Double quote
|
||||
val.push_back('"');break;
|
||||
case '\\': //Backslash character
|
||||
val.push_back('\\');break;
|
||||
case '/': //Slash character
|
||||
val.push_back('/');break;
|
||||
case 'u': //Unicode code point
|
||||
if (buf_end - it < 4)
|
||||
{
|
||||
ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t dst = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
const unsigned char tmp = isx[(unsigned char)*++it];
|
||||
CHECK_AND_ASSERT_THROW_MES(tmp != 0xff, "Bad Unicode encoding");
|
||||
dst = dst << 4 | tmp;
|
||||
}
|
||||
// encode as UTF-8
|
||||
if (dst <= 0x7f)
|
||||
{
|
||||
val.push_back(dst);
|
||||
}
|
||||
else if (dst <= 0x7ff)
|
||||
{
|
||||
val.push_back(0xc0 | (dst >> 6));
|
||||
val.push_back(0x80 | (dst & 0x3f));
|
||||
}
|
||||
else if (dst <= 0xffff)
|
||||
{
|
||||
val.push_back(0xe0 | (dst >> 12));
|
||||
val.push_back(0x80 | ((dst >> 6) & 0x3f));
|
||||
val.push_back(0x80 | (dst & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_MES_AND_THROW("Unicode code point is out or range");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val.push_back(*it);
|
||||
LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
|
||||
}
|
||||
escape_mode = false;
|
||||
}else if(*it == '"')
|
||||
{
|
||||
star_end_string = it;
|
||||
return;
|
||||
}else if(*it == '\\')
|
||||
{
|
||||
escape_mode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
val.push_back(*it);
|
||||
}
|
||||
}
|
||||
ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end));
|
||||
}
|
||||
inline bool match_string(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
match_string2(star_end_string, buf_end, val);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val, bool& is_float_val, bool& is_signed_val)
|
||||
{
|
||||
val.clear();
|
||||
uint8_t float_flag = 0;
|
||||
is_signed_val = false;
|
||||
size_t chars = 0;
|
||||
std::string::const_iterator it = star_end_string;
|
||||
if (it != buf_end && *it == '-')
|
||||
{
|
||||
is_signed_val = true;
|
||||
++chars;
|
||||
++it;
|
||||
}
|
||||
for(;it != buf_end;it++)
|
||||
{
|
||||
const uint8_t flags = lut[(uint8_t)*it];
|
||||
if (flags & 16)
|
||||
{
|
||||
float_flag |= flags;
|
||||
++chars;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = boost::string_ref(&*star_end_string, chars);
|
||||
if(val.size())
|
||||
{
|
||||
star_end_string = --it;
|
||||
is_float_val = !!(float_flag & 2);
|
||||
return;
|
||||
}
|
||||
else
|
||||
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
|
||||
}
|
||||
}
|
||||
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
|
||||
}
|
||||
inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool is_v_float = false;bool is_signed_val = false;
|
||||
match_number2(star_end_string, buf_end, val, is_v_float, is_signed_val);
|
||||
return !is_v_float;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
|
||||
{
|
||||
val.clear();
|
||||
|
||||
for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
|
||||
{
|
||||
if (!(lut[(uint8_t)*it] & 4))
|
||||
{
|
||||
val = boost::string_ref(&*star_end_string, std::distance(star_end_string, it));
|
||||
if(val.size())
|
||||
{
|
||||
star_end_string = --it;
|
||||
return;
|
||||
}else
|
||||
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
|
||||
}
|
||||
}
|
||||
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
|
||||
}
|
||||
inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
|
||||
{
|
||||
try
|
||||
{
|
||||
match_word2(star_end_string, buf_end, val);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
inline bool match_word_with_extrasymb(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
|
||||
{
|
||||
val.clear();
|
||||
|
||||
for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
|
||||
{
|
||||
if(!isalnum(*it) && *it != '-' && *it != '_')
|
||||
{
|
||||
val.assign(star_end_string, it);
|
||||
if(val.size())
|
||||
{
|
||||
star_end_string = --it;
|
||||
return true;
|
||||
}else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline bool match_word_til_equal_mark(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string::const_iterator& word_end)
|
||||
{
|
||||
word_end = star_end_string;
|
||||
|
||||
for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
|
||||
{
|
||||
if(isspace(*it))
|
||||
{
|
||||
|
||||
continue;
|
||||
}else if( *it == '=' )
|
||||
{
|
||||
star_end_string = it;
|
||||
word_end = it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "portable_storage_to_bin.h"
|
||||
#include "portable_storage_from_bin.h"
|
||||
#include "portable_storage_to_json.h"
|
||||
#include "portable_storage_from_json.h"
|
||||
#include "portable_storage_val_converters.h"
|
||||
#include "span.h"
|
||||
#include "int-util.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class portable_storage
|
||||
{
|
||||
public:
|
||||
typedef epee::serialization::hsection hsection;
|
||||
typedef epee::serialization::harray harray;
|
||||
typedef storage_entry meta_entry;
|
||||
|
||||
portable_storage(){}
|
||||
virtual ~portable_storage(){}
|
||||
hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false);
|
||||
template<class t_value>
|
||||
bool get_value(const std::string& value_name, t_value& val, hsection hparent_section);
|
||||
bool get_value(const std::string& value_name, storage_entry& val, hsection hparent_section);
|
||||
template<class t_value>
|
||||
bool set_value(const std::string& value_name, t_value&& target, hsection hparent_section);
|
||||
|
||||
//serial access for arrays of values --------------------------------------
|
||||
//values
|
||||
template<class t_value>
|
||||
harray get_first_value(const std::string& value_name, t_value& target, hsection hparent_section);
|
||||
template<class t_value>
|
||||
bool get_next_value(harray hval_array, t_value& target);
|
||||
template<class t_value>
|
||||
harray insert_first_value(const std::string& value_name, t_value&& target, hsection hparent_section);
|
||||
template<class t_value>
|
||||
bool insert_next_value(harray hval_array, t_value&& target);
|
||||
//sections
|
||||
harray get_first_section(const std::string& pSectionName, hsection& h_child_section, hsection hparent_section);
|
||||
bool get_next_section(harray hSecArray, hsection& h_child_section);
|
||||
harray insert_first_section(const std::string& pSectionName, hsection& hinserted_childsection, hsection hparent_section);
|
||||
bool insert_next_section(harray hSecArray, hsection& hinserted_childsection);
|
||||
//------------------------------------------------------------------------
|
||||
//delete entry (section, value or array)
|
||||
bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
bool store_to_binary(binarybuffer& target);
|
||||
bool load_from_binary(const epee::span<const uint8_t> target);
|
||||
bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); }
|
||||
template<class trace_policy>
|
||||
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
|
||||
bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true);
|
||||
bool load_from_json(const std::string& source);
|
||||
|
||||
private:
|
||||
section m_root;
|
||||
hsection get_root_section() {return &m_root;}
|
||||
storage_entry* find_storage_entry(const std::string& pentry_name, hsection psection);
|
||||
template<class entry_type>
|
||||
storage_entry* insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, entry_type&& entry);
|
||||
|
||||
hsection insert_new_section(const std::string& pentry_name, hsection psection);
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct storage_block_header
|
||||
{
|
||||
uint32_t m_signature_a;
|
||||
uint32_t m_signature_b;
|
||||
uint8_t m_ver;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
};
|
||||
inline
|
||||
bool portable_storage::dump_as_json(std::string& buff, size_t indent, bool insert_newlines)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
std::stringstream ss;
|
||||
epee::serialization::dump_as_json(ss, m_root, indent, insert_newlines);
|
||||
buff = ss.str();
|
||||
return true;
|
||||
CATCH_ENTRY("portable_storage::dump_as_json", false)
|
||||
}
|
||||
inline
|
||||
bool portable_storage::load_from_json(const std::string& source)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
return json::load_from_json(source, *this);
|
||||
CATCH_ENTRY("portable_storage::load_from_json", false)
|
||||
}
|
||||
|
||||
template<class trace_policy>
|
||||
bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name)
|
||||
{
|
||||
return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
|
||||
}
|
||||
|
||||
inline
|
||||
bool portable_storage::store_to_binary(binarybuffer& target)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
std::stringstream ss;
|
||||
storage_block_header sbh = AUTO_VAL_INIT(sbh);
|
||||
sbh.m_signature_a = SWAP32LE(PORTABLE_STORAGE_SIGNATUREA);
|
||||
sbh.m_signature_b = SWAP32LE(PORTABLE_STORAGE_SIGNATUREB);
|
||||
sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER;
|
||||
ss.write((const char*)&sbh, sizeof(storage_block_header));
|
||||
pack_entry_to_buff(ss, m_root);
|
||||
target = ss.str();
|
||||
return true;
|
||||
CATCH_ENTRY("portable_storage::store_to_binary", false)
|
||||
}
|
||||
inline
|
||||
bool portable_storage::load_from_binary(const epee::span<const uint8_t> source)
|
||||
{
|
||||
m_root.m_entries.clear();
|
||||
if(source.size() < sizeof(storage_block_header))
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)=" << sizeof(storage_block_header));
|
||||
return false;
|
||||
}
|
||||
storage_block_header* pbuff = (storage_block_header*)source.data();
|
||||
if(pbuff->m_signature_a != SWAP32LE(PORTABLE_STORAGE_SIGNATUREA) ||
|
||||
pbuff->m_signature_b != SWAP32LE(PORTABLE_STORAGE_SIGNATUREB)
|
||||
)
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format - signature mismatch");
|
||||
return false;
|
||||
}
|
||||
if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER)
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver);
|
||||
return false;
|
||||
}
|
||||
TRY_ENTRY();
|
||||
throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header));
|
||||
buf_reader.read(m_root);
|
||||
return true;//TODO:
|
||||
CATCH_ENTRY("portable_storage::load_from_binary", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
hparent_section = hparent_section ? hparent_section:&m_root;
|
||||
storage_entry* pentry = find_storage_entry(section_name, hparent_section);
|
||||
if(!pentry)
|
||||
{
|
||||
if(!create_if_notexist)
|
||||
return nullptr;
|
||||
return insert_new_section(section_name, hparent_section);
|
||||
}
|
||||
CHECK_AND_ASSERT(pentry , nullptr);
|
||||
//check that section_entry we find is real "CSSection"
|
||||
if(pentry->type() != typeid(section))
|
||||
{
|
||||
if(create_if_notexist)
|
||||
*pentry = storage_entry(section());//replace
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
return &boost::get<section>(*pentry);
|
||||
CATCH_ENTRY("portable_storage::open_section", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class to_type>
|
||||
struct get_value_visitor: boost::static_visitor<void>
|
||||
{
|
||||
to_type& m_target;
|
||||
get_value_visitor(to_type& target):m_target(target){}
|
||||
template<class from_type>
|
||||
void operator()(const from_type& v){convert_t(v, m_target);}
|
||||
};
|
||||
|
||||
template<class t_value>
|
||||
bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section)
|
||||
{
|
||||
BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
|
||||
//TRY_ENTRY();
|
||||
if(!hparent_section) hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(value_name, hparent_section);
|
||||
if(!pentry)
|
||||
return false;
|
||||
|
||||
get_value_visitor<t_value> gvv(val);
|
||||
boost::apply_visitor(gvv, *pentry);
|
||||
return true;
|
||||
//CATCH_ENTRY("portable_storage::template<>get_value", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
bool portable_storage::get_value(const std::string& value_name, storage_entry& val, hsection hparent_section)
|
||||
{
|
||||
//TRY_ENTRY();
|
||||
if(!hparent_section) hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(value_name, hparent_section);
|
||||
if(!pentry)
|
||||
return false;
|
||||
|
||||
val = *pentry;
|
||||
return true;
|
||||
//CATCH_ENTRY("portable_storage::template<>get_value", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class t_value>
|
||||
bool portable_storage::set_value(const std::string& value_name, t_value&& v, hsection hparent_section)
|
||||
{
|
||||
using t_real_value = typename std::decay<t_value>::type;
|
||||
BOOST_MPL_ASSERT(( boost::mpl::contains<boost::mpl::push_front<storage_entry::types, storage_entry>::type, t_real_value> ));
|
||||
TRY_ENTRY();
|
||||
if(!hparent_section)
|
||||
hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(value_name, hparent_section);
|
||||
if(!pentry)
|
||||
{
|
||||
pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, std::forward<t_value>(v));
|
||||
if(!pentry)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
*pentry = std::forward<t_value>(v);
|
||||
return true;
|
||||
CATCH_ENTRY("portable_storage::template<>set_value", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
storage_entry* portable_storage::find_storage_entry(const std::string& pentry_name, hsection psection)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(psection, nullptr);
|
||||
auto it = psection->m_entries.find(pentry_name);
|
||||
if(it == psection->m_entries.end())
|
||||
return nullptr;
|
||||
|
||||
return &it->second;
|
||||
CATCH_ENTRY("portable_storage::find_storage_entry", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class entry_type>
|
||||
storage_entry* portable_storage::insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, entry_type&& entry)
|
||||
{
|
||||
static_assert(std::is_rvalue_reference<entry_type&&>(), "unexpected copy of value");
|
||||
TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(psection, nullptr);
|
||||
auto ins_res = psection->m_entries.emplace(pentry_name, std::forward<entry_type>(entry));
|
||||
return &ins_res.first->second;
|
||||
CATCH_ENTRY("portable_storage::insert_new_entry_get_storage_entry", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
hsection portable_storage::insert_new_section(const std::string& pentry_name, hsection psection)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
storage_entry* pse = insert_new_entry_get_storage_entry(pentry_name, psection, section());
|
||||
if(!pse) return nullptr;
|
||||
return &boost::get<section>(*pse);
|
||||
CATCH_ENTRY("portable_storage::insert_new_section", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class to_type>
|
||||
struct get_first_value_visitor: boost::static_visitor<bool>
|
||||
{
|
||||
to_type& m_target;
|
||||
get_first_value_visitor(to_type& target):m_target(target){}
|
||||
template<class from_type>
|
||||
bool operator()(const array_entry_t<from_type>& a)
|
||||
{
|
||||
const from_type* pv = a.get_first_val();
|
||||
if(!pv)
|
||||
return false;
|
||||
convert_t(*pv, m_target);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class t_value>
|
||||
harray portable_storage::get_first_value(const std::string& value_name, t_value& target, hsection hparent_section)
|
||||
{
|
||||
BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
|
||||
//TRY_ENTRY();
|
||||
if(!hparent_section) hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(value_name, hparent_section);
|
||||
if(!pentry)
|
||||
return nullptr;
|
||||
if(pentry->type() != typeid(array_entry))
|
||||
return nullptr;
|
||||
array_entry& ar_entry = boost::get<array_entry>(*pentry);
|
||||
|
||||
get_first_value_visitor<t_value> gfv(target);
|
||||
if(!boost::apply_visitor(gfv, ar_entry))
|
||||
return nullptr;
|
||||
return &ar_entry;
|
||||
//CATCH_ENTRY("portable_storage::get_first_value", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class to_type>
|
||||
struct get_next_value_visitor: boost::static_visitor<bool>
|
||||
{
|
||||
to_type& m_target;
|
||||
get_next_value_visitor(to_type& target):m_target(target){}
|
||||
template<class from_type>
|
||||
bool operator()(const array_entry_t<from_type>& a)
|
||||
{
|
||||
//TODO: optimize code here: work without get_next_val function
|
||||
const from_type* pv = a.get_next_val();
|
||||
if(!pv)
|
||||
return false;
|
||||
convert_t(*pv, m_target);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class t_value>
|
||||
bool portable_storage::get_next_value(harray hval_array, t_value& target)
|
||||
{
|
||||
BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
|
||||
//TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(hval_array, false);
|
||||
array_entry& ar_entry = *hval_array;
|
||||
get_next_value_visitor<t_value> gnv(target);
|
||||
if(!boost::apply_visitor(gnv, ar_entry))
|
||||
return false;
|
||||
return true;
|
||||
//CATCH_ENTRY("portable_storage::get_next_value", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class t_value>
|
||||
harray portable_storage::insert_first_value(const std::string& value_name, t_value&& target, hsection hparent_section)
|
||||
{
|
||||
using t_real_value = typename std::decay<t_value>::type;
|
||||
static_assert(std::is_rvalue_reference<t_value&&>(), "unexpected copy of value");
|
||||
TRY_ENTRY();
|
||||
if(!hparent_section) hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(value_name, hparent_section);
|
||||
if(!pentry)
|
||||
{
|
||||
pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, array_entry(array_entry_t<t_real_value>()));
|
||||
if(!pentry)
|
||||
return nullptr;
|
||||
}
|
||||
if(pentry->type() != typeid(array_entry))
|
||||
*pentry = storage_entry(array_entry(array_entry_t<t_real_value>()));
|
||||
|
||||
array_entry& arr = boost::get<array_entry>(*pentry);
|
||||
if(arr.type() != typeid(array_entry_t<t_real_value>))
|
||||
arr = array_entry(array_entry_t<t_real_value>());
|
||||
|
||||
array_entry_t<t_real_value>& arr_typed = boost::get<array_entry_t<t_real_value> >(arr);
|
||||
arr_typed.insert_first_val(std::forward<t_value>(target));
|
||||
return &arr;
|
||||
CATCH_ENTRY("portable_storage::insert_first_value", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class t_value>
|
||||
bool portable_storage::insert_next_value(harray hval_array, t_value&& target)
|
||||
{
|
||||
using t_real_value = typename std::decay<t_value>::type;
|
||||
static_assert(std::is_rvalue_reference<t_value&&>(), "unexpected copy of value");
|
||||
TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(hval_array, false);
|
||||
|
||||
CHECK_AND_ASSERT_MES(hval_array->type() == typeid(array_entry_t<t_real_value>),
|
||||
false, "unexpected type in insert_next_value: " << typeid(array_entry_t<t_real_value>).name());
|
||||
|
||||
array_entry_t<t_real_value>& arr_typed = boost::get<array_entry_t<t_real_value> >(*hval_array);
|
||||
arr_typed.insert_next_value(std::forward<t_value>(target));
|
||||
return true;
|
||||
CATCH_ENTRY("portable_storage::insert_next_value", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
//sections
|
||||
inline
|
||||
harray portable_storage::get_first_section(const std::string& sec_name, hsection& h_child_section, hsection hparent_section)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
if(!hparent_section) hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(sec_name, hparent_section);
|
||||
if(!pentry)
|
||||
return nullptr;
|
||||
if(pentry->type() != typeid(array_entry))
|
||||
return nullptr;
|
||||
array_entry& ar_entry = boost::get<array_entry>(*pentry);
|
||||
if(ar_entry.type() != typeid(array_entry_t<section>))
|
||||
return nullptr;
|
||||
array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
|
||||
section* psec = sec_array.get_first_val();
|
||||
if(!psec)
|
||||
return nullptr;
|
||||
h_child_section = psec;
|
||||
return &ar_entry;
|
||||
CATCH_ENTRY("portable_storage::get_first_section", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
bool portable_storage::get_next_section(harray hsec_array, hsection& h_child_section)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(hsec_array, false);
|
||||
if(hsec_array->type() != typeid(array_entry_t<section>))
|
||||
return false;
|
||||
array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
|
||||
h_child_section = sec_array.get_next_val();
|
||||
if(!h_child_section)
|
||||
return false;
|
||||
return true;
|
||||
CATCH_ENTRY("portable_storage::get_next_section", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
harray portable_storage::insert_first_section(const std::string& sec_name, hsection& hinserted_childsection, hsection hparent_section)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
if(!hparent_section) hparent_section = &m_root;
|
||||
storage_entry* pentry = find_storage_entry(sec_name, hparent_section);
|
||||
if(!pentry)
|
||||
{
|
||||
pentry = insert_new_entry_get_storage_entry(sec_name, hparent_section, array_entry(array_entry_t<section>()));
|
||||
if(!pentry)
|
||||
return nullptr;
|
||||
}
|
||||
if(pentry->type() != typeid(array_entry))
|
||||
*pentry = storage_entry(array_entry(array_entry_t<section>()));
|
||||
|
||||
array_entry& ar_entry = boost::get<array_entry>(*pentry);
|
||||
if(ar_entry.type() != typeid(array_entry_t<section>))
|
||||
ar_entry = array_entry(array_entry_t<section>());
|
||||
|
||||
array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
|
||||
hinserted_childsection = &sec_array.insert_first_val(section());
|
||||
return &ar_entry;
|
||||
CATCH_ENTRY("portable_storage::insert_first_section", nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
inline
|
||||
bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(hsec_array, false);
|
||||
CHECK_AND_ASSERT_MES(hsec_array->type() == typeid(array_entry_t<section>),
|
||||
false, "unexpected type(not 'section') in insert_next_section, type: " << hsec_array->type().name());
|
||||
|
||||
array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
|
||||
hinserted_childsection = &sec_array.insert_next_value(section());
|
||||
return true;
|
||||
CATCH_ENTRY("portable_storage::insert_next_section", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#define PORTABLE_STORAGE_SIGNATUREA 0x01011101
|
||||
#define PORTABLE_STORAGE_SIGNATUREB 0x01020101 // bender's nightmare
|
||||
#define PORTABLE_STORAGE_FORMAT_VER 1
|
||||
|
||||
#define PORTABLE_RAW_SIZE_MARK_MASK 0x03
|
||||
#define PORTABLE_RAW_SIZE_MARK_BYTE 0
|
||||
#define PORTABLE_RAW_SIZE_MARK_WORD 1
|
||||
#define PORTABLE_RAW_SIZE_MARK_DWORD 2
|
||||
#define PORTABLE_RAW_SIZE_MARK_INT64 3
|
||||
|
||||
#ifndef MAX_STRING_LEN_POSSIBLE
|
||||
#define MAX_STRING_LEN_POSSIBLE 2000000000 //do not let string be so big
|
||||
#endif
|
||||
|
||||
//data types
|
||||
#define SERIALIZE_TYPE_INT64 1
|
||||
#define SERIALIZE_TYPE_INT32 2
|
||||
#define SERIALIZE_TYPE_INT16 3
|
||||
#define SERIALIZE_TYPE_INT8 4
|
||||
#define SERIALIZE_TYPE_UINT64 5
|
||||
#define SERIALIZE_TYPE_UINT32 6
|
||||
#define SERIALIZE_TYPE_UINT16 7
|
||||
#define SERIALIZE_TYPE_UINT8 8
|
||||
#define SERIALIZE_TYPE_DUOBLE 9
|
||||
#define SERIALIZE_TYPE_STRING 10
|
||||
#define SERIALIZE_TYPE_BOOL 11
|
||||
#define SERIALIZE_TYPE_OBJECT 12
|
||||
#define SERIALIZE_TYPE_ARRAY 13
|
||||
|
||||
#define SERIALIZE_FLAG_ARRAY 0x80
|
||||
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
struct section;
|
||||
|
||||
template<typename T> struct entry_container { typedef std::vector<T> type; static void reserve(type &t, size_t n) { t.reserve(n); } };
|
||||
template<> struct entry_container<bool> { typedef std::deque<bool> type; static void reserve(type &t, size_t n) {} };
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class t_entry_type>
|
||||
struct array_entry_t
|
||||
{
|
||||
array_entry_t():m_it(m_array.end()){}
|
||||
array_entry_t(const array_entry_t& other):m_array(other.m_array), m_it(m_array.end()){}
|
||||
|
||||
array_entry_t& operator=(const array_entry_t& other)
|
||||
{
|
||||
m_array = other.m_array;
|
||||
m_it = m_array.end();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const t_entry_type* get_first_val() const
|
||||
{
|
||||
m_it = m_array.begin();
|
||||
return get_next_val();
|
||||
}
|
||||
|
||||
t_entry_type* get_first_val()
|
||||
{
|
||||
m_it = m_array.begin();
|
||||
return get_next_val();
|
||||
}
|
||||
|
||||
|
||||
const t_entry_type* get_next_val() const
|
||||
{
|
||||
if(m_it == m_array.end())
|
||||
return nullptr;
|
||||
return &(*(m_it++));
|
||||
}
|
||||
|
||||
t_entry_type* get_next_val()
|
||||
{
|
||||
if(m_it == m_array.end())
|
||||
return nullptr;
|
||||
return (t_entry_type*)&(*(m_it++));//fuckoff
|
||||
}
|
||||
|
||||
t_entry_type& insert_first_val(t_entry_type&& v)
|
||||
{
|
||||
m_array.clear();
|
||||
m_it = m_array.end();
|
||||
return insert_next_value(std::move(v));
|
||||
}
|
||||
|
||||
t_entry_type& insert_next_value(t_entry_type&& v)
|
||||
{
|
||||
m_array.push_back(std::move(v));
|
||||
return m_array.back();
|
||||
}
|
||||
|
||||
void reserve(size_t n)
|
||||
{
|
||||
entry_container<t_entry_type>::reserve(m_array, n);
|
||||
}
|
||||
|
||||
typename entry_container<t_entry_type>::type m_array;
|
||||
mutable typename entry_container<t_entry_type>::type::const_iterator m_it;
|
||||
};
|
||||
|
||||
|
||||
typedef boost::make_recursive_variant<
|
||||
array_entry_t<section>,
|
||||
array_entry_t<uint64_t>,
|
||||
array_entry_t<uint32_t>,
|
||||
array_entry_t<uint16_t>,
|
||||
array_entry_t<uint8_t>,
|
||||
array_entry_t<int64_t>,
|
||||
array_entry_t<int32_t>,
|
||||
array_entry_t<int16_t>,
|
||||
array_entry_t<int8_t>,
|
||||
array_entry_t<double>,
|
||||
array_entry_t<bool>,
|
||||
array_entry_t<std::string>,
|
||||
array_entry_t<section>,
|
||||
array_entry_t<boost::recursive_variant_>
|
||||
>::type array_entry;
|
||||
|
||||
typedef boost::variant<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, section, array_entry> storage_entry;
|
||||
|
||||
typedef std::string binarybuffer;//it's ok
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct section
|
||||
{
|
||||
std::map<std::string, storage_entry> m_entries;
|
||||
};
|
||||
|
||||
//handle-like aliases
|
||||
typedef section* hsection;
|
||||
typedef array_entry* harray;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "int-util.h"
|
||||
|
||||
template<typename T> T convert_swapper(T t) { return t; }
|
||||
template<> inline uint16_t convert_swapper(uint16_t t) { return SWAP16LE(t); }
|
||||
template<> inline int16_t convert_swapper(int16_t t) { return SWAP16LE((uint16_t&)t); }
|
||||
template<> inline uint32_t convert_swapper(uint32_t t) { return SWAP32LE(t); }
|
||||
template<> inline int32_t convert_swapper(int32_t t) { return SWAP32LE((uint32_t&)t); }
|
||||
template<> inline uint64_t convert_swapper(uint64_t t) { return SWAP64LE(t); }
|
||||
template<> inline int64_t convert_swapper(int64_t t) { return SWAP64LE((uint64_t&)t); }
|
||||
template<> inline double convert_swapper(double t) { union { uint64_t u; double d; } u; u.d = t; u.u = SWAP64LE(u.u); return u.d; }
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define CONVERT_POD(x) convert_swapper(x)
|
||||
#else
|
||||
#define CONVERT_POD(x) (x)
|
||||
#endif
|
||||
@@ -0,0 +1,293 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "portable_storage_bin_utils.h"
|
||||
|
||||
#ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
|
||||
#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
|
||||
#else
|
||||
#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL 100
|
||||
#endif
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
struct throwable_buffer_reader
|
||||
{
|
||||
throwable_buffer_reader(const void* ptr, size_t sz);
|
||||
void read(void* target, size_t count);
|
||||
void read_sec_name(std::string& sce_name);
|
||||
template<class t_pod_type>
|
||||
void read(t_pod_type& pod_val);
|
||||
template<class t_type>
|
||||
t_type read();
|
||||
template<class type_name>
|
||||
storage_entry read_ae();
|
||||
storage_entry load_storage_array_entry(uint8_t type);
|
||||
size_t read_varint();
|
||||
template<class t_type>
|
||||
storage_entry read_se();
|
||||
storage_entry load_storage_entry();
|
||||
void read(section& sec);
|
||||
void read(std::string& str);
|
||||
void read(array_entry &ae);
|
||||
private:
|
||||
struct recursuion_limitation_guard
|
||||
{
|
||||
size_t& m_counter_ref;
|
||||
recursuion_limitation_guard(size_t& counter):m_counter_ref(counter)
|
||||
{
|
||||
++m_counter_ref;
|
||||
CHECK_AND_ASSERT_THROW_MES(m_counter_ref < EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL, "Wrong blob data in portable storage: recursion limitation (" << EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL << ") exceeded");
|
||||
}
|
||||
~recursuion_limitation_guard() noexcept(false)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_counter_ref != 0, "Internal error: m_counter_ref == 0 while ~recursuion_limitation_guard()");
|
||||
--m_counter_ref;
|
||||
}
|
||||
};
|
||||
#define RECURSION_LIMITATION() recursuion_limitation_guard rl(m_recursion_count)
|
||||
|
||||
const uint8_t* m_ptr;
|
||||
size_t m_count;
|
||||
size_t m_recursion_count;
|
||||
};
|
||||
|
||||
inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz)
|
||||
{
|
||||
if(!ptr)
|
||||
throw std::runtime_error("throwable_buffer_reader: ptr==nullptr");
|
||||
if(!sz)
|
||||
throw std::runtime_error("throwable_buffer_reader: sz==0");
|
||||
m_ptr = (uint8_t*)ptr;
|
||||
m_count = sz;
|
||||
m_recursion_count = 0;
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::read(void* target, size_t count)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
CHECK_AND_ASSERT_THROW_MES(m_count >= count, " attempt to read " << count << " bytes from buffer with " << m_count << " bytes remained");
|
||||
memcpy(target, m_ptr, count);
|
||||
m_ptr += count;
|
||||
m_count -= count;
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::read_sec_name(std::string& sce_name)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
uint8_t name_len = 0;
|
||||
read(name_len);
|
||||
sce_name.resize(name_len);
|
||||
read((void*)sce_name.data(), name_len);
|
||||
}
|
||||
|
||||
template<class t_pod_type>
|
||||
void throwable_buffer_reader::read(t_pod_type& pod_val)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
static_assert(std::is_pod<t_pod_type>::value, "POD type expected");
|
||||
read(&pod_val, sizeof(pod_val));
|
||||
pod_val = CONVERT_POD(pod_val);
|
||||
}
|
||||
|
||||
template<class t_type>
|
||||
t_type throwable_buffer_reader::read()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
t_type v;
|
||||
read(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
template<class type_name>
|
||||
storage_entry throwable_buffer_reader::read_ae()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
//for pod types
|
||||
array_entry_t<type_name> sa;
|
||||
size_t size = read_varint();
|
||||
CHECK_AND_ASSERT_THROW_MES(size <= m_count, "Size sanity check failed");
|
||||
sa.reserve(size);
|
||||
//TODO: add some optimization here later
|
||||
while(size--)
|
||||
sa.m_array.push_back(read<type_name>());
|
||||
return storage_entry(array_entry(std::move(sa)));
|
||||
}
|
||||
|
||||
inline
|
||||
storage_entry throwable_buffer_reader::load_storage_array_entry(uint8_t type)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
type &= ~SERIALIZE_FLAG_ARRAY;
|
||||
switch(type)
|
||||
{
|
||||
case SERIALIZE_TYPE_INT64: return read_ae<int64_t>();
|
||||
case SERIALIZE_TYPE_INT32: return read_ae<int32_t>();
|
||||
case SERIALIZE_TYPE_INT16: return read_ae<int16_t>();
|
||||
case SERIALIZE_TYPE_INT8: return read_ae<int8_t>();
|
||||
case SERIALIZE_TYPE_UINT64: return read_ae<uint64_t>();
|
||||
case SERIALIZE_TYPE_UINT32: return read_ae<uint32_t>();
|
||||
case SERIALIZE_TYPE_UINT16: return read_ae<uint16_t>();
|
||||
case SERIALIZE_TYPE_UINT8: return read_ae<uint8_t>();
|
||||
case SERIALIZE_TYPE_DUOBLE: return read_ae<double>();
|
||||
case SERIALIZE_TYPE_BOOL: return read_ae<bool>();
|
||||
case SERIALIZE_TYPE_STRING: return read_ae<std::string>();
|
||||
case SERIALIZE_TYPE_OBJECT: return read_ae<section>();
|
||||
case SERIALIZE_TYPE_ARRAY: return read_ae<array_entry>();
|
||||
default:
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << type);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
size_t throwable_buffer_reader::read_varint()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
CHECK_AND_ASSERT_THROW_MES(m_count >= 1, "empty buff, expected place for varint");
|
||||
size_t v = 0;
|
||||
uint8_t size_mask = (*(uint8_t*)m_ptr) &PORTABLE_RAW_SIZE_MARK_MASK;
|
||||
switch (size_mask)
|
||||
{
|
||||
case PORTABLE_RAW_SIZE_MARK_BYTE: v = read<uint8_t>();break;
|
||||
case PORTABLE_RAW_SIZE_MARK_WORD: v = read<uint16_t>();break;
|
||||
case PORTABLE_RAW_SIZE_MARK_DWORD: v = read<uint32_t>();break;
|
||||
case PORTABLE_RAW_SIZE_MARK_INT64: v = read<uint64_t>();break;
|
||||
default:
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "unknown varint size_mask = " << size_mask);
|
||||
}
|
||||
v >>= 2;
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class t_type>
|
||||
storage_entry throwable_buffer_reader::read_se()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
t_type v;
|
||||
read(v);
|
||||
return storage_entry(v);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline storage_entry throwable_buffer_reader::read_se<std::string>()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
return storage_entry(read<std::string>());
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
inline storage_entry throwable_buffer_reader::read_se<section>()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
section s;//use extra variable due to vs bug, line "storage_entry se(section()); " can't be compiled in visual studio
|
||||
storage_entry se(std::move(s));
|
||||
section& section_entry = boost::get<section>(se);
|
||||
read(section_entry);
|
||||
return se;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline storage_entry throwable_buffer_reader::read_se<array_entry>()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
uint8_t ent_type = 0;
|
||||
read(ent_type);
|
||||
CHECK_AND_ASSERT_THROW_MES(ent_type&SERIALIZE_FLAG_ARRAY, "wrong type sequenses");
|
||||
return load_storage_array_entry(ent_type);
|
||||
}
|
||||
|
||||
inline
|
||||
storage_entry throwable_buffer_reader::load_storage_entry()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
uint8_t ent_type = 0;
|
||||
read(ent_type);
|
||||
if(ent_type&SERIALIZE_FLAG_ARRAY)
|
||||
return load_storage_array_entry(ent_type);
|
||||
|
||||
switch(ent_type)
|
||||
{
|
||||
case SERIALIZE_TYPE_INT64: return read_se<int64_t>();
|
||||
case SERIALIZE_TYPE_INT32: return read_se<int32_t>();
|
||||
case SERIALIZE_TYPE_INT16: return read_se<int16_t>();
|
||||
case SERIALIZE_TYPE_INT8: return read_se<int8_t>();
|
||||
case SERIALIZE_TYPE_UINT64: return read_se<uint64_t>();
|
||||
case SERIALIZE_TYPE_UINT32: return read_se<uint32_t>();
|
||||
case SERIALIZE_TYPE_UINT16: return read_se<uint16_t>();
|
||||
case SERIALIZE_TYPE_UINT8: return read_se<uint8_t>();
|
||||
case SERIALIZE_TYPE_DUOBLE: return read_se<double>();
|
||||
case SERIALIZE_TYPE_BOOL: return read_se<bool>();
|
||||
case SERIALIZE_TYPE_STRING: return read_se<std::string>();
|
||||
case SERIALIZE_TYPE_OBJECT: return read_se<section>();
|
||||
case SERIALIZE_TYPE_ARRAY: return read_se<array_entry>();
|
||||
default:
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << ent_type);
|
||||
}
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::read(section& sec)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
sec.m_entries.clear();
|
||||
size_t count = read_varint();
|
||||
while(count--)
|
||||
{
|
||||
//read section name string
|
||||
std::string sec_name;
|
||||
read_sec_name(sec_name);
|
||||
sec.m_entries.emplace(std::move(sec_name), load_storage_entry());
|
||||
}
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::read(std::string& str)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
size_t len = read_varint();
|
||||
CHECK_AND_ASSERT_THROW_MES(len < MAX_STRING_LEN_POSSIBLE, "to big string len value in storage: " << len);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_count >= len, "string len count value " << len << " goes out of remain storage len " << m_count);
|
||||
//do this manually to avoid double memory write in huge strings (first time at resize, second at read)
|
||||
str.assign((const char*)m_ptr, len);
|
||||
m_ptr+=len;
|
||||
m_count -= len;
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::read(array_entry &ae)
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "Reading array entry is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "parserse_base_utils.h"
|
||||
#include "file_io_utils.h"
|
||||
|
||||
#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100
|
||||
|
||||
namespace epee
|
||||
{
|
||||
using namespace misc_utils::parse;
|
||||
namespace serialization
|
||||
{
|
||||
namespace json
|
||||
{
|
||||
#define CHECK_ISSPACE() if(!epee::misc_utils::parse::isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
|
||||
|
||||
/*inline void parse_error()
|
||||
{
|
||||
ASSERT_MES_AND_THROW("json parse error");
|
||||
}*/
|
||||
template<class t_storage>
|
||||
inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg, unsigned int recursion)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(recursion < EPEE_JSON_RECURSION_LIMIT_INTERNAL, "Wrong JSON data: recursion limitation (" << EPEE_JSON_RECURSION_LIMIT_INTERNAL << ") exceeded");
|
||||
|
||||
std::string::const_iterator sub_element_start;
|
||||
std::string name;
|
||||
typename t_storage::harray h_array = nullptr;
|
||||
enum match_state
|
||||
{
|
||||
match_state_lookup_for_section_start,
|
||||
match_state_lookup_for_name,
|
||||
match_state_waiting_separator,
|
||||
match_state_wonder_after_separator,
|
||||
match_state_wonder_after_value,
|
||||
match_state_wonder_array,
|
||||
match_state_array_after_value,
|
||||
match_state_array_waiting_value,
|
||||
match_state_error
|
||||
};
|
||||
|
||||
enum array_mode
|
||||
{
|
||||
array_mode_undifined = 0,
|
||||
array_mode_sections,
|
||||
array_mode_string,
|
||||
array_mode_numbers,
|
||||
array_mode_booleans
|
||||
};
|
||||
|
||||
match_state state = match_state_lookup_for_section_start;
|
||||
array_mode array_md = array_mode_undifined;
|
||||
std::string::const_iterator it = sec_buf_begin;
|
||||
for(;it != buf_end;it++)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case match_state_lookup_for_section_start:
|
||||
if(*it == '{')
|
||||
state = match_state_lookup_for_name;
|
||||
else CHECK_ISSPACE();
|
||||
break;
|
||||
case match_state_lookup_for_name:
|
||||
switch(*it)
|
||||
{
|
||||
case '"':
|
||||
match_string2(it, buf_end, name);
|
||||
state = match_state_waiting_separator;
|
||||
break;
|
||||
case '}':
|
||||
//this is it! section ends here.
|
||||
//seems that it is empty section
|
||||
sec_buf_begin = it;
|
||||
return;
|
||||
default:
|
||||
CHECK_ISSPACE();
|
||||
}
|
||||
break;
|
||||
case match_state_waiting_separator:
|
||||
if(*it == ':')
|
||||
state = match_state_wonder_after_separator;
|
||||
else CHECK_ISSPACE();
|
||||
break;
|
||||
case match_state_wonder_after_separator:
|
||||
if(*it == '"')
|
||||
{//just a named string value started
|
||||
std::string val;
|
||||
match_string2(it, buf_end, val);
|
||||
//insert text value
|
||||
stg.set_value(name, std::move(val), current_section);
|
||||
state = match_state_wonder_after_value;
|
||||
}else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
|
||||
{//just a named number value started
|
||||
boost::string_ref val;
|
||||
bool is_v_float = false;bool is_signed = false;
|
||||
match_number2(it, buf_end, val, is_v_float, is_signed);
|
||||
if(!is_v_float)
|
||||
{
|
||||
if(is_signed)
|
||||
{
|
||||
errno = 0;
|
||||
int64_t nval = strtoll(val.data(), NULL, 10);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
stg.set_value(name, int64_t(nval), current_section);
|
||||
}else
|
||||
{
|
||||
errno = 0;
|
||||
uint64_t nval = strtoull(val.data(), NULL, 10);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
stg.set_value(name, uint64_t(nval), current_section);
|
||||
}
|
||||
}else
|
||||
{
|
||||
errno = 0;
|
||||
double nval = strtod(val.data(), NULL);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
stg.set_value(name, double(nval), current_section);
|
||||
}
|
||||
state = match_state_wonder_after_value;
|
||||
}else if(isalpha(*it) )
|
||||
{// could be null, true or false
|
||||
boost::string_ref word;
|
||||
match_word2(it, buf_end, word);
|
||||
if(boost::iequals(word, "null"))
|
||||
{
|
||||
state = match_state_wonder_after_value;
|
||||
//just skip this,
|
||||
}else if(boost::iequals(word, "true"))
|
||||
{
|
||||
stg.set_value(name, true, current_section);
|
||||
state = match_state_wonder_after_value;
|
||||
}else if(boost::iequals(word, "false"))
|
||||
{
|
||||
stg.set_value(name, false, current_section);
|
||||
state = match_state_wonder_after_value;
|
||||
}else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
|
||||
}else if(*it == '{')
|
||||
{
|
||||
//sub section here
|
||||
typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
|
||||
CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
|
||||
run_handler(new_sec, it, buf_end, stg, recursion + 1);
|
||||
state = match_state_wonder_after_value;
|
||||
}else if(*it == '[')
|
||||
{//array of something
|
||||
state = match_state_wonder_array;
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case match_state_wonder_after_value:
|
||||
if(*it == ',')
|
||||
state = match_state_lookup_for_name;
|
||||
else if(*it == '}')
|
||||
{
|
||||
//this is it! section ends here.
|
||||
sec_buf_begin = it;
|
||||
return;
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case match_state_wonder_array:
|
||||
if(*it == '[')
|
||||
{
|
||||
ASSERT_MES_AND_THROW("array of array not suppoerted yet :( sorry");
|
||||
//mean array of array
|
||||
}
|
||||
if(*it == '{')
|
||||
{
|
||||
//mean array of sections
|
||||
typename t_storage::hsection new_sec = nullptr;
|
||||
h_array = stg.insert_first_section(name, new_sec, current_section);
|
||||
CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section");
|
||||
run_handler(new_sec, it, buf_end, stg, recursion + 1);
|
||||
state = match_state_array_after_value;
|
||||
array_md = array_mode_sections;
|
||||
}else if(*it == '"')
|
||||
{
|
||||
//mean array of strings
|
||||
std::string val;
|
||||
match_string2(it, buf_end, val);
|
||||
h_array = stg.insert_first_value(name, std::move(val), current_section);
|
||||
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
|
||||
state = match_state_array_after_value;
|
||||
array_md = array_mode_string;
|
||||
}else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
|
||||
{//array of numbers value started
|
||||
boost::string_ref val;
|
||||
bool is_v_float = false;bool is_signed_val = false;
|
||||
match_number2(it, buf_end, val, is_v_float, is_signed_val);
|
||||
if(!is_v_float)
|
||||
{
|
||||
if (is_signed_val)
|
||||
{
|
||||
errno = 0;
|
||||
int64_t nval = strtoll(val.data(), NULL, 10);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
h_array = stg.insert_first_value(name, int64_t(nval), current_section);
|
||||
}else
|
||||
{
|
||||
errno = 0;
|
||||
uint64_t nval = strtoull(val.data(), NULL, 10);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
h_array = stg.insert_first_value(name, uint64_t(nval), current_section);
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
||||
}else
|
||||
{
|
||||
errno = 0;
|
||||
double nval = strtod(val.data(), NULL);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
h_array = stg.insert_first_value(name, double(nval), current_section);
|
||||
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
||||
}
|
||||
|
||||
state = match_state_array_after_value;
|
||||
array_md = array_mode_numbers;
|
||||
}else if(*it == ']')//empty array
|
||||
{
|
||||
array_md = array_mode_undifined;
|
||||
state = match_state_wonder_after_value;
|
||||
}else if(isalpha(*it) )
|
||||
{// array of booleans
|
||||
boost::string_ref word;
|
||||
match_word2(it, buf_end, word);
|
||||
if(boost::iequals(word, "true"))
|
||||
{
|
||||
h_array = stg.insert_first_value(name, true, current_section);
|
||||
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
||||
state = match_state_array_after_value;
|
||||
array_md = array_mode_booleans;
|
||||
}else if(boost::iequals(word, "false"))
|
||||
{
|
||||
h_array = stg.insert_first_value(name, false, current_section);
|
||||
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
|
||||
state = match_state_array_after_value;
|
||||
array_md = array_mode_booleans;
|
||||
|
||||
}else ASSERT_MES_AND_THROW("Unknown value keyword " << word)
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case match_state_array_after_value:
|
||||
if(*it == ',')
|
||||
state = match_state_array_waiting_value;
|
||||
else if(*it == ']')
|
||||
{
|
||||
h_array = nullptr;
|
||||
array_md = array_mode_undifined;
|
||||
state = match_state_wonder_after_value;
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case match_state_array_waiting_value:
|
||||
switch(array_md)
|
||||
{
|
||||
case array_mode_sections:
|
||||
if(*it == '{')
|
||||
{
|
||||
typename t_storage::hsection new_sec = NULL;
|
||||
bool res = stg.insert_next_section(h_array, new_sec);
|
||||
CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section");
|
||||
run_handler(new_sec, it, buf_end, stg, recursion + 1);
|
||||
state = match_state_array_after_value;
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case array_mode_string:
|
||||
if(*it == '"')
|
||||
{
|
||||
std::string val;
|
||||
match_string2(it, buf_end, val);
|
||||
bool res = stg.insert_next_value(h_array, std::move(val));
|
||||
CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
|
||||
state = match_state_array_after_value;
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case array_mode_numbers:
|
||||
if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
|
||||
{//array of numbers value started
|
||||
boost::string_ref val;
|
||||
bool is_v_float = false;bool is_signed_val = false;
|
||||
match_number2(it, buf_end, val, is_v_float, is_signed_val);
|
||||
bool insert_res = false;
|
||||
if(!is_v_float)
|
||||
{
|
||||
if (is_signed_val)
|
||||
{
|
||||
errno = 0;
|
||||
int64_t nval = strtoll(val.data(), NULL, 10);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
insert_res = stg.insert_next_value(h_array, int64_t(nval));
|
||||
}else
|
||||
{
|
||||
errno = 0;
|
||||
uint64_t nval = strtoull(val.data(), NULL, 10);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
insert_res = stg.insert_next_value(h_array, uint64_t(nval));
|
||||
}
|
||||
}else
|
||||
{
|
||||
errno = 0;
|
||||
double nval = strtod(val.data(), NULL);
|
||||
if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
|
||||
insert_res = stg.insert_next_value(h_array, double(nval));
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value");
|
||||
state = match_state_array_after_value;
|
||||
array_md = array_mode_numbers;
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case array_mode_booleans:
|
||||
if(isalpha(*it) )
|
||||
{// array of booleans
|
||||
boost::string_ref word;
|
||||
match_word2(it, buf_end, word);
|
||||
if(boost::iequals(word, "true"))
|
||||
{
|
||||
bool r = stg.insert_next_value(h_array, true);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
|
||||
state = match_state_array_after_value;
|
||||
}else if(boost::iequals(word, "false"))
|
||||
{
|
||||
bool r = stg.insert_next_value(h_array, false);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
|
||||
state = match_state_array_after_value;
|
||||
}
|
||||
else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
|
||||
}else CHECK_ISSPACE();
|
||||
break;
|
||||
case array_mode_undifined:
|
||||
default:
|
||||
ASSERT_MES_AND_THROW("Bad array state");
|
||||
}
|
||||
break;
|
||||
case match_state_error:
|
||||
default:
|
||||
ASSERT_MES_AND_THROW("WRONG JSON STATE");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "Smith",
|
||||
"age": 25,
|
||||
"address": {
|
||||
"streetAddress": "21 2nd Street",
|
||||
"city": "New York",
|
||||
"state": "NY",
|
||||
"postalCode": -10021,
|
||||
"have_boobs": true,
|
||||
"have_balls": false
|
||||
},
|
||||
"phoneNumber": [
|
||||
{
|
||||
"type": "home",
|
||||
"number": "212 555-1234"
|
||||
},
|
||||
{
|
||||
"type": "fax",
|
||||
"number": "646 555-4567"
|
||||
}
|
||||
],
|
||||
"phoneNumbers": [
|
||||
"812 123-1234",
|
||||
"916 123-4567"
|
||||
]
|
||||
}
|
||||
*/
|
||||
template<class t_storage>
|
||||
inline bool load_from_json(const std::string& buff_json, t_storage& stg)
|
||||
{
|
||||
std::string::const_iterator sec_buf_begin = buff_json.begin();
|
||||
try
|
||||
{
|
||||
run_handler(nullptr, sec_buf_begin, buff_json.end(), stg, 0);
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
MERROR("Failed to parse json, what: " << ex.what());
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
MERROR("Failed to parse json");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "parserse_base_utils.h"
|
||||
#include "portable_storage.h"
|
||||
#include "file_io_utils.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool load_t_from_json(t_struct& out, const std::string& json_buff)
|
||||
{
|
||||
portable_storage ps;
|
||||
bool rs = ps.load_from_json(json_buff);
|
||||
if(!rs)
|
||||
return false;
|
||||
|
||||
return out.load(ps);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool load_t_from_json_file(t_struct& out, const std::string& json_file)
|
||||
{
|
||||
std::string f_buff;
|
||||
if(!file_io_utils::load_file_to_string(json_file, f_buff))
|
||||
return false;
|
||||
|
||||
return load_t_from_json(out, f_buff);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool store_t_to_json(t_struct& str_in, std::string& json_buff, size_t indent = 0, bool insert_newlines = true)
|
||||
{
|
||||
portable_storage ps;
|
||||
str_in.store(ps);
|
||||
ps.dump_as_json(json_buff, indent, insert_newlines);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
std::string store_t_to_json(t_struct& str_in, size_t indent = 0, bool insert_newlines = true)
|
||||
{
|
||||
std::string json_buff;
|
||||
store_t_to_json(str_in, json_buff, indent, insert_newlines);
|
||||
return json_buff;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool store_t_to_json_file(t_struct& str_in, const std::string& fpath)
|
||||
{
|
||||
std::string json_buff;
|
||||
store_t_to_json(str_in, json_buff);
|
||||
return file_io_utils::save_string_to_file(fpath, json_buff);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool load_t_from_binary(t_struct& out, const epee::span<const uint8_t> binary_buff)
|
||||
{
|
||||
portable_storage ps;
|
||||
bool rs = ps.load_from_binary(binary_buff);
|
||||
if(!rs)
|
||||
return false;
|
||||
|
||||
return out.load(ps);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool load_t_from_binary(t_struct& out, const std::string& binary_buff)
|
||||
{
|
||||
return load_t_from_binary(out, epee::strspan<uint8_t>(binary_buff));
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool load_t_from_binary_file(t_struct& out, const std::string& binary_file)
|
||||
{
|
||||
std::string f_buff;
|
||||
if(!file_io_utils::load_file_to_string(binary_file, f_buff))
|
||||
return false;
|
||||
|
||||
return load_t_from_binary(out, f_buff);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool store_t_to_binary(t_struct& str_in, std::string& binary_buff, size_t indent = 0)
|
||||
{
|
||||
portable_storage ps;
|
||||
str_in.store(ps);
|
||||
return ps.store_to_binary(binary_buff);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
std::string store_t_to_binary(t_struct& str_in, size_t indent = 0)
|
||||
{
|
||||
std::string binary_buff;
|
||||
store_t_to_binary(str_in, binary_buff, indent);
|
||||
return binary_buff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pragma_comp_defs.h"
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "portable_storage_bin_utils.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
|
||||
template<class pack_value, class t_stream>
|
||||
size_t pack_varint_t(t_stream& strm, uint8_t type_or, size_t& pv)
|
||||
{
|
||||
pack_value v = pv << 2;
|
||||
v |= type_or;
|
||||
v = CONVERT_POD(v);
|
||||
strm.write((const char*)&v, sizeof(pack_value));
|
||||
return sizeof(pack_value);
|
||||
}
|
||||
|
||||
PRAGMA_WARNING_PUSH
|
||||
PRAGMA_GCC("GCC diagnostic ignored \"-Wstrict-aliasing\"")
|
||||
#ifdef __clang__
|
||||
PRAGMA_GCC("GCC diagnostic ignored \"-Wtautological-constant-out-of-range-compare\"")
|
||||
#endif
|
||||
template<class t_stream>
|
||||
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<uint8_t>(strm, PORTABLE_RAW_SIZE_MARK_BYTE, val);
|
||||
}
|
||||
else if(val <= 16383)
|
||||
{//mean need word
|
||||
return pack_varint_t<uint16_t>(strm, PORTABLE_RAW_SIZE_MARK_WORD, val);
|
||||
}else if(val <= 1073741823)
|
||||
{//mean need dword
|
||||
return pack_varint_t<uint32_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<uint64_t>(strm, PORTABLE_RAW_SIZE_MARK_INT64, val);
|
||||
}
|
||||
}
|
||||
PRAGMA_WARNING_POP
|
||||
|
||||
template<class t_stream>
|
||||
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<class t_stream>
|
||||
struct array_entry_store_visitor: public boost::static_visitor<bool>
|
||||
{
|
||||
t_stream& m_strm;
|
||||
|
||||
template<class t_pod_type>
|
||||
bool pack_pod_array_type(uint8_t contained_type, const array_entry_t<t_pod_type>& 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(t_pod_type x: arr_pod.m_array)
|
||||
{
|
||||
x = CONVERT_POD(x);
|
||||
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<uint64_t>& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT64, v);}
|
||||
bool operator()(const array_entry_t<uint32_t>& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT32, v);}
|
||||
bool operator()(const array_entry_t<uint16_t>& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT16, v);}
|
||||
bool operator()(const array_entry_t<uint8_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_UINT8, v);}
|
||||
bool operator()(const array_entry_t<int64_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT64, v);}
|
||||
bool operator()(const array_entry_t<int32_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT32, v);}
|
||||
bool operator()(const array_entry_t<int16_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT16, v);}
|
||||
bool operator()(const array_entry_t<int8_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT8, v);}
|
||||
bool operator()(const array_entry_t<double>& v) { return pack_pod_array_type(SERIALIZE_TYPE_DUOBLE, v);}
|
||||
bool operator()(const array_entry_t<bool>& v) { return pack_pod_array_type(SERIALIZE_TYPE_BOOL, v);}
|
||||
bool operator()(const array_entry_t<std::string>& 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<section>& 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<array_entry>& 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<class t_stream>
|
||||
struct storage_entry_store_visitor: public boost::static_visitor<bool>
|
||||
{
|
||||
t_stream& m_strm;
|
||||
storage_entry_store_visitor(t_stream& strm):m_strm(strm){}
|
||||
template<class pod_type>
|
||||
bool pack_pod_type(uint8_t type, const pod_type& v)
|
||||
{
|
||||
m_strm.write((const char*)&type, 1);
|
||||
pod_type v0 = CONVERT_POD(v);
|
||||
m_strm.write((const char*)&v0, 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<class t_stream>
|
||||
bool pack_entry_to_buff(t_stream& strm, const array_entry& ae)
|
||||
{
|
||||
array_entry_store_visitor<t_stream> aesv(strm);
|
||||
return boost::apply_visitor(aesv, ae);
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
bool pack_entry_to_buff(t_stream& strm, const storage_entry& se)
|
||||
{
|
||||
storage_entry_store_visitor<t_stream> sv(strm);
|
||||
return boost::apply_visitor(sv, se);
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
bool pack_entry_to_buff(t_stream& strm, const section& sec)
|
||||
{
|
||||
typedef std::map<std::string, storage_entry>::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<uint8_t>::max(), "storage_entry_name is too long: " << se.first.size() << ", val: " << se.first);
|
||||
uint8_t len = static_cast<uint8_t>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "parserse_base_utils.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, bool insert_newlines);
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, bool insert_newlines);
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, bool insert_newlines);
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, bool insert_newlines);
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, bool insert_newlines);
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const bool& v, size_t indent, bool insert_newlines);
|
||||
template<class t_stream, class t_type>
|
||||
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, bool insert_newlines);
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const section& sec, size_t indent, bool insert_newlines);
|
||||
|
||||
|
||||
inline std::string make_indent(size_t indent)
|
||||
{
|
||||
return std::string(indent*2, ' ');
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
struct array_entry_store_to_json_visitor: public boost::static_visitor<void>
|
||||
{
|
||||
t_stream& m_strm;
|
||||
size_t m_indent;
|
||||
bool m_insert_newlines;
|
||||
array_entry_store_to_json_visitor(t_stream& strm, size_t indent,
|
||||
bool insert_newlines = true)
|
||||
: m_strm(strm), m_indent(indent), m_insert_newlines(insert_newlines)
|
||||
{}
|
||||
|
||||
template<class t_type>
|
||||
void operator()(const array_entry_t<t_type>& a)
|
||||
{
|
||||
m_strm << "[";
|
||||
if(a.m_array.size())
|
||||
{
|
||||
auto last_it = --a.m_array.end();
|
||||
for(auto it = a.m_array.begin(); it != a.m_array.end(); it++)
|
||||
{
|
||||
dump_as_json(m_strm, *it, m_indent, m_insert_newlines);
|
||||
if(it != last_it)
|
||||
m_strm << ",";
|
||||
}
|
||||
}
|
||||
m_strm << "]";
|
||||
}
|
||||
};
|
||||
|
||||
template<class t_stream>
|
||||
struct storage_entry_store_to_json_visitor: public boost::static_visitor<void>
|
||||
{
|
||||
t_stream& m_strm;
|
||||
size_t m_indent;
|
||||
bool m_insert_newlines;
|
||||
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent,
|
||||
bool insert_newlines = true)
|
||||
: m_strm(strm), m_indent(indent), m_insert_newlines(insert_newlines)
|
||||
{}
|
||||
//section, array_entry
|
||||
template<class visited_type>
|
||||
void operator()(const visited_type& v)
|
||||
{
|
||||
dump_as_json(m_strm, v, m_indent, m_insert_newlines);
|
||||
}
|
||||
};
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, bool insert_newlines)
|
||||
{
|
||||
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent, insert_newlines);
|
||||
boost::apply_visitor(aesv, ae);
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, bool insert_newlines)
|
||||
{
|
||||
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent, insert_newlines);
|
||||
boost::apply_visitor(sv, se);
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, bool insert_newlines)
|
||||
{
|
||||
strm << "\"" << misc_utils::parse::transform_to_escape_sequence(v) << "\"";
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, bool insert_newlines)
|
||||
{
|
||||
strm << static_cast<int32_t>(v);
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, bool insert_newlines)
|
||||
{
|
||||
strm << static_cast<int32_t>(v);
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const bool& v, size_t indent, bool insert_newlines)
|
||||
{
|
||||
if(v)
|
||||
strm << "true";
|
||||
else
|
||||
strm << "false";
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class t_stream, class t_type>
|
||||
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, bool insert_newlines)
|
||||
{
|
||||
strm << v;
|
||||
}
|
||||
|
||||
template<class t_stream>
|
||||
void dump_as_json(t_stream& strm, const section& sec, size_t indent, bool insert_newlines)
|
||||
{
|
||||
size_t local_indent = indent + 1;
|
||||
std::string newline = insert_newlines ? "\r\n" : "";
|
||||
strm << "{" << newline;
|
||||
std::string indent_str = make_indent(local_indent);
|
||||
if(sec.m_entries.size())
|
||||
{
|
||||
auto it_last = --sec.m_entries.end();
|
||||
for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++)
|
||||
{
|
||||
strm << indent_str << "\"" << misc_utils::parse::transform_to_escape_sequence(it->first) << "\"" << ": ";
|
||||
dump_as_json(strm, it->second, local_indent, insert_newlines);
|
||||
if(it_last != it)
|
||||
strm << ",";
|
||||
strm << newline;
|
||||
}
|
||||
}
|
||||
strm << make_indent(indent) << "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "warnings.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
#define ASSERT_AND_THROW_WRONG_CONVERSION() ASSERT_MES_AND_THROW("WRONG DATA CONVERSION: from type=" << typeid(from).name() << " to type " << typeid(to).name())
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
void convert_int_to_uint(const from_type& from, to_type& to)
|
||||
{
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4018)
|
||||
CHECK_AND_ASSERT_THROW_MES(from >=0, "unexpected int value with signed storage value less than 0, and unsigned receiver value");
|
||||
DISABLE_GCC_AND_CLANG_WARNING(sign-compare)
|
||||
CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits<to_type>::max(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits<to_type>::max());
|
||||
to = static_cast<to_type>(from);
|
||||
POP_WARNINGS
|
||||
}
|
||||
template<typename from_type, typename to_type>
|
||||
void convert_int_to_int(const from_type& from, to_type& to)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(from >= boost::numeric::bounds<to_type>::lowest(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with lowest possible value = " << boost::numeric::bounds<to_type>::lowest());
|
||||
PUSH_WARNINGS
|
||||
DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare)
|
||||
CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits<to_type>::max(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits<to_type>::max());
|
||||
POP_WARNINGS
|
||||
to = static_cast<to_type>(from);
|
||||
}
|
||||
template<typename from_type, typename to_type>
|
||||
void convert_uint_to_any_int(const from_type& from, to_type& to)
|
||||
{
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4018)
|
||||
DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare)
|
||||
CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits<to_type>::max(), "uint value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits<to_type>::max());
|
||||
to = static_cast<to_type>(from);
|
||||
POP_WARNINGS
|
||||
}
|
||||
|
||||
template<typename from_type, typename to_type, bool, bool> //is from signed, is from to signed
|
||||
struct convert_to_signed_unsigned;
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_signed_unsigned<from_type, to_type, true, true>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{//from signed to signed
|
||||
convert_int_to_int(from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_signed_unsigned<from_type, to_type, true, false>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{//from signed to unsigned
|
||||
convert_int_to_uint(from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_signed_unsigned<from_type, to_type, false, true>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{//from unsigned to signed
|
||||
convert_uint_to_any_int(from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_signed_unsigned<from_type, to_type, false, false>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{
|
||||
//from unsigned to unsigned
|
||||
convert_uint_to_any_int(from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename from_type, typename to_type, bool>
|
||||
struct convert_to_integral;
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_integral<from_type, to_type, true>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{
|
||||
convert_to_signed_unsigned<from_type, to_type, std::is_signed<from_type>::value, std::is_signed<to_type>::value>::convert(from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_integral<from_type, to_type, false>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{
|
||||
ASSERT_AND_THROW_WRONG_CONVERSION();
|
||||
}
|
||||
};
|
||||
|
||||
// For MyMonero/OpenMonero backend compatibility
|
||||
// MyMonero backend sends amount, fees and timestamp values as strings.
|
||||
// Until MM backend is updated, this is needed for compatibility between OpenMonero and MyMonero.
|
||||
template<>
|
||||
struct convert_to_integral<std::string, uint64_t, false>
|
||||
{
|
||||
static void convert(const std::string& from, uint64_t& to)
|
||||
{
|
||||
MTRACE("Converting std::string to uint64_t. Source: " << from);
|
||||
// String only contains digits
|
||||
if(std::all_of(from.begin(), from.end(), epee::misc_utils::parse::isdigit))
|
||||
to = boost::lexical_cast<uint64_t>(from);
|
||||
// MyMonero ISO 8061 timestamp (2017-05-06T16:27:06Z)
|
||||
else if (boost::regex_match (from, boost::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ")))
|
||||
{
|
||||
// Convert to unix timestamp
|
||||
#ifdef HAVE_STRPTIME
|
||||
struct tm tm;
|
||||
if (strptime(from.c_str(), "%Y-%m-%dT%H:%M:%S", &tm))
|
||||
#else
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(from);
|
||||
if (ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"))
|
||||
#endif
|
||||
to = std::mktime(&tm);
|
||||
} else
|
||||
ASSERT_AND_THROW_WRONG_CONVERSION();
|
||||
}
|
||||
};
|
||||
|
||||
template<class from_type, class to_type>
|
||||
struct is_convertable: std::integral_constant<bool,
|
||||
std::is_integral<to_type>::value &&
|
||||
std::is_integral<from_type>::value &&
|
||||
!std::is_same<from_type, bool>::value &&
|
||||
!std::is_same<to_type, bool>::value > {};
|
||||
|
||||
template<typename from_type, typename to_type, bool>
|
||||
struct convert_to_same;
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_same<from_type, to_type, true>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{
|
||||
to = from;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename from_type, typename to_type>
|
||||
struct convert_to_same<from_type, to_type, false>
|
||||
{
|
||||
static void convert(const from_type& from, to_type& to)
|
||||
{
|
||||
convert_to_integral<from_type, to_type, is_convertable<from_type, to_type>::value>::convert(from, to);// ASSERT_AND_THROW_WRONG_CONVERSION();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class from_type, class to_type>
|
||||
void convert_t(const from_type& from, to_type& to)
|
||||
{
|
||||
convert_to_same<from_type, to_type, std::is_same<to_type, from_type>::value>::convert(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
// Copyright (c) 2019, Haven Protocol
|
||||
// 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.
|
||||
//
|
||||
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
|
||||
|
||||
#include "pricing_record.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "storages/portable_storage.h"
|
||||
|
||||
namespace offshore
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct pr_serialized
|
||||
{
|
||||
uint64_t xAG;
|
||||
uint64_t xAU;
|
||||
uint64_t xAUD;
|
||||
uint64_t xBTC;
|
||||
uint64_t xCAD;
|
||||
uint64_t xCHF;
|
||||
uint64_t xCNY;
|
||||
uint64_t xEUR;
|
||||
uint64_t xGBP;
|
||||
uint64_t xJPY;
|
||||
uint64_t xNOK;
|
||||
uint64_t xNZD;
|
||||
uint64_t xUSD;
|
||||
uint64_t unused1;
|
||||
uint64_t unused2;
|
||||
uint64_t unused3;
|
||||
std::string signature;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(xAG)
|
||||
KV_SERIALIZE(xAU)
|
||||
KV_SERIALIZE(xAUD)
|
||||
KV_SERIALIZE(xBTC)
|
||||
KV_SERIALIZE(xCAD)
|
||||
KV_SERIALIZE(xCHF)
|
||||
KV_SERIALIZE(xCNY)
|
||||
KV_SERIALIZE(xEUR)
|
||||
KV_SERIALIZE(xGBP)
|
||||
KV_SERIALIZE(xJPY)
|
||||
KV_SERIALIZE(xNOK)
|
||||
KV_SERIALIZE(xNZD)
|
||||
KV_SERIALIZE(xUSD)
|
||||
KV_SERIALIZE(unused1)
|
||||
KV_SERIALIZE(unused2)
|
||||
KV_SERIALIZE(unused3)
|
||||
KV_SERIALIZE(signature)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
||||
|
||||
pricing_record::pricing_record() noexcept
|
||||
: xAG(0)
|
||||
, xAU(0)
|
||||
, xAUD(0)
|
||||
, xBTC(0)
|
||||
, xCAD(0)
|
||||
, xCHF(0)
|
||||
, xCNY(0)
|
||||
, xEUR(0)
|
||||
, xGBP(0)
|
||||
, xJPY(0)
|
||||
, xNOK(0)
|
||||
, xNZD(0)
|
||||
, xUSD(0)
|
||||
, unused1(0)
|
||||
, unused2(0)
|
||||
, unused3(0)
|
||||
{
|
||||
std::memset(signature, 0, sizeof(signature));
|
||||
}
|
||||
|
||||
bool pricing_record::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
|
||||
{
|
||||
pr_serialized in{};
|
||||
if (in._load(src, hparent))
|
||||
{
|
||||
// Copy everything into the local instance
|
||||
xAG = in.xAG;
|
||||
xAU = in.xAU;
|
||||
xAUD = in.xAUD;
|
||||
xBTC = in.xBTC;
|
||||
xCAD = in.xCAD;
|
||||
xCHF = in.xCHF;
|
||||
xCNY = in.xCNY;
|
||||
xEUR = in.xEUR;
|
||||
xGBP = in.xGBP;
|
||||
xJPY = in.xJPY;
|
||||
xNOK = in.xNOK;
|
||||
xNZD = in.xNZD;
|
||||
xUSD = in.xUSD;
|
||||
unused1 = in.unused1;
|
||||
unused2 = in.unused2;
|
||||
unused3 = in.unused3;
|
||||
for (unsigned int i = 0; i < in.signature.length(); i += 2) {
|
||||
std::string byteString = in.signature.substr(i, 2);
|
||||
signature[i>>1] = (char) strtol(byteString.c_str(), NULL, 16);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Report error here?
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pricing_record::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
|
||||
{
|
||||
std::string sig_hex;
|
||||
for (unsigned int i=0; i<64; i++) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]);
|
||||
sig_hex += ss.str();
|
||||
}
|
||||
const pr_serialized out{xAG,xAU,xAUD,xBTC,xCAD,xCHF,xCNY,xEUR,xGBP,xJPY,xNOK,xNZD,xUSD,unused1,unused2,unused3,sig_hex};
|
||||
return out.store(dest, hparent);
|
||||
}
|
||||
|
||||
pricing_record::pricing_record(const pricing_record& orig) noexcept
|
||||
: xAG(orig.xAG)
|
||||
, xAU(orig.xAU)
|
||||
, xAUD(orig.xAUD)
|
||||
, xBTC(orig.xBTC)
|
||||
, xCAD(orig.xCAD)
|
||||
, xCHF(orig.xCHF)
|
||||
, xCNY(orig.xCNY)
|
||||
, xEUR(orig.xEUR)
|
||||
, xGBP(orig.xGBP)
|
||||
, xJPY(orig.xJPY)
|
||||
, xNOK(orig.xNOK)
|
||||
, xNZD(orig.xNZD)
|
||||
, xUSD(orig.xUSD)
|
||||
, unused1(orig.unused1)
|
||||
, unused2(orig.unused2)
|
||||
, unused3(orig.unused3)
|
||||
{
|
||||
std::memcpy(signature, orig.signature, sizeof(signature));
|
||||
}
|
||||
|
||||
pricing_record& pricing_record::operator=(const pricing_record& orig) noexcept
|
||||
{
|
||||
xAG = orig.xAG;
|
||||
xAU = orig.xAU;
|
||||
xAUD = orig.xAUD;
|
||||
xBTC = orig.xBTC;
|
||||
xCAD = orig.xCAD;
|
||||
xCHF = orig.xCHF;
|
||||
xCNY = orig.xCNY;
|
||||
xEUR = orig.xEUR;
|
||||
xGBP = orig.xGBP;
|
||||
xJPY = orig.xJPY;
|
||||
xNOK = orig.xNOK;
|
||||
xNZD = orig.xNZD;
|
||||
xUSD = orig.xUSD;
|
||||
unused1 = orig.unused1;
|
||||
unused2 = orig.unused2;
|
||||
unused3 = orig.unused3;
|
||||
::memcpy(signature, orig.signature, sizeof(signature));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool pricing_record::equal(const pricing_record& other) const noexcept
|
||||
{
|
||||
return ((xAG == other.xAG) &&
|
||||
(xAU == other.xAU) &&
|
||||
(xAUD == other.xAUD) &&
|
||||
(xBTC == other.xBTC) &&
|
||||
(xCAD == other.xCAD) &&
|
||||
(xCHF == other.xCHF) &&
|
||||
(xCNY == other.xCNY) &&
|
||||
(xEUR == other.xEUR) &&
|
||||
(xGBP == other.xGBP) &&
|
||||
(xJPY == other.xJPY) &&
|
||||
(xNOK == other.xNOK) &&
|
||||
(xNZD == other.xNZD) &&
|
||||
(xUSD == other.xUSD) &&
|
||||
(unused1 == other.unused1) &&
|
||||
(unused2 == other.unused2) &&
|
||||
(unused3 == other.unused3) &&
|
||||
!::memcmp(signature, other.signature, sizeof(signature)));
|
||||
}
|
||||
|
||||
|
||||
bool pricing_record::verifySignature() const noexcept
|
||||
{
|
||||
// Sanity check - accept empty pricing records
|
||||
unsigned char test_sig[64];
|
||||
std::memset(test_sig, 0, sizeof(test_sig));
|
||||
if (std::memcmp(test_sig, signature, sizeof(signature)) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert our internal 64-byte binary representation into 128-byte hex string
|
||||
std::string sig_hex;
|
||||
for (unsigned int i=0; i<64; i++) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]);
|
||||
sig_hex += ss.str();
|
||||
}
|
||||
|
||||
// Rebuild the OpenSSL format of the signature from the r+s values
|
||||
std::string sig_rebuilt = "30";
|
||||
std::string r_rebuilt = (signature[0] == 0) ? sig_hex.substr(2, 62) : sig_hex.substr(0,64);
|
||||
if (signature[(signature[0] == 0) ? 1 : 0] & 0x80)
|
||||
r_rebuilt = "00" + r_rebuilt;
|
||||
std::string s_rebuilt = (signature[(signature[32] == 0) ? 33 : 32] == 0) ? sig_hex.substr(66, 62) : sig_hex.substr(64,64);
|
||||
if (signature[(signature[32] == 0) ? 33 : 32] & 0x80)
|
||||
s_rebuilt = "00" + s_rebuilt;
|
||||
size_t sig_length = (r_rebuilt.length() + s_rebuilt.length() + 8) >> 1;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << sig_length;
|
||||
sig_rebuilt += std::string(2-ss.str().length(), '0') + ss.str();
|
||||
ss.clear();
|
||||
sig_rebuilt += "02";
|
||||
size_t r_length = r_rebuilt.length() >> 1;
|
||||
std::stringstream ss2;
|
||||
ss2 << std::hex << r_length;
|
||||
sig_rebuilt += std::string(2-ss2.str().length(), '0') + ss2.str();
|
||||
ss2.clear();
|
||||
sig_rebuilt += r_rebuilt;
|
||||
sig_rebuilt += "02";
|
||||
size_t s_length = s_rebuilt.length() >> 1;
|
||||
std::stringstream ss3;
|
||||
ss3 << std::hex << s_length;
|
||||
sig_rebuilt += std::string(2-ss3.str().length(), '0') + ss3.str();
|
||||
ss3.clear();
|
||||
sig_rebuilt += s_rebuilt;
|
||||
|
||||
// Build the JSON string, so that we can verify the signature
|
||||
std::ostringstream oss;
|
||||
oss << "{\"xAG\":" << xAG;
|
||||
oss << ",\"xAU\":" << xAU;
|
||||
oss << ",\"xAUD\":" << xAUD;
|
||||
oss << ",\"xBTC\":" << xBTC;
|
||||
oss << ",\"xCAD\":" << xCAD;
|
||||
oss << ",\"xCHF\":" << xCHF;
|
||||
oss << ",\"xCNY\":" << xCNY;
|
||||
oss << ",\"xEUR\":" << xEUR;
|
||||
oss << ",\"xGBP\":" << xGBP;
|
||||
oss << ",\"xJPY\":" << xJPY;
|
||||
oss << ",\"xNOK\":" << xNOK;
|
||||
oss << ",\"xNZD\":" << xNZD;
|
||||
oss << ",\"xUSD\":" << xUSD;
|
||||
oss << ",\"unused1\":" << unused1;
|
||||
oss << ",\"unused2\":" << unused2;
|
||||
oss << ",\"unused3\":" << unused3;
|
||||
oss << "}";
|
||||
std::string message = oss.str();
|
||||
|
||||
// Convert signature from hex-encoded to binary
|
||||
std::string compact;
|
||||
for (unsigned int i = 0; i < sig_rebuilt.length(); i += 2) {
|
||||
std::string byteString = sig_rebuilt.substr(i, 2);
|
||||
char byte = (char) strtol(byteString.c_str(), NULL, 16);
|
||||
compact += (byte);
|
||||
}
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// NEAC: the public key should be in a file
|
||||
static const char public_key[] = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n"
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
// LAND AHOY!!!
|
||||
|
||||
// Grab the public key and make it usable
|
||||
BIO* bio = BIO_new_mem_buf(public_key, (int)sizeof(public_key));
|
||||
assert(bio != NULL);
|
||||
EVP_PKEY* pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
assert(pubkey != NULL);
|
||||
|
||||
// Create a verify digest from the message
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
int ret = 0;
|
||||
if (ctx) {
|
||||
ret=EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, pubkey);
|
||||
if (ret == 1) {
|
||||
ret=EVP_DigestVerifyUpdate(ctx, message.data(), message.length());
|
||||
if (ret == 1) {
|
||||
ret=EVP_DigestVerifyFinal(ctx, (const unsigned char *)compact.data(), compact.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cleanup the context we created
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
|
||||
// Cleanup the openssl stuff
|
||||
EVP_PKEY_free(pubkey);
|
||||
|
||||
if (ret == 1)
|
||||
return true;
|
||||
|
||||
// Get the errors from OpenSSL
|
||||
//ERR_print_errors_fp (stderr);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user