liblcf
Loading...
Searching...
No Matches
lsd_reader.cpp
Go to the documentation of this file.
1/*
2 * This file is part of liblcf. Copyright (c) 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 <cmath>
11#include <fstream>
12#include <cerrno>
13#include <cstring>
14
15#include "lcf/lsd/reader.h"
16#include "lcf/lsd/chunks.h"
17#include "lcf/rpg/save.h"
18#include "lcf/reader_util.h"
19#include "reader_struct.h"
20
21namespace lcf {
22
23double LSD_Reader::ToTDateTime(std::time_t t) {
24 // 25569 is UnixDateDelta: number of days between 1970-01-01 and 1900-01-01
25 return(t / 86400.0 + 25569.0);
26}
27
28std::time_t LSD_Reader::ToUnixTimestamp(double ms) {
29 return(std::time_t(ms * 86400.0 - 25569.0 * 86400.0 + 0.5));
30}
31
32double LSD_Reader::GenerateTimestamp(std::time_t t) {
33 return ToTDateTime(t);
34}
35
36void LSD_Reader::PrepareSave(rpg::Save& save, int32_t version, int32_t codepage) {
37 ++save.system.save_count;
38 save.title.timestamp = LSD_Reader::GenerateTimestamp();
39 save.easyrpg_data.version = version;
40 save.easyrpg_data.codepage = codepage;
41}
42
43std::unique_ptr<rpg::Save> LSD_Reader::Load(StringView filename, StringView encoding) {
44 std::ifstream stream(ToString(filename), std::ios::binary);
45 if (!stream.is_open()) {
46 fprintf(stderr, "Failed to open LSD file `%s' for reading : %s\n", ToString(filename).c_str(), strerror(errno));
47 return nullptr;
48 }
49 return LSD_Reader::Load(stream, encoding);
50}
51
52bool LSD_Reader::Save(StringView filename, const rpg::Save& save, EngineVersion engine, StringView encoding) {
53 std::ofstream stream(ToString(filename), std::ios::binary);
54 if (!stream.is_open()) {
55 fprintf(stderr, "Failed to open LSD file `%s' for writing : %s\n", ToString(filename).c_str(), strerror(errno));
56 return false;
57 }
58 return LSD_Reader::Save(stream, save, engine, encoding);
59}
60
61bool LSD_Reader::SaveXml(StringView filename, const rpg::Save& save, EngineVersion engine) {
62 std::ofstream stream(ToString(filename), std::ios::binary);
63 if (!stream.is_open()) {
64 fprintf(stderr, "Failed to open LSD XML file `%s' for writing : %s\n", ToString(filename).c_str(), strerror(errno));
65 return false;
66 }
67 return LSD_Reader::SaveXml(stream, save, engine);
68}
69
70std::unique_ptr<rpg::Save> LSD_Reader::LoadXml(StringView filename) {
71 std::ifstream stream(ToString(filename), std::ios::binary);
72 if (!stream.is_open()) {
73 fprintf(stderr, "Failed to open LSD XML file `%s' for reading : %s\n", ToString(filename).c_str(), strerror(errno));
74 return nullptr;
75 }
76 return LSD_Reader::LoadXml(stream);
77}
78
79std::unique_ptr<rpg::Save> LSD_Reader::Load(std::istream& filestream, StringView encoding) {
80 LcfReader reader(filestream, ToString(encoding));
81
82 if (!reader.IsOk()) {
83 LcfReader::SetError("Couldn't parse save file.\n");
84 return std::unique_ptr<rpg::Save>();
85 }
86 std::string header;
87 reader.ReadString(header, reader.ReadInt());
88 if (header.length() != 11) {
89 LcfReader::SetError("This is not a valid RPG2000 save.\n");
90 return std::unique_ptr<rpg::Save>();
91 }
92 if (header != "LcfSaveData") {
93 fprintf(stderr, "Warning: This header is not LcfSaveData and might not be a valid RPG2000 save.\n");
94 }
95
96 auto pos = reader.Tell();
97
98 std::unique_ptr<rpg::Save> save(new rpg::Save());
99 Struct<rpg::Save>::ReadLcf(*save, reader);
100
101 if (save->easyrpg_data.codepage > 0) {
102 filestream.clear();
103 filestream.seekg(pos, std::ios_base::beg);
104 LcfReader reader2(filestream, std::to_string(save->easyrpg_data.codepage));
105 if (!reader2.IsOk()) {
106 LcfReader::SetError("Couldn't parse save file.\n");
107 return std::unique_ptr<rpg::Save>();
108 }
109 save.reset(new rpg::Save());
110 Struct<rpg::Save>::ReadLcf(*save, reader2);
111 }
112
113 return save;
114}
115
116bool LSD_Reader::Save(std::ostream& filestream, const rpg::Save& save, EngineVersion engine, StringView encoding) {
117 std::string enc;
118
119 if (save.easyrpg_data.codepage > 0) {
120 enc = std::to_string(save.easyrpg_data.codepage);
121 } else {
122 enc = ToString(encoding);
123 }
124
125 LcfWriter writer(filestream, engine, enc);
126 if (!writer.IsOk()) {
127 LcfReader::SetError("Couldn't parse save file.\n");
128 return false;
129 }
130 const std::string header("LcfSaveData");
131 writer.WriteInt(header.size());
132 writer.Write(header);
133
134 Struct<rpg::Save>::WriteLcf(save, writer);
135 return true;
136}
137
138bool LSD_Reader::SaveXml(std::ostream& filestream, const rpg::Save& save, EngineVersion engine) {
139 XmlWriter writer(filestream, engine);
140 if (!writer.IsOk()) {
141 LcfReader::SetError("Couldn't parse save file.\n");
142 return false;
143 }
144
145 writer.BeginElement("LSD");
146 Struct<rpg::Save>::WriteXml(save, writer);
147 writer.EndElement("LSD");
148 return true;
149}
150
151std::unique_ptr<rpg::Save> LSD_Reader::LoadXml(std::istream& filestream) {
152 XmlReader reader(filestream);
153 if (!reader.IsOk()) {
154 LcfReader::SetError("Couldn't parse save file.\n");
155 return std::unique_ptr<rpg::Save>();
156 }
157
158 rpg::Save* save = new rpg::Save();
159 reader.SetHandler(new RootXmlHandler<rpg::Save>(*save, "LSD"));
160 reader.Parse();
161 return std::unique_ptr<rpg::Save>(save);
162}
163
164} //namespace lcf
static void WriteXml(const S &obj, XmlWriter &stream)
static void WriteLcf(const S &obj, LcfWriter &stream)
static void ReadLcf(S &obj, LcfReader &stream)