liblcf
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 
21 namespace lcf {
22 
23 double 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 
28 std::time_t LSD_Reader::ToUnixTimestamp(double ms) {
29  return(std::time_t(ms * 86400.0 - 25569.0 * 86400.0 + 0.5));
30 }
31 
32 double LSD_Reader::GenerateTimestamp(std::time_t t) {
33  return ToTDateTime(t);
34 }
35 
36 void 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 
43 std::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 
52 bool 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 
61 bool 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 
70 std::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 
79 std::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 
116 bool 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 
138 bool 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 
151 std::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)
Definition: dbarray.cpp:13