1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifndef FS_FILELOADER_H_9B663D19E58D42E6BFACFE5B09D7A05E
21#define FS_FILELOADER_H_9B663D19E58D42E6BFACFE5B09D7A05E
22
23#include <limits>
24#include <vector>
25#include <boost/iostreams/device/mapped_file.hpp>
26
27class PropStream;
28
29namespace OTB {
30using MappedFile = boost::iostreams::mapped_file_source;
31using ContentIt = MappedFile::iterator;
32using Identifier = std::array<char, 4>;
33
34struct Node
35{
36 using ChildrenVector = std::vector<Node>;
37
38 ChildrenVector children;
39 ContentIt propsBegin;
40 ContentIt propsEnd;
41 uint8_t type;
42 enum NodeChar: uint8_t
43 {
44 ESCAPE = 0xFD,
45 START = 0xFE,
46 END = 0xFF,
47 };
48};
49
50struct LoadError : std::exception {
51 const char* what() const noexcept override = 0;
52};
53
54struct InvalidOTBFormat final : LoadError {
55 const char* what() const noexcept override {
56 return "Invalid OTBM file format";
57 }
58};
59
60class Loader {
61 MappedFile fileContents;
62 Node root;
63 std::vector<char> propBuffer;
64public:
65 Loader(const std::string& fileName, const Identifier& acceptedIdentifier);
66 bool getProps(const Node& node, PropStream& props);
67 const Node& parseTree();
68};
69
70} //namespace OTB
71
72class PropStream
73{
74 public:
75 void init(const char* a, size_t size) {
76 p = a;
77 end = a + size;
78 }
79
80 size_t size() const {
81 return end - p;
82 }
83
84 template <typename T>
85 bool read(T& ret) {
86 if (size() < sizeof(T)) {
87 return false;
88 }
89
90 memcpy(&ret, p, sizeof(T));
91 p += sizeof(T);
92 return true;
93 }
94
95 bool readString(std::string& ret) {
96 uint16_t strLen;
97 if (!read<uint16_t>(strLen)) {
98 return false;
99 }
100
101 if (size() < strLen) {
102 return false;
103 }
104
105 char* str = new char[strLen + 1];
106 memcpy(str, p, strLen);
107 str[strLen] = 0;
108 ret.assign(str, strLen);
109 delete[] str;
110 p += strLen;
111 return true;
112 }
113
114 bool skip(size_t n) {
115 if (size() < n) {
116 return false;
117 }
118
119 p += n;
120 return true;
121 }
122
123 private:
124 const char* p = nullptr;
125 const char* end = nullptr;
126};
127
128class PropWriteStream
129{
130 public:
131 PropWriteStream() = default;
132
133 // non-copyable
134 PropWriteStream(const PropWriteStream&) = delete;
135 PropWriteStream& operator=(const PropWriteStream&) = delete;
136
137 const char* getStream(size_t& size) const {
138 size = buffer.size();
139 return buffer.data();
140 }
141
142 void clear() {
143 buffer.clear();
144 }
145
146 template <typename T>
147 void write(T add) {
148 char* addr = reinterpret_cast<char*>(&add);
149 std::copy(addr, addr + sizeof(T), std::back_inserter(buffer));
150 }
151
152 void writeString(const std::string& str) {
153 size_t strLength = str.size();
154 if (strLength > std::numeric_limits<uint16_t>::max()) {
155 write<uint16_t>(0);
156 return;
157 }
158
159 write(static_cast<uint16_t>(strLength));
160 std::copy(str.begin(), str.end(), std::back_inserter(buffer));
161 }
162
163 private:
164 std::vector<char> buffer;
165};
166
167#endif
168