]> git.localhorst.tv Git - l2e.git/blob - src/loader/Loader.cpp
ba5dcc066d2b6c941534eb1160f57ded7106b74a
[l2e.git] / src / loader / Loader.cpp
1 #include "Loader.h"
2
3 #include <climits>
4 #include <cstring>
5 #include <fstream>
6 #include <ostream>
7 #include <stdexcept>
8 #include <utility>
9 #include <SDL_image.h>
10
11 using std::endl;
12 using std::make_pair;
13 using std::map;
14 using std::ostream;
15 using std::string;
16 using std::vector;
17
18 namespace loader {
19
20 Loader::~Loader() {
21         for(map<string, char *>::const_iterator
22                         i(objectFiles.begin()), end(objectFiles.end());
23                         i != end; ++i) {
24                 delete[] i->second;
25         }
26 }
27
28
29 void Loader::Load(const std::string &filePath) {
30         std::ifstream file(filePath.c_str());
31         file.seekg(0, std::ios::end);
32         int fileLength(file.tellg());
33         int length(fileLength + 15);
34
35         char *block = new char[length];
36         ObjectFileHeader *header =
37                         reinterpret_cast<ObjectFileHeader *>(block);
38
39         unsigned long padding =
40                         reinterpret_cast<unsigned long>(block) % 16;
41         if (padding) {
42                 header = reinterpret_cast<ObjectFileHeader *>(
43                                 block + (16 - padding));
44         }
45
46         file.seekg(0, std::ios::beg);
47         file.read(reinterpret_cast<char *>(header), fileLength);
48
49         try {
50                 header->IntegrityCheck(fileLength);
51
52                 LoadExports(header->ident,
53                                 header->ExportsBegin(),
54                                 header->ExportsEnd());
55                 LoadExternals(header->ident,
56                                 header->ExternalsBegin(),
57                                 header->ExternalsEnd());
58                 LoadObjects(header->ident,
59                                 header->ObjectsBegin(),
60                                 header->ObjectsEnd());
61                 LoadArrays(header->ident,
62                                 header->ArraysBegin(),
63                                 header->ArraysEnd());
64                 LoadImages(header->ident,
65                                 header->ImagesBegin(),
66                                 header->ImagesEnd());
67
68                 InitObjects(
69                                 header->ObjectsBegin(),
70                                 header->ObjectsEnd());
71                 InitArrays(
72                                 header->ArraysBegin(),
73                                 header->ArraysEnd());
74         } catch (...) {
75                 delete[] block;
76                 throw;
77         }
78         objectFiles.insert(make_pair(filePath, block));
79
80         if (objectFiles.size() > 1) {
81                 for (std::vector<MissingExternal>::iterator
82                                 i(unlinked.begin()); i != unlinked.end();) {
83                         std::map<string, LoadedExport>::const_iterator
84                                         found(exports.find(i->identifier));
85                         if (found != exports.end()) {
86                                 LinkExternal(*i, found->second);
87                                 i = unlinked.erase(i);
88                         } else {
89                                 ++i;
90                         }
91                 }
92         }
93 }
94
95 void Loader::LinkExternal(
96                 const MissingExternal &ext,
97                 const LoadedExport &exp) {
98         if (ext.typeId != exp.typeId) {
99                 throw std::runtime_error("casting not implemented in loader");
100         }
101         const TypeDescription &td = TypeDescription::Get(ext.typeId);
102         if (ext.inlined) {
103                 std::memcpy(ext.dest, exp.location, td.Size());
104         } else {
105                 std::memcpy(ext.dest, &exp.location, sizeof(void *));
106         }
107 }
108
109 void Loader::LoadExports(char *src, Export *begin, Export *end) {
110         for (Export *i = begin; i < end; ++i) {
111                 string identifier(src + i->nameOffset);
112                 LoadedExport &exp(exports[identifier]);
113                 exp.typeId = i->typeId;
114                 exp.location = src + i->dataOffset;
115                 exports.insert(make_pair(identifier, exp));
116         }
117 }
118
119 void Loader::LoadExternals(char *src, External *begin, External *end) {
120         for (External *i = begin; i < end; ++i) {
121                 string identifier(src + i->nameOffset);
122                 char *dest = src + i->referenceOffset;
123
124                 map<string, LoadedExport>::const_iterator
125                                 exp(exports.find(identifier));
126                 if (exp == exports.end()) {
127                         MissingExternal m;
128                         m.identifier = identifier;
129                         m.dest = dest;
130                         m.typeId = i->typeId;
131                         m.inlined = i->inlined;
132                         unlinked.push_back(m);
133                 } else {
134                         const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
135                         if (i->inlined) {
136                                 std::memcpy(dest, exp->second.location, td.Size());
137                         } else {
138                                 std::memcpy(dest, &exp->second.location, sizeof(char *));
139                         }
140                 }
141         }
142 }
143
144 void Loader::LoadImages(char *src, Image *begin, Image *end) {
145         for (Image *i = begin; i != end; ++i) {
146                 const string path(src + i->pathOffset);
147                 SDL_Surface **dest = reinterpret_cast<SDL_Surface **>(src + i->destOffset);
148                 std::map<string, SDL_Surface *>::const_iterator
149                                 found(images.find(path));
150                 if (found != images.end()) {
151                         *dest = found->second;
152                 } else {
153                         SDL_Surface *loaded = IMG_Load(path.c_str());
154                         images.insert(make_pair(path, loaded));
155                         *dest = loaded;
156                 }
157         }
158 }
159
160 void Loader::LoadObjects(char *src, Object *begin, Object *end) {
161         for (Object *i = begin; i < end; i = i->Next()) {
162                 const TypeDescription &td =
163                                 TypeDescription::Get(i->typeId);
164                 LoadObject(src, i->RawObject(), td);
165         }
166 }
167
168 void Loader::LoadObject(char *src, char *object, const TypeDescription &td) {
169         for (TypeDescription::FieldIterator
170                         i(td.FieldsBegin()), end(td.FieldsEnd());
171                         i != end; ++i) {
172                 const FieldDescription &field = i->second;
173                 if (field.IsReferenced() || field.IsAggregate()) {
174                         char **dest(reinterpret_cast<char **>(object + field.Offset()));
175                         if (*dest) {
176                                 *dest = src + *reinterpret_cast<unsigned int *>(dest);
177                         }
178                 } else {
179                         const TypeDescription &nestedType
180                                         = TypeDescription::Get(field.TypeId());
181                         LoadObject(src, object + field.Offset(), nestedType);
182                 }
183         }
184 }
185
186 void Loader::LoadArrays(char *src, Array *begin, Array *end) {
187         for (Array *i = begin; i < end; i = i->Next()) {
188                 if (i->ref) {
189                         for (char *j = i->Data(), *end = i->Data() + i->size;
190                                         j < end; j += sizeof(void *)) {
191                                 unsigned int offset = *reinterpret_cast<unsigned int *>(j);
192                                 if (offset) {
193                                         *reinterpret_cast<char **>(j) = src + offset;
194                                 }
195                         }
196                 } else {
197                         const TypeDescription &td = TypeDescription::Get(i->typeId);
198                         for (char *j = i->Data(), *end = i->Data() + i->size;
199                                         j < end; j += td.Size()) {
200                                 LoadObject(src, j, td);
201                         }
202                 }
203         }
204 }
205
206
207 void Loader::InitObjects(Object *begin, Object *end) {
208         for (Object *i = begin; i < end; i = i->Next()) {
209                 const TypeDescription &td =
210                                 TypeDescription::Get(i->typeId);
211                 InitObject(i->RawObject(), td);
212         }
213 }
214
215 void Loader::InitObject(char *object, const TypeDescription &td) {
216         td.Init(object);
217         td.Load(object);
218         for (TypeDescription::FieldIterator
219                         i(td.FieldsBegin()), end(td.FieldsEnd());
220                         i != end; ++i) {
221                 const FieldDescription &field = i->second;
222                 if (field.IsReferenced() || field.IsAggregate()) {
223                         continue;
224                 }
225                 const TypeDescription &nestedType
226                                 = TypeDescription::Get(field.TypeId());
227                 InitObject(object + field.Offset(), nestedType);
228         }
229 }
230
231 void Loader::InitArrays(Array *begin, Array *end) {
232         for (Array *i = begin; i < end; i = i->Next()) {
233                 if (i->ref) {
234                         continue;
235                 }
236                 const TypeDescription &td = TypeDescription::Get(i->typeId);
237                 for (char *j = i->Data(), *end = i->Data() + i->size;
238                                 j < end; j += td.Size()) {
239                         InitObject(j, td);
240                 }
241         }
242 }
243
244
245 ostream &Loader::Dump(ostream &out) const {
246         out << "loaded objects" << endl;
247         out << "==============" << endl;
248
249         out << objectFiles.size() << " object files" << endl;
250         for (std::map<string, char *>::const_iterator
251                         i(objectFiles.begin()), end(objectFiles.end());
252                         i != end; ++i) {
253                 out << " - " << i->first << endl;
254         }
255
256         out << exports.size() << " exports" << endl;
257         for (std::map<string, LoadedExport>::const_iterator
258                         i(exports.begin()), end(exports.end());
259                         i != end; ++i) {
260                 const TypeDescription &td = TypeDescription::Get(i->second.typeId);
261                 out << " - " << td.TypeName() << ' ' << i->first << endl;
262         }
263
264         out << images.size() << " images" << endl;
265         for (std::map<string, SDL_Surface *>::const_iterator
266                         i(images.begin()), end(images.end());
267                         i != end; ++i) {
268                 out << " - " << i->first << endl;
269         }
270
271         out << unlinked.size() << " missing objects" << endl;
272         for (std::vector<MissingExternal>::const_iterator
273                         i(unlinked.begin()), end(unlinked.end());
274                         i != end; ++i) {
275                 const TypeDescription &td = TypeDescription::Get(
276                                 i->typeId);
277                 out << " - " << td.TypeName() << ' ';
278                 if (!i->inlined) {
279                         out << '*';
280                 }
281                 out << i->identifier << endl;
282         }
283
284         return out;
285 }
286
287 }