1 /*
2 * This file is part of liblcf. Copyright (c) 2021 liblcf authors.
3 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
4 *
5 * liblcf is Free/Libre Open Source Software, released under the MIT License.
6 * For the full copyright and license information, please view the COPYING
7 * file that was distributed with this source code.
8 */
9
10 #include <fstream>
11 #include <cerrno>
12 #include <cstring>
13
14 #include "lcf/ldb/reader.h"
15 #include "lcf/ldb/chunks.h"
16 #include "lcf/reader_util.h"
17 #include "reader_struct.h"
18
19 namespace lcf {
20
PrepareSave(rpg::Database & db)21 void LDB_Reader::PrepareSave(rpg::Database& db) {
22 ++db.system.save_count;
23 }
24
Load(StringView filename,StringView encoding)25 std::unique_ptr<lcf::rpg::Database> LDB_Reader::Load(StringView filename, StringView encoding) {
26 std::ifstream stream(ToString(filename), std::ios::binary);
27 if (!stream.is_open()) {
28 fprintf(stderr, "Failed to open LDB file `%s' for reading : %s\n", ToString(filename).c_str(), strerror(errno));
29 return nullptr;
30 }
31 return LDB_Reader::Load(stream, encoding);
32 }
33
Save(StringView filename,const lcf::rpg::Database & db,StringView encoding,SaveOpt opt)34 bool LDB_Reader::Save(StringView filename, const lcf::rpg::Database& db, StringView encoding, SaveOpt opt) {
35 std::ofstream stream(ToString(filename), std::ios::binary);
36 if (!stream.is_open()) {
37 fprintf(stderr, "Failed to open LDB file `%s' for writing : %s\n", ToString(filename).c_str(), strerror(errno));
38 return false;
39 }
40 return LDB_Reader::Save(stream, db, encoding, opt);
41 }
42
SaveXml(StringView filename,const lcf::rpg::Database & db)43 bool LDB_Reader::SaveXml(StringView filename, const lcf::rpg::Database& db) {
44 std::ofstream stream(ToString(filename), std::ios::binary);
45 if (!stream.is_open()) {
46 fprintf(stderr, "Failed to open LDB XML file `%s' for writing : %s\n", ToString(filename).c_str(), strerror(errno));
47 return false;
48 }
49 return LDB_Reader::SaveXml(stream, db);
50 }
51
LoadXml(StringView filename)52 std::unique_ptr<lcf::rpg::Database> LDB_Reader::LoadXml(StringView filename) {
53 std::ifstream stream(ToString(filename), std::ios::binary);
54 if (!stream.is_open()) {
55 fprintf(stderr, "Failed to open LDB XML file `%s' for reading : %s\n", ToString(filename).c_str(), strerror(errno));
56 return nullptr;
57 }
58 return LDB_Reader::LoadXml(stream);
59 }
60
Load(std::istream & filestream,StringView encoding)61 std::unique_ptr<lcf::rpg::Database> LDB_Reader::Load(std::istream& filestream, StringView encoding) {
62 LcfReader reader(filestream, ToString(encoding));
63 if (!reader.IsOk()) {
64 LcfReader::SetError("Couldn't parse database file.\n");
65 return nullptr;
66 }
67 std::string header;
68 reader.ReadString(header, reader.ReadInt());
69 if (header.length() != 11) {
70 LcfReader::SetError("This is not a valid RPG2000 database.\n");
71 return nullptr;
72 }
73 if (header != "LcfDataBase") {
74 fprintf(stderr, "Warning: This header is not LcfDataBase and might not be a valid RPG2000 database.\n");
75 }
76 auto db = std::make_unique<lcf::rpg::Database>();
77 db->ldb_header = header;
78 TypeReader<rpg::Database>::ReadLcf(*db, reader, 0);
79
80 const auto engine = GetEngineVersion(*db);
81 // Delayed initialization of some actor fields because they are engine
82 // dependent
83 for (auto& actor: db->actors) {
84 actor.Setup(engine == EngineVersion::e2k3);
85 }
86
87 return db;
88 }
89
Save(std::ostream & filestream,const lcf::rpg::Database & db,StringView encoding,SaveOpt opt)90 bool LDB_Reader::Save(std::ostream& filestream, const lcf::rpg::Database& db, StringView encoding, SaveOpt opt) {
91 const auto engine = GetEngineVersion(db);
92 LcfWriter writer(filestream, engine, ToString(encoding));
93 if (!writer.IsOk()) {
94 LcfReader::SetError("Couldn't parse database file.\n");
95 return false;
96 }
97 std::string header;
98 if ( db.ldb_header.empty() || !bool(opt & SaveOpt::ePreserveHeader)) {
99 header = "LcfDataBase";
100 } else {
101 header= db.ldb_header;
102 }
103 writer.WriteInt(header.size());
104 writer.Write(header);
105 TypeReader<rpg::Database>::WriteLcf(db, writer);
106 return true;
107 }
108
SaveXml(std::ostream & filestream,const lcf::rpg::Database & db)109 bool LDB_Reader::SaveXml(std::ostream& filestream, const lcf::rpg::Database& db) {
110 const auto engine = GetEngineVersion(db);
111 XmlWriter writer(filestream, engine);
112 if (!writer.IsOk()) {
113 LcfReader::SetError("Couldn't parse database file.\n");
114 return false;
115 }
116 writer.BeginElement("LDB");
117 TypeReader<rpg::Database>::WriteXml(db, writer);
118 writer.EndElement("LDB");
119 return true;
120 }
121
LoadXml(std::istream & filestream)122 std::unique_ptr<lcf::rpg::Database> LDB_Reader::LoadXml(std::istream& filestream) {
123 XmlReader reader(filestream);
124 if (!reader.IsOk()) {
125 LcfReader::SetError("Couldn't parse database file.\n");
126 return nullptr;;
127 }
128 auto db = std::make_unique<lcf::rpg::Database>();
129 reader.SetHandler(new RootXmlHandler<rpg::Database>(*db, "LDB"));
130 reader.Parse();
131
132 const auto engine = GetEngineVersion(*db);
133 // Delayed initialization of some actor fields because they are engine
134 // dependent
135 for (auto& actor: db->actors) {
136 actor.Setup(engine == EngineVersion::e2k3);
137 }
138
139 return db;
140 }
141
142 } // namespace lcf
143