mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Fix compile
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <data/format/formats.hpp>
|
||||
#include <data/format/clipboard.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/field/image.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/card.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
@@ -175,7 +176,7 @@ Image export_image(const SetP& set, const CardP& card, const bool write_metadata
|
||||
if (write_metadata) {
|
||||
String metadata = _("<mse-card-data>[");
|
||||
IndexMap<FieldP, ValueP>& card_data = card->data;
|
||||
boost::json::object& cardv = mse_to_json(card, set.get());
|
||||
boost::json::object cardv = mse_to_json(card, set.get());
|
||||
boost::json::object& cardv_data = cardv["data"].as_object();
|
||||
StyleSheetP stylesheet = set->stylesheetForP(card);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
|
||||
@@ -259,7 +260,7 @@ Image export_image( const SetP& set, const vector<CardP>& cards,
|
||||
if (i > 0) metadata += _(",");
|
||||
CardP card = cards[i];
|
||||
IndexMap<FieldP, ValueP>& card_data = card->data;
|
||||
boost::json::object& cardv = mse_to_json(card, set.get());
|
||||
boost::json::object cardv = mse_to_json(card, set.get());
|
||||
boost::json::object& cardv_data = cardv["data"].as_object();
|
||||
StyleSheetP stylesheet = set->stylesheetForP(card);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
|
||||
|
||||
@@ -205,7 +205,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
|
||||
}
|
||||
// get the new script values
|
||||
vector<shared_ptr<Action>> actions;
|
||||
String& field_name = field_type->GetString(field_type->GetSelection());
|
||||
String field_name = field_type->GetString(field_type->GetSelection());
|
||||
// stylesheet, notes or id change
|
||||
if (field_name == _("stylesheet") || field_name == _("notes") || field_name == _("id")) {
|
||||
vector<String> new_values;
|
||||
|
||||
@@ -296,7 +296,8 @@ bool CardListBase::parseFiles(wxArrayString& filenames, vector<CardP>& out) {
|
||||
bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
|
||||
size_t j = out.size();
|
||||
if (image.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
||||
parseText(image.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), out);
|
||||
auto text = image.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION);
|
||||
parseText(text, out);
|
||||
// crop image rects to populate image fields
|
||||
for (; j < out.size(); j++) {
|
||||
CardP& card = out[j];
|
||||
@@ -307,7 +308,7 @@ bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
|
||||
int degrees = 0;
|
||||
value->filename.getExternalRect(rect, degrees);
|
||||
if (rect.width > 0 && rect.height > 0) {
|
||||
Image& img = image.GetSubImage(rect);
|
||||
Image img = image.GetSubImage(rect);
|
||||
img = rotate_image(img, deg_to_rad(360-degrees));
|
||||
LocalFileName filename = set->newFileName((*it)->fieldP->name, settings.internal_image_extension ? _(".png") : _("")); // a new unique name in the package
|
||||
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG);
|
||||
@@ -326,7 +327,7 @@ bool CardListBase::parseText(String& text, vector<CardP>& out) {
|
||||
text = text.substr(pos + 14, text.find("</mse-card-data>") - pos - 14);
|
||||
}
|
||||
try {
|
||||
ScriptValueP& sv = json_to_mse(text, set.get());
|
||||
ScriptValueP sv = json_to_mse(text, set.get());
|
||||
if (sv->type() == SCRIPT_COLLECTION) {
|
||||
if (ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get())) {
|
||||
for (size_t i = 0; i < custom->value.size(); i++) {
|
||||
|
||||
@@ -42,8 +42,11 @@ private:
|
||||
|| t == wxEVT_LEFT_DOWN || t == wxEVT_RIGHT_DOWN
|
||||
|| t == wxEVT_MOVE
|
||||
|| t == wxEVT_MENU_HIGHLIGHT || t == wxEVT_MENU_OPEN
|
||||
|| t == wxEVT_CLOSE_WINDOW || t == wxEVT_KILL_FOCUS
|
||||
|| t == wxEVT_CLOSE_WINDOW
|
||||
#if defined(_WIN32)
|
||||
|| t == wxEVT_KILL_FOCUS
|
||||
//|| t == wxEVT_ACTIVATE
|
||||
#endif
|
||||
|| t == wxEVT_COMMAND_TOOL_CLICKED)
|
||||
{
|
||||
// close the list, and pass on the event
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <script/functions/json.hpp>
|
||||
|
||||
#include <util/delayed_index_maps.hpp>
|
||||
#include <util/prec.hpp>
|
||||
#include <data/card.hpp>
|
||||
#include <data/format/clipboard.hpp>
|
||||
#include <script/functions/construction_helper.hpp>
|
||||
#include <sstream>
|
||||
#include <wx/sstream.h>
|
||||
|
||||
|
||||
// All this isn't great, but it will do for now. Idealy you would create JsonWriter and JsonReader classes
|
||||
// that inherit from Writer and Reader, and just have a switch to go from normal mode to JSON mode...
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : JSON to String
|
||||
|
||||
void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* indent)
|
||||
{
|
||||
std::string indent_;
|
||||
if(! indent)
|
||||
indent = &indent_;
|
||||
switch(jv.kind())
|
||||
{
|
||||
case boost::json::kind::object:
|
||||
{
|
||||
os << "{\n";
|
||||
indent->append(4, ' ');
|
||||
auto const& obj = jv.get_object();
|
||||
if(! obj.empty())
|
||||
{
|
||||
auto it = obj.begin();
|
||||
for(;;)
|
||||
{
|
||||
os << *indent << boost::json::serialize(it->key()) << " : ";
|
||||
pretty_print(os, it->value(), indent);
|
||||
if(++it == obj.end())
|
||||
break;
|
||||
os << ",\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
indent->resize(indent->size() - 4);
|
||||
os << *indent << "}";
|
||||
break;
|
||||
}
|
||||
|
||||
case boost::json::kind::array:
|
||||
{
|
||||
os << "[\n";
|
||||
indent->append(4, ' ');
|
||||
auto const& arr = jv.get_array();
|
||||
if(! arr.empty())
|
||||
{
|
||||
auto it = arr.begin();
|
||||
for(;;)
|
||||
{
|
||||
os << *indent;
|
||||
pretty_print( os, *it, indent);
|
||||
if(++it == arr.end())
|
||||
break;
|
||||
os << ",\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
indent->resize(indent->size() - 4);
|
||||
os << *indent << "]";
|
||||
break;
|
||||
}
|
||||
|
||||
case boost::json::kind::string:
|
||||
{
|
||||
os << boost::json::serialize(jv.get_string());
|
||||
break;
|
||||
}
|
||||
|
||||
case boost::json::kind::uint64:
|
||||
case boost::json::kind::int64:
|
||||
case boost::json::kind::double_:
|
||||
os << jv;
|
||||
break;
|
||||
|
||||
case boost::json::kind::bool_:
|
||||
if(jv.get_bool())
|
||||
os << "true";
|
||||
else
|
||||
os << "false";
|
||||
break;
|
||||
|
||||
case boost::json::kind::null:
|
||||
os << "null";
|
||||
break;
|
||||
}
|
||||
|
||||
if(indent->empty())
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
String json_pretty_print(const boost::json::value& jv, std::string* indent) {
|
||||
std::ostringstream stream;
|
||||
pretty_print(stream, jv, indent);
|
||||
String string = wxString(stream.str().c_str());
|
||||
return string;
|
||||
}
|
||||
|
||||
String json_ugly_print(const boost::json::value& jv) {
|
||||
String string = wxString(boost::json::serialize(jv).c_str());
|
||||
return string;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : JSON to MSE
|
||||
|
||||
ScriptValueP json_to_mse(const boost::json::value& jv, Set* set);
|
||||
|
||||
template <typename T>
|
||||
void read(T& out, boost::json::object& jv, const char value_name[]) {
|
||||
if (!jv.contains(value_name)) return;
|
||||
else {
|
||||
wxStringInputStream stream = {_("")};
|
||||
Reader reader(stream, nullptr, _(""));
|
||||
reader.setValue(wxString(jv[value_name].as_string().c_str()));
|
||||
reader.handle(out);
|
||||
}
|
||||
}
|
||||
|
||||
// templates don't work with enums? are you kidding me with this language?
|
||||
void read(PackSelectType& out, boost::json::object& jv, const char value_name[]) {
|
||||
if (!jv.contains(value_name)) return;
|
||||
else {
|
||||
wxStringInputStream stream = {_("")};
|
||||
Reader reader(stream, nullptr, _(""));
|
||||
reader.setValue(wxString(jv[value_name].as_string().c_str()));
|
||||
reader.handle(out);
|
||||
}
|
||||
}
|
||||
|
||||
PackItemP json_to_mse_pack_item(boost::json::object& jv) {
|
||||
PackItemP pack_item = make_intrusive<PackItem>();
|
||||
read(pack_item->name, jv, "name");
|
||||
read(pack_item->amount, jv, "amount");
|
||||
read(pack_item->weight, jv, "weight");
|
||||
return pack_item;
|
||||
}
|
||||
|
||||
PackTypeP json_to_mse_pack_type(boost::json::object& jv) {
|
||||
PackTypeP pack_type = make_intrusive<PackType>();
|
||||
read(pack_type->name, jv, "name");
|
||||
read(pack_type->enabled, jv, "enabled");
|
||||
read(pack_type->selectable, jv, "selectable");
|
||||
read(pack_type->summary, jv, "summary");
|
||||
read(pack_type->select, jv, "select");
|
||||
if (jv.contains("items") && jv["items"].is_array()) {
|
||||
boost::json::array pack_itemsv = jv["items"].as_array();
|
||||
for (int i = 0; i < pack_itemsv.size(); i++) {
|
||||
boost::json::object pack_itemv = pack_itemsv[i].as_object();
|
||||
pack_type->items.emplace_back(json_to_mse_pack_item(pack_itemv));
|
||||
}
|
||||
}
|
||||
return pack_type;
|
||||
}
|
||||
|
||||
KeywordP json_to_mse_keyword(boost::json::object& jv) {
|
||||
KeywordP keyword = make_intrusive<Keyword>();
|
||||
read(keyword->keyword, jv, "keyword");
|
||||
read(keyword->match, jv, "match");
|
||||
read(keyword->reminder, jv, "reminder");
|
||||
read(keyword->rules, jv, "rules");
|
||||
read(keyword->mode, jv, "mode");
|
||||
return keyword;
|
||||
}
|
||||
|
||||
CardP json_to_mse_card(boost::json::object& jv, Set* set) {
|
||||
CardP card = make_intrusive<Card>(*set->game);
|
||||
read(card->time_created, jv, "time_created");
|
||||
read(card->time_modified, jv, "time_modified");
|
||||
read(card->notes, jv, "notes");
|
||||
read(card->uid, jv, "uid");
|
||||
read(card->linked_card_1, jv, "linked_card_1");
|
||||
read(card->linked_card_2, jv, "linked_card_2");
|
||||
read(card->linked_card_3, jv, "linked_card_3");
|
||||
read(card->linked_card_4, jv, "linked_card_4");
|
||||
read(card->linked_relation_1, jv, "linked_relation_1");
|
||||
read(card->linked_relation_2, jv, "linked_relation_2");
|
||||
read(card->linked_relation_3, jv, "linked_relation_3");
|
||||
read(card->linked_relation_4, jv, "linked_relation_4");
|
||||
// card fields
|
||||
if (jv.contains("data") && jv["data"].is_object()) {
|
||||
boost::json::object datav = jv["data"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
String key_name = wxString(it->key_c_str());
|
||||
Value* container = get_card_field_container(*set->game, card->data, key_name, false);
|
||||
ScriptValueP value = json_to_mse(it->value(), set);
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
// stylesheet
|
||||
if (jv.contains("stylesheet")) card->stylesheet = StyleSheet::byGameAndName(*set->game, wxString(jv["stylesheet"].as_string().c_str()));
|
||||
if (card->stylesheet) {
|
||||
// styling fields
|
||||
card->styling_data.init(card->stylesheet->styling_fields);
|
||||
if (jv.contains("styling_data") && jv["styling_data"].is_object()) {
|
||||
boost::json::object datav = jv["styling_data"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
String key_name = wxString(it->key_c_str());
|
||||
Value* container = get_container(card->styling_data, wxString("styling"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(it->value(), set);
|
||||
set_container(container, value, key_name);
|
||||
card->has_styling = true;
|
||||
}
|
||||
}
|
||||
// extra card fields
|
||||
if (jv.contains("extra_data") && jv["extra_data"].is_object()) {
|
||||
boost::json::object datav = jv["extra_data"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str());
|
||||
if (!stylesheet) continue;
|
||||
IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet);
|
||||
boost::json::object stylesheet_datav = it->value().as_object();
|
||||
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
|
||||
String key_name = wxString(stylesheet_it->key_c_str());
|
||||
Value* container = get_container(stylesheet_data, wxString("extra card"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(stylesheet_it->value(), set);
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return card;
|
||||
}
|
||||
|
||||
SetP json_to_mse_set(boost::json::object& jv) {
|
||||
if (!jv.contains("game")) {
|
||||
throw ScriptError(_ERROR_("json set without game"));
|
||||
}
|
||||
if (!jv.contains("stylesheet")) {
|
||||
throw ScriptError(_ERROR_("json set without stylesheet"));
|
||||
}
|
||||
GameP game = Game::byName(wxString(jv["game"].as_string().c_str()));
|
||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*game, wxString(jv["stylesheet"].as_string().c_str()));
|
||||
SetP set = make_intrusive<Set>(stylesheet);
|
||||
// set fields
|
||||
if (jv.contains("set_info") && jv["set_info"].is_object()) {
|
||||
boost::json::object datav = jv["set_info"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
String key_name = wxString(it->key_c_str());
|
||||
Value* container = get_container(set->data, wxString("set"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(it->value(), set.get());
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
// styling
|
||||
if (jv.contains("styling") && jv["styling"].is_object()) {
|
||||
boost::json::object datav = jv["styling"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str());
|
||||
if (!stylesheet) continue;
|
||||
IndexMap<FieldP, ValueP>& stylesheet_data = set->stylingDataFor(*stylesheet);
|
||||
boost::json::object stylesheet_datav = it->value().as_object();
|
||||
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
|
||||
String key_name = wxString(stylesheet_it->key_c_str());
|
||||
Value* container = get_container(stylesheet_data, wxString("styling"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(stylesheet_it->value(), set.get());
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// cards
|
||||
if (jv.contains("cards") && jv["cards"].is_array()) {
|
||||
boost::json::array cardsv = jv["cards"].as_array();
|
||||
for (int i = 0; i < cardsv.size(); i++) {
|
||||
boost::json::object cardv = cardsv[i].as_object();
|
||||
set->cards.emplace_back(json_to_mse_card(cardv, set.get()));
|
||||
}
|
||||
}
|
||||
// keywords
|
||||
if (jv.contains("keywords") && jv["keywords"].is_array()) {
|
||||
boost::json::array keywordsv = jv["keywords"].as_array();
|
||||
for (int i = 0; i < keywordsv.size(); i++) {
|
||||
boost::json::object keywordv = keywordsv[i].as_object();
|
||||
set->keywords.emplace_back(json_to_mse_keyword(keywordv));
|
||||
}
|
||||
}
|
||||
// pack types
|
||||
if (jv.contains("pack_types") && jv["pack_types"].is_array()) {
|
||||
boost::json::array pack_typesv = jv["pack_types"].as_array();
|
||||
for (int i = 0; i < pack_typesv.size(); i++) {
|
||||
boost::json::object pack_typev = pack_typesv[i].as_object();
|
||||
set->pack_types.emplace_back(json_to_mse_pack_type(pack_typev));
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
ScriptValueP json_to_mse(const boost::json::value& jv, Set* set) {
|
||||
if (jv == nullptr) return script_nil;
|
||||
else if (jv.is_null()) return script_nil;
|
||||
else if (jv.is_bool()) return to_script(jv.get_bool());
|
||||
else if (jv.is_double()) return to_script(jv.get_double());
|
||||
else if (jv.is_int64()) {
|
||||
int integer = jv.get_int64();
|
||||
return to_script(integer);
|
||||
}
|
||||
else if (jv.is_uint64()) {
|
||||
int integer = jv.get_uint64();
|
||||
return to_script(integer);
|
||||
}
|
||||
else if (jv.is_string()) {
|
||||
std::string string = boost::json::value_to<std::string>(jv);
|
||||
return to_script(String(string.c_str()));
|
||||
}
|
||||
else if (jv.is_array()) {
|
||||
boost::json::array array = jv.get_array();
|
||||
ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>();
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
boost::json::value jvalue = array[i];
|
||||
ScriptValueP value = json_to_mse(jvalue, set);
|
||||
result->value.push_back(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (jv.is_object()) {
|
||||
boost::json::object object = jv.get_object();
|
||||
if (object.contains("mse_object_type")) {
|
||||
boost::json::string mse_object_type = object["mse_object_type"].as_string();
|
||||
if (mse_object_type == "set") return make_intrusive<ScriptObject<SetP>> (json_to_mse_set(object));
|
||||
if (mse_object_type == "card") return make_intrusive<ScriptObject<CardP>> (json_to_mse_card(object, set));
|
||||
if (mse_object_type == "keyword") return make_intrusive<ScriptObject<KeywordP>> (json_to_mse_keyword(object));
|
||||
if (mse_object_type == "pack_type") return make_intrusive<ScriptObject<PackTypeP>>(json_to_mse_pack_type(object));
|
||||
if (mse_object_type == "pack_item") return make_intrusive<ScriptObject<PackItemP>>(json_to_mse_pack_item(object));
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json unknown type") + _("(") + wxString(mse_object_type.c_str()) + _(")"));
|
||||
return script_nil;
|
||||
}
|
||||
ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>();
|
||||
for (auto it = object.begin(); it != object.end(); ++it) {
|
||||
boost::json::string_view jview = it->key();
|
||||
std::string_view stdview = std::string_view(jview.data(), jview.size());
|
||||
std::string stdstring = { stdview.begin(), stdview.end() };
|
||||
String key(stdstring.c_str(), wxConvUTF8);
|
||||
boost::json::value jvalue = it->value();
|
||||
ScriptValueP value = json_to_mse(jvalue, set);
|
||||
result->key_value[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json unknown type"));
|
||||
return script_nil;
|
||||
}
|
||||
}
|
||||
ScriptValueP json_to_mse(const String& string, Set* set) {
|
||||
try {
|
||||
boost::system::error_code ec;
|
||||
boost::json::parse_options options;
|
||||
options.allow_invalid_utf8 = true;
|
||||
boost::json::value jv = boost::json::parse(string.ToStdString(), ec, {}, options);
|
||||
//if(ec) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
|
||||
if(ec) return script_nil;
|
||||
return json_to_mse(jv, set);
|
||||
}
|
||||
catch (...) {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant parse"));
|
||||
return script_nil;
|
||||
}
|
||||
}
|
||||
ScriptValueP json_to_mse(const ScriptValueP& sv, Set* set) {
|
||||
try {
|
||||
String string = sv->toString();
|
||||
return json_to_mse(string, set);
|
||||
}
|
||||
catch (...) {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant convert"));
|
||||
return script_nil;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : MSE to JSON
|
||||
|
||||
template <typename T>
|
||||
void write(boost::json::object& out, const String& name, const T& value) {
|
||||
wxStringOutputStream stream;
|
||||
Writer writer(stream);
|
||||
writer.indentation = -1000;
|
||||
writer.handle(name, value);
|
||||
String string = stream.GetString();
|
||||
if (!string.empty()) {
|
||||
if (string.StartsWith(name + ":")) string = string.substr(name.length() + 1).Trim(false);
|
||||
if (string.EndsWith("\n")) string = string.substr(0, string.length() - 1);
|
||||
out.emplace(name.ToStdString(), string);
|
||||
}
|
||||
}
|
||||
|
||||
void write(boost::json::object& out, const String& name, IndexMap<FieldP, ValueP>& map) {
|
||||
boost::json::object indexmapv;
|
||||
for (IndexMap<FieldP, ValueP>::iterator it = map.begin(); it != map.end(); ++it) {
|
||||
write(indexmapv, (*it)->fieldP->name, *it);
|
||||
}
|
||||
if (!indexmapv.empty()) out.emplace(name.ToStdString(), indexmapv);
|
||||
}
|
||||
|
||||
void write(boost::json::object& out, const String& name, DelayedIndexMaps<FieldP,ValueP>& map) {
|
||||
boost::json::object delayedindexmapv;
|
||||
for (auto it = map.data.begin() ; it != map.data.end() ; ++it) {
|
||||
write(delayedindexmapv, it->first, it->second->read_data);
|
||||
}
|
||||
if (!delayedindexmapv.empty()) out.emplace(name.ToStdString(), delayedindexmapv);
|
||||
}
|
||||
|
||||
boost::json::object mse_to_json(const PackItemP& item) {
|
||||
boost::json::object itemv;
|
||||
itemv.emplace("mse_object_type", "pack_item");
|
||||
write(itemv, "name", item->name);
|
||||
write(itemv, "amount", item->amount);
|
||||
write(itemv, "weight", item->weight);
|
||||
return itemv;
|
||||
}
|
||||
|
||||
boost::json::object mse_to_json(const PackTypeP& pack) {
|
||||
boost::json::object packv;
|
||||
packv.emplace("mse_object_type", "pack_type");
|
||||
write(packv, "name", pack->name);
|
||||
write(packv, "enabled", pack->enabled);
|
||||
write(packv, "selectable", pack->selectable);
|
||||
write(packv, "summary", pack->summary);
|
||||
write(packv, "select", pack->select);
|
||||
write(packv, "filter", pack->filter);
|
||||
boost::json::array itemsv;
|
||||
for (auto item : pack->items) {
|
||||
itemsv.emplace_back(mse_to_json(item));
|
||||
}
|
||||
packv.emplace("items", itemsv);
|
||||
return packv;
|
||||
}
|
||||
|
||||
boost::json::object mse_to_json(const KeywordP& keyword) {
|
||||
boost::json::object keywordv;
|
||||
keywordv.emplace("mse_object_type", "keyword");
|
||||
write(keywordv, "keyword", keyword->keyword);
|
||||
write(keywordv, "match", keyword->match);
|
||||
write(keywordv, "reminder", keyword->reminder);
|
||||
write(keywordv, "rules", keyword->rules);
|
||||
write(keywordv, "mode", keyword->mode);
|
||||
return keywordv;
|
||||
}
|
||||
|
||||
boost::json::object mse_to_json(const CardP& card, const Set* set) {
|
||||
boost::json::object cardv;
|
||||
cardv.emplace("mse_object_type", "card");
|
||||
// built-in values
|
||||
write(cardv, "time_created", card->time_created);
|
||||
write(cardv, "time_modified", card->time_modified);
|
||||
write(cardv, "notes", card->notes);
|
||||
write(cardv, "uid", card->uid);
|
||||
write(cardv, "linked_card_1", card->linked_card_1);
|
||||
write(cardv, "linked_card_2", card->linked_card_2);
|
||||
write(cardv, "linked_card_3", card->linked_card_3);
|
||||
write(cardv, "linked_card_4", card->linked_card_4);
|
||||
write(cardv, "linked_relation_1", card->linked_relation_1);
|
||||
write(cardv, "linked_relation_2", card->linked_relation_2);
|
||||
write(cardv, "linked_relation_3", card->linked_relation_3);
|
||||
write(cardv, "linked_relation_4", card->linked_relation_4);
|
||||
// card fields
|
||||
write(cardv, "data", card->data);
|
||||
// stylesheet
|
||||
bool change_stylesheet = set && !card->stylesheet;
|
||||
if (change_stylesheet) {
|
||||
card->stylesheet = set->stylesheet;
|
||||
}
|
||||
if (card->stylesheet) {
|
||||
write(cardv, "stylesheet", card->stylesheet);
|
||||
write(cardv, "stylesheet_version", card->stylesheet->version);
|
||||
// extra card fields
|
||||
write(cardv, "extra_data", card->extra_data);
|
||||
}
|
||||
// style
|
||||
write(cardv, "has_styling", card->has_styling);
|
||||
if (card->has_styling) {
|
||||
write(cardv, "styling_data", card->styling_data);
|
||||
}
|
||||
// restore stylesheet
|
||||
if (change_stylesheet) {
|
||||
card->stylesheet = StyleSheetP();
|
||||
}
|
||||
// done
|
||||
return cardv;
|
||||
}
|
||||
|
||||
boost::json::object mse_to_json(const Set* set) {
|
||||
boost::json::object setv;
|
||||
setv.emplace("mse_object_type", "set");
|
||||
// built-in values
|
||||
write(setv, "mse_version", set->fileVersion());
|
||||
write(setv, "game", set->game);
|
||||
write(setv, "game_version", set->game->version);
|
||||
write(setv, "stylesheet", set->stylesheet);
|
||||
write(setv, "stylesheet_version", set->stylesheet->version);
|
||||
// set fields
|
||||
write(setv, "set_info", set->data);
|
||||
// styling
|
||||
write(setv, "styling", set->styling_data);
|
||||
// cards
|
||||
boost::json::array cardsv;
|
||||
for (const CardP& card : set->cards) {
|
||||
cardsv.emplace_back(mse_to_json(card, set));
|
||||
}
|
||||
setv.emplace("cards", cardsv);
|
||||
// keywords
|
||||
boost::json::array keywordsv;
|
||||
for (const KeywordP& keyword : set->keywords) {
|
||||
keywordsv.emplace_back(mse_to_json(keyword));
|
||||
}
|
||||
if (!keywordsv.empty()) setv.emplace("keywords", keywordsv);
|
||||
// pack types
|
||||
boost::json::array pack_typesv;
|
||||
for (const PackTypeP& pack_type : set->pack_types) {
|
||||
pack_typesv.emplace_back(mse_to_json(pack_type));
|
||||
}
|
||||
if (!pack_typesv.empty()) setv.emplace("pack_types", pack_typesv);
|
||||
// done
|
||||
return setv;
|
||||
}
|
||||
|
||||
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set) {
|
||||
ScriptType type = sv->type();
|
||||
// special types
|
||||
if (ScriptObject<PackItemP>* i = dynamic_cast<ScriptObject<PackItemP>*>(sv.get())) return mse_to_json(i->getValue());
|
||||
if (ScriptObject<PackTypeP>* t = dynamic_cast<ScriptObject<PackTypeP>*>(sv.get())) return mse_to_json(t->getValue());
|
||||
if (ScriptObject<KeywordP>* k = dynamic_cast<ScriptObject<KeywordP>*> (sv.get())) return mse_to_json(k->getValue());
|
||||
if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*> (sv.get())) return mse_to_json(c->getValue(), set);
|
||||
if (ScriptObject<SetP>* z = dynamic_cast<ScriptObject<SetP>*> (sv.get())) return mse_to_json(z->getValue().get());
|
||||
if (ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>*> (sv.get())) return mse_to_json(s->getValue());
|
||||
|
||||
// primitive types
|
||||
if (type == SCRIPT_NIL) return boost::json::value(nullptr);
|
||||
if (type == SCRIPT_INT) return boost::json::value(sv->toInt());
|
||||
if (type == SCRIPT_DOUBLE) return boost::json::value(sv->toDouble());
|
||||
if (type == SCRIPT_BOOL) return boost::json::value(sv->toBool());
|
||||
if (type == SCRIPT_STRING) return boost::json::value(sv->toString());
|
||||
if (type == SCRIPT_REGEX) return boost::json::value(sv->toString());
|
||||
if (type == SCRIPT_COLOR) return boost::json::value(format_color(sv->toColor()));
|
||||
if (type == SCRIPT_DATETIME) return boost::json::value(sv->toDateTime().FormatISOCombined(' '));
|
||||
if (type == SCRIPT_COLLECTION) {
|
||||
ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get());
|
||||
if (custom) {
|
||||
if (custom->value.size() > 0) {
|
||||
boost::json::array array;
|
||||
for (int i = 0; i < custom->value.size(); i++) {
|
||||
array.emplace_back(mse_to_json(custom->value[i], set));
|
||||
}
|
||||
return array;
|
||||
} else if (custom->key_value.size() > 0) {
|
||||
boost::json::object object;
|
||||
map<String, ScriptValueP>::iterator it;
|
||||
for (it = custom->key_value.begin(); it != custom->key_value.end(); it++) {
|
||||
object.emplace(it->first.ToStdString(), mse_to_json(it->second, set));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
} else {
|
||||
ScriptConcatCollection* concat = dynamic_cast<ScriptConcatCollection*>(sv.get());
|
||||
if (concat) {
|
||||
boost::json::value a = mse_to_json(concat->getA(), set);
|
||||
boost::json::value b = mse_to_json(concat->getB(), set);
|
||||
if (a.is_array() && b.is_array()) {
|
||||
boost::json::array array_a = a.get_array();
|
||||
boost::json::array array_b = b.get_array();
|
||||
for (int i = 0; i < array_b.size(); i++) {
|
||||
array_a.emplace_back(array_b[i]);
|
||||
}
|
||||
return array_a;
|
||||
} else if (a.is_object() && b.is_object()) {
|
||||
boost::json::object object_a = a.get_object();
|
||||
boost::json::object object_b = b.get_object();
|
||||
for (auto it = object_b.begin(); it != object_b.end(); ++it) {
|
||||
object_a.emplace(it->key(), it->value());
|
||||
}
|
||||
return object_a;
|
||||
} else {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant concat"));
|
||||
return boost::json::value(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
queue_message(MESSAGE_ERROR, _ERROR_1_("json unknown script type", sv->typeName()));
|
||||
return boost::json::value(nullptr);
|
||||
}
|
||||
+25
-550
@@ -8,16 +8,9 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/card.hpp>
|
||||
#include <data/pack.hpp>
|
||||
#include <data/format/clipboard.hpp>
|
||||
#include <script/functions/construction_helper.hpp>
|
||||
#include <boost/json.hpp>
|
||||
#include <sstream>
|
||||
#include <wx/sstream.h>
|
||||
|
||||
#include <data/set.hpp>
|
||||
#include <data/pack.hpp>
|
||||
|
||||
// All this isn't great, but it will do for now. Idealy you would create JsonWriter and JsonReader classes
|
||||
// that inherit from Writer and Reader, and just have a switch to go from normal mode to JSON mode...
|
||||
@@ -25,572 +18,54 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : JSON to String
|
||||
|
||||
inline static void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* indent = nullptr)
|
||||
{
|
||||
std::string indent_;
|
||||
if(! indent)
|
||||
indent = &indent_;
|
||||
switch(jv.kind())
|
||||
{
|
||||
case boost::json::kind::object:
|
||||
{
|
||||
os << "{\n";
|
||||
indent->append(4, ' ');
|
||||
auto const& obj = jv.get_object();
|
||||
if(! obj.empty())
|
||||
{
|
||||
auto it = obj.begin();
|
||||
for(;;)
|
||||
{
|
||||
os << *indent << boost::json::serialize(it->key()) << " : ";
|
||||
pretty_print(os, it->value(), indent);
|
||||
if(++it == obj.end())
|
||||
break;
|
||||
os << ",\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
indent->resize(indent->size() - 4);
|
||||
os << *indent << "}";
|
||||
break;
|
||||
}
|
||||
void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* indent = nullptr);
|
||||
|
||||
case boost::json::kind::array:
|
||||
{
|
||||
os << "[\n";
|
||||
indent->append(4, ' ');
|
||||
auto const& arr = jv.get_array();
|
||||
if(! arr.empty())
|
||||
{
|
||||
auto it = arr.begin();
|
||||
for(;;)
|
||||
{
|
||||
os << *indent;
|
||||
pretty_print( os, *it, indent);
|
||||
if(++it == arr.end())
|
||||
break;
|
||||
os << ",\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
indent->resize(indent->size() - 4);
|
||||
os << *indent << "]";
|
||||
break;
|
||||
}
|
||||
|
||||
case boost::json::kind::string:
|
||||
{
|
||||
os << boost::json::serialize(jv.get_string());
|
||||
break;
|
||||
}
|
||||
String json_pretty_print(const boost::json::value& jv, std::string* indent = nullptr);
|
||||
|
||||
case boost::json::kind::uint64:
|
||||
case boost::json::kind::int64:
|
||||
case boost::json::kind::double_:
|
||||
os << jv;
|
||||
break;
|
||||
|
||||
case boost::json::kind::bool_:
|
||||
if(jv.get_bool())
|
||||
os << "true";
|
||||
else
|
||||
os << "false";
|
||||
break;
|
||||
|
||||
case boost::json::kind::null:
|
||||
os << "null";
|
||||
break;
|
||||
}
|
||||
|
||||
if(indent->empty())
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
inline static String json_pretty_print(const boost::json::value& jv, std::string* indent = nullptr) {
|
||||
std::ostringstream stream;
|
||||
pretty_print(stream, jv, indent);
|
||||
String string = wxString(stream.str().c_str());
|
||||
return string;
|
||||
}
|
||||
|
||||
inline static String json_ugly_print(const boost::json::value& jv) {
|
||||
String string = wxString(boost::json::serialize(jv).c_str());
|
||||
return string;
|
||||
}
|
||||
String json_ugly_print(const boost::json::value& jv);
|
||||
|
||||
// ----------------------------------------------------------------------------- : JSON to MSE
|
||||
|
||||
inline static ScriptValueP json_to_mse(const boost::json::value& jv, Set* set);
|
||||
ScriptValueP json_to_mse(const boost::json::value& jv, Set* set);
|
||||
|
||||
template <typename T>
|
||||
static void read(T& out, boost::json::object& jv, const char value_name[]) {
|
||||
if (!jv.contains(value_name)) return;
|
||||
else {
|
||||
wxStringInputStream stream = {_("")};
|
||||
Reader reader(stream, nullptr, _(""));
|
||||
reader.setValue(wxString(jv[value_name].as_string().c_str()));
|
||||
reader.handle(out);
|
||||
}
|
||||
}
|
||||
void read(T& out, boost::json::object& jv, const char value_name[]);
|
||||
|
||||
// templates don't work with enums? are you kidding me with this language?
|
||||
static void read(PackSelectType& out, boost::json::object& jv, const char value_name[]) {
|
||||
if (!jv.contains(value_name)) return;
|
||||
else {
|
||||
wxStringInputStream stream = {_("")};
|
||||
Reader reader(stream, nullptr, _(""));
|
||||
reader.setValue(wxString(jv[value_name].as_string().c_str()));
|
||||
reader.handle(out);
|
||||
}
|
||||
}
|
||||
void read(PackSelectType& out, boost::json::object& jv, const char value_name[]);
|
||||
|
||||
inline static PackItemP json_to_mse_pack_item(boost::json::object& jv) {
|
||||
PackItemP pack_item = make_intrusive<PackItem>();
|
||||
read(pack_item->name, jv, "name");
|
||||
read(pack_item->amount, jv, "amount");
|
||||
read(pack_item->weight, jv, "weight");
|
||||
return pack_item;
|
||||
}
|
||||
PackItemP json_to_mse_pack_item(boost::json::object& jv);
|
||||
|
||||
inline static PackTypeP json_to_mse_pack_type(boost::json::object& jv) {
|
||||
PackTypeP pack_type = make_intrusive<PackType>();
|
||||
read(pack_type->name, jv, "name");
|
||||
read(pack_type->enabled, jv, "enabled");
|
||||
read(pack_type->selectable, jv, "selectable");
|
||||
read(pack_type->summary, jv, "summary");
|
||||
read(pack_type->select, jv, "select");
|
||||
if (jv.contains("items") && jv["items"].is_array()) {
|
||||
boost::json::array pack_itemsv = jv["items"].as_array();
|
||||
for (int i = 0; i < pack_itemsv.size(); i++) {
|
||||
boost::json::object pack_itemv = pack_itemsv[i].as_object();
|
||||
pack_type->items.emplace_back(json_to_mse_pack_item(pack_itemv));
|
||||
}
|
||||
}
|
||||
return pack_type;
|
||||
}
|
||||
PackTypeP json_to_mse_pack_type(boost::json::object& jv);
|
||||
|
||||
inline static KeywordP json_to_mse_keyword(boost::json::object& jv) {
|
||||
KeywordP keyword = make_intrusive<Keyword>();
|
||||
read(keyword->keyword, jv, "keyword");
|
||||
read(keyword->match, jv, "match");
|
||||
read(keyword->reminder, jv, "reminder");
|
||||
read(keyword->rules, jv, "rules");
|
||||
read(keyword->mode, jv, "mode");
|
||||
return keyword;
|
||||
}
|
||||
KeywordP json_to_mse_keyword(boost::json::object& jv);
|
||||
|
||||
inline static CardP json_to_mse_card(boost::json::object& jv, Set* set) {
|
||||
CardP card = make_intrusive<Card>(*set->game);
|
||||
read(card->time_created, jv, "time_created");
|
||||
read(card->time_modified, jv, "time_modified");
|
||||
read(card->notes, jv, "notes");
|
||||
read(card->uid, jv, "uid");
|
||||
read(card->linked_card_1, jv, "linked_card_1");
|
||||
read(card->linked_card_2, jv, "linked_card_2");
|
||||
read(card->linked_card_3, jv, "linked_card_3");
|
||||
read(card->linked_card_4, jv, "linked_card_4");
|
||||
read(card->linked_relation_1, jv, "linked_relation_1");
|
||||
read(card->linked_relation_2, jv, "linked_relation_2");
|
||||
read(card->linked_relation_3, jv, "linked_relation_3");
|
||||
read(card->linked_relation_4, jv, "linked_relation_4");
|
||||
// card fields
|
||||
if (jv.contains("data") && jv["data"].is_object()) {
|
||||
boost::json::object datav = jv["data"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
String key_name = wxString(it->key_c_str());
|
||||
Value* container = get_card_field_container(*set->game, card->data, key_name, false);
|
||||
ScriptValueP value = json_to_mse(it->value(), set);
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
// stylesheet
|
||||
if (jv.contains("stylesheet")) card->stylesheet = StyleSheet::byGameAndName(*set->game, wxString(jv["stylesheet"].as_string().c_str()));
|
||||
if (card->stylesheet) {
|
||||
// styling fields
|
||||
card->styling_data.init(card->stylesheet->styling_fields);
|
||||
if (jv.contains("styling_data") && jv["styling_data"].is_object()) {
|
||||
boost::json::object datav = jv["styling_data"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
String key_name = wxString(it->key_c_str());
|
||||
Value* container = get_container(card->styling_data, wxString("styling"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(it->value(), set);
|
||||
set_container(container, value, key_name);
|
||||
card->has_styling = true;
|
||||
}
|
||||
}
|
||||
// extra card fields
|
||||
if (jv.contains("extra_data") && jv["extra_data"].is_object()) {
|
||||
boost::json::object datav = jv["extra_data"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str());
|
||||
if (!stylesheet) continue;
|
||||
IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet);
|
||||
boost::json::object stylesheet_datav = it->value().as_object();
|
||||
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
|
||||
String key_name = wxString(stylesheet_it->key_c_str());
|
||||
Value* container = get_container(stylesheet_data, wxString("extra card"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(stylesheet_it->value(), set);
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return card;
|
||||
}
|
||||
CardP json_to_mse_card(boost::json::object& jv, Set* set);
|
||||
|
||||
inline static SetP json_to_mse_set(boost::json::object& jv) {
|
||||
if (!jv.contains("game")) {
|
||||
throw ScriptError(_ERROR_("json set without game"));
|
||||
}
|
||||
if (!jv.contains("stylesheet")) {
|
||||
throw ScriptError(_ERROR_("json set without stylesheet"));
|
||||
}
|
||||
GameP game = Game::byName(wxString(jv["game"].as_string().c_str()));
|
||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*game, wxString(jv["stylesheet"].as_string().c_str()));
|
||||
SetP set = make_intrusive<Set>(stylesheet);
|
||||
// set fields
|
||||
if (jv.contains("set_info") && jv["set_info"].is_object()) {
|
||||
boost::json::object datav = jv["set_info"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
String key_name = wxString(it->key_c_str());
|
||||
Value* container = get_container(set->data, wxString("set"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(it->value(), set.get());
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
// styling
|
||||
if (jv.contains("styling") && jv["styling"].is_object()) {
|
||||
boost::json::object datav = jv["styling"].as_object();
|
||||
for (auto it = datav.begin(); it != datav.end(); ++it) {
|
||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str());
|
||||
if (!stylesheet) continue;
|
||||
IndexMap<FieldP, ValueP>& stylesheet_data = set->stylingDataFor(*stylesheet);
|
||||
boost::json::object stylesheet_datav = it->value().as_object();
|
||||
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
|
||||
String key_name = wxString(stylesheet_it->key_c_str());
|
||||
Value* container = get_container(stylesheet_data, wxString("styling"), key_name, false);
|
||||
ScriptValueP value = json_to_mse(stylesheet_it->value(), set.get());
|
||||
set_container(container, value, key_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// cards
|
||||
if (jv.contains("cards") && jv["cards"].is_array()) {
|
||||
boost::json::array cardsv = jv["cards"].as_array();
|
||||
for (int i = 0; i < cardsv.size(); i++) {
|
||||
boost::json::object cardv = cardsv[i].as_object();
|
||||
set->cards.emplace_back(json_to_mse_card(cardv, set.get()));
|
||||
}
|
||||
}
|
||||
// keywords
|
||||
if (jv.contains("keywords") && jv["keywords"].is_array()) {
|
||||
boost::json::array keywordsv = jv["keywords"].as_array();
|
||||
for (int i = 0; i < keywordsv.size(); i++) {
|
||||
boost::json::object keywordv = keywordsv[i].as_object();
|
||||
set->keywords.emplace_back(json_to_mse_keyword(keywordv));
|
||||
}
|
||||
}
|
||||
// pack types
|
||||
if (jv.contains("pack_types") && jv["pack_types"].is_array()) {
|
||||
boost::json::array pack_typesv = jv["pack_types"].as_array();
|
||||
for (int i = 0; i < pack_typesv.size(); i++) {
|
||||
boost::json::object pack_typev = pack_typesv[i].as_object();
|
||||
set->pack_types.emplace_back(json_to_mse_pack_type(pack_typev));
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
SetP json_to_mse_set(boost::json::object& jv);
|
||||
|
||||
inline static ScriptValueP json_to_mse(const boost::json::value& jv, Set* set) {
|
||||
if (jv == nullptr) return script_nil;
|
||||
else if (jv.is_null()) return script_nil;
|
||||
else if (jv.is_bool()) return to_script(jv.get_bool());
|
||||
else if (jv.is_double()) return to_script(jv.get_double());
|
||||
else if (jv.is_int64()) {
|
||||
int integer = jv.get_int64();
|
||||
return to_script(integer);
|
||||
}
|
||||
else if (jv.is_uint64()) {
|
||||
int integer = jv.get_uint64();
|
||||
return to_script(integer);
|
||||
}
|
||||
else if (jv.is_string()) {
|
||||
std::string string = boost::json::value_to<std::string>(jv);
|
||||
return to_script(String(string.c_str()));
|
||||
}
|
||||
else if (jv.is_array()) {
|
||||
boost::json::array array = jv.get_array();
|
||||
ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>();
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
boost::json::value jvalue = array[i];
|
||||
ScriptValueP value = json_to_mse(jvalue, set);
|
||||
result->value.push_back(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (jv.is_object()) {
|
||||
boost::json::object object = jv.get_object();
|
||||
if (object.contains("mse_object_type")) {
|
||||
boost::json::string mse_object_type = object["mse_object_type"].as_string();
|
||||
if (mse_object_type == "set") return make_intrusive<ScriptObject<SetP>> (json_to_mse_set(object));
|
||||
if (mse_object_type == "card") return make_intrusive<ScriptObject<CardP>> (json_to_mse_card(object, set));
|
||||
if (mse_object_type == "keyword") return make_intrusive<ScriptObject<KeywordP>> (json_to_mse_keyword(object));
|
||||
if (mse_object_type == "pack_type") return make_intrusive<ScriptObject<PackTypeP>>(json_to_mse_pack_type(object));
|
||||
if (mse_object_type == "pack_item") return make_intrusive<ScriptObject<PackItemP>>(json_to_mse_pack_item(object));
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json unknown type") + _("(") + wxString(mse_object_type.c_str()) + _(")"));
|
||||
return script_nil;
|
||||
}
|
||||
ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>();
|
||||
for (auto it = object.begin(); it != object.end(); ++it) {
|
||||
boost::json::string_view jview = it->key();
|
||||
std::string_view stdview = std::string_view(jview.data(), jview.size());
|
||||
std::string stdstring = { stdview.begin(), stdview.end() };
|
||||
String key(stdstring.c_str(), wxConvUTF8);
|
||||
boost::json::value jvalue = it->value();
|
||||
ScriptValueP value = json_to_mse(jvalue, set);
|
||||
result->key_value[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json unknown type"));
|
||||
return script_nil;
|
||||
}
|
||||
}
|
||||
inline static ScriptValueP json_to_mse(const String& string, Set* set) {
|
||||
try {
|
||||
boost::system::error_code ec;
|
||||
boost::json::parse_options options;
|
||||
options.allow_invalid_utf8 = true;
|
||||
boost::json::value jv = boost::json::parse(string.ToStdString(), ec, {}, options);
|
||||
//if(ec) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
|
||||
if(ec) return script_nil;
|
||||
return json_to_mse(jv, set);
|
||||
}
|
||||
catch (...) {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant parse"));
|
||||
return script_nil;
|
||||
}
|
||||
}
|
||||
inline static ScriptValueP json_to_mse(const ScriptValueP& sv, Set* set) {
|
||||
try {
|
||||
String string = sv->toString();
|
||||
return json_to_mse(string, set);
|
||||
}
|
||||
catch (...) {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant convert"));
|
||||
return script_nil;
|
||||
}
|
||||
}
|
||||
ScriptValueP json_to_mse(const boost::json::value& jv, Set* set);
|
||||
ScriptValueP json_to_mse(const String& string, Set* set);
|
||||
ScriptValueP json_to_mse(const ScriptValueP& sv, Set* set);
|
||||
|
||||
// ----------------------------------------------------------------------------- : MSE to JSON
|
||||
|
||||
template <typename T>
|
||||
static void write(boost::json::object& out, const String& name, const T& value) {
|
||||
wxStringOutputStream stream;
|
||||
Writer writer(stream);
|
||||
writer.indentation = -1000;
|
||||
writer.handle(name, value);
|
||||
String string = stream.GetString();
|
||||
if (!string.empty()) {
|
||||
if (string.StartsWith(name + ":")) string = string.substr(name.length() + 1).Trim(false);
|
||||
if (string.EndsWith("\n")) string = string.substr(0, string.length() - 1);
|
||||
out.emplace(name.ToStdString(), string);
|
||||
}
|
||||
}
|
||||
void write(boost::json::object& out, const String& name, const T& value);
|
||||
|
||||
static void write(boost::json::object& out, const String& name, IndexMap<FieldP, ValueP>& map) {
|
||||
boost::json::object indexmapv;
|
||||
for (IndexMap<FieldP, ValueP>::iterator it = map.begin(); it != map.end(); ++it) {
|
||||
write(indexmapv, (*it)->fieldP->name, *it);
|
||||
}
|
||||
if (!indexmapv.empty()) out.emplace(name.ToStdString(), indexmapv);
|
||||
}
|
||||
void write(boost::json::object& out, const String& name, IndexMap<FieldP, ValueP>& map);
|
||||
|
||||
static void write(boost::json::object& out, const String& name, DelayedIndexMaps<FieldP,ValueP>& map) {
|
||||
boost::json::object delayedindexmapv;
|
||||
for (auto it = map.data.begin() ; it != map.data.end() ; ++it) {
|
||||
write(delayedindexmapv, it->first, it->second->read_data);
|
||||
}
|
||||
if (!delayedindexmapv.empty()) out.emplace(name.ToStdString(), delayedindexmapv);
|
||||
}
|
||||
void write(boost::json::object& out, const String& name, DelayedIndexMaps<FieldP,ValueP>& map);
|
||||
|
||||
inline static boost::json::object mse_to_json(const PackItemP& item) {
|
||||
boost::json::object itemv;
|
||||
itemv.emplace("mse_object_type", "pack_item");
|
||||
write(itemv, "name", item->name);
|
||||
write(itemv, "amount", item->amount);
|
||||
write(itemv, "weight", item->weight);
|
||||
return itemv;
|
||||
}
|
||||
boost::json::object mse_to_json(const PackItemP& item);
|
||||
|
||||
inline static boost::json::object mse_to_json(const PackTypeP& pack) {
|
||||
boost::json::object packv;
|
||||
packv.emplace("mse_object_type", "pack_type");
|
||||
write(packv, "name", pack->name);
|
||||
write(packv, "enabled", pack->enabled);
|
||||
write(packv, "selectable", pack->selectable);
|
||||
write(packv, "summary", pack->summary);
|
||||
write(packv, "select", pack->select);
|
||||
write(packv, "filter", pack->filter);
|
||||
boost::json::array itemsv;
|
||||
for (auto item : pack->items) {
|
||||
itemsv.emplace_back(mse_to_json(item));
|
||||
}
|
||||
packv.emplace("items", itemsv);
|
||||
return packv;
|
||||
}
|
||||
boost::json::object mse_to_json(const PackTypeP& pack);
|
||||
|
||||
inline static boost::json::object mse_to_json(const KeywordP& keyword) {
|
||||
boost::json::object keywordv;
|
||||
keywordv.emplace("mse_object_type", "keyword");
|
||||
write(keywordv, "keyword", keyword->keyword);
|
||||
write(keywordv, "match", keyword->match);
|
||||
write(keywordv, "reminder", keyword->reminder);
|
||||
write(keywordv, "rules", keyword->rules);
|
||||
write(keywordv, "mode", keyword->mode);
|
||||
return keywordv;
|
||||
}
|
||||
boost::json::object mse_to_json(const KeywordP& keyword);
|
||||
|
||||
inline static boost::json::object mse_to_json(const CardP& card, const Set* set) {
|
||||
boost::json::object cardv;
|
||||
cardv.emplace("mse_object_type", "card");
|
||||
// built-in values
|
||||
write(cardv, "time_created", card->time_created);
|
||||
write(cardv, "time_modified", card->time_modified);
|
||||
write(cardv, "notes", card->notes);
|
||||
write(cardv, "uid", card->uid);
|
||||
write(cardv, "linked_card_1", card->linked_card_1);
|
||||
write(cardv, "linked_card_2", card->linked_card_2);
|
||||
write(cardv, "linked_card_3", card->linked_card_3);
|
||||
write(cardv, "linked_card_4", card->linked_card_4);
|
||||
write(cardv, "linked_relation_1", card->linked_relation_1);
|
||||
write(cardv, "linked_relation_2", card->linked_relation_2);
|
||||
write(cardv, "linked_relation_3", card->linked_relation_3);
|
||||
write(cardv, "linked_relation_4", card->linked_relation_4);
|
||||
// card fields
|
||||
write(cardv, "data", card->data);
|
||||
// stylesheet
|
||||
bool change_stylesheet = set && !card->stylesheet;
|
||||
if (change_stylesheet) {
|
||||
card->stylesheet = set->stylesheet;
|
||||
}
|
||||
if (card->stylesheet) {
|
||||
write(cardv, "stylesheet", card->stylesheet);
|
||||
write(cardv, "stylesheet_version", card->stylesheet->version);
|
||||
// extra card fields
|
||||
write(cardv, "extra_data", card->extra_data);
|
||||
}
|
||||
// style
|
||||
write(cardv, "has_styling", card->has_styling);
|
||||
if (card->has_styling) {
|
||||
write(cardv, "styling_data", card->styling_data);
|
||||
}
|
||||
// restore stylesheet
|
||||
if (change_stylesheet) {
|
||||
card->stylesheet = StyleSheetP();
|
||||
}
|
||||
// done
|
||||
return cardv;
|
||||
}
|
||||
boost::json::object mse_to_json(const CardP& card, const Set* set);
|
||||
|
||||
inline static boost::json::object mse_to_json(const Set* set) {
|
||||
boost::json::object setv;
|
||||
setv.emplace("mse_object_type", "set");
|
||||
// built-in values
|
||||
write(setv, "mse_version", set->fileVersion());
|
||||
write(setv, "game", set->game);
|
||||
write(setv, "game_version", set->game->version);
|
||||
write(setv, "stylesheet", set->stylesheet);
|
||||
write(setv, "stylesheet_version", set->stylesheet->version);
|
||||
// set fields
|
||||
write(setv, "set_info", set->data);
|
||||
// styling
|
||||
write(setv, "styling", set->styling_data);
|
||||
// cards
|
||||
boost::json::array cardsv;
|
||||
for (const CardP& card : set->cards) {
|
||||
cardsv.emplace_back(mse_to_json(card, set));
|
||||
}
|
||||
setv.emplace("cards", cardsv);
|
||||
// keywords
|
||||
boost::json::array keywordsv;
|
||||
for (const KeywordP& keyword : set->keywords) {
|
||||
keywordsv.emplace_back(mse_to_json(keyword));
|
||||
}
|
||||
if (!keywordsv.empty()) setv.emplace("keywords", keywordsv);
|
||||
// pack types
|
||||
boost::json::array pack_typesv;
|
||||
for (const PackTypeP& pack_type : set->pack_types) {
|
||||
pack_typesv.emplace_back(mse_to_json(pack_type));
|
||||
}
|
||||
if (!pack_typesv.empty()) setv.emplace("pack_types", pack_typesv);
|
||||
// done
|
||||
return setv;
|
||||
}
|
||||
boost::json::object mse_to_json(const Set* set);
|
||||
|
||||
inline static boost::json::value mse_to_json(const ScriptValueP& sv, Set* set) {
|
||||
ScriptType type = sv->type();
|
||||
// special types
|
||||
if (ScriptObject<PackItemP>* i = dynamic_cast<ScriptObject<PackItemP>*>(sv.get())) return mse_to_json(i->getValue());
|
||||
if (ScriptObject<PackTypeP>* t = dynamic_cast<ScriptObject<PackTypeP>*>(sv.get())) return mse_to_json(t->getValue());
|
||||
if (ScriptObject<KeywordP>* k = dynamic_cast<ScriptObject<KeywordP>*> (sv.get())) return mse_to_json(k->getValue());
|
||||
if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*> (sv.get())) return mse_to_json(c->getValue(), set);
|
||||
if (ScriptObject<SetP>* z = dynamic_cast<ScriptObject<SetP>*> (sv.get())) return mse_to_json(z->getValue().get());
|
||||
if (ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>*> (sv.get())) return mse_to_json(s->getValue());
|
||||
|
||||
// primitive types
|
||||
if (type == SCRIPT_NIL) return boost::json::value(nullptr);
|
||||
if (type == SCRIPT_INT) return boost::json::value(sv->toInt());
|
||||
if (type == SCRIPT_DOUBLE) return boost::json::value(sv->toDouble());
|
||||
if (type == SCRIPT_BOOL) return boost::json::value(sv->toBool());
|
||||
if (type == SCRIPT_STRING) return boost::json::value(sv->toString());
|
||||
if (type == SCRIPT_REGEX) return boost::json::value(sv->toString());
|
||||
if (type == SCRIPT_COLOR) return boost::json::value(format_color(sv->toColor()));
|
||||
if (type == SCRIPT_DATETIME) return boost::json::value(sv->toDateTime().FormatISOCombined(' '));
|
||||
if (type == SCRIPT_COLLECTION) {
|
||||
ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get());
|
||||
if (custom) {
|
||||
if (custom->value.size() > 0) {
|
||||
boost::json::array array;
|
||||
for (int i = 0; i < custom->value.size(); i++) {
|
||||
array.emplace_back(mse_to_json(custom->value[i], set));
|
||||
}
|
||||
return array;
|
||||
} else if (custom->key_value.size() > 0) {
|
||||
boost::json::object object;
|
||||
map<String, ScriptValueP>::iterator it;
|
||||
for (it = custom->key_value.begin(); it != custom->key_value.end(); it++) {
|
||||
object.emplace(it->first.ToStdString(), mse_to_json(it->second, set));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
} else {
|
||||
ScriptConcatCollection* concat = dynamic_cast<ScriptConcatCollection*>(sv.get());
|
||||
if (concat) {
|
||||
boost::json::value a = mse_to_json(concat->getA(), set);
|
||||
boost::json::value b = mse_to_json(concat->getB(), set);
|
||||
if (a.is_array() && b.is_array()) {
|
||||
boost::json::array array_a = a.get_array();
|
||||
boost::json::array array_b = b.get_array();
|
||||
for (int i = 0; i < array_b.size(); i++) {
|
||||
array_a.emplace_back(array_b[i]);
|
||||
}
|
||||
return array_a;
|
||||
} else if (a.is_object() && b.is_object()) {
|
||||
boost::json::object object_a = a.get_object();
|
||||
boost::json::object object_b = b.get_object();
|
||||
for (auto it = object_b.begin(); it != object_b.end(); ++it) {
|
||||
object_a.emplace(it->key(), it->value());
|
||||
}
|
||||
return object_a;
|
||||
} else {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant concat"));
|
||||
return boost::json::value(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
queue_message(MESSAGE_ERROR, _ERROR_1_("json unknown script type", sv->typeName()));
|
||||
return boost::json::value(nullptr);
|
||||
}
|
||||
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set);
|
||||
|
||||
Reference in New Issue
Block a user