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