liblcf
ldb_eventcommand.cpp
Go to the documentation of this file.
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 <string>
11 #include <vector>
12 #include "reader_struct.h"
13 #include "lcf/rpg/eventcommand.h"
14 
15 namespace lcf {
16 
17 template <>
18 struct RawStruct<rpg::EventCommand> {
19  static void ReadLcf(rpg::EventCommand& ref, LcfReader& stream, uint32_t length);
20  static void WriteLcf(const rpg::EventCommand& ref, LcfWriter& stream);
21  static int LcfSize(const rpg::EventCommand& ref, LcfWriter& stream);
22  static void WriteXml(const rpg::EventCommand& ref, XmlWriter& stream);
23  static void BeginXml(rpg::EventCommand& ref, XmlReader& stream);
24 };
25 
26 template <>
27 struct RawStruct<std::vector<rpg::EventCommand> > {
28  static void ReadLcf(std::vector<rpg::EventCommand>& ref, LcfReader& stream, uint32_t length);
29  static void WriteLcf(const std::vector<rpg::EventCommand>& ref, LcfWriter& stream);
30  static int LcfSize(const std::vector<rpg::EventCommand>& ref, LcfWriter& stream);
31  static void WriteXml(const std::vector<rpg::EventCommand>& ref, XmlWriter& stream);
32  static void BeginXml(std::vector<rpg::EventCommand>& ref, XmlReader& stream);
33 };
34 
38 void RawStruct<rpg::EventCommand>::ReadLcf(rpg::EventCommand& event_command, LcfReader& stream, uint32_t /* length */) {
39  stream.Read(event_command.code);
40  if (event_command.code != 0) {
41  stream.Read(event_command.indent);
42  stream.ReadString(event_command.string, stream.ReadInt());
43 
44  auto& param_buf = stream.IntBuffer();
45 
46  param_buf.clear();
47  for (int i = stream.ReadInt(); i > 0; i--) {
48  param_buf.push_back(stream.ReadInt());
49  }
50  if (!param_buf.empty()) {
51  event_command.parameters = DBArray<int32_t>(param_buf.begin(), param_buf.end());
52  }
53  }
54 }
55 
56 void RawStruct<rpg::EventCommand>::WriteLcf(const rpg::EventCommand& event_command, LcfWriter& stream) {
57  stream.Write(event_command.code);
58  stream.Write(event_command.indent);
59  stream.WriteInt(stream.Decode(event_command.string).size());
60  stream.Write(event_command.string);
61  int32_t count = (int32_t)event_command.parameters.size();
62  stream.Write(count);
63  for (int i = 0; i < count; i++)
64  stream.Write(event_command.parameters[i]);
65 }
66 
67 int RawStruct<rpg::EventCommand>::LcfSize(const rpg::EventCommand& event_command, LcfWriter& stream) {
68  int result = 0;
69  result += LcfReader::IntSize(event_command.code);
70  result += LcfReader::IntSize(event_command.indent);
71  result += LcfReader::IntSize(stream.Decode(event_command.string).size());
72  result += stream.Decode(event_command.string).size();
73  int count = event_command.parameters.size();
74  result += LcfReader::IntSize(count);
75  for (int i = 0; i < count; i++)
76  result += LcfReader::IntSize(event_command.parameters[i]);
77  return result;
78 }
79 
80 void RawStruct<rpg::EventCommand>::WriteXml(const rpg::EventCommand& event_command, XmlWriter& stream) {
81  stream.BeginElement("EventCommand");
82  stream.WriteNode("code", event_command.code);
83  stream.WriteNode("indent", event_command.indent);
84  stream.WriteNode("string", event_command.string);
85  stream.WriteNode("parameters", event_command.parameters);
86  stream.EndElement("EventCommand");
87 }
88 
89 class EventCommandXmlHandler : public XmlHandler {
90 private:
91  rpg::EventCommand& ref;
92  enum {
98  } field;
99 public:
100  EventCommandXmlHandler(rpg::EventCommand& ref) : ref(ref), field(None) {}
101  void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
102  if (strcmp(name, "code") == 0)
103  field = Code;
104  else if (strcmp(name, "indent") == 0)
105  field = Indent;
106  else if (strcmp(name, "string") == 0)
107  field = String;
108  else if (strcmp(name, "parameters") == 0)
109  field = Parameters;
110  else {
111  stream.Error("Unrecognized field '%s'", name);
112  field = None;
113  }
114  }
115  void EndElement(XmlReader& /* stream */, const char* /* name */) {
116  field = None;
117  }
118  void CharacterData(XmlReader& /* stream */, const std::string& data) {
119  switch (field) {
120  case None:
121  break;
122  case Code:
123  XmlReader::Read(ref.code, data);
124  break;
125  case Indent:
126  XmlReader::Read(ref.indent, data);
127  break;
128  case String:
129  XmlReader::Read(ref.string, data);
130  break;
131  case Parameters:
132  XmlReader::Read(ref.parameters, data);
133  break;
134  }
135  }
136 };
137 
138 void RawStruct<rpg::EventCommand>::BeginXml(rpg::EventCommand& ref, XmlReader& stream) {
139  stream.SetHandler(new WrapperXmlHandler("EventCommand", new EventCommandXmlHandler(ref)));
140 }
141 
146  std::vector<rpg::EventCommand>& event_commands, LcfReader& stream, uint32_t length) {
147  // Event Commands is a special array
148  // Has no size information. Is terminated by 4 times 0x00.
149  unsigned long startpos = stream.Tell();
150  unsigned long endpos = startpos + length;
151 
152  // Since we don't know the number of event parameters without reading, we store
153  // them all in a temporary buffer and then copy it to EventCommand::parameters.
154  // This prevents extra allocations from repeated calls to push_back().
155  for (;;) {
156  uint8_t ch = (uint8_t)stream.Peek();
157  if (ch == 0) {
158  stream.Seek(4, LcfReader::FromCurrent);
159  break;
160  }
161 
162  if (stream.Tell() >= endpos) {
163  stream.Seek(endpos, LcfReader::FromStart);
164  fprintf(stderr, "Event command corrupted at %" PRIu32 "\n", stream.Tell());
165  for (;;) {
166  // Try finding the real end of the event command (4 0-bytes)
167  int i = 0;
168  for (; i < 4; ++i) {
169  stream.Read(ch);
170 
171  if (ch != 0) {
172  break;
173  }
174  }
175 
176  if (i == 4 || stream.Eof()) {
177  break;
178  }
179  }
180 
181  break;
182  }
183 
184  rpg::EventCommand command;
185  RawStruct<rpg::EventCommand>::ReadLcf(command, stream, 0);
186  event_commands.push_back(command);
187  }
188 }
189 
190 void RawStruct<std::vector<rpg::EventCommand> >::WriteLcf(const std::vector<rpg::EventCommand>& event_commands, LcfWriter& stream) {
191  int count = event_commands.size();
192  for (int i = 0; i < count; i++)
193  RawStruct<rpg::EventCommand>::WriteLcf(event_commands[i], stream);
194  for (int i = 0; i < 4; i++)
195  stream.WriteInt(0);
196 }
197 
198 int RawStruct<std::vector<rpg::EventCommand> >::LcfSize(const std::vector<rpg::EventCommand>& event_commands, LcfWriter& stream) {
199  int result = 0;
200  int count = event_commands.size();
201  for (int i = 0; i < count; i++)
202  result += RawStruct<rpg::EventCommand>::LcfSize(event_commands[i], stream);
203  result += 4;
204  return result;
205 }
206 
207 void RawStruct<std::vector<rpg::EventCommand> >::WriteXml(const std::vector<rpg::EventCommand>& event_commands, XmlWriter& stream) {
208  std::vector<rpg::EventCommand>::const_iterator it;
209  for (it = event_commands.begin(); it != event_commands.end(); it++)
211 }
212 
213 class EventCommandVectorXmlHandler : public XmlHandler {
214 public:
215  EventCommandVectorXmlHandler(std::vector<rpg::EventCommand>& ref) : ref(ref) {}
216 
217  void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
218  if (strcmp(name, "EventCommand") != 0)
219  stream.Error("Expecting %s but got %s", "EventCommand", name);
220  ref.resize(ref.size() + 1);
221  rpg::EventCommand& obj = ref.back();
222  stream.SetHandler(new EventCommandXmlHandler(obj));
223  }
224 private:
225  std::vector<rpg::EventCommand>& ref;
226 };
227 
228 void RawStruct<std::vector<rpg::EventCommand> >::BeginXml(std::vector<rpg::EventCommand>& obj, XmlReader& stream) {
229  stream.SetHandler(new EventCommandVectorXmlHandler(obj));
230 }
231 
232 } //namespace lcf
std::vector< rpg::EventCommand > & ref
void StartElement(XmlReader &stream, const char *name, const char **)
EventCommandVectorXmlHandler(std::vector< rpg::EventCommand > &ref)
EventCommandXmlHandler(rpg::EventCommand &ref)
void EndElement(XmlReader &, const char *)
void CharacterData(XmlReader &, const std::string &data)
void StartElement(XmlReader &stream, const char *name, const char **)
enum lcf::EventCommandXmlHandler::@0 field
Definition: dbarray.cpp:13
static void WriteXml(const T &ref, XmlWriter &stream)
static void BeginXml(T &ref, XmlReader &stream)
static void ReadLcf(T &ref, LcfReader &stream, uint32_t length)
static void WriteLcf(const T &ref, LcfWriter &stream)
static int LcfSize(const T &ref, LcfWriter &stream)