Strengthen paste logic

This commit is contained in:
GenevensiS
2026-05-11 13:51:43 +02:00
committed by GitHub
parent 2135a14b17
commit f4fe9ab6b0
9 changed files with 497 additions and 375 deletions
+53 -49
View File
@@ -13,6 +13,7 @@
#include <boost/json.hpp> #include <boost/json.hpp>
#include <wx/filename.h> #include <wx/filename.h>
#include <fstream> #include <fstream>
#include <filesystem>
// ----------------------------------------------------------------------------- : Crop Rect Encoding // ----------------------------------------------------------------------------- : Crop Rect Encoding
@@ -111,67 +112,70 @@ inline static String transformAllEncodedRects(const String& rectString, RectTran
// ----------------------------------------------------------------------------- : File to UTF8 Encoding // ----------------------------------------------------------------------------- : File to UTF8 Encoding
inline static const char Base64Alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
inline static const std::vector<int> Base64ReverseAlphabet = [] {
std::vector<int> table(256, -1);
for (int i = 0; i < 64; i++) table[(uint8_t)Base64Alphabet[i]] = i;
return table;
}();
/// Encode a file in a string /// Encode a file in a string
inline static std::string fileToUTF8(const std::string& filepath) { inline static std::string fileToUTF8(const std::string& filepath) {
// File to char // Load file
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
file.unsetf(std::ios::skipws); if (!file) {
std::vector<unsigned char> buffer = std::vector<unsigned char>(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); queue_message(MESSAGE_WARNING, _("Could not find file: ") + String(filepath));
int size = buffer.size();
if (size < 2) {
queue_message(MESSAGE_WARNING, _("File too small to encode"));
return ""; return "";
} }
// All bytes that have a highest bit of 0 are valid UTF8 characters, so: size_t size = std::filesystem::file_size(filepath);
// Reset the highest bit of each byte, store these bits in additional bytes at the end std::vector<uint8_t> data(size);
const unsigned char highest_bit = 1 << 7; file.read(reinterpret_cast<char*>(data.data()), size);
unsigned char added_byte = 0; // Base64 encode
for (int i = 0, b = 0 ; i < size ; ++i, ++b) { std::string out;
if (b == 7) { // Never set the highest bit of the added byte out.reserve(((size + 2) / 3) * 4);
buffer.push_back(added_byte); int val = 0;
b = 0; int valb = -6;
} for (uint8_t c : data) {
unsigned char bit = 1 << b; val = (val << 8) | c;
if ((buffer[i] & highest_bit) != 0) { // The highest bit of the buffer is set valb += 8;
buffer[i] &= ~highest_bit; // Reset the highest bit of the buffer while (valb >= 0) {
added_byte |= bit; // Set the bit of the added byte out.push_back(Base64Alphabet[(val >> valb) & 0x3F]);
} else { valb -= 6;
added_byte &= ~bit; // Reset the bit of the added byte
} }
} }
buffer.push_back(added_byte); if (valb > -6) {
// Char to string out.push_back(Base64Alphabet[((val << 8) >> (valb + 8)) & 0x3F]);
return std::string(buffer.begin(), buffer.end()); }
// Pad
while (out.size() % 4) {
out.push_back('=');
}
return out;
} }
/// Retreive a file encoded in a string, return true if successful /// Retreive a file encoded in a string, return true if successful
inline static bool UTF8ToFile(const std::string& filepath, std::string& string) { inline static bool UTF8ToFile(const std::string& filepath, std::string& data) {
// String to char // Base64 decode
std::vector<unsigned char> buffer(string.begin(), string.end()); std::string out;
int size = buffer.size(); out.reserve(data.size() * 3 / 4);
if (size < 2) { int val = 0;
queue_message(MESSAGE_WARNING, _("File too small to decode")); int valb = -8;
return false; for (uint8_t c : data) {
} if (c == '=') break; // padding, we're done
// Restore the highest bit of each byte val = (val << 6) | Base64ReverseAlphabet[c];
size = (size * 7) / 8; valb += 6;
const unsigned char highest_bit = 1 << 7; if (valb >= 0) {
unsigned char added_byte = buffer[size]; out.push_back(static_cast<char>((val >> valb) & 0xFF));
for (int i = 0, j = size, b = 0 ; i < size ; ++i, ++b) { valb -= 8;
if (b == 7) {
++j;
added_byte = buffer[j];
b = 0;
}
unsigned char bit = 1 << b;
if ((added_byte & bit) != 0) { // The bit of the added byte is set
buffer[i] |= highest_bit; // Set the highest bit of the buffer
} }
} }
buffer.resize(size); // Save file
// Char to file std::ofstream file(filepath, std::ios::binary);
std::ofstream file(filepath, std::ios::out|std::ios::binary); file.write(out.data(), out.size());
std::copy(buffer.cbegin(), buffer.cend(), std::ostream_iterator<unsigned char>(file));
return true; return true;
} }
+2 -5
View File
@@ -850,14 +850,11 @@ DownloadedImage::DownloadedImage(Set* set, const String& url)
} }
// is the data an image? // is the data an image?
const String& content_type = wnd.out.GetContentType(); if (!wnd.content_type.StartsWith(_("image/"))) throw ScriptError(_ERROR_1_("download not image", loadpath));
if (!content_type.StartsWith(_("image"))) throw ScriptError(_ERROR_1_("download not image", loadpath));
Image img(*wnd.out.GetStream());
if (!img.IsOk()) throw ScriptError(_ERROR_("web request corrupted"));
// add the file to the set (or overwrite it if pre-existing), save set // add the file to the set (or overwrite it if pre-existing), save set
auto outStream = set->openOut(savename); auto outStream = set->openOut(savename);
img.SaveFile(*outStream, wxBITMAP_TYPE_PNG); wnd.image_out.SaveFile(*outStream, wxBITMAP_TYPE_PNG);
if (!outStream->IsOk()) throw ScriptError(_ERROR_1_("can't write image to set", loadpath)); if (!outStream->IsOk()) throw ScriptError(_ERROR_1_("can't write image to set", loadpath));
outStream->Close(); outStream->Close();
set->save(false); set->save(false);
+66 -13
View File
@@ -305,18 +305,11 @@ bool CardListBase::parseUrl(String& url, vector<CardP>& out) {
WebRequestWindow wnd(url); WebRequestWindow wnd(url);
if (wnd.ShowModal() == wxID_OK) { if (wnd.ShowModal() == wxID_OK) {
const String& content_type = wnd.out.GetContentType(); if (wnd.content_type.StartsWith(_("image/"))) {
if (content_type.StartsWith(_("image"))) { parseImage(wnd.image_out, out);
Image img(*wnd.out.GetStream());
if (img.IsOk()) {
parseImage(img, out);
} }
else { else if (wnd.content_type.StartsWith(_("text/"))) {
queue_message(MESSAGE_ERROR, _ERROR_("web request corrupted")); String text = String(wnd.text_out.data(), wnd.text_out.size());
}
}
else if (content_type.StartsWith(_("text"))) {
String text = wnd.out.AsString();
parseText(text, out); parseText(text, out);
} }
else { else {
@@ -369,6 +362,9 @@ bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
} }
bool CardListBase::parseText(String& text, vector<CardP>& out) { bool CardListBase::parseText(String& text, vector<CardP>& out) {
if (text.size() == 0) {
return false;
}
size_t j = out.size(); size_t j = out.size();
size_t pos = text.find("<mse-card-data>"); size_t pos = text.find("<mse-card-data>");
if (pos != wxString::npos) { if (pos != wxString::npos) {
@@ -407,7 +403,14 @@ bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
if (format == CardsDataObject::format) { if (format == CardsDataObject::format) {
String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _(""); String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _("");
size_t size = composite->GetDataSize(format); size_t size = composite->GetDataSize(format);
if (size > 0) { if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: CardsDataObject corrupted"));
return false;
}
if (size > 10000000) { // 10Mb
queue_message(MESSAGE_ERROR, _("Too much card data, paste less cards!"));
return false;
}
std::vector<char> buffer(size); std::vector<char> buffer(size);
if (composite->GetDataHere(format, buffer.data())) { if (composite->GetDataHere(format, buffer.data())) {
CardsDataObject card_data; CardsDataObject card_data;
@@ -415,7 +418,6 @@ bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
card_data.getCards(set, id, new_cards); card_data.getCards(set, id, new_cards);
} }
} }
}
else { else {
wxDataObject *data = composite->GetObject(format); wxDataObject *data = composite->GetObject(format);
@@ -432,17 +434,59 @@ bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
case wxDF_PNG: case wxDF_PNG:
{ {
wxImageDataObject* image_data = static_cast<wxImageDataObject*>(data); wxImageDataObject* image_data = static_cast<wxImageDataObject*>(data);
size_t size = image_data->GetDataSize();
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: ImageDataObject corrupted"));
return false;
}
if (size > 50000000) { // 50Mb
queue_message(MESSAGE_ERROR, _("Image data too large or corrupted"));
return false;
}
try {
Image image = image_data->GetImage(); Image image = image_data->GetImage();
if (!image.IsOk() || image.GetWidth() > 20000 || image.GetHeight() > 20000) {
queue_message(MESSAGE_ERROR, _("Image too large or corrupted"));
return false;
}
parseImage(image, new_cards); parseImage(image, new_cards);
} catch (const std::bad_alloc&) {
//queue_message(MESSAGE_ERROR, _("Image couldn't be allocated"));
return false;
} catch (...) {
queue_message(MESSAGE_ERROR, _("Image couldn't be processed"));
return false;
}
} }
break; break;
case wxDF_BITMAP: case wxDF_BITMAP:
{ {
wxBitmapDataObject* bitmap_data = static_cast<wxBitmapDataObject*>(data); wxBitmapDataObject* bitmap_data = static_cast<wxBitmapDataObject*>(data);
size_t size = bitmap_data->GetDataSize();
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: BitmapDataObject corrupted"));
return false;
}
if (size > 50000000) { // 50Mb
queue_message(MESSAGE_ERROR, _("Bitmap data too large or corrupted"));
return false;
}
try {
wxBitmap bitmap = bitmap_data->GetBitmap(); wxBitmap bitmap = bitmap_data->GetBitmap();
if (!bitmap.IsOk() || bitmap.GetWidth() > 20000 || bitmap.GetHeight() > 20000) {
queue_message(MESSAGE_ERROR, _("Bitmap too large or corrupted"));
return false;
}
Image image = bitmap.ConvertToImage(); Image image = bitmap.ConvertToImage();
parseImage(image, new_cards); parseImage(image, new_cards);
} catch (const std::bad_alloc&) {
//queue_message(MESSAGE_ERROR, _("Bitmap or Image couldn't be allocated"));
return false;
} catch (...) {
queue_message(MESSAGE_ERROR, _("Bitmap or Image couldn't be processed"));
return false;
}
} }
break; break;
@@ -451,6 +495,15 @@ bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
case wxDF_HTML: case wxDF_HTML:
{ {
wxTextDataObject* text_data = static_cast<wxTextDataObject*>(data); wxTextDataObject* text_data = static_cast<wxTextDataObject*>(data);
size_t size = text_data->GetDataSize();
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: TextDataObject corrupted"));
return false;
}
if (size > 30000000) { // 30Mb
queue_message(MESSAGE_ERROR, _("Text too large or corrupted"));
return false;
}
String text = text_data->GetText(); String text = text_data->GetText();
if (!parseUrl(text, new_cards)) parseText(text, new_cards); if (!parseUrl(text, new_cards)) parseText(text, new_cards);
} }
+39 -4
View File
@@ -9,6 +9,7 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <gui/web_request_window.hpp> #include <gui/web_request_window.hpp>
#include <util/window_id.hpp> #include <util/window_id.hpp>
#include <wx/mstream.h>
// ----------------------------------------------------------------------------- : WebRequestWindow // ----------------------------------------------------------------------------- : WebRequestWindow
@@ -76,16 +77,50 @@ void WebRequestWindow::onUpdate(wxWebRequestEvent& evt) {
} }
void WebRequestWindow::onComplete(wxWebRequestEvent& evt) { void WebRequestWindow::onComplete(wxWebRequestEvent& evt) {
out = evt.GetResponse(); wxWebResponse response = evt.GetResponse();
if (out.IsOk()) { if (!response.IsOk()) {
EndModal(wxID_OK); onFail(_ERROR_("web request corrupted"));
return;
}
wxInputStream* stream = response.GetStream();
if (!stream || !stream->IsOk()) {
onFail(_ERROR_("web request corrupted"));
return;
}
content_type = response.GetContentType();
if (content_type.StartsWith("image/")) {
image_out = Image(*stream);
if (!image_out.IsOk()) {
onFail(_ERROR_("web request corrupted"));
return;
}
}
else if (content_type.StartsWith("text/") || content_type.Contains("json")) {
wxMemoryOutputStream mem;
char buffer[8192];
while (true) {
stream->Read(buffer, sizeof(buffer));
size_t read = stream->LastRead();
if (read > 0) mem.Write(buffer, read);
if (stream->Eof()) break;
if (stream->GetLastError() != wxSTREAM_NO_ERROR) {
onFail(_ERROR_("web request corrupted"));
return;
}
}
text_out.resize(mem.GetSize());
mem.CopyTo(text_out.data(), mem.GetSize());
} }
else { else {
onFail(_ERROR_("web request corrupted")); onFail(_ERROR_("web request unsupported format"));
return;
} }
EndModal(wxID_OK);
} }
void WebRequestWindow::onFail(const String& message) { void WebRequestWindow::onFail(const String& message) {
content_type.Clear();
info->SetLabel(_ERROR_("web request failed")); info->SetLabel(_ERROR_("web request failed"));
address->SetLabel(message); address->SetLabel(message);
} }
+3 -1
View File
@@ -19,7 +19,9 @@ class WebRequestWindow : public wxDialog {
public: public:
WebRequestWindow(const String& url, bool sizer=true); WebRequestWindow(const String& url, bool sizer=true);
wxWebResponse out; String content_type;
std::string text_out;
Image image_out;
protected: protected:
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
+186 -157
View File
@@ -112,13 +112,25 @@ void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* i
String json_pretty_print(const boost::json::value& jv, std::string* indent) { String json_pretty_print(const boost::json::value& jv, std::string* indent) {
std::ostringstream stream; std::ostringstream stream;
pretty_print(stream, jv, indent); pretty_print(stream, jv, indent);
String string = wxString(stream.str().c_str()); std::string stdstring = stream.str();
return string; const char* data = stdstring.data();
size_t size = stdstring.size();
String wxstring = String::FromUTF8(data, size);
if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
}
return wxstring;
} }
String json_ugly_print(const boost::json::value& jv) { String json_ugly_print(const boost::json::value& jv) {
String string = wxString(boost::json::serialize(jv).c_str()); std::string stdstring = boost::json::serialize(jv);
return string; const char* data = stdstring.data();
size_t size = stdstring.size();
String wxstring = String::FromUTF8(data, size);
if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
}
return wxstring;
} }
// ----------------------------------------------------------------------------- : JSON to MSE // ----------------------------------------------------------------------------- : JSON to MSE
@@ -128,23 +140,33 @@ ScriptValueP json_to_mse(const boost::json::value& jv, Set* set);
template <typename T> template <typename T>
void read(T& out, boost::json::object& jv, const char value_name[]) { void read(T& out, boost::json::object& jv, const char value_name[]) {
if (!jv.contains(value_name)) return; if (!jv.contains(value_name)) return;
else { boost::json::string jstring = jv[value_name].as_string();
wxStringInputStream stream = {_("")}; const char* data = jstring.data();
Reader reader(stream, nullptr, _("")); size_t size = jstring.size();
reader.setValue(wxString(jv[value_name].as_string().c_str())); String wxstring = String::FromUTF8(data, size);
reader.handle(out); if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
} }
wxStringInputStream stream(wxstring);
Reader reader(stream, nullptr, _(""), false, true);
reader.setValue(wxstring);
reader.handle(out);
} }
// templates don't work with enums? are you kidding me with this language? // 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[]) { void read(PackSelectType& out, boost::json::object& jv, const char value_name[]) {
if (!jv.contains(value_name)) return; if (!jv.contains(value_name)) return;
else { boost::json::string jstring = jv[value_name].as_string();
wxStringInputStream stream = {_("")}; const char* data = jstring.data();
Reader reader(stream, nullptr, _("")); size_t size = jstring.size();
reader.setValue(wxString(jv[value_name].as_string().c_str())); String wxstring = String::FromUTF8(data, size);
reader.handle(out); if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
} }
wxStringInputStream stream(wxstring);
Reader reader(stream, nullptr, _(""), false, true);
reader.setValue(wxstring);
reader.handle(out);
} }
PackItemP json_to_mse_pack_item(boost::json::object& jv) { PackItemP json_to_mse_pack_item(boost::json::object& jv) {
@@ -163,7 +185,7 @@ PackTypeP json_to_mse_pack_type(boost::json::object& jv) {
read(pack_type->summary, jv, "summary"); read(pack_type->summary, jv, "summary");
read(pack_type->select, jv, "select"); read(pack_type->select, jv, "select");
if (jv.contains("items") && jv["items"].is_array()) { if (jv.contains("items") && jv["items"].is_array()) {
boost::json::array pack_itemsv = jv["items"].as_array(); boost::json::array pack_itemsv = jv["items"].get_array();
for (size_t i = 0; i < pack_itemsv.size(); i++) { for (size_t i = 0; i < pack_itemsv.size(); i++) {
boost::json::object pack_itemv = pack_itemsv[i].as_object(); boost::json::object pack_itemv = pack_itemsv[i].as_object();
pack_type->items.emplace_back(json_to_mse_pack_item(pack_itemv)); pack_type->items.emplace_back(json_to_mse_pack_item(pack_itemv));
@@ -198,24 +220,29 @@ CardP json_to_mse_card(boost::json::object& jv, Set* set) {
read(card->linked_relation_4, jv, "linked_relation_4"); read(card->linked_relation_4, jv, "linked_relation_4");
// card fields // card fields
if (jv.contains("data") && jv["data"].is_object()) { if (jv.contains("data") && jv["data"].is_object()) {
boost::json::object datav = jv["data"].as_object(); boost::json::object datav = jv["data"].get_object();
for (auto it = datav.begin(); it != datav.end(); ++it) { for (auto it = datav.begin(); it != datav.end(); ++it) {
String key_name = wxString(it->key_c_str()); boost::json::string_view key_view = it->key();
String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_card_field_container(*set->game, card->data, key_name, false); Value* container = get_card_field_container(*set->game, card->data, key_name, false);
ScriptValueP value = json_to_mse(it->value(), set); ScriptValueP value = json_to_mse(it->value(), set);
set_container(container, value, key_name); set_container(container, value, key_name);
} }
} }
// stylesheet // stylesheet
if (jv.contains("stylesheet")) card->stylesheet = StyleSheet::byGameAndName(*set->game, wxString(jv["stylesheet"].as_string().c_str())); if (jv.contains("stylesheet")) {
boost::json::string stylesheet_name = jv["stylesheet"].as_string();
card->stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_name.data(), stylesheet_name.size()));
}
if (card->stylesheet) { if (card->stylesheet) {
// styling fields // styling fields
card->styling_data.init(card->stylesheet->styling_fields); card->styling_data.init(card->stylesheet->styling_fields);
if (jv.contains("styling_data") && jv["styling_data"].is_object()) { if (jv.contains("styling_data") && jv["styling_data"].is_object()) {
boost::json::object datav = jv["styling_data"].as_object(); boost::json::object datav = jv["styling_data"].get_object();
for (auto it = datav.begin(); it != datav.end(); ++it) { for (auto it = datav.begin(); it != datav.end(); ++it) {
String key_name = wxString(it->key_c_str()); boost::json::string_view key_view = it->key();
Value* container = get_container(card->styling_data, wxString("styling"), key_name, false); String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(card->styling_data, String("styling"), key_name, false);
ScriptValueP value = json_to_mse(it->value(), set); ScriptValueP value = json_to_mse(it->value(), set);
set_container(container, value, key_name); set_container(container, value, key_name);
card->has_styling = true; card->has_styling = true;
@@ -223,15 +250,17 @@ CardP json_to_mse_card(boost::json::object& jv, Set* set) {
} }
// extra card fields // extra card fields
if (jv.contains("extra_data") && jv["extra_data"].is_object()) { if (jv.contains("extra_data") && jv["extra_data"].is_object()) {
boost::json::object datav = jv["extra_data"].as_object(); boost::json::object datav = jv["extra_data"].get_object();
for (auto it = datav.begin(); it != datav.end(); ++it) { for (auto it = datav.begin(); it != datav.end(); ++it) {
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str()); boost::json::string_view stylesheet_view = it->key();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_view.data(), stylesheet_view.size()));
if (!stylesheet) continue; if (!stylesheet) continue;
IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet); IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet);
boost::json::object stylesheet_datav = it->value().as_object(); boost::json::object stylesheet_datav = it->value().as_object();
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) { for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
String key_name = wxString(stylesheet_it->key_c_str()); boost::json::string_view key_view = stylesheet_it->key();
Value* container = get_container(stylesheet_data, wxString("extra card"), key_name, false); String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(stylesheet_data, String("extra card"), key_name, false);
ScriptValueP value = json_to_mse(stylesheet_it->value(), set); ScriptValueP value = json_to_mse(stylesheet_it->value(), set);
set_container(container, value, key_name); set_container(container, value, key_name);
} }
@@ -248,30 +277,35 @@ SetP json_to_mse_set(boost::json::object& jv) {
if (!jv.contains("stylesheet")) { if (!jv.contains("stylesheet")) {
throw ScriptError(_ERROR_("json set without stylesheet")); throw ScriptError(_ERROR_("json set without stylesheet"));
} }
GameP game = Game::byName(wxString(jv["game"].as_string().c_str())); boost::json::string game_name = jv["game"].as_string();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*game, wxString(jv["stylesheet"].as_string().c_str())); GameP game = Game::byName(String::FromUTF8(game_name.data(), game_name.size()));
boost::json::string stylesheet_name = jv["stylesheet"].as_string();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*game, String::FromUTF8(stylesheet_name.data(), stylesheet_name.size()));
SetP set = make_intrusive<Set>(stylesheet); SetP set = make_intrusive<Set>(stylesheet);
// set fields // set fields
if (jv.contains("set_info") && jv["set_info"].is_object()) { if (jv.contains("set_info") && jv["set_info"].is_object()) {
boost::json::object datav = jv["set_info"].as_object(); boost::json::object datav = jv["set_info"].get_object();
for (auto it = datav.begin(); it != datav.end(); ++it) { for (auto it = datav.begin(); it != datav.end(); ++it) {
String key_name = wxString(it->key_c_str()); boost::json::string_view key_view = it->key();
Value* container = get_container(set->data, wxString("set"), key_name, false); String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(set->data, String("set"), key_name, false);
ScriptValueP value = json_to_mse(it->value(), set.get()); ScriptValueP value = json_to_mse(it->value(), set.get());
set_container(container, value, key_name); set_container(container, value, key_name);
} }
} }
// styling // styling
if (jv.contains("styling") && jv["styling"].is_object()) { if (jv.contains("styling") && jv["styling"].is_object()) {
boost::json::object datav = jv["styling"].as_object(); boost::json::object datav = jv["styling"].get_object();
for (auto it = datav.begin(); it != datav.end(); ++it) { for (auto it = datav.begin(); it != datav.end(); ++it) {
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str()); boost::json::string_view stylesheet_view = it->key();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_view.data(), stylesheet_view.size()));
if (!stylesheet) continue; if (!stylesheet) continue;
IndexMap<FieldP, ValueP>& stylesheet_data = set->stylingDataFor(*stylesheet); IndexMap<FieldP, ValueP>& stylesheet_data = set->stylingDataFor(*stylesheet);
boost::json::object stylesheet_datav = it->value().as_object(); boost::json::object stylesheet_datav = it->value().as_object();
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) { for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
String key_name = wxString(stylesheet_it->key_c_str()); boost::json::string_view key_view = stylesheet_it->key();
Value* container = get_container(stylesheet_data, wxString("styling"), key_name, false); String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(stylesheet_data, String("styling"), key_name, false);
ScriptValueP value = json_to_mse(stylesheet_it->value(), set.get()); ScriptValueP value = json_to_mse(stylesheet_it->value(), set.get());
set_container(container, value, key_name); set_container(container, value, key_name);
} }
@@ -279,7 +313,7 @@ SetP json_to_mse_set(boost::json::object& jv) {
} }
// cards // cards
if (jv.contains("cards") && jv["cards"].is_array()) { if (jv.contains("cards") && jv["cards"].is_array()) {
boost::json::array cardsv = jv["cards"].as_array(); boost::json::array cardsv = jv["cards"].get_array();
for (size_t i = 0; i < cardsv.size(); i++) { for (size_t i = 0; i < cardsv.size(); i++) {
boost::json::object cardv = cardsv[i].as_object(); boost::json::object cardv = cardsv[i].as_object();
set->cards.emplace_back(json_to_mse_card(cardv, set.get())); set->cards.emplace_back(json_to_mse_card(cardv, set.get()));
@@ -287,7 +321,7 @@ SetP json_to_mse_set(boost::json::object& jv) {
} }
// keywords // keywords
if (jv.contains("keywords") && jv["keywords"].is_array()) { if (jv.contains("keywords") && jv["keywords"].is_array()) {
boost::json::array keywordsv = jv["keywords"].as_array(); boost::json::array keywordsv = jv["keywords"].get_array();
for (size_t i = 0; i < keywordsv.size(); i++) { for (size_t i = 0; i < keywordsv.size(); i++) {
boost::json::object keywordv = keywordsv[i].as_object(); boost::json::object keywordv = keywordsv[i].as_object();
set->keywords.emplace_back(json_to_mse_keyword(keywordv)); set->keywords.emplace_back(json_to_mse_keyword(keywordv));
@@ -295,7 +329,7 @@ SetP json_to_mse_set(boost::json::object& jv) {
} }
// pack types // pack types
if (jv.contains("pack_types") && jv["pack_types"].is_array()) { if (jv.contains("pack_types") && jv["pack_types"].is_array()) {
boost::json::array pack_typesv = jv["pack_types"].as_array(); boost::json::array pack_typesv = jv["pack_types"].get_array();
for (size_t i = 0; i < pack_typesv.size(); i++) { for (size_t i = 0; i < pack_typesv.size(); i++) {
boost::json::object pack_typev = pack_typesv[i].as_object(); boost::json::object pack_typev = pack_typesv[i].as_object();
set->pack_types.emplace_back(json_to_mse_pack_type(pack_typev)); set->pack_types.emplace_back(json_to_mse_pack_type(pack_typev));
@@ -318,17 +352,13 @@ ScriptValueP json_to_mse(const boost::json::value& jv, Set* set) {
return to_script(integer); return to_script(integer);
} }
else if (jv.is_string()) { else if (jv.is_string()) {
if (jv.as_string().empty()) return to_script(String()); boost::json::string jstring = jv.get_string();
std::string string = boost::json::value_to<std::string>(jv); if (jstring.empty()) return to_script(String());
const char* cstring = string.c_str(); const char* data = jstring.data();
size_t nulpos = strlen(cstring); size_t size = jstring.size();
// if the string contains nul bytes, we have to use the std::string constructor, even though we can't specify the encoding String wxstring = String::FromUTF8(data, size);
if (nulpos < string.size()) return to_script(String(string));
// if the string doesn't contain nul bytes, we can use the constructor that allows to specify the encoding
String wxstring(cstring, wxConvUTF8);
if (!wxstring.empty()) return to_script(wxstring); if (!wxstring.empty()) return to_script(wxstring);
// if all else fails, use "Whatever Works" return to_script(String(data, wxConvWhateverWorks, size));
return to_script(String(cstring, wxConvWhateverWorks));
} }
else if (jv.is_array()) { else if (jv.is_array()) {
boost::json::array array = jv.get_array(); boost::json::array array = jv.get_array();
@@ -349,18 +379,16 @@ ScriptValueP json_to_mse(const boost::json::value& jv, Set* set) {
if (mse_object_type == "keyword") return make_intrusive<ScriptObject<KeywordP>> (json_to_mse_keyword(object)); 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_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)); 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()) + _(")")); queue_message(MESSAGE_ERROR, _ERROR_("json unknown type") + _("(") + String(mse_object_type.c_str()) + _(")"));
return script_nil; return script_nil;
} }
ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>(); ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>();
for (auto it = object.begin(); it != object.end(); ++it) { for (auto it = object.begin(); it != object.end(); ++it) {
boost::json::string_view jview = it->key(); boost::json::string_view jview = it->key();
std::string_view stdview = std::string_view(jview.data(), jview.size()); String key_name = String::FromUTF8(jview.data(), jview.size());
std::string stdstring = { stdview.begin(), stdview.end() };
String key(stdstring.c_str(), wxConvUTF8);
boost::json::value jvalue = it->value(); boost::json::value jvalue = it->value();
ScriptValueP value = json_to_mse(jvalue, set); ScriptValueP value = json_to_mse(jvalue, set);
result->key_value[key] = value; result->key_value[key_name] = value;
} }
return result; return result;
} }
@@ -374,8 +402,9 @@ ScriptValueP json_to_mse(const String& string, Set* set) {
boost::system::error_code ec; boost::system::error_code ec;
boost::json::parse_options options; boost::json::parse_options options;
options.allow_invalid_utf8 = true; options.allow_invalid_utf8 = true;
boost::json::value jv = boost::json::parse(string.ToStdString(), ec, {}, options); wxScopedCharBuffer buffer = string.ToUTF8();
//if(ec) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message()); boost::json::value jv = boost::json::parse(boost::json::string_view(buffer.data(), buffer.length()), ec, {}, options);
if(ec && buffer.length() > 0) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
if(ec) return script_nil; if(ec) return script_nil;
return json_to_mse(jv, set); return json_to_mse(jv, set);
} }
@@ -512,15 +541,15 @@ boost::json::object mse_to_json(const StyleP& style) {
boost::json::object stylev; boost::json::object stylev;
stylev.emplace("mse_object_type", "style"); stylev.emplace("mse_object_type", "style");
stylev.emplace("z_index", wxString::Format(wxT("%i"), style->z_index)); stylev.emplace("z_index", String::Format(wxT("%i"), style->z_index));
stylev.emplace("tab_index", wxString::Format(wxT("%i"), style->tab_index)); stylev.emplace("tab_index", String::Format(wxT("%i"), style->tab_index));
stylev.emplace("left", wxString::Format(wxT("%.2f"), style->left())); stylev.emplace("left", String::Format(wxT("%.2f"), style->left()));
stylev.emplace("top", wxString::Format(wxT("%.2f"), style->top())); stylev.emplace("top", String::Format(wxT("%.2f"), style->top()));
stylev.emplace("right", wxString::Format(wxT("%.2f"), style->right())); stylev.emplace("right", String::Format(wxT("%.2f"), style->right()));
stylev.emplace("bottom", wxString::Format(wxT("%.2f"), style->bottom())); stylev.emplace("bottom", String::Format(wxT("%.2f"), style->bottom()));
stylev.emplace("width", wxString::Format(wxT("%.2f"), style->width())); stylev.emplace("width", String::Format(wxT("%.2f"), style->width()));
stylev.emplace("height", wxString::Format(wxT("%.2f"), style->height())); stylev.emplace("height", String::Format(wxT("%.2f"), style->height()));
stylev.emplace("angle", wxString::Format(wxT("%.2f"), style->angle())); stylev.emplace("angle", String::Format(wxT("%.2f"), style->angle()));
stylev.emplace("visible", style->visible()); stylev.emplace("visible", style->visible());
stylev.emplace("mask", style->mask.toScriptString()); stylev.emplace("mask", style->mask.toScriptString());
@@ -530,74 +559,74 @@ boost::json::object mse_to_json(const StyleP& style) {
boost::json::object fontv; boost::json::object fontv;
fontv.emplace("name", s->font.name()); fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name()); fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size())); fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight()); fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style()); fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline()); fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough()); fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to)); fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch)); fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color())); fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color())); fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x())); fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y())); fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur())); fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color())); fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius())); fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur())); fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color)); fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags)); fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv); stylev.emplace("font", fontv);
boost::json::object symbolfontv; boost::json::object symbolfontv;
symbolfontv.emplace("name", s->symbol_font.name()); symbolfontv.emplace("name", s->symbol_font.name());
symbolfontv.emplace("size", wxString::Format(wxT("%.2f"), s->symbol_font.size())); symbolfontv.emplace("size", String::Format(wxT("%.2f"), s->symbol_font.size()));
symbolfontv.emplace("underline", s->symbol_font.underline()); symbolfontv.emplace("underline", s->symbol_font.underline());
symbolfontv.emplace("strikethrough", s->symbol_font.strikethrough()); symbolfontv.emplace("strikethrough", s->symbol_font.strikethrough());
symbolfontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->symbol_font.scale_down_to)); symbolfontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->symbol_font.scale_down_to));
symbolfontv.emplace("shadow_color", format_color( s->symbol_font.shadow_color())); symbolfontv.emplace("shadow_color", format_color( s->symbol_font.shadow_color()));
symbolfontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_x())); symbolfontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_x()));
symbolfontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_y())); symbolfontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_y()));
symbolfontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->symbol_font.shadow_blur())); symbolfontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->symbol_font.shadow_blur()));
symbolfontv.emplace("stroke_color", format_color( s->symbol_font.stroke_color())); symbolfontv.emplace("stroke_color", format_color( s->symbol_font.stroke_color()));
symbolfontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->symbol_font.stroke_radius())); symbolfontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->symbol_font.stroke_radius()));
symbolfontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->symbol_font.stroke_blur())); symbolfontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->symbol_font.stroke_blur()));
stylev.emplace("symbol_font", symbolfontv); stylev.emplace("symbol_font", symbolfontv);
stylev.emplace("always_symbol", s->always_symbol); stylev.emplace("always_symbol", s->always_symbol);
stylev.emplace("allow_formating", s->allow_formating); stylev.emplace("allow_formating", s->allow_formating);
stylev.emplace("alignment", alignment_to_string( s->alignment())); stylev.emplace("alignment", alignment_to_string( s->alignment()));
stylev.emplace("direction", direction_to_string( s->direction)); stylev.emplace("direction", direction_to_string( s->direction));
stylev.emplace("padding_left", wxString::Format(wxT("%.2f"), s->padding_left())); stylev.emplace("padding_left", String::Format(wxT("%.2f"), s->padding_left()));
stylev.emplace("padding_right", wxString::Format(wxT("%.2f"), s->padding_right())); stylev.emplace("padding_right", String::Format(wxT("%.2f"), s->padding_right()));
stylev.emplace("padding_top", wxString::Format(wxT("%.2f"), s->padding_top())); stylev.emplace("padding_top", String::Format(wxT("%.2f"), s->padding_top()));
stylev.emplace("padding_bottom", wxString::Format(wxT("%.2f"), s->padding_bottom())); stylev.emplace("padding_bottom", String::Format(wxT("%.2f"), s->padding_bottom()));
stylev.emplace("padding_left_min", wxString::Format(wxT("%.2f"), s->padding_left_min())); stylev.emplace("padding_left_min", String::Format(wxT("%.2f"), s->padding_left_min()));
stylev.emplace("padding_right_min", wxString::Format(wxT("%.2f"), s->padding_right_min())); stylev.emplace("padding_right_min", String::Format(wxT("%.2f"), s->padding_right_min()));
stylev.emplace("padding_top_min", wxString::Format(wxT("%.2f"), s->padding_top_min())); stylev.emplace("padding_top_min", String::Format(wxT("%.2f"), s->padding_top_min()));
stylev.emplace("padding_bottom_min", wxString::Format(wxT("%.2f"), s->padding_bottom_min())); stylev.emplace("padding_bottom_min", String::Format(wxT("%.2f"), s->padding_bottom_min()));
stylev.emplace("line_height_soft", wxString::Format(wxT("%.2f"), s->line_height_soft())); stylev.emplace("line_height_soft", String::Format(wxT("%.2f"), s->line_height_soft()));
stylev.emplace("line_height_hard", wxString::Format(wxT("%.2f"), s->line_height_hard())); stylev.emplace("line_height_hard", String::Format(wxT("%.2f"), s->line_height_hard()));
stylev.emplace("line_height_line", wxString::Format(wxT("%.2f"), s->line_height_line())); stylev.emplace("line_height_line", String::Format(wxT("%.2f"), s->line_height_line()));
stylev.emplace("line_height_soft_max", wxString::Format(wxT("%.2f"), s->line_height_soft_max())); stylev.emplace("line_height_soft_max", String::Format(wxT("%.2f"), s->line_height_soft_max()));
stylev.emplace("line_height_hard_max", wxString::Format(wxT("%.2f"), s->line_height_hard_max())); stylev.emplace("line_height_hard_max", String::Format(wxT("%.2f"), s->line_height_hard_max()));
stylev.emplace("line_height_line_max", wxString::Format(wxT("%.2f"), s->line_height_line_max())); stylev.emplace("line_height_line_max", String::Format(wxT("%.2f"), s->line_height_line_max()));
stylev.emplace("paragraph_height", wxString::Format(wxT("%.2f"), s->paragraph_height())); stylev.emplace("paragraph_height", String::Format(wxT("%.2f"), s->paragraph_height()));
boost::json::object layoutv; boost::json::object layoutv;
layoutv.emplace("content_top", wxString::Format(wxT("%.2f"), s->layout->top)); layoutv.emplace("content_top", String::Format(wxT("%.2f"), s->layout->top));
layoutv.emplace("content_middle", wxString::Format(wxT("%.2f"), s->layout->middle())); layoutv.emplace("content_middle", String::Format(wxT("%.2f"), s->layout->middle()));
layoutv.emplace("content_bottom", wxString::Format(wxT("%.2f"), s->layout->bottom())); layoutv.emplace("content_bottom", String::Format(wxT("%.2f"), s->layout->bottom()));
layoutv.emplace("content_width", wxString::Format(wxT("%.2f"), s->layout->width)); layoutv.emplace("content_width", String::Format(wxT("%.2f"), s->layout->width));
layoutv.emplace("content_height", wxString::Format(wxT("%.2f"), s->layout->height)); layoutv.emplace("content_height", String::Format(wxT("%.2f"), s->layout->height));
layoutv.emplace("content_lines", wxString::Format(wxT("%i"), s->layout->lines.size())); layoutv.emplace("content_lines", String::Format(wxT("%i"), s->layout->lines.size()));
layoutv.emplace("content_clauses", wxString::Format(wxT("%i"), s->layout->clauses.size())); layoutv.emplace("content_clauses", String::Format(wxT("%i"), s->layout->clauses.size()));
layoutv.emplace("content_paragraphs", wxString::Format(wxT("%i"), s->layout->paragraphs.size())); layoutv.emplace("content_paragraphs", String::Format(wxT("%i"), s->layout->paragraphs.size()));
layoutv.emplace("content_blocks", wxString::Format(wxT("%i"), s->layout->blocks.size())); layoutv.emplace("content_blocks", String::Format(wxT("%i"), s->layout->blocks.size()));
boost::json::array separatorsv; boost::json::array separatorsv;
int size = s->layout->separators.size(); int size = s->layout->separators.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
separatorsv.emplace_back(wxString::Format(wxT("%.2f"), s->layout->separators[i])); separatorsv.emplace_back(String::Format(wxT("%.2f"), s->layout->separators[i]));
} }
if (size > 0) layoutv.emplace("content_separators", separatorsv); if (size > 0) layoutv.emplace("content_separators", separatorsv);
@@ -618,28 +647,28 @@ boost::json::object mse_to_json(const StyleP& style) {
stylev.emplace("combine", combine_to_string( s->combine)); stylev.emplace("combine", combine_to_string( s->combine));
stylev.emplace("alignment", alignment_to_string( s->alignment)); stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("direction", direction_to_string( s->direction())); stylev.emplace("direction", direction_to_string( s->direction()));
stylev.emplace("spacing", wxString::Format(wxT("%.2f"), s->spacing())); stylev.emplace("spacing", String::Format(wxT("%.2f"), s->spacing()));
boost::json::object fontv; boost::json::object fontv;
fontv.emplace("name", s->font.name()); fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name()); fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size())); fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight()); fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style()); fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline()); fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough()); fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to)); fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch)); fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color())); fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color())); fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x())); fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y())); fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur())); fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color())); fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius())); fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur())); fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color)); fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags)); fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv); stylev.emplace("font", fontv);
boost::json::object choiceimagesv; boost::json::object choiceimagesv;
@@ -661,23 +690,23 @@ boost::json::object mse_to_json(const StyleP& style) {
boost::json::object fontv; boost::json::object fontv;
fontv.emplace("name", s->font.name()); fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name()); fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size())); fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight()); fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style()); fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline()); fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough()); fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to)); fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch)); fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color())); fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color())); fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x())); fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y())); fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur())); fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color())); fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius())); fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur())); fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color)); fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags)); fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv); stylev.emplace("font", fontv);
boost::json::object choiceimagesv; boost::json::object choiceimagesv;
@@ -694,46 +723,46 @@ boost::json::object mse_to_json(const StyleP& style) {
boost::json::object fontv; boost::json::object fontv;
fontv.emplace("name", s->font.name()); fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name()); fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size())); fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight()); fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style()); fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline()); fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough()); fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to)); fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch)); fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color())); fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color())); fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x())); fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y())); fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur())); fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color())); fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius())); fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur())); fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color)); fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags)); fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv); stylev.emplace("font", fontv);
} }
else if (ColorStyle* s = dynamic_cast<ColorStyle*>(style.get())) { else if (ColorStyle* s = dynamic_cast<ColorStyle*>(style.get())) {
stylev.emplace("field_type", "color"); stylev.emplace("field_type", "color");
stylev.emplace("radius", wxString::Format(wxT("%.2f"), s->radius())); stylev.emplace("radius", String::Format(wxT("%.2f"), s->radius()));
stylev.emplace("left_width", wxString::Format(wxT("%.2f"), s->left_width())); stylev.emplace("left_width", String::Format(wxT("%.2f"), s->left_width()));
stylev.emplace("right_width", wxString::Format(wxT("%.2f"), s->right_width())); stylev.emplace("right_width", String::Format(wxT("%.2f"), s->right_width()));
stylev.emplace("top_width", wxString::Format(wxT("%.2f"), s->top_width())); stylev.emplace("top_width", String::Format(wxT("%.2f"), s->top_width()));
stylev.emplace("bottom_width", wxString::Format(wxT("%.2f"), s->bottom_width())); stylev.emplace("bottom_width", String::Format(wxT("%.2f"), s->bottom_width()));
stylev.emplace("combine", combine_to_string( s->combine)); stylev.emplace("combine", combine_to_string( s->combine));
} }
else if (SymbolStyle* s = dynamic_cast<SymbolStyle*>(style.get())) { else if (SymbolStyle* s = dynamic_cast<SymbolStyle*>(style.get())) {
stylev.emplace("field_type", "symbol"); stylev.emplace("field_type", "symbol");
stylev.emplace("min_aspect_ratio", wxString::Format(wxT("%.2f"), s->min_aspect_ratio)); stylev.emplace("min_aspect_ratio", String::Format(wxT("%.2f"), s->min_aspect_ratio));
stylev.emplace("max_aspect_ratio", wxString::Format(wxT("%.2f"), s->max_aspect_ratio)); stylev.emplace("max_aspect_ratio", String::Format(wxT("%.2f"), s->max_aspect_ratio));
boost::json::array variationsv; boost::json::array variationsv;
int size = s->variations.size(); int size = s->variations.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
boost::json::object variationv; boost::json::object variationv;
variationv.emplace("name", s->variations[i]->name); variationv.emplace("name", s->variations[i]->name);
variationv.emplace("border_radius", wxString::Format(wxT("%.2f"), s->variations[i]->border_radius)); variationv.emplace("border_radius", String::Format(wxT("%.2f"), s->variations[i]->border_radius));
SymbolFilterP filter = s->variations[i]->filter; SymbolFilterP filter = s->variations[i]->filter;
if (SolidFillSymbolFilter* f = dynamic_cast<SolidFillSymbolFilter*>(filter.get())) { if (SolidFillSymbolFilter* f = dynamic_cast<SolidFillSymbolFilter*>(filter.get())) {
variationv.emplace("fill_type", f->fillType()); variationv.emplace("fill_type", f->fillType());
@@ -753,10 +782,10 @@ boost::json::object mse_to_json(const StyleP& style) {
variationv.emplace("fill_color_2", format_color( f->fill_color_2)); variationv.emplace("fill_color_2", format_color( f->fill_color_2));
variationv.emplace("border_color_1", format_color( f->border_color_1)); variationv.emplace("border_color_1", format_color( f->border_color_1));
variationv.emplace("border_color_2", format_color( f->border_color_2)); variationv.emplace("border_color_2", format_color( f->border_color_2));
variationv.emplace("center_x", wxString::Format(wxT("%.2f"), f->center_x)); variationv.emplace("center_x", String::Format(wxT("%.2f"), f->center_x));
variationv.emplace("center_y", wxString::Format(wxT("%.2f"), f->center_y)); variationv.emplace("center_y", String::Format(wxT("%.2f"), f->center_y));
variationv.emplace("end_x", wxString::Format(wxT("%.2f"), f->end_x)); variationv.emplace("end_x", String::Format(wxT("%.2f"), f->end_x));
variationv.emplace("end_y", wxString::Format(wxT("%.2f"), f->end_y)); variationv.emplace("end_y", String::Format(wxT("%.2f"), f->end_y));
} }
variationsv.emplace_back(variationv); variationsv.emplace_back(variationv);
} }
@@ -766,32 +795,32 @@ boost::json::object mse_to_json(const StyleP& style) {
else if (InfoStyle* s = dynamic_cast<InfoStyle*>(style.get())) { else if (InfoStyle* s = dynamic_cast<InfoStyle*>(style.get())) {
stylev.emplace("field_type", "info"); stylev.emplace("field_type", "info");
stylev.emplace("alignment", alignment_to_string( s->alignment)); stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("padding_left", wxString::Format(wxT("%.2f"), s->padding_left)); stylev.emplace("padding_left", String::Format(wxT("%.2f"), s->padding_left));
stylev.emplace("padding_right", wxString::Format(wxT("%.2f"), s->padding_right)); stylev.emplace("padding_right", String::Format(wxT("%.2f"), s->padding_right));
stylev.emplace("padding_top", wxString::Format(wxT("%.2f"), s->padding_top)); stylev.emplace("padding_top", String::Format(wxT("%.2f"), s->padding_top));
stylev.emplace("padding_bottom", wxString::Format(wxT("%.2f"), s->padding_bottom)); stylev.emplace("padding_bottom", String::Format(wxT("%.2f"), s->padding_bottom));
stylev.emplace("background_color", format_color( s->background_color)); stylev.emplace("background_color", format_color( s->background_color));
boost::json::object fontv; boost::json::object fontv;
fontv.emplace("name", s->font.name()); fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name()); fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size())); fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight()); fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style()); fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline()); fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough()); fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to)); fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch)); fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color())); fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color())); fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x())); fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y())); fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur())); fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color())); fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius())); fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur())); fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color)); fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags)); fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv); stylev.emplace("font", fontv);
} }
+3 -3
View File
@@ -18,9 +18,9 @@ using boost::tribool;
// ----------------------------------------------------------------------------- : Reader // ----------------------------------------------------------------------------- : Reader
Reader::Reader(wxInputStream& input, Packaged* package, const String& filename, bool ignore_invalid) Reader::Reader(wxInputStream& input, Packaged* package, const String& filename, bool ignore_invalid, bool suppress_warnings)
: indent(0), expected_indent(0), state(OUTSIDE) : indent(0), expected_indent(0), state(OUTSIDE)
, ignore_invalid(ignore_invalid) , ignore_invalid(ignore_invalid), suppress_warnings(suppress_warnings)
, filename(filename), package(package), line_number(0), previous_line_number(0) , filename(filename), package(package), line_number(0), previous_line_number(0)
, input(input) , input(input)
{ {
@@ -53,7 +53,7 @@ void Reader::warning(const String& msg, int line_number_delta, bool warn_on_prev
} }
void Reader::showWarnings() { void Reader::showWarnings() {
if (!warnings.empty()) { if (!suppress_warnings && !warnings.empty()) {
queue_message(MESSAGE_WARNING, _("Warnings while reading file:\n") + filename + _("\n") + warnings); queue_message(MESSAGE_WARNING, _("Warnings while reading file:\n") + filename + _("\n") + warnings);
warnings.clear(); warnings.clear();
} }
+3 -1
View File
@@ -38,7 +38,7 @@ public:
/** filename is used only for error messages /** filename is used only for error messages
* package is used for looking up included files. * package is used for looking up included files.
*/ */
Reader(wxInputStream& input, Packaged* package = nullptr, const String& filename = _(""), bool ignore_invalid = false); Reader(wxInputStream& input, Packaged* package = nullptr, const String& filename = _(""), bool ignore_invalid = false, bool suppress_warnings = false);
~Reader() { showWarnings(); } ~Reader() { showWarnings(); }
@@ -148,6 +148,8 @@ private:
} state; } state;
/// Should all invalid keys be ignored? /// Should all invalid keys be ignored?
bool ignore_invalid; bool ignore_invalid;
/// Should warnings be emitted?
bool suppress_warnings;
/// Filename for error messages /// Filename for error messages
String filename; String filename;