]> git.localhorst.tv Git - l2e.git/blob - src/loader/Loader.cpp
961ec7cff6d315dec5537338fe08ba8cfc0b9450
[l2e.git] / src / loader / Loader.cpp
1 #include "Loader.h"
2
3 #include <climits>
4 #include <cstring>
5 #include <fstream>
6 #include <stdexcept>
7 #include <utility>
8 #include <SDL_image.h>
9
10 using std::make_pair;
11 using std::map;
12 using std::string;
13 using std::vector;
14
15 namespace loader {
16
17 Loader::~Loader() {
18         for(map<string, char *>::const_iterator
19                         i(objectFiles.begin()), end(objectFiles.end());
20                         i != end; ++i) {
21                 delete[] i->second;
22         }
23 }
24
25
26 void Loader::Load(const std::string &filePath) {
27         std::ifstream file(filePath.c_str());
28         file.seekg(0, std::ios::end);
29         int fileLength(file.tellg());
30         int length(fileLength + 15);
31
32         char *block = new char[length];
33         ObjectFileHeader *header =
34                         reinterpret_cast<ObjectFileHeader *>(block);
35
36         unsigned long padding =
37                         reinterpret_cast<unsigned long>(block) % 16;
38         if (padding) {
39                 header = reinterpret_cast<ObjectFileHeader *>(
40                                 block + (16 - padding));
41         }
42
43         file.seekg(0, std::ios::beg);
44         file.read(reinterpret_cast<char *>(header), fileLength);
45
46         try {
47                 header->IntegrityCheck(fileLength);
48
49                 LoadExports(header->ident,
50                                 header->ExportsBegin(),
51                                 header->ExportsEnd());
52                 LoadExternals(header->ident,
53                                 header->ExternalsBegin(),
54                                 header->ExternalsEnd());
55                 LoadObjects(header->ident,
56                                 header->ObjectsBegin(),
57                                 header->ObjectsEnd());
58                 LoadArrays(header->ident,
59                                 header->ArraysBegin(),
60                                 header->ArraysEnd());
61                 LoadImages(header->ident,
62                                 header->ImagesBegin(),
63                                 header->ImagesEnd());
64
65                 InitObjects(
66                                 header->ObjectsBegin(),
67                                 header->ObjectsEnd());
68                 InitArrays(
69                                 header->ArraysBegin(),
70                                 header->ArraysEnd());
71         } catch (...) {
72                 delete[] block;
73                 throw;
74         }
75         objectFiles.insert(make_pair(filePath, block));
76 }
77
78 void Loader::LoadExports(char *src, Export *begin, Export *end) {
79         for (Export *i = begin; i < end; ++i) {
80                 string identifier(src + i->nameOffset);
81                 LoadedExport &exp(exports[identifier]);
82                 exp.typeId = i->typeId;
83                 exp.location = src + i->dataOffset;
84                 exports.insert(make_pair(identifier, exp));
85         }
86 }
87
88 void Loader::LoadExternals(char *src, External *begin, External *end) {
89         for (External *i = begin; i < end; ++i) {
90                 string identifier(src + i->nameOffset);
91                 map<string, LoadedExport>::const_iterator
92                                 exp(exports.find(identifier));
93                 if (exp == exports.end()) {
94                         throw std::runtime_error("undefined reference to "
95                                         + identifier);
96                 }
97                 const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
98                 char *dest = src + i->referenceOffset;
99                 if (i->inlined) {
100                         std::memcpy(dest, exp->second.location, td.Size());
101                 } else {
102                         std::memcpy(dest, &exp->second.location, sizeof(char *));
103                 }
104         }
105 }
106
107 void Loader::LoadImages(char *src, Image *begin, Image *end) {
108         for (Image *i = begin; i != end; ++i) {
109                 const string path(src + i->pathOffset);
110                 SDL_Surface **dest = reinterpret_cast<SDL_Surface **>(src + i->destOffset);
111                 std::map<string, SDL_Surface *>::const_iterator
112                                 found(images.find(path));
113                 if (found != images.end()) {
114                         *dest = found->second;
115                 } else {
116                         SDL_Surface *loaded = IMG_Load(path.c_str());
117                         images.insert(make_pair(path, loaded));
118                         *dest = loaded;
119                 }
120         }
121 }
122
123 void Loader::LoadObjects(char *src, Object *begin, Object *end) {
124         for (Object *i = begin; i < end; i = i->Next()) {
125                 const TypeDescription &td =
126                                 TypeDescription::Get(i->typeId);
127                 LoadObject(src, i->RawObject(), td);
128         }
129 }
130
131 void Loader::LoadObject(char *src, char *object, const TypeDescription &td) {
132         for (TypeDescription::FieldIterator
133                         i(td.FieldsBegin()), end(td.FieldsEnd());
134                         i != end; ++i) {
135                 const FieldDescription &field = i->second;
136                 if (field.IsReferenced() || field.IsAggregate()) {
137                         char **dest(reinterpret_cast<char **>(object + field.Offset()));
138                         if (*dest) {
139                                 *dest = src + *reinterpret_cast<unsigned int *>(dest);
140                         }
141                 } else {
142                         const TypeDescription &nestedType
143                                         = TypeDescription::Get(field.TypeId());
144                         LoadObject(src, object + field.Offset(), nestedType);
145                 }
146         }
147 }
148
149 void Loader::LoadArrays(char *src, Array *begin, Array *end) {
150         for (Array *i = begin; i < end; i = i->Next()) {
151                 if (i->ref) {
152                         for (char *j = i->Data(), *end = i->Data() + i->size;
153                                         j < end; j += sizeof(void *)) {
154                                 unsigned int offset = *reinterpret_cast<unsigned int *>(j);
155                                 if (offset) {
156                                         *reinterpret_cast<char **>(j) = src + offset;
157                                 }
158                         }
159                 } else {
160                         const TypeDescription &td = TypeDescription::Get(i->typeId);
161                         for (char *j = i->Data(), *end = i->Data() + i->size;
162                                         j < end; j += td.Size()) {
163                                 LoadObject(src, j, td);
164                         }
165                 }
166         }
167 }
168
169
170 void Loader::InitObjects(Object *begin, Object *end) {
171         for (Object *i = begin; i < end; i = i->Next()) {
172                 const TypeDescription &td =
173                                 TypeDescription::Get(i->typeId);
174                 InitObject(i->RawObject(), td);
175         }
176 }
177
178 void Loader::InitObject(char *object, const TypeDescription &td) {
179         td.Init(object);
180         td.Load(object);
181         for (TypeDescription::FieldIterator
182                         i(td.FieldsBegin()), end(td.FieldsEnd());
183                         i != end; ++i) {
184                 const FieldDescription &field = i->second;
185                 if (field.IsReferenced() || field.IsAggregate()) {
186                         continue;
187                 }
188                 const TypeDescription &nestedType
189                                 = TypeDescription::Get(field.TypeId());
190                 InitObject(object + field.Offset(), nestedType);
191         }
192 }
193
194 void Loader::InitArrays(Array *begin, Array *end) {
195         for (Array *i = begin; i < end; i = i->Next()) {
196                 if (i->ref) {
197                         continue;
198                 }
199                 const TypeDescription &td = TypeDescription::Get(i->typeId);
200                 for (char *j = i->Data(), *end = i->Data() + i->size;
201                                 j < end; j += td.Size()) {
202                         InitObject(j, td);
203                 }
204         }
205 }
206
207 }