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.
410 lines
14 KiB
C++
410 lines
14 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_JSON_DECODER_HPP
|
|
#define JSONCONS_JSON_DECODER_HPP
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <type_traits> // std::true_type
|
|
#include <memory> // std::allocator
|
|
#include <iterator> // std::make_move_iterator
|
|
#include <utility> // std::move
|
|
#include <jsoncons/json_exception.hpp>
|
|
#include <jsoncons/json_visitor.hpp>
|
|
|
|
namespace jsoncons {
|
|
|
|
template <class Json,class TempAllocator=std::allocator<char>>
|
|
class json_decoder final : public basic_json_visitor<typename Json::char_type>
|
|
{
|
|
public:
|
|
using char_type = typename Json::char_type;
|
|
using typename basic_json_visitor<char_type>::string_view_type;
|
|
|
|
using key_value_type = typename Json::key_value_type;
|
|
using key_type = typename Json::key_type;
|
|
using array = typename Json::array;
|
|
using object = typename Json::object;
|
|
using result_allocator_type = typename Json::allocator_type;
|
|
using json_string_allocator = typename key_type::allocator_type;
|
|
using json_array_allocator = typename array::allocator_type;
|
|
using json_object_allocator = typename object::allocator_type;
|
|
typedef typename std::allocator_traits<result_allocator_type>:: template rebind_alloc<uint8_t> json_byte_allocator_type;
|
|
private:
|
|
|
|
enum class structure_type {root_t, array_t, object_t};
|
|
|
|
struct structure_info
|
|
{
|
|
structure_type type_;
|
|
std::size_t container_index_;
|
|
|
|
structure_info(structure_type type, std::size_t offset) noexcept
|
|
: type_(type), container_index_(offset)
|
|
{
|
|
}
|
|
|
|
};
|
|
|
|
using temp_allocator_type = TempAllocator;
|
|
typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<key_index_value<Json>> stack_item_allocator_type;
|
|
typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<structure_info> structure_info_allocator_type;
|
|
|
|
result_allocator_type result_allocator_;
|
|
temp_allocator_type temp_allocator_;
|
|
|
|
Json result_;
|
|
|
|
std::size_t index_;
|
|
key_type name_;
|
|
std::vector<key_index_value<Json>,stack_item_allocator_type> item_stack_;
|
|
std::vector<structure_info,structure_info_allocator_type> structure_stack_;
|
|
bool is_valid_;
|
|
|
|
public:
|
|
json_decoder(const temp_allocator_type& temp_alloc = temp_allocator_type())
|
|
: result_allocator_(result_allocator_type()),
|
|
temp_allocator_(temp_alloc),
|
|
result_(),
|
|
index_(0),
|
|
name_(result_allocator_),
|
|
item_stack_(temp_allocator_),
|
|
structure_stack_(temp_allocator_),
|
|
is_valid_(false)
|
|
{
|
|
item_stack_.reserve(1000);
|
|
structure_stack_.reserve(100);
|
|
structure_stack_.emplace_back(structure_type::root_t, 0);
|
|
}
|
|
|
|
json_decoder(result_allocator_arg_t,
|
|
const result_allocator_type& result_alloc)
|
|
: result_allocator_(result_alloc),
|
|
temp_allocator_(),
|
|
result_(),
|
|
index_(0),
|
|
name_(result_allocator_),
|
|
item_stack_(),
|
|
structure_stack_(),
|
|
is_valid_(false)
|
|
{
|
|
item_stack_.reserve(1000);
|
|
structure_stack_.reserve(100);
|
|
structure_stack_.emplace_back(structure_type::root_t, 0);
|
|
}
|
|
|
|
json_decoder(result_allocator_arg_t,
|
|
const result_allocator_type& result_alloc,
|
|
const temp_allocator_type& temp_alloc)
|
|
: result_allocator_(result_alloc),
|
|
temp_allocator_(temp_alloc),
|
|
result_(),
|
|
index_(0),
|
|
name_(result_allocator_),
|
|
item_stack_(temp_allocator_),
|
|
structure_stack_(temp_allocator_),
|
|
is_valid_(false)
|
|
{
|
|
item_stack_.reserve(1000);
|
|
structure_stack_.reserve(100);
|
|
structure_stack_.emplace_back(structure_type::root_t, 0);
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
is_valid_ = false;
|
|
index_ = 0;
|
|
item_stack_.clear();
|
|
structure_stack_.clear();
|
|
structure_stack_.emplace_back(structure_type::root_t, 0);
|
|
}
|
|
|
|
bool is_valid() const
|
|
{
|
|
return is_valid_;
|
|
}
|
|
|
|
Json get_result()
|
|
{
|
|
JSONCONS_ASSERT(is_valid_);
|
|
is_valid_ = false;
|
|
return std::move(result_);
|
|
}
|
|
|
|
#if !defined(JSONCONS_NO_DEPRECATED)
|
|
JSONCONS_DEPRECATED_MSG("Instead, use get_result()")
|
|
Json& root()
|
|
{
|
|
return result_;
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
|
|
void visit_flush() override
|
|
{
|
|
}
|
|
|
|
bool visit_begin_object(semantic_tag tag, const ser_context&, std::error_code&) override
|
|
{
|
|
if (structure_stack_.back().type_ == structure_type::root_t)
|
|
{
|
|
index_ = 0;
|
|
item_stack_.clear();
|
|
is_valid_ = false;
|
|
}
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, json_object_arg, tag, result_allocator_);
|
|
structure_stack_.emplace_back(structure_type::object_t, item_stack_.size()-1);
|
|
return true;
|
|
}
|
|
|
|
bool visit_end_object(const ser_context&, std::error_code&) override
|
|
{
|
|
JSONCONS_ASSERT(structure_stack_.size() > 0);
|
|
JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::object_t);
|
|
const size_t structure_index = structure_stack_.back().container_index_;
|
|
JSONCONS_ASSERT(item_stack_.size() > structure_index);
|
|
const size_t count = item_stack_.size() - (structure_index + 1);
|
|
auto first = item_stack_.begin() + (structure_index+1);
|
|
|
|
if (count > 0)
|
|
{
|
|
item_stack_[structure_index].value.object_value().init(&item_stack_[structure_index+1], count);
|
|
}
|
|
|
|
item_stack_.erase(first, item_stack_.end());
|
|
structure_stack_.pop_back();
|
|
if (structure_stack_.back().type_ == structure_type::root_t)
|
|
{
|
|
result_.swap(item_stack_.front().value);
|
|
item_stack_.pop_back();
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_begin_array(semantic_tag tag, const ser_context&, std::error_code&) override
|
|
{
|
|
if (structure_stack_.back().type_ == structure_type::root_t)
|
|
{
|
|
index_ = 0;
|
|
item_stack_.clear();
|
|
is_valid_ = false;
|
|
}
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, json_array_arg, tag, result_allocator_);
|
|
structure_stack_.emplace_back(structure_type::array_t, item_stack_.size()-1);
|
|
return true;
|
|
}
|
|
|
|
bool visit_end_array(const ser_context&, std::error_code&) override
|
|
{
|
|
JSONCONS_ASSERT(structure_stack_.size() > 1);
|
|
JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::array_t);
|
|
const size_t container_index = structure_stack_.back().container_index_;
|
|
JSONCONS_ASSERT(item_stack_.size() > container_index);
|
|
|
|
auto& container = item_stack_[container_index].value;
|
|
|
|
const size_t size = item_stack_.size() - (container_index + 1);
|
|
//std::cout << "size on item stack: " << size << "\n";
|
|
|
|
if (size > 0)
|
|
{
|
|
container.reserve(size);
|
|
auto first = item_stack_.begin() + (container_index+1);
|
|
auto last = first + size;
|
|
for (auto it = first; it != last; ++it)
|
|
{
|
|
container.push_back(std::move(it->value));
|
|
}
|
|
item_stack_.erase(first, item_stack_.end());
|
|
}
|
|
|
|
structure_stack_.pop_back();
|
|
if (structure_stack_.back().type_ == structure_type::root_t)
|
|
{
|
|
result_.swap(item_stack_.front().value);
|
|
item_stack_.pop_back();
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
|
|
{
|
|
name_ = key_type(name.data(),name.length(),result_allocator_);
|
|
return true;
|
|
}
|
|
|
|
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, sv, tag, result_allocator_);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(sv, tag, result_allocator_);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_byte_string(const byte_string_view& b,
|
|
semantic_tag tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, byte_string_arg, b, tag, result_allocator_);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(byte_string_arg, b, tag, result_allocator_);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_byte_string(const byte_string_view& b,
|
|
uint64_t ext_tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, byte_string_arg, b, ext_tag, result_allocator_);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(byte_string_arg, b, ext_tag, result_allocator_);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_int64(int64_t value,
|
|
semantic_tag tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(value,tag);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_uint64(uint64_t value,
|
|
semantic_tag tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(value,tag);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_half(uint16_t value,
|
|
semantic_tag tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, half_arg, value, tag);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(half_arg, value, tag);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_double(double value,
|
|
semantic_tag tag,
|
|
const ser_context&,
|
|
std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(value, tag);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_bool(bool value, semantic_tag tag, const ser_context&, std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(value, tag);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override
|
|
{
|
|
switch (structure_stack_.back().type_)
|
|
{
|
|
case structure_type::object_t:
|
|
case structure_type::array_t:
|
|
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, null_type(), tag);
|
|
break;
|
|
case structure_type::root_t:
|
|
result_ = Json(null_type(), tag);
|
|
is_valid_ = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // namespace jsoncons
|
|
|
|
#endif
|