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