Merge lp:~widelands-dev/widelands/json_writer into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8969
Proposed branch: lp:~widelands-dev/widelands/json_writer
Merge into: lp:widelands
Diff against target: 982 lines (+461/-289)
8 files modified
src/website/CMakeLists.txt (+4/-0)
src/website/json/CMakeLists.txt (+10/-0)
src/website/json/json.cc (+138/-0)
src/website/json/json.h (+96/-0)
src/website/json/value.cc (+56/-0)
src/website/json/value.h (+67/-0)
src/website/map_info.cc (+12/-39)
src/website/map_object_info.cc (+78/-250)
To merge this branch: bzr merge lp:~widelands-dev/widelands/json_writer
Reviewer Review Type Date Requested Status
Klaus Halfmann code review Approve
kaputtnik (community) testing Approve
Review via email: mp+357908@code.launchpad.net

Commit message

Refactor website binaries to use a real tree data structure for writing JSON

Description of the change

Getting rid of some spaghetti code. Only affects the website, not Widelands itself.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4173. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/447150251.
Appveyor build 3971. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_json_writer-3971.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4178. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/447958040.
Appveyor build 3976. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_json_writer-3976.

Revision history for this message
kaputtnik (franku) wrote :

LGTM :-)

Successfully tested locally on the website: Upload a map, create Encyclopedia

review: Approve (testing)
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4395. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/478759403.
Appveyor build 4186. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_json_writer-4186.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4401. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/478975042.
Appveyor build 4192. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_json_writer-4192.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Anything I can test for this?

Revision history for this message
GunChleoc (gunchleoc) wrote :

It has already been tested, what's missing is a code review.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

OK, for the Reeview:

This branch substitutes a streaming JSON aproach with a Tree Object model.
Streaming is normally better as of resource usage,
but in this case this does not matter.

If kaputtnik likes it his way, its all fine with me.
(Solange nix kaputt geht ;-)

Please explain which website tools are actually affected.

review: Approve (code review)
Revision history for this message
kaputtnik (franku) wrote :

This affects uploading a map onto the website (wl_map_info) and creating the encyclopedia (wl_map_object_info) https://wl.widelands.org/encyclopedia/

Revision history for this message
GunChleoc (gunchleoc) wrote :

The problem with the streaming was that it's very hacky and hard to read. So, we have sacrificed some efficiency and gained a lot of readability/code stability.

Thanks for the review!

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/website/CMakeLists.txt'
2--- src/website/CMakeLists.txt 2018-08-14 20:42:18 +0000
3+++ src/website/CMakeLists.txt 2019-01-13 09:00:00 +0000
4@@ -1,3 +1,5 @@
5+add_subdirectory(json)
6+
7 wl_library(website_common
8 SRCS
9 website_common.cc
10@@ -23,6 +25,7 @@
11 graphic_surface
12 io_fileread
13 io_filesystem
14+ json
15 logic
16 map_io_map_loader
17 website_common
18@@ -38,6 +41,7 @@
19 graphic
20 io_fileread
21 io_filesystem
22+ json
23 logic
24 logic_tribe_basic_info
25 website_common
26
27=== added directory 'src/website/json'
28=== added file 'src/website/json/CMakeLists.txt'
29--- src/website/json/CMakeLists.txt 1970-01-01 00:00:00 +0000
30+++ src/website/json/CMakeLists.txt 2019-01-13 09:00:00 +0000
31@@ -0,0 +1,10 @@
32+wl_library(json
33+ SRCS
34+ json.cc
35+ json.h
36+ value.cc
37+ value.h
38+ DEPENDS
39+ io_fileread
40+ io_filesystem
41+)
42
43=== added file 'src/website/json/json.cc'
44--- src/website/json/json.cc 1970-01-01 00:00:00 +0000
45+++ src/website/json/json.cc 2019-01-13 09:00:00 +0000
46@@ -0,0 +1,138 @@
47+/*
48+ * Copyright (C) 2018 by the Widelands Development Team
49+ *
50+ * This program is free software; you can redistribute it and/or
51+ * modify it under the terms of the GNU General Public License
52+ * as published by the Free Software Foundation; either version 2
53+ * of the License, or (at your option) any later version.
54+ *
55+ * This program is distributed in the hope that it will be useful,
56+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
57+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58+ * GNU General Public License for more details.
59+ *
60+ * You should have received a copy of the GNU General Public License
61+ * along with this program; if not, write to the Free Software
62+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
63+ *
64+ */
65+
66+#include "website/json/json.h"
67+
68+#include <memory>
69+
70+#include "io/filewrite.h"
71+
72+// ########################## JSON Element #############################
73+
74+namespace JSON {
75+const std::string JSON::Element::tab_ = " ";
76+
77+JSON::Object* Element::add_object(const std::string& key) {
78+ children_.push_back(std::unique_ptr<JSON::Object>(new JSON::Object(key, level_ + 1)));
79+ return dynamic_cast<JSON::Object*>(children_.back().get());
80+}
81+
82+JSON::Array* Element::add_array(const std::string& key) {
83+ children_.push_back(std::unique_ptr<JSON::Array>(new JSON::Array(key, level_ + 1)));
84+ return dynamic_cast<JSON::Array*>(children_.back().get());
85+}
86+
87+void Element::add_bool(const std::string& key, bool value) {
88+ values_.push_back(std::make_pair(key, std::unique_ptr<JSON::Value>(new JSON::Boolean(value))));
89+}
90+
91+void Element::add_double(const std::string& key, double value) {
92+ values_.push_back(std::make_pair(key, std::unique_ptr<JSON::Value>(new JSON::Double(value))));
93+}
94+void Element::add_int(const std::string& key, int value) {
95+ values_.push_back(std::make_pair(key, std::unique_ptr<JSON::Value>(new JSON::Int(value))));
96+}
97+void Element::add_empty(const std::string& key) {
98+ values_.push_back(std::make_pair(key, std::unique_ptr<JSON::Value>(new JSON::Empty())));
99+}
100+void Element::add_string(const std::string& key, const std::string& value) {
101+ values_.push_back(std::make_pair(key, std::unique_ptr<JSON::Value>(new JSON::String(value))));
102+}
103+
104+void Element::write_to_file(FileSystem& fs, const std::string& filename) const {
105+ FileWrite file_writer;
106+ file_writer.text(as_string());
107+ file_writer.write(fs, filename);
108+}
109+
110+std::string Element::as_string() const {
111+ return "{\n" + children_as_string() + "}\n";
112+}
113+
114+std::string Element::values_as_string(const std::string& tabs) const {
115+ std::string result = "";
116+ if (!values_.empty()) {
117+ for (size_t i = 0; i < values_.size() - 1; ++i) {
118+ const auto& element = values_.at(i);
119+ const std::string element_as_string = element.second->as_string();
120+ result +=
121+ tabs + tab_ + key_to_string(element.first, element_as_string.empty()) + element_as_string + ",\n";
122+ }
123+ const auto& element = values_.at(values_.size() - 1);
124+ const std::string element_as_string = element.second->as_string();
125+ result += tabs + tab_ + key_to_string(element.first, element_as_string.empty()) + element_as_string +
126+ (children_.empty() ? "\n" : ",\n");
127+ }
128+ return result;
129+}
130+
131+std::string Element::children_as_string() const {
132+ std::string result = "";
133+ if (!children_.empty()) {
134+ for (size_t i = 0; i < children_.size() - 1; ++i) {
135+ result += children_.at(i)->as_string() + ",\n";
136+ }
137+ result += children_.at(children_.size() - 1)->as_string() + "\n";
138+ }
139+ return result;
140+}
141+
142+std::string Element::key_to_string(const std::string& value, bool value_is_empty) {
143+ return "\"" + value + (value_is_empty ? "\"" : "\": ");
144+}
145+
146+// ########################## JSON Object #############################
147+
148+Object::Object(const std::string& key, int level) : JSON::Element(key, level) {
149+}
150+
151+std::string Object::as_string() const {
152+ std::string result = "";
153+ std::string tabs = "";
154+ for (int i = 0; i < level_; ++i) {
155+ tabs += tab_;
156+ }
157+
158+ result += tabs + (key_.empty() ? "" : key_to_string(key_)) + "{\n";
159+ result += values_as_string(tabs);
160+ result += children_as_string();
161+ result += tabs + "}";
162+ return result;
163+}
164+
165+// ########################## JSON Array #############################
166+
167+Array::Array(const std::string& key, int level) : JSON::Element(key, level) {
168+}
169+
170+std::string Array::as_string() const {
171+ std::string result = "";
172+ std::string tabs = "";
173+ for (int i = 0; i < level_; ++i) {
174+ tabs += tab_;
175+ }
176+
177+ result += tabs + key_to_string(key_) + "[\n";
178+ result += values_as_string(tabs);
179+ result += children_as_string();
180+ result += tabs + "]";
181+ return result;
182+}
183+
184+} // namespace JSON
185
186=== added file 'src/website/json/json.h'
187--- src/website/json/json.h 1970-01-01 00:00:00 +0000
188+++ src/website/json/json.h 2019-01-13 09:00:00 +0000
189@@ -0,0 +1,96 @@
190+/*
191+ * Copyright (C) 2018 by the Widelands Development Team
192+ *
193+ * This program is free software; you can redistribute it and/or
194+ * modify it under the terms of the GNU General Public License
195+ * as published by the Free Software Foundation; either version 2
196+ * of the License, or (at your option) any later version.
197+ *
198+ * This program is distributed in the hope that it will be useful,
199+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
200+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
201+ * GNU General Public License for more details.
202+ *
203+ * You should have received a copy of the GNU General Public License
204+ * along with this program; if not, write to the Free Software
205+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
206+ *
207+ */
208+
209+#ifndef WL_WEBSITE_JSON_JSON_H
210+#define WL_WEBSITE_JSON_JSON_H
211+
212+#include <cassert>
213+#include <memory>
214+#include <string>
215+#include <vector>
216+
217+#include "io/filesystem/filesystem.h"
218+#include "website/json/value.h"
219+
220+namespace JSON {
221+
222+class Array;
223+class Object;
224+
225+class Element {
226+protected:
227+ // Constructor for child node
228+ explicit Element(const std::string& key, int level) : key_(key), level_(level) {
229+ }
230+
231+public:
232+ // Constructor for root node
233+ explicit Element() : JSON::Element("", 0) {
234+ }
235+
236+ JSON::Object* add_object(const std::string& key = "");
237+ JSON::Array* add_array(const std::string& key);
238+ void add_bool(const std::string& key, bool value);
239+ void add_double(const std::string& key, double value);
240+ void add_int(const std::string& key, int value);
241+ void add_empty(const std::string& key);
242+ void add_string(const std::string& key, const std::string& value);
243+
244+ void write_to_file(FileSystem& fs, const std::string& filename) const;
245+
246+ virtual std::string as_string() const;
247+
248+protected:
249+ static const std::string tab_;
250+
251+ std::string values_as_string(const std::string& tabs) const;
252+ std::string children_as_string() const;
253+ static std::string key_to_string(const std::string& value, bool value_is_empty = false);
254+
255+ std::string key_;
256+ const int level_;
257+ std::vector<std::unique_ptr<JSON::Element>> children_;
258+ std::vector<std::pair<std::string, std::unique_ptr<JSON::Value>>> values_;
259+};
260+
261+class Object : public Element {
262+ friend class JSON::Element;
263+
264+protected:
265+ // Constructor for child node
266+ explicit Object(const std::string& key, int level);
267+
268+public:
269+ // Constructor for root node
270+ explicit Object() : JSON::Element("", 0) {
271+ }
272+ std::string as_string() const override;
273+};
274+
275+class Array : public Element {
276+ friend class JSON::Element;
277+protected:
278+ // Constructor for child node
279+ explicit Array(const std::string& key, int level);
280+
281+public:
282+ std::string as_string() const override;
283+};
284+} // namespace JSON
285+#endif // end of include guard: WL_WEBSITE_JSON_JSON_H
286
287=== added file 'src/website/json/value.cc'
288--- src/website/json/value.cc 1970-01-01 00:00:00 +0000
289+++ src/website/json/value.cc 2019-01-13 09:00:00 +0000
290@@ -0,0 +1,56 @@
291+/*
292+ * Copyright (C) 2018 by the Widelands Development Team
293+ *
294+ * This program is free software; you can redistribute it and/or
295+ * modify it under the terms of the GNU General Public License
296+ * as published by the Free Software Foundation; either version 2
297+ * of the License, or (at your option) any later version.
298+ *
299+ * This program is distributed in the hope that it will be useful,
300+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
301+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
302+ * GNU General Public License for more details.
303+ *
304+ * You should have received a copy of the GNU General Public License
305+ * along with this program; if not, write to the Free Software
306+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
307+ *
308+ */
309+
310+#include "website/json/value.h"
311+
312+#include <sstream>
313+
314+namespace JSON {
315+
316+Boolean::Boolean(bool value) : bool_value(value) {
317+}
318+std::string Boolean::as_string() const {
319+ return bool_value ? "true" : "false";
320+}
321+
322+Double::Double(double value) : double_value(value) {
323+}
324+std::string Double::as_string() const {
325+ std::ostringstream strs;
326+ strs << double_value;
327+ return strs.str();
328+}
329+
330+Int::Int(int value) : int_value(value) {}
331+std::string Int::as_string() const {
332+ std::ostringstream strs;
333+ strs << int_value;
334+ return strs.str();
335+}
336+
337+std::string Empty::as_string() const {
338+ return "";
339+}
340+
341+String::String(std::string value) : string_value(value) {}
342+std::string String::as_string() const {
343+ return "\"" + string_value + "\"";
344+}
345+
346+} // namespace JSON
347
348=== added file 'src/website/json/value.h'
349--- src/website/json/value.h 1970-01-01 00:00:00 +0000
350+++ src/website/json/value.h 2019-01-13 09:00:00 +0000
351@@ -0,0 +1,67 @@
352+/*
353+ * Copyright (C) 2018 by the Widelands Development Team
354+ *
355+ * This program is free software; you can redistribute it and/or
356+ * modify it under the terms of the GNU General Public License
357+ * as published by the Free Software Foundation; either version 2
358+ * of the License, or (at your option) any later version.
359+ *
360+ * This program is distributed in the hope that it will be useful,
361+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
362+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
363+ * GNU General Public License for more details.
364+ *
365+ * You should have received a copy of the GNU General Public License
366+ * along with this program; if not, write to the Free Software
367+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
368+ *
369+ */
370+
371+#ifndef WL_WEBSITE_JSON_VALUE_H
372+#define WL_WEBSITE_JSON_VALUE_H
373+
374+#include <string>
375+
376+namespace JSON {
377+
378+/// Value types for JSON
379+struct Value {
380+ Value() = default;
381+ virtual std::string as_string() const = 0;
382+};
383+
384+struct Boolean : Value {
385+ explicit Boolean(bool value);
386+ std::string as_string() const override;
387+private:
388+ const bool bool_value;
389+};
390+
391+struct Double : Value {
392+ explicit Double(double value);
393+ std::string as_string() const override;
394+private:
395+ const double double_value;
396+};
397+
398+struct Empty : Value {
399+ Empty() = default;
400+ std::string as_string() const override;
401+};
402+
403+struct Int : Value {
404+ explicit Int(int value);
405+ std::string as_string() const override;
406+private:
407+ const int int_value;
408+};
409+
410+struct String : Value {
411+ explicit String(std::string value);
412+ std::string as_string() const override;
413+private:
414+ const std::string string_value;
415+};
416+
417+} // namespace JSON
418+#endif // end of include guard: WL_WEBSITE_JSON_VALUE_H
419
420=== modified file 'src/website/map_info.cc'
421--- src/website/map_info.cc 2018-12-13 07:24:01 +0000
422+++ src/website/map_info.cc 2019-01-13 09:00:00 +0000
423@@ -36,6 +36,7 @@
424 #include "logic/editor_game_base.h"
425 #include "logic/map.h"
426 #include "map_io/widelands_map_loader.h"
427+#include "website/json/json.h"
428 #include "website/website_common.h"
429
430 using namespace Widelands;
431@@ -83,48 +84,20 @@
432
433 // Write JSON.
434 {
435- FileWrite fw;
436-
437- const auto write_string = [&fw](const std::string& s) { fw.data(s.c_str(), s.size()); };
438- const auto write_key_value = [&write_string](
439- const std::string& key, const std::string& quoted_value) {
440- write_string((boost::format("\"%s\": %s") % key % quoted_value).str());
441- };
442- const auto write_key_value_string = [&write_key_value](
443- const std::string& key, const std::string& value) {
444- std::string quoted_value = value;
445- boost::replace_all(quoted_value, "\"", "\\\"");
446- write_key_value(key, "\"" + value + "\"");
447- };
448- const auto write_key_value_int = [&write_key_value](
449- const std::string& key, const int value) {
450- write_key_value(key, boost::lexical_cast<std::string>(value));
451- };
452- write_string("{\n ");
453- write_key_value_string("name", map->get_name());
454- write_string(",\n ");
455- write_key_value_string("author", map->get_author());
456- write_string(",\n ");
457- write_key_value_string("description", map->get_description());
458- write_string(",\n ");
459- write_key_value_string("hint", map->get_hint());
460- write_string(",\n ");
461- write_key_value_int("width", map->get_width());
462- write_string(",\n ");
463- write_key_value_int("height", map->get_height());
464- write_string(",\n ");
465- write_key_value_int("nr_players", map->get_nrplayers());
466- write_string(",\n ");
467+ std::unique_ptr<JSON::Object> json(new JSON::Object());
468+ json->add_string("name", map->get_name());
469+ json->add_string("author", map->get_author());
470+ json->add_string("description", map->get_description());
471+ json->add_string("hint", map->get_hint());
472+ json->add_int("width", map->get_width());
473+ json->add_int("height", map->get_height());
474+ json->add_int("nr_players", map->get_nrplayers());
475
476 const std::string world_name =
477 static_cast<Widelands::WidelandsMapLoader*>(ml.get())->old_world_name();
478- write_key_value_string("world_name", world_name);
479- write_string(",\n ");
480- write_key_value_string("minimap", map_path + ".png");
481- write_string("\n");
482-
483- write_string("}\n");
484- fw.write(*in_out_filesystem, (map_file + ".json").c_str());
485+ json->add_string("world_name", world_name);
486+ json->add_string("minimap", map_path + ".png");
487+ json->write_to_file(*in_out_filesystem, (map_file + ".json").c_str());
488 }
489 egbase.cleanup_objects();
490 } catch (std::exception& e) {
491
492=== modified file 'src/website/map_object_info.cc'
493--- src/website/map_object_info.cc 2018-08-14 20:42:18 +0000
494+++ src/website/map_object_info.cc 2019-01-13 09:00:00 +0000
495@@ -35,6 +35,7 @@
496 #include "logic/map_objects/tribes/tribe_basic_info.h"
497 #include "logic/map_objects/tribes/tribes.h"
498 #include "logic/map_objects/world/world.h"
499+#include "website/json/json.h"
500 #include "website/website_common.h"
501
502 using namespace Widelands;
503@@ -43,95 +44,12 @@
504
505 /*
506 ==========================================================
507- SPECIALIZED FILEWRITE
508- ==========================================================
509- */
510-
511-// Defines some convenience writing functions for the JSON format
512-class JSONFileWrite : public FileWrite {
513-public:
514- JSONFileWrite() : FileWrite(), level_(0) {
515- }
516-
517- void write_string(const std::string& s, bool use_indent = false) {
518- std::string writeme = s;
519- if (use_indent) {
520- for (int i = 0; i < level_; ++i) {
521- writeme = (boost::format(" %s") % writeme).str();
522- }
523- }
524- data(writeme.c_str(), writeme.size());
525- }
526- void write_key(const std::string& key) {
527- write_string((boost::format("\"%s\":\n") % key).str(), true);
528- }
529- void write_value_string(const std::string& quoted_value) {
530- write_string((boost::format("\"%s\"") % quoted_value).str(), true);
531- }
532- void write_key_value(const std::string& key, const std::string& quoted_value) {
533- write_string((boost::format("\"%s\": %s") % key % quoted_value).str(), true);
534- }
535- void write_key_value_string(const std::string& key, const std::string& value) {
536- std::string quoted_value = value;
537- boost::replace_all(quoted_value, "\"", "\\\"");
538- write_key_value(key, "\"" + value + "\"");
539- }
540- void write_key_value_int(const std::string& key, const int value) {
541- write_key_value(key, boost::lexical_cast<std::string>(value));
542- }
543- void open_brace() {
544- write_string("{\n", true);
545- ++level_;
546- }
547- // JSON hates a final comma. This defaults to having NO comma.
548- void close_brace(bool precede_newline = false, int current = 0, int total = 0) {
549- --level_;
550- if (precede_newline) {
551- write_string("\n");
552- }
553- if (current < total - 1) {
554- write_string("},\n", true);
555- } else {
556- write_string("}", true);
557- }
558- }
559- void open_array(const std::string& name) {
560- write_string((boost::format("\"%s\":[\n") % name).str(), true);
561- ++level_;
562- }
563- // JSON hates a final comma. This defaults to having NO comma.
564- void close_array(int current = 0, int total = 0) {
565- --level_;
566- write_string("\n");
567- if (current < total - 1) {
568- write_string("],\n", true);
569- } else {
570- write_string("]\n", true);
571- }
572- }
573- // JSON hates a final comma. This defaults to having a comma.
574- void close_element(int current = -2, int total = 0) {
575- if (current < total - 1) {
576- write_string(",\n");
577- }
578- }
579-
580-private:
581- int level_;
582-};
583-
584-/*
585- ==========================================================
586 BUILDINGS
587 ==========================================================
588 */
589
590 void write_buildings(const TribeDescr& tribe, EditorGameBase& egbase, FileSystem* out_filesystem) {
591-
592 log("\n==================\nWriting buildings:\n==================\n");
593- JSONFileWrite fw;
594- fw.open_brace(); // Main
595- fw.open_array("buildings"); // Buildings
596
597 // We don't want any partially finished buildings
598 std::vector<const BuildingDescr*> buildings;
599@@ -143,144 +61,92 @@
600 }
601 }
602
603- // Now write
604+ std::unique_ptr<JSON::Element> json(new JSON::Element());
605+ JSON::Array* json_buildings_array = json->add_array("buildings");
606 for (size_t i = 0; i < buildings.size(); ++i) {
607 const BuildingDescr& building = *buildings[i];
608 log(" %s", building.name().c_str());
609- fw.open_brace(); // Building
610-
611- fw.write_key_value_string("name", building.name());
612- fw.close_element();
613- fw.write_key_value_string("descname", building.descname());
614- fw.close_element();
615- fw.write_key_value_string("icon", building.representative_image_filename());
616- fw.close_element();
617-
618- // Conditional stuff in between, so we won't run into trouble with the commas.
619+
620+ JSON::Object* json_building = json_buildings_array->add_object();
621+ json_building->add_string("name", building.name());
622+ json_building->add_string("descname", building.descname());
623+ json_building->add_string("icon", building.representative_image_filename());
624
625 // Buildcost
626 if (building.is_buildable()) {
627- fw.open_array("buildcost"); // Buildcost
628- size_t buildcost_counter = 0;
629+ JSON::Array* json_builcost_array = json_building->add_array("buildcost");
630 for (WareAmount buildcost : building.buildcost()) {
631 const WareDescr& ware = *tribe.get_ware_descr(buildcost.first);
632- fw.open_brace(); // Buildcost
633- fw.write_key_value_string("name", ware.name());
634- fw.close_element();
635- fw.write_key_value_int("amount", buildcost.second);
636- fw.close_brace(true, buildcost_counter, building.buildcost().size()); // Buildcost
637- ++buildcost_counter;
638+ JSON::Object* json_builcost = json_builcost_array->add_object();
639+ json_builcost->add_string("name", ware.name());
640+ json_builcost->add_int("amount", buildcost.second);
641 }
642- fw.close_array(1, 5); // Buildcost - we need a comma
643 }
644
645 if (building.is_enhanced()) {
646- fw.write_key_value_string(
647+ json_building->add_string(
648 "enhanced", tribe.get_building_descr(building.enhanced_from())->name());
649- fw.close_element();
650 }
651
652 if (building.enhancement() != INVALID_INDEX) {
653- fw.write_key_value_string(
654+ json_building->add_string(
655 "enhancement", tribe.get_building_descr(building.enhancement())->name());
656- fw.close_element();
657 }
658
659 if (upcast(ProductionSiteDescr const, productionsite, &building)) {
660- // Produces
661+ // Produces wares
662 if (productionsite->output_ware_types().size() > 0) {
663- fw.open_array("produced_wares"); // Produces
664- size_t produces_counter = 0;
665+ JSON::Array* json_wares_array = json_building->add_array("produced_wares");
666 for (DescriptionIndex ware_index : productionsite->output_ware_types()) {
667- fw.write_value_string(tribe.get_ware_descr(ware_index)->name());
668- fw.close_element(produces_counter, productionsite->output_ware_types().size());
669- ++produces_counter;
670+ json_wares_array->add_empty(tribe.get_ware_descr(ware_index)->name());
671 }
672- fw.close_array(1, 5); // Produces - we need a comma
673 }
674+ // Produces workers
675 if (productionsite->output_worker_types().size() > 0) {
676- fw.open_array("produced_workers"); // Produces
677- size_t produces_counter = 0;
678+ JSON::Array* json_workers_array = json_building->add_array("produced_workers");
679 for (DescriptionIndex worker_index : productionsite->output_worker_types()) {
680- fw.write_value_string(tribe.get_worker_descr(worker_index)->name());
681- fw.close_element(produces_counter, productionsite->output_worker_types().size());
682- ++produces_counter;
683+ json_workers_array->add_empty(tribe.get_worker_descr(worker_index)->name());
684 }
685- fw.close_array(1, 5); // Produces - we need a comma
686 }
687
688 // Consumes
689 if (productionsite->input_wares().size() > 0) {
690- fw.open_array("stored_wares"); // Consumes
691- size_t consumes_counter = 0;
692+ JSON::Array* json_wares_array = json_building->add_array("stored_wares");
693 for (WareAmount input : productionsite->input_wares()) {
694 const WareDescr& ware = *tribe.get_ware_descr(input.first);
695- fw.open_brace(); // Input
696- fw.write_key_value_string("name", ware.name());
697- fw.close_element();
698- fw.write_key_value_int("amount", input.second);
699- fw.close_brace(
700- true, consumes_counter, productionsite->input_wares().size()); // Input
701- ++consumes_counter;
702+ JSON::Object* json_input = json_wares_array->add_object();
703+ json_input->add_string("name", ware.name());
704+ json_input->add_int("amount", input.second);
705 }
706- fw.close_array(1, 5); // Consumes - we need a comma
707 }
708
709- fw.open_array("workers"); // Workers
710- size_t worker_counter = 0;
711+ // Workers
712+ JSON::Array* json_workers_array = json_building->add_array("workers");
713 for (WareAmount input : productionsite->working_positions()) {
714 const WorkerDescr& worker = *tribe.get_worker_descr(input.first);
715- fw.open_brace(); // Worker
716- fw.write_key_value_string("name", worker.name());
717- fw.close_element();
718- fw.write_key_value_int("amount", input.second);
719- fw.close_brace(
720- true, worker_counter, productionsite->working_positions().size()); // Worker
721- ++worker_counter;
722+ JSON::Object* json_input = json_workers_array->add_object();
723+ json_input->add_string("name", worker.name());
724+ json_input->add_int("amount", input.second);
725 }
726- fw.close_array(1, 5); // Workers - we need a comma
727 } else if (upcast(MilitarySiteDescr const, militarysite, &building)) {
728- fw.write_key_value_int("conquers", militarysite->get_conquers());
729- fw.close_element();
730- fw.write_key_value_int("max_soldiers", militarysite->get_max_number_of_soldiers());
731- fw.close_element();
732- fw.write_key_value_int("heal_per_second", militarysite->get_heal_per_second());
733- fw.close_element();
734+ json_building->add_int("conquers", militarysite->get_conquers());
735+ json_building->add_int("max_soldiers", militarysite->get_max_number_of_soldiers());
736+ json_building->add_int("heal_per_second", militarysite->get_heal_per_second());
737 }
738
739- switch (building.type()) {
740- case MapObjectType::PRODUCTIONSITE:
741- fw.write_key_value_string("type", "productionsite");
742- break;
743- case MapObjectType::WAREHOUSE:
744- fw.write_key_value_string("type", "warehouse");
745- break;
746- case MapObjectType::MARKET:
747- fw.write_key_value_string("type", "market");
748- break;
749- case MapObjectType::MILITARYSITE:
750- fw.write_key_value_string("type", "militarysite");
751- break;
752- case MapObjectType::TRAININGSITE:
753- fw.write_key_value_string("type", "trainingsite");
754- break;
755- default:
756- NEVER_HERE();
757- }
758- fw.close_element();
759+ json_building->add_string("type", to_string(building.type()));
760
761 // Size
762 if (building.type() == MapObjectType::WAREHOUSE && !building.is_buildable() &&
763 !building.is_enhanced()) {
764- fw.write_key_value_string("size", "headquarters");
765+ json_building->add_string("size", "headquarters");
766 } else if (building.get_ismine()) {
767- fw.write_key_value_string("size", "mine");
768+ json_building->add_string("size", "mine");
769 } else if (building.get_isport()) {
770- fw.write_key_value_string("size", "port");
771+ json_building->add_string("size", "port");
772 } else {
773- fw.write_key_value_string("size", BaseImmovable::size_to_string(building.get_size()));
774+ json_building->add_string("size", BaseImmovable::size_to_string(building.get_size()));
775 }
776- fw.close_element();
777
778 // Helptext
779 try {
780@@ -290,16 +156,13 @@
781 cr->push_arg(building.helptext_script());
782 cr->resume();
783 const std::string help_text = cr->pop_string();
784- fw.write_key_value_string("helptext", help_text);
785+ json_building->add_string("helptext", help_text);
786 } catch (LuaError& err) {
787- fw.write_key_value_string("helptext", err.what());
788+ json_building->add_string("helptext", err.what());
789 }
790-
791- fw.close_brace(true, i, buildings.size()); // Building
792 }
793- fw.close_array(); // Buildings
794- fw.close_brace(); // Main
795- fw.write(*out_filesystem, (boost::format("%s_buildings.json") % tribe.name()).str().c_str());
796+
797+ json->write_to_file(*out_filesystem, (boost::format("%s_buildings.json") % tribe.name()).str().c_str());
798 log("\n");
799 }
800
801@@ -311,22 +174,16 @@
802
803 void write_wares(const TribeDescr& tribe, EditorGameBase& egbase, FileSystem* out_filesystem) {
804 log("\n===============\nWriting wares:\n===============\n");
805- JSONFileWrite fw;
806- fw.open_brace(); // Main
807
808- fw.open_array("wares"); // Wares
809- size_t counter = 0;
810- const size_t no_of_wares = tribe.wares().size();
811+ std::unique_ptr<JSON::Element> json(new JSON::Element());
812+ JSON::Array* json_wares_array = json->add_array("wares");
813 for (DescriptionIndex ware_index : tribe.wares()) {
814 const WareDescr& ware = *tribe.get_ware_descr(ware_index);
815 log(" %s", ware.name().c_str());
816- fw.open_brace();
817- fw.write_key_value_string("name", ware.name());
818- fw.close_element();
819- fw.write_key_value_string("descname", ware.descname());
820- fw.close_element();
821- fw.write_key_value_string("icon", ware.icon_filename());
822- fw.close_element();
823+ JSON::Object* json_ware = json_wares_array->add_object();
824+ json_ware->add_string("name", ware.name());
825+ json_ware->add_string("descname", ware.descname());
826+ json_ware->add_string("icon", ware.icon_filename());
827
828 // Helptext
829 try {
830@@ -337,17 +194,13 @@
831 cr->push_arg(ware.helptext_script());
832 cr->resume();
833 const std::string help_text = cr->pop_string();
834- fw.write_key_value_string("helptext", help_text);
835+ json_ware->add_string("helptext", help_text);
836 } catch (LuaError& err) {
837- fw.write_key_value_string("helptext", err.what());
838+ json_ware->add_string("helptext", err.what());
839 }
840- fw.close_brace(true, counter, no_of_wares); // Ware
841- ++counter;
842 }
843- fw.close_array(); // Wares
844
845- fw.close_brace(); // Main
846- fw.write(*out_filesystem, (boost::format("%s_wares.json") % tribe.name()).str().c_str());
847+ json->write_to_file(*out_filesystem, (boost::format("%s_wares.json") % tribe.name()).str().c_str());
848 log("\n");
849 }
850
851@@ -359,22 +212,16 @@
852
853 void write_workers(const TribeDescr& tribe, EditorGameBase& egbase, FileSystem* out_filesystem) {
854 log("\n================\nWriting workers:\n================\n");
855- JSONFileWrite fw;
856- fw.open_brace(); // Main
857
858- fw.open_array("workers"); // Workers
859- size_t counter = 0;
860- const size_t no_of_workers = tribe.workers().size();
861+ std::unique_ptr<JSON::Element> json(new JSON::Element());
862+ JSON::Array* json_workers_array = json->add_array("workers");
863 for (DescriptionIndex worker_index : tribe.workers()) {
864 const WorkerDescr& worker = *tribe.get_worker_descr(worker_index);
865 log(" %s", worker.name().c_str());
866- fw.open_brace();
867- fw.write_key_value_string("name", worker.name());
868- fw.close_element();
869- fw.write_key_value_string("descname", worker.descname());
870- fw.close_element();
871- fw.write_key_value_string("icon", worker.icon_filename());
872- fw.close_element();
873+ JSON::Object* json_worker = json_workers_array->add_object();
874+ json_worker->add_string("name", worker.name());
875+ json_worker->add_string("descname", worker.descname());
876+ json_worker->add_string("icon", worker.icon_filename());
877
878 // Helptext
879 try {
880@@ -384,28 +231,20 @@
881 cr->push_arg(worker.helptext_script());
882 cr->resume();
883 const std::string help_text = cr->pop_string();
884- fw.write_key_value_string("helptext", help_text);
885+ json_worker->add_string("helptext", help_text);
886 } catch (LuaError& err) {
887- fw.write_key_value_string("helptext", err.what());
888+ json_worker->add_string("helptext", err.what());
889 }
890
891 if (worker.becomes() != INVALID_INDEX) {
892- fw.close_element();
893 const WorkerDescr& becomes = *tribe.get_worker_descr(worker.becomes());
894- fw.write_key("becomes");
895- fw.open_brace();
896- fw.write_key_value_string("name", becomes.name());
897- fw.close_element();
898- fw.write_key_value_int("experience", worker.get_needed_experience());
899- fw.close_brace(true);
900+ JSON::Object* json_becomes = json_worker->add_object("becomes");
901+ json_becomes->add_string("name", becomes.name());
902+ json_becomes->add_int("experience", worker.get_needed_experience());
903 }
904- fw.close_brace(true, counter, no_of_workers); // Worker
905- ++counter;
906 }
907- fw.close_array(); // Workers
908
909- fw.close_brace(); // Main
910- fw.write(*out_filesystem, (boost::format("%s_workers.json") % tribe.name()).str().c_str());
911+ json->write_to_file(*out_filesystem, (boost::format("%s_workers.json") % tribe.name()).str().c_str());
912 log("\n");
913 }
914
915@@ -415,22 +254,17 @@
916 ==========================================================
917 */
918
919-void add_tribe_info(const Widelands::TribeBasicInfo& tribe_info, JSONFileWrite* fw) {
920- fw->write_key_value_string("name", tribe_info.name);
921- fw->close_element();
922- fw->write_key_value_string("descname", tribe_info.descname);
923- fw->close_element();
924- fw->write_key_value_string("author", tribe_info.author);
925- fw->close_element();
926- fw->write_key_value_string("tooltip", tribe_info.tooltip);
927- fw->close_element();
928- fw->write_key_value_string("icon", tribe_info.icon);
929+void add_tribe_info(const Widelands::TribeBasicInfo& tribe_info, JSON::Element* json_tribe) {
930+ json_tribe->add_string("name", tribe_info.name);
931+ json_tribe->add_string("descname", tribe_info.descname);
932+ json_tribe->add_string("author", tribe_info.author);
933+ json_tribe->add_string("tooltip", tribe_info.tooltip);
934+ json_tribe->add_string("icon", tribe_info.icon);
935 }
936
937 void write_tribes(EditorGameBase& egbase, FileSystem* out_filesystem) {
938- JSONFileWrite fw;
939- fw.open_brace(); // Main
940- fw.open_array("tribes"); // Tribes
941+ std::unique_ptr<JSON::Element> json(new JSON::Element());
942+ JSON::Array* json_tribes_array = json->add_array("tribes");
943
944 /// Tribes
945 egbase.mutable_tribes()->postload(); // Make sure that all values have been set.
946@@ -442,28 +276,22 @@
947 log("\n\n=========================\nWriting tribe: %s\n=========================\n",
948 tribe_info.name.c_str());
949
950- fw.open_brace(); // TribeDescr
951- add_tribe_info(tribe_info, &fw);
952- fw.close_brace(true, tribe_index, tribeinfos.size()); // TribeDescr
953+ // Main file
954+ JSON::Object* json_tribe = json_tribes_array->add_object();
955+ add_tribe_info(tribe_info, json_tribe);
956
957 // These go in separate files
958-
959- JSONFileWrite fw_tribe;
960- fw_tribe.open_brace(); // TribeDescr
961- add_tribe_info(tribe_info, &fw_tribe);
962- fw_tribe.close_brace(true); // TribeDescr
963- fw_tribe.write(
964- *out_filesystem, (boost::format("tribe_%s.json") % tribe_info.name).str().c_str());
965+ std::unique_ptr<JSON::Object> json_tribe_for_file(new JSON::Object());
966+ add_tribe_info(tribe_info, json_tribe_for_file.get());
967+ json_tribe_for_file->write_to_file(*out_filesystem, (boost::format("tribe_%s.json") % tribe_info.name).str().c_str());
968
969 const TribeDescr& tribe = *tribes.get_tribe_descr(tribes.tribe_index(tribe_info.name));
970-
971 write_buildings(tribe, egbase, out_filesystem);
972 write_wares(tribe, egbase, out_filesystem);
973 write_workers(tribe, egbase, out_filesystem);
974 }
975- fw.close_array(); // Tribes
976- fw.close_brace(); // Main
977- fw.write(*out_filesystem, "tribes.json");
978+
979+ json->write_to_file(*out_filesystem, "tribes.json");
980 }
981
982 } // namespace

Subscribers

People subscribed via source and target branches

to status/vote changes: