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.
502 lines
16 KiB
C++
502 lines
16 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_UBJSON_UBJSON_ENCODER_HPP
|
|
#define JSONCONS_UBJSON_UBJSON_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/ubjson/ubjson_type.hpp>
|
|
#include <jsoncons_ext/ubjson/ubjson_error.hpp>
|
|
#include <jsoncons_ext/ubjson/ubjson_options.hpp>
|
|
|
|
namespace jsoncons { namespace ubjson {
|
|
|
|
enum class ubjson_container_type {object, indefinite_length_object, array, indefinite_length_array};
|
|
|
|
template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
|
|
class basic_ubjson_encoder final : public basic_json_visitor<char>
|
|
{
|
|
|
|
enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 };
|
|
public:
|
|
using allocator_type = Allocator;
|
|
using typename basic_json_visitor<char>::string_view_type;
|
|
using sink_type = Sink;
|
|
|
|
private:
|
|
struct stack_item
|
|
{
|
|
ubjson_container_type type_;
|
|
std::size_t length_;
|
|
std::size_t count_;
|
|
|
|
stack_item(ubjson_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_ == ubjson_container_type::object || type_ == ubjson_container_type::indefinite_length_object;
|
|
}
|
|
|
|
bool is_indefinite_length() const
|
|
{
|
|
return type_ == ubjson_container_type::indefinite_length_array || type_ == ubjson_container_type::indefinite_length_object;
|
|
}
|
|
|
|
};
|
|
|
|
Sink sink_;
|
|
const ubjson_encode_options options_;
|
|
allocator_type alloc_;
|
|
|
|
std::vector<stack_item> stack_;
|
|
int nesting_depth_;
|
|
|
|
// Noncopyable and nonmoveable
|
|
basic_ubjson_encoder(const basic_ubjson_encoder&) = delete;
|
|
basic_ubjson_encoder& operator=(const basic_ubjson_encoder&) = delete;
|
|
public:
|
|
basic_ubjson_encoder(Sink&& sink,
|
|
const Allocator& alloc = Allocator())
|
|
: basic_ubjson_encoder(std::forward<Sink>(sink), ubjson_encode_options(), alloc)
|
|
{
|
|
}
|
|
|
|
explicit basic_ubjson_encoder(Sink&& sink,
|
|
const ubjson_encode_options& options,
|
|
const Allocator& alloc = Allocator())
|
|
: sink_(std::forward<Sink>(sink)),
|
|
options_(options),
|
|
alloc_(alloc),
|
|
nesting_depth_(0)
|
|
{
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
stack_.clear();
|
|
nesting_depth_ = 0;
|
|
}
|
|
|
|
void reset(Sink&& sink)
|
|
{
|
|
sink_ = std::move(sink);
|
|
reset();
|
|
}
|
|
|
|
~basic_ubjson_encoder() noexcept
|
|
{
|
|
JSONCONS_TRY
|
|
{
|
|
sink_.flush();
|
|
}
|
|
JSONCONS_CATCH(...)
|
|
{
|
|
}
|
|
}
|
|
|
|
private:
|
|
// Implementing methods
|
|
|
|
void visit_flush() override
|
|
{
|
|
sink_.flush();
|
|
}
|
|
|
|
bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override
|
|
{
|
|
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
|
|
{
|
|
ec = ubjson_errc::max_nesting_depth_exceeded;
|
|
return false;
|
|
}
|
|
stack_.emplace_back(ubjson_container_type::indefinite_length_object);
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::start_object_marker);
|
|
|
|
return true;
|
|
}
|
|
|
|
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 = ubjson_errc::max_nesting_depth_exceeded;
|
|
return false;
|
|
}
|
|
stack_.emplace_back(ubjson_container_type::object, length);
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::start_object_marker);
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::count_marker);
|
|
put_length(length);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool visit_end_object(const ser_context&, std::error_code& ec) override
|
|
{
|
|
JSONCONS_ASSERT(!stack_.empty());
|
|
--nesting_depth_;
|
|
|
|
if (stack_.back().is_indefinite_length())
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::end_object_marker);
|
|
}
|
|
else
|
|
{
|
|
if (stack_.back().count() < stack_.back().length())
|
|
{
|
|
ec = ubjson_errc::too_few_items;
|
|
return false;
|
|
}
|
|
if (stack_.back().count() > stack_.back().length())
|
|
{
|
|
ec = ubjson_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
|
|
{
|
|
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
|
|
{
|
|
ec = ubjson_errc::max_nesting_depth_exceeded;
|
|
return false;
|
|
}
|
|
stack_.emplace_back(ubjson_container_type::indefinite_length_array);
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::start_array_marker);
|
|
|
|
return true;
|
|
}
|
|
|
|
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 = ubjson_errc::max_nesting_depth_exceeded;
|
|
return false;
|
|
}
|
|
stack_.emplace_back(ubjson_container_type::array, length);
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::start_array_marker);
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::count_marker);
|
|
put_length(length);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool visit_end_array(const ser_context&, std::error_code& ec) override
|
|
{
|
|
JSONCONS_ASSERT(!stack_.empty());
|
|
--nesting_depth_;
|
|
|
|
if (stack_.back().is_indefinite_length())
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::end_array_marker);
|
|
}
|
|
else
|
|
{
|
|
if (stack_.back().count() < stack_.back().length())
|
|
{
|
|
ec = ubjson_errc::too_few_items;
|
|
return false;
|
|
}
|
|
if (stack_.back().count() > stack_.back().length())
|
|
{
|
|
ec = ubjson_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& ec) override
|
|
{
|
|
auto sink = unicode_traits::validate(name.data(), name.size());
|
|
if (sink.ec != unicode_traits::conv_errc())
|
|
{
|
|
ec = ubjson_errc::invalid_utf8_text_string;
|
|
return false;
|
|
}
|
|
|
|
put_length(name.length());
|
|
|
|
for (auto c : name)
|
|
{
|
|
sink_.push_back(c);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_null(semantic_tag, const ser_context&, std::error_code&) override
|
|
{
|
|
// nil
|
|
binary::native_to_big(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::null_type), std::back_inserter(sink_));
|
|
end_value();
|
|
return true;
|
|
}
|
|
|
|
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override
|
|
{
|
|
switch (tag)
|
|
{
|
|
case semantic_tag::bigint:
|
|
case semantic_tag::bigdec:
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::high_precision_number_type);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::string_type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
auto sink = unicode_traits::validate(sv.data(), sv.size());
|
|
if (sink.ec != unicode_traits::conv_errc())
|
|
{
|
|
ec = ubjson_errc::invalid_utf8_text_string;
|
|
return false;
|
|
}
|
|
|
|
put_length(sv.length());
|
|
|
|
for (auto c : sv)
|
|
{
|
|
sink_.push_back(c);
|
|
}
|
|
|
|
end_value();
|
|
return true;
|
|
}
|
|
|
|
void put_length(std::size_t length)
|
|
{
|
|
if (length <= (std::numeric_limits<uint8_t>::max)())
|
|
{
|
|
sink_.push_back(ubjson_type::uint8_type);
|
|
binary::native_to_big(static_cast<uint8_t>(length), std::back_inserter(sink_));
|
|
}
|
|
else if (length <= (std::size_t)(std::numeric_limits<int16_t>::max)())
|
|
{
|
|
sink_.push_back(ubjson_type::int16_type);
|
|
binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
|
|
}
|
|
else if (length <= (std::size_t)(std::numeric_limits<int32_t>::max)())
|
|
{
|
|
sink_.push_back(ubjson_type::int32_type);
|
|
binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
|
|
}
|
|
else if (length <= (std::size_t)(std::numeric_limits<int64_t>::max)())
|
|
{
|
|
sink_.push_back(ubjson_type::int64_type);
|
|
binary::native_to_big(static_cast<uint64_t>(length),std::back_inserter(sink_));
|
|
}
|
|
else
|
|
{
|
|
JSONCONS_THROW(ser_error(ubjson_errc::too_many_items));
|
|
}
|
|
}
|
|
|
|
bool visit_byte_string(const byte_string_view& b,
|
|
semantic_tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
|
|
const size_t length = b.size();
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::start_array_marker);
|
|
binary::native_to_big(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::type_marker), std::back_inserter(sink_));
|
|
binary::native_to_big(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::uint8_type), std::back_inserter(sink_));
|
|
put_length(length);
|
|
|
|
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(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::float32_type));
|
|
binary::native_to_big(valf,std::back_inserter(sink_));
|
|
}
|
|
else
|
|
{
|
|
// float 64
|
|
sink_.push_back(static_cast<uint8_t>(jsoncons::ubjson::ubjson_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,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
if (val >= 0)
|
|
{
|
|
if (val <= (std::numeric_limits<uint8_t>::max)())
|
|
{
|
|
// uint 8 stores a 8-bit unsigned integer
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::uint8_type);
|
|
binary::native_to_big(static_cast<uint8_t>(val),std::back_inserter(sink_));
|
|
}
|
|
else if (val <= (std::numeric_limits<int16_t>::max)())
|
|
{
|
|
// uint 16 stores a 16-bit big-endian unsigned integer
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::int16_type);
|
|
binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_));
|
|
}
|
|
else if (val <= (std::numeric_limits<int32_t>::max)())
|
|
{
|
|
// uint 32 stores a 32-bit big-endian unsigned integer
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::int32_type);
|
|
binary::native_to_big(static_cast<int32_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::ubjson::ubjson_type::int64_type);
|
|
binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_));
|
|
}
|
|
else
|
|
{
|
|
// big integer
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (val >= (std::numeric_limits<int8_t>::lowest)())
|
|
{
|
|
// int 8 stores a 8-bit signed integer
|
|
sink_.push_back(jsoncons::ubjson::ubjson_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::ubjson::ubjson_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::ubjson::ubjson_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::ubjson::ubjson_type::int64_type);
|
|
binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_));
|
|
}
|
|
}
|
|
end_value();
|
|
return true;
|
|
}
|
|
|
|
bool visit_uint64(uint64_t val,
|
|
semantic_tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
if (val <= (std::numeric_limits<uint8_t>::max)())
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::uint8_type);
|
|
binary::native_to_big(static_cast<uint8_t>(val),std::back_inserter(sink_));
|
|
}
|
|
else if (val <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::int16_type);
|
|
binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_));
|
|
}
|
|
else if (val <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::int32_type);
|
|
binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_));
|
|
}
|
|
else if (val <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
|
|
{
|
|
sink_.push_back(jsoncons::ubjson::ubjson_type::int64_type);
|
|
binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_));
|
|
}
|
|
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::ubjson::ubjson_type::true_type : jsoncons::ubjson::ubjson_type::false_type));
|
|
|
|
end_value();
|
|
return true;
|
|
}
|
|
|
|
void end_value()
|
|
{
|
|
if (!stack_.empty())
|
|
{
|
|
++stack_.back().count_;
|
|
}
|
|
}
|
|
};
|
|
|
|
using ubjson_stream_encoder = basic_ubjson_encoder<jsoncons::binary_stream_sink>;
|
|
using ubjson_bytes_encoder = basic_ubjson_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
|
|
|
|
#if !defined(JSONCONS_NO_DEPRECATED)
|
|
template<class Sink=jsoncons::binary_stream_sink>
|
|
using basic_ubjson_serializer = basic_ubjson_encoder<Sink>;
|
|
|
|
JSONCONS_DEPRECATED_MSG("Instead, use ubjson_stream_encoder") typedef ubjson_stream_encoder ubjson_encoder;
|
|
JSONCONS_DEPRECATED_MSG("Instead, use ubjson_stream_encoder") typedef ubjson_stream_encoder ubjson_serializer;
|
|
JSONCONS_DEPRECATED_MSG("Instead, use ubjson_bytes_encoder") typedef ubjson_bytes_encoder ubjson_buffer_serializer;
|
|
#endif
|
|
|
|
}}
|
|
#endif
|