build_exe.py compiles every unit in data/compile.json with the pinned toolchain and links Ragexe.exe. Not part of the decompilation and not in data/compile.json: imports/*.def (original DLL import tables), jsoncons/ (v0.170.2 headers + JsonCppLoader glue), nProtect/GameGuard.cpp (no-op GameGuard stand-in).
377 lines
15 KiB
C++
377 lines
15 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_JSONPATH_FLATTEN_HPP
|
|
#define JSONCONS_JSONPATH_FLATTEN_HPP
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <type_traits> // std::is_const
|
|
#include <limits> // std::numeric_limits
|
|
#include <utility> // std::move
|
|
#include <algorithm> // std::copy
|
|
#include <iterator> // std::back_inserter
|
|
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
|
|
#include <jsoncons_ext/jsonpath/jsonpath_utilities.hpp>
|
|
|
|
namespace jsoncons { namespace jsonpath {
|
|
|
|
template<class Json>
|
|
void flatten_(const typename Json::string_type& parent_key,
|
|
const Json& parent_value,
|
|
Json& result)
|
|
{
|
|
using char_type = typename Json::char_type;
|
|
using string_type = std::basic_string<char_type>;
|
|
|
|
switch (parent_value.type())
|
|
{
|
|
case json_type::array_value:
|
|
{
|
|
if (parent_value.empty())
|
|
{
|
|
result.try_emplace(parent_key, parent_value);
|
|
}
|
|
else
|
|
{
|
|
for (std::size_t i = 0; i < parent_value.size(); ++i)
|
|
{
|
|
string_type key(parent_key);
|
|
key.push_back('[');
|
|
jsoncons::detail::from_integer(i,key);
|
|
key.push_back(']');
|
|
flatten_(key, parent_value.at(i), result);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case json_type::object_value:
|
|
{
|
|
if (parent_value.empty())
|
|
{
|
|
result.try_emplace(parent_key, Json());
|
|
}
|
|
else
|
|
{
|
|
for (const auto& item : parent_value.object_range())
|
|
{
|
|
string_type key(parent_key);
|
|
key.push_back('[');
|
|
key.push_back('\'');
|
|
escape_string(item.key().data(), item.key().length(), key);
|
|
key.push_back('\'');
|
|
key.push_back(']');
|
|
flatten_(key, item.value(), result);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
result[parent_key] = parent_value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class Json>
|
|
Json flatten(const Json& value)
|
|
{
|
|
Json result;
|
|
typename Json::string_type parent_key = {'$'};
|
|
flatten_(parent_key, value, result);
|
|
return result;
|
|
}
|
|
|
|
enum class unflatten_state
|
|
{
|
|
start,
|
|
expect_lbracket,
|
|
lbracket,
|
|
single_quoted_name_state,
|
|
double_quoted_name_state,
|
|
index_state,
|
|
expect_rbracket,
|
|
double_quoted_string_escape_char,
|
|
single_quoted_string_escape_char
|
|
};
|
|
|
|
template<class Json>
|
|
Json unflatten(const Json& value)
|
|
{
|
|
using char_type = typename Json::char_type;
|
|
using string_type = std::basic_string<char_type>;
|
|
|
|
if (JSONCONS_UNLIKELY(!value.is_object()))
|
|
{
|
|
JSONCONS_THROW(jsonpath_error(jsonpath_errc::argument_to_unflatten_invalid));
|
|
}
|
|
|
|
Json result;
|
|
|
|
for (const auto& item : value.object_range())
|
|
{
|
|
Json* part = &result;
|
|
string_type buffer;
|
|
unflatten_state state = unflatten_state::start;
|
|
|
|
auto it = item.key().begin();
|
|
auto last = item.key().end();
|
|
|
|
for (; it != last; ++it)
|
|
{
|
|
switch (state)
|
|
{
|
|
case unflatten_state::start:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case '$':
|
|
state = unflatten_state::expect_lbracket;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case unflatten_state::expect_lbracket:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case '[':
|
|
state = unflatten_state::lbracket;
|
|
break;
|
|
default:
|
|
JSONCONS_THROW(jsonpath_error(jsonpath_errc::invalid_flattened_key));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case unflatten_state::lbracket:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case '\'':
|
|
state = unflatten_state::single_quoted_name_state;
|
|
break;
|
|
case '\"':
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
|
|
buffer.push_back(*it);
|
|
state = unflatten_state::index_state;
|
|
break;
|
|
default:
|
|
JSONCONS_THROW(jsonpath_error(jsonpath_errc::invalid_flattened_key));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case unflatten_state::single_quoted_name_state:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case '\'':
|
|
if (it != last-2)
|
|
{
|
|
auto res = part->try_emplace(buffer,Json());
|
|
part = &(res.first->value());
|
|
}
|
|
else
|
|
{
|
|
auto res = part->try_emplace(buffer,item.value());
|
|
part = &(res.first->value());
|
|
}
|
|
buffer.clear();
|
|
state = unflatten_state::expect_rbracket;
|
|
break;
|
|
case '\\':
|
|
state = unflatten_state::single_quoted_string_escape_char;
|
|
break;
|
|
default:
|
|
buffer.push_back(*it);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case unflatten_state::double_quoted_name_state:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case '\"':
|
|
if (it != last-2)
|
|
{
|
|
auto res = part->try_emplace(buffer,Json());
|
|
part = &(res.first->value());
|
|
}
|
|
else
|
|
{
|
|
auto res = part->try_emplace(buffer,item.value());
|
|
part = &(res.first->value());
|
|
}
|
|
buffer.clear();
|
|
state = unflatten_state::expect_rbracket;
|
|
break;
|
|
case '\\':
|
|
state = unflatten_state::double_quoted_string_escape_char;
|
|
break;
|
|
default:
|
|
buffer.push_back(*it);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case unflatten_state::double_quoted_string_escape_char:
|
|
switch (*it)
|
|
{
|
|
case '\"':
|
|
buffer.push_back('\"');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case '\\':
|
|
buffer.push_back('\\');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case '/':
|
|
buffer.push_back('/');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'b':
|
|
buffer.push_back('\b');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'f':
|
|
buffer.push_back('\f');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'n':
|
|
buffer.push_back('\n');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'r':
|
|
buffer.push_back('\r');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 't':
|
|
buffer.push_back('\t');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case unflatten_state::single_quoted_string_escape_char:
|
|
switch (*it)
|
|
{
|
|
case '\'':
|
|
buffer.push_back('\'');
|
|
state = unflatten_state::single_quoted_name_state;
|
|
break;
|
|
case '\\':
|
|
buffer.push_back('\\');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case '/':
|
|
buffer.push_back('/');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'b':
|
|
buffer.push_back('\b');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'f':
|
|
buffer.push_back('\f');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'n':
|
|
buffer.push_back('\n');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 'r':
|
|
buffer.push_back('\r');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
case 't':
|
|
buffer.push_back('\t');
|
|
state = unflatten_state::double_quoted_name_state;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case unflatten_state::index_state:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case ']':
|
|
{
|
|
std::size_t n{0};
|
|
auto r = jsoncons::detail::to_integer(buffer.data(), buffer.size(), n);
|
|
if (r)
|
|
{
|
|
if (!part->is_array())
|
|
{
|
|
*part = Json(json_array_arg, semantic_tag::none, value.get_allocator());
|
|
}
|
|
if (it != last-1)
|
|
{
|
|
if (n+1 > part->size())
|
|
{
|
|
Json& ref = part->emplace_back();
|
|
part = std::addressof(ref);
|
|
}
|
|
else
|
|
{
|
|
part = &part->at(n);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Json& ref = part->emplace_back(item.value());
|
|
part = std::addressof(ref);
|
|
}
|
|
}
|
|
buffer.clear();
|
|
state = unflatten_state::expect_lbracket;
|
|
break;
|
|
}
|
|
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
|
|
buffer.push_back(*it);
|
|
break;
|
|
default:
|
|
JSONCONS_THROW(jsonpath_error(jsonpath_errc::invalid_flattened_key));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case unflatten_state::expect_rbracket:
|
|
{
|
|
switch (*it)
|
|
{
|
|
case ']':
|
|
state = unflatten_state::expect_lbracket;
|
|
break;
|
|
default:
|
|
JSONCONS_THROW(jsonpath_error(jsonpath_errc::invalid_flattened_key));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
JSONCONS_UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}}
|
|
|
|
#endif
|