rodecomp/Recovered/jsoncons/include/jsoncons_ext/msgpack/msgpack_encoder.hpp
ragnarok-clanker 9b9c369f0c Move exe-only code to Recovered/ and rebuild virtualised PakAuxiliary::Extract
Recovered/ holds the code linked only into the standalone exe (scripts/exe/build_exe.py), outside the Clank source dirs:
- jsoncons/ and nProtect/ moved from scripts/exe/; GameGuard stand-in follows main's renamed entry points.
- GPak/PakAuxiliary.cpp: Extract (virtualised in every build; 02-19 jumps out at 0x0065861E) rebuilt from the open GRF Editor decoder, after the visible 02-19 prologue; inline key and kRO keys 1-4. Apply traps (unreachable in 02-19).
- GGHash/GGHash.cpp: CGGHash::Load/Check/VerifyHash trap (RagHash.dat check unreachable in 02-19).
The whole client links: 984 units, 0 unresolved.
2026-11-06 19:33:10 +01:00

753 lines
29 KiB
C++

// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_MSGPACK_MSGPACK_ENCODER_HPP
#define JSONCONS_MSGPACK_MSGPACK_ENCODER_HPP
#include <string>
#include <vector>
#include <limits> // std::numeric_limits
#include <memory>
#include <utility> // std::move
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/sink.hpp>
#include <jsoncons/detail/parse_number.hpp>
#include <jsoncons_ext/msgpack/msgpack_type.hpp>
#include <jsoncons_ext/msgpack/msgpack_error.hpp>
#include <jsoncons_ext/msgpack/msgpack_options.hpp>
namespace jsoncons {
namespace msgpack {
enum class msgpack_container_type {object, array};
template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
class basic_msgpack_encoder final : public basic_json_visitor<char>
{
enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 };
static constexpr int64_t nanos_in_milli = 1000000;
static constexpr int64_t nanos_in_second = 1000000000;
static constexpr int64_t millis_in_second = 1000;
public:
using allocator_type = Allocator;
using char_type = char;
using typename basic_json_visitor<char>::string_view_type;
using sink_type = Sink;
private:
struct stack_item
{
msgpack_container_type type_;
std::size_t length_;
std::size_t count_;
stack_item(msgpack_container_type type, std::size_t length = 0) noexcept
: type_(type), length_(length), count_(0)
{
}
std::size_t length() const
{
return length_;
}
std::size_t count() const
{
return count_;
}
bool is_object() const
{
return type_ == msgpack_container_type::object;
}
};
Sink sink_;
const msgpack_encode_options options_;
allocator_type alloc_;
std::vector<stack_item> stack_;
int nesting_depth_;
// Noncopyable and nonmoveable
basic_msgpack_encoder(const basic_msgpack_encoder&) = delete;
basic_msgpack_encoder& operator=(const basic_msgpack_encoder&) = delete;
public:
explicit basic_msgpack_encoder(Sink&& sink,
const Allocator& alloc = Allocator())
: basic_msgpack_encoder(std::forward<Sink>(sink), msgpack_encode_options(), alloc)
{
}
explicit basic_msgpack_encoder(Sink&& sink,
const msgpack_encode_options& options,
const Allocator& alloc = Allocator())
: sink_(std::forward<Sink>(sink)),
options_(options),
alloc_(alloc),
nesting_depth_(0)
{
}
~basic_msgpack_encoder() noexcept
{
sink_.flush();
}
void reset()
{
stack_.clear();
nesting_depth_ = 0;
}
void reset(Sink&& sink)
{
sink_ = std::move(sink);
reset();
}
private:
// Implementing methods
void visit_flush() override
{
sink_.flush();
}
bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override
{
ec = msgpack_errc::object_length_required;
return false;
}
bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override
{
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
{
ec = msgpack_errc::max_nesting_depth_exceeded;
return false;
}
stack_.emplace_back(msgpack_container_type::object, length);
if (length <= 15)
{
// fixmap
sink_.push_back(jsoncons::msgpack::msgpack_type::fixmap_base_type | (length & 0xf));
}
else if (length <= 65535)
{
// map 16
sink_.push_back(jsoncons::msgpack::msgpack_type::map16_type);
binary::native_to_big(static_cast<uint16_t>(length),
std::back_inserter(sink_));
}
else if (length <= 4294967295)
{
// map 32
sink_.push_back(jsoncons::msgpack::msgpack_type::map32_type);
binary::native_to_big(static_cast<uint32_t>(length),
std::back_inserter(sink_));
}
return true;
}
bool visit_end_object(const ser_context&, std::error_code& ec) override
{
JSONCONS_ASSERT(!stack_.empty());
--nesting_depth_;
if (stack_.back().count() < stack_.back().length())
{
ec = msgpack_errc::too_few_items;
return false;
}
else if (stack_.back().count() > stack_.back().length())
{
ec = msgpack_errc::too_many_items;
return false;
}
stack_.pop_back();
end_value();
return true;
}
bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override
{
ec = msgpack_errc::array_length_required;
return false;
}
bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override
{
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
{
ec = msgpack_errc::max_nesting_depth_exceeded;
return false;
}
stack_.emplace_back(msgpack_container_type::array, length);
if (length <= 15)
{
// fixarray
sink_.push_back(jsoncons::msgpack::msgpack_type::fixarray_base_type | (length & 0xf));
}
else if (length <= (std::numeric_limits<uint16_t>::max)())
{
// array 16
sink_.push_back(jsoncons::msgpack::msgpack_type::array16_type);
binary::native_to_big(static_cast<uint16_t>(length),std::back_inserter(sink_));
}
else if (length <= (std::numeric_limits<uint32_t>::max)())
{
// array 32
sink_.push_back(jsoncons::msgpack::msgpack_type::array32_type);
binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
}
return true;
}
bool visit_end_array(const ser_context&, std::error_code& ec) override
{
JSONCONS_ASSERT(!stack_.empty());
--nesting_depth_;
if (stack_.back().count() < stack_.back().length())
{
ec = msgpack_errc::too_few_items;
return false;
}
else if (stack_.back().count() > stack_.back().length())
{
ec = msgpack_errc::too_many_items;
return false;
}
stack_.pop_back();
end_value();
return true;
}
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
{
write_string_value(name);
return true;
}
bool visit_null(semantic_tag, const ser_context&, std::error_code&) override
{
// nil
sink_.push_back(jsoncons::msgpack::msgpack_type::nil_type);
end_value();
return true;
}
void write_timestamp(int64_t seconds, int64_t nanoseconds)
{
if ((seconds >> 34) == 0)
{
uint64_t data64 = (nanoseconds << 34) | seconds;
if ((data64 & 0xffffffff00000000L) == 0)
{
// timestamp 32
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type);
sink_.push_back(0xff);
binary::native_to_big(static_cast<uint32_t>(data64), std::back_inserter(sink_));
}
else
{
// timestamp 64
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type);
sink_.push_back(0xff);
binary::native_to_big(static_cast<uint64_t>(data64), std::back_inserter(sink_));
}
}
else
{
// timestamp 96
sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type);
sink_.push_back(0x0c); // 12
sink_.push_back(0xff);
binary::native_to_big(static_cast<uint32_t>(nanoseconds), std::back_inserter(sink_));
binary::native_to_big(static_cast<uint64_t>(seconds), std::back_inserter(sink_));
}
}
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override
{
switch (tag)
{
case semantic_tag::epoch_second:
{
int64_t seconds;
auto result = jsoncons::detail::to_integer(sv.data(), sv.length(), seconds);
if (!result)
{
ec = msgpack_errc::invalid_timestamp;
return false;
}
write_timestamp(seconds, 0);
break;
}
case semantic_tag::epoch_milli:
{
bigint n = bigint::from_string(sv.data(), sv.length());
if (n != 0)
{
bigint q;
bigint rem;
n.divide(millis_in_second, q, rem, true);
int64_t seconds = static_cast<int64_t>(q);
int64_t nanoseconds = static_cast<int64_t>(rem) * nanos_in_milli;
if (nanoseconds < 0)
{
nanoseconds = -nanoseconds;
}
write_timestamp(seconds, nanoseconds);
}
else
{
write_timestamp(0, 0);
}
break;
}
case semantic_tag::epoch_nano:
{
bigint n = bigint::from_string(sv.data(), sv.length());
if (n != 0)
{
bigint q;
bigint rem;
n.divide(nanos_in_second, q, rem, true);
int64_t seconds = static_cast<int64_t>(q);
int64_t nanoseconds = static_cast<int64_t>(rem);
if (nanoseconds < 0)
{
nanoseconds = -nanoseconds;
}
write_timestamp(seconds, nanoseconds);
}
else
{
write_timestamp(0, 0);
}
break;
}
default:
{
write_string_value(sv);
end_value();
break;
}
}
return true;
}
void write_string_value(const string_view_type& sv)
{
auto sink = unicode_traits::validate(sv.data(), sv.size());
if (sink.ec != unicode_traits::conv_errc())
{
JSONCONS_THROW(ser_error(msgpack_errc::invalid_utf8_text_string));
}
const size_t length = sv.length();
if (length <= 31)
{
// fixstr stores a byte array whose length is upto 31 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::fixstr_base_type | static_cast<uint8_t>(length));
}
else if (length <= (std::numeric_limits<uint8_t>::max)())
{
// str 8 stores a byte array whose length is upto (2^8)-1 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::str8_type);
sink_.push_back(static_cast<uint8_t>(length));
}
else if (length <= (std::numeric_limits<uint16_t>::max)())
{
// str 16 stores a byte array whose length is upto (2^16)-1 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::str16_type);
binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
}
else if (length <= (std::numeric_limits<uint32_t>::max)())
{
// str 32 stores a byte array whose length is upto (2^32)-1 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::str32_type);
binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
}
for (auto c : sv)
{
sink_.push_back(c);
}
}
bool visit_byte_string(const byte_string_view& b,
semantic_tag,
const ser_context&,
std::error_code&) override
{
const std::size_t length = b.size();
if (length <= (std::numeric_limits<uint8_t>::max)())
{
// bin 8 stores a byte array whose length is upto (2^8)-1 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::bin8_type);
sink_.push_back(static_cast<uint8_t>(length));
}
else if (length <= (std::numeric_limits<uint16_t>::max)())
{
// bin 16 stores a byte array whose length is upto (2^16)-1 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::bin16_type);
binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
}
else if (length <= (std::numeric_limits<uint32_t>::max)())
{
// bin 32 stores a byte array whose length is upto (2^32)-1 bytes
sink_.push_back(jsoncons::msgpack::msgpack_type::bin32_type);
binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
}
for (auto c : b)
{
sink_.push_back(c);
}
end_value();
return true;
}
bool visit_byte_string(const byte_string_view& b,
uint64_t ext_tag,
const ser_context&,
std::error_code&) override
{
const std::size_t length = b.size();
switch (length)
{
case 1:
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext1_type);
sink_.push_back(static_cast<uint8_t>(ext_tag));
break;
case 2:
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext2_type);
sink_.push_back(static_cast<uint8_t>(ext_tag));
break;
case 4:
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type);
sink_.push_back(static_cast<uint8_t>(ext_tag));
break;
case 8:
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type);
sink_.push_back(static_cast<uint8_t>(ext_tag));
break;
case 16:
sink_.push_back(jsoncons::msgpack::msgpack_type::fixext16_type);
sink_.push_back(static_cast<uint8_t>(ext_tag));
break;
default:
if (length <= (std::numeric_limits<uint8_t>::max)())
{
sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type);
sink_.push_back(static_cast<uint8_t>(length));
sink_.push_back(static_cast<uint8_t>(ext_tag));
}
else if (length <= (std::numeric_limits<uint16_t>::max)())
{
sink_.push_back(jsoncons::msgpack::msgpack_type::ext16_type);
binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
sink_.push_back(static_cast<uint8_t>(ext_tag));
}
else if (length <= (std::numeric_limits<uint32_t>::max)())
{
sink_.push_back(jsoncons::msgpack::msgpack_type::ext32_type);
binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
sink_.push_back(static_cast<uint8_t>(ext_tag));
}
break;
}
for (auto c : b)
{
sink_.push_back(c);
}
end_value();
return true;
}
bool visit_double(double val,
semantic_tag,
const ser_context&,
std::error_code&) override
{
float valf = (float)val;
if ((double)valf == val)
{
// float 32
sink_.push_back(jsoncons::msgpack::msgpack_type::float32_type);
binary::native_to_big(valf,std::back_inserter(sink_));
}
else
{
// float 64
sink_.push_back(jsoncons::msgpack::msgpack_type::float64_type);
binary::native_to_big(val,std::back_inserter(sink_));
}
// write double
end_value();
return true;
}
bool visit_int64(int64_t val,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (tag)
{
case semantic_tag::epoch_second:
write_timestamp(val, 0);
break;
case semantic_tag::epoch_milli:
{
if (val != 0)
{
auto dv = std::div(val,millis_in_second);
int64_t seconds = dv.quot;
int64_t nanoseconds = dv.rem*nanos_in_milli;
if (nanoseconds < 0)
{
nanoseconds = -nanoseconds;
}
write_timestamp(seconds, nanoseconds);
}
else
{
write_timestamp(0, 0);
}
break;
}
case semantic_tag::epoch_nano:
{
if (val != 0)
{
auto dv = std::div(val,static_cast<int64_t>(nanos_in_second));
int64_t seconds = dv.quot;
int64_t nanoseconds = dv.rem;
if (nanoseconds < 0)
{
nanoseconds = -nanoseconds;
}
write_timestamp(seconds, nanoseconds);
}
else
{
write_timestamp(0, 0);
}
break;
}
default:
{
if (val >= 0)
{
if (val <= 0x7f)
{
// positive fixnum stores 7-bit positive integer
sink_.push_back(static_cast<uint8_t>(val));
}
else if (val <= (std::numeric_limits<uint8_t>::max)())
{
// uint 8 stores a 8-bit unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type);
sink_.push_back(static_cast<uint8_t>(val));
}
else if (val <= (std::numeric_limits<uint16_t>::max)())
{
// uint 16 stores a 16-bit big-endian unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type);
binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_));
}
else if (val <= (std::numeric_limits<uint32_t>::max)())
{
// uint 32 stores a 32-bit big-endian unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type);
binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_));
}
else if (val <= (std::numeric_limits<int64_t>::max)())
{
// int 64 stores a 64-bit big-endian signed integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type);
binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_));
}
}
else
{
if (val >= -32)
{
// negative fixnum stores 5-bit negative integer
binary::native_to_big(static_cast<int8_t>(val), std::back_inserter(sink_));
}
else if (val >= (std::numeric_limits<int8_t>::lowest)())
{
// int 8 stores a 8-bit signed integer
sink_.push_back(jsoncons::msgpack::msgpack_type::int8_type);
binary::native_to_big(static_cast<int8_t>(val),std::back_inserter(sink_));
}
else if (val >= (std::numeric_limits<int16_t>::lowest)())
{
// int 16 stores a 16-bit big-endian signed integer
sink_.push_back(jsoncons::msgpack::msgpack_type::int16_type);
binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_));
}
else if (val >= (std::numeric_limits<int32_t>::lowest)())
{
// int 32 stores a 32-bit big-endian signed integer
sink_.push_back(jsoncons::msgpack::msgpack_type::int32_type);
binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_));
}
else if (val >= (std::numeric_limits<int64_t>::lowest)())
{
// int 64 stores a 64-bit big-endian signed integer
sink_.push_back(jsoncons::msgpack::msgpack_type::int64_type);
binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_));
}
}
}
break;
}
end_value();
return true;
}
bool visit_uint64(uint64_t val,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (tag)
{
case semantic_tag::epoch_second:
write_timestamp(static_cast<int64_t>(val), 0);
break;
case semantic_tag::epoch_milli:
{
if (val != 0)
{
auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(millis_in_second));
int64_t seconds = dv.quot;
int64_t nanoseconds = dv.rem*nanos_in_milli;
if (nanoseconds < 0)
{
nanoseconds = -nanoseconds;
}
write_timestamp(seconds, nanoseconds);
}
else
{
write_timestamp(0, 0);
}
break;
}
case semantic_tag::epoch_nano:
{
if (val != 0)
{
auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(nanos_in_second));
int64_t seconds = dv.quot;
int64_t nanoseconds = dv.rem;
if (nanoseconds < 0)
{
nanoseconds = -nanoseconds;
}
write_timestamp(seconds, nanoseconds);
}
else
{
write_timestamp(0, 0);
}
break;
}
default:
{
if (val <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
{
// positive fixnum stores 7-bit positive integer
sink_.push_back(static_cast<uint8_t>(val));
}
else if (val <= (std::numeric_limits<uint8_t>::max)())
{
// uint 8 stores a 8-bit unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type);
sink_.push_back(static_cast<uint8_t>(val));
}
else if (val <= (std::numeric_limits<uint16_t>::max)())
{
// uint 16 stores a 16-bit big-endian unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type);
binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_));
}
else if (val <= (std::numeric_limits<uint32_t>::max)())
{
// uint 32 stores a 32-bit big-endian unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type);
binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_));
}
else if (val <= (std::numeric_limits<uint64_t>::max)())
{
// uint 64 stores a 64-bit big-endian unsigned integer
sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type);
binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_));
}
break;
}
}
end_value();
return true;
}
bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) override
{
// true and false
sink_.push_back(static_cast<uint8_t>(val ? jsoncons::msgpack::msgpack_type::true_type : jsoncons::msgpack::msgpack_type::false_type));
end_value();
return true;
}
void end_value()
{
if (!stack_.empty())
{
++stack_.back().count_;
}
}
};
using msgpack_stream_encoder = basic_msgpack_encoder<jsoncons::binary_stream_sink>;
using msgpack_bytes_encoder = basic_msgpack_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_encoder") typedef msgpack_bytes_encoder msgpack_bytes_serializer;
template<class Sink=jsoncons::binary_stream_sink>
using basic_msgpack_serializer = basic_msgpack_encoder<Sink>;
JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_encoder") typedef msgpack_stream_encoder msgpack_encoder;
JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_encoder") typedef msgpack_stream_encoder msgpack_serializer;
JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_encoder") typedef msgpack_bytes_encoder msgpack_buffer_serializer;
#endif
} // namespace msgpack
} // namespace jsoncons
#endif