]> git.localhorst.tv Git - l2e.git/blob - src/loader/Loader.cpp
dbfbe3186fdd93e8a508110c082753197778cc3c
[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         } catch (...) {
65                 delete[] block;
66                 throw;
67         }
68         objectFiles.insert(make_pair(filePath, block));
69 }
70
71 void Loader::LoadExports(char *src, Export *begin, Export *end) {
72         for (Export *i = begin; i < end; ++i) {
73                 string identifier(src + i->nameOffset);
74                 LoadedExport &exp(exports[identifier]);
75                 exp.typeId = i->typeId;
76                 exp.location = src + i->dataOffset;
77                 exports.insert(make_pair(identifier, exp));
78         }
79 }
80
81 void Loader::LoadExternals(char *src, External *begin, External *end) {
82         for (External *i = begin; i < end; ++i) {
83                 string identifier(src + i->nameOffset);
84                 map<string, LoadedExport>::const_iterator
85                                 exp(exports.find(identifier));
86                 if (exp == exports.end()) {
87                         throw std::runtime_error("undefined reference to "
88                                         + identifier);
89                 }
90                 const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
91                 char *dest = src + i->referenceOffset;
92                 if (i->inlined) {
93                         std::memcpy(dest, exp->second.location, td.Size());
94                 } else {
95                         std::memcpy(dest, &exp->second.location, sizeof(char *));
96                 }
97         }
98 }
99
100 void Loader::LoadImages(char *src, Image *begin, Image *end) {
101         for (Image *i = begin; i != end; ++i) {
102                 const string path(src + i->pathOffset);
103                 SDL_Surface **dest = reinterpret_cast<SDL_Surface **>(src + i->destOffset);
104                 std::map<string, SDL_Surface *>::const_iterator
105                                 found(images.find(path));
106                 if (found != images.end()) {
107                         *dest = found->second;
108                 } else {
109                         SDL_Surface *loaded = IMG_Load(path.c_str());
110                         images.insert(make_pair(path, loaded));
111                         *dest = loaded;
112                 }
113         }
114 }
115
116 void Loader::LoadObjects(char *src, Object *begin, Object *end) {
117         for (Object *i = begin; i < end; i = i->Next()) {
118                 const TypeDescription &td =
119                                 TypeDescription::Get(i->typeId);
120                 LoadObject(src, i->RawObject(), td);
121         }
122 }
123
124 void Loader::LoadObject(char *src, char *object, const TypeDescription &td) {
125         for (TypeDescription::FieldIterator
126                         i(td.FieldsBegin()), end(td.FieldsEnd());
127                         i != end; ++i) {
128                 const FieldDescription &field = i->second;
129                 if (field.IsReferenced() || field.IsAggregate()) {
130                         char **dest(reinterpret_cast<char **>(object + field.Offset()));
131                         if (*dest) {
132                                 *dest = src + *reinterpret_cast<unsigned int *>(dest);
133                         }
134                 } else {
135                         const TypeDescription &nestedType
136                                         = TypeDescription::Get(field.TypeId());
137                         LoadObject(src, object + field.Offset(), nestedType);
138                 }
139         }
140 }
141
142 void Loader::LoadArrays(char *src, Array *begin, Array *end) {
143         for (Array *i = begin; i < end; i = i->Next()) {
144                 if (i->ref) {
145                         for (char *j = i->Data(), *end = i->Data() + i->size;
146                                         j < end; j += sizeof(void *)) {
147                                 unsigned int offset = *reinterpret_cast<unsigned int *>(j);
148                                 if (offset) {
149                                         *reinterpret_cast<char **>(j) = src + offset;
150                                 }
151                         }
152                 } else {
153                         const TypeDescription &td = TypeDescription::Get(i->typeId);
154                         for (char *j = i->Data(), *end = i->Data() + i->size;
155                                         j < end; j += td.Size()) {
156                                 LoadObject(src, j, td);
157                         }
158                 }
159         }
160 }
161
162 }