]> git.localhorst.tv Git - l2e.git/blob - src/loader/Loader.cpp
1e0050dbc022a64c1d7896428caad0b152dac2f0
[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
9 using std::make_pair;
10 using std::map;
11 using std::string;
12 using std::vector;
13
14 namespace loader {
15
16 Loader::~Loader() {
17         for(map<string, char *>::const_iterator
18                         i(objectFiles.begin()), end(objectFiles.end());
19                         i != end; ++i) {
20                 delete[] i->second;
21         }
22 }
23
24
25 void Loader::Load(const std::string &filePath) {
26         std::ifstream file(filePath.c_str());
27         file.seekg(0, std::ios::end);
28         int fileLength(file.tellg());
29         int length(fileLength + 15);
30
31         char *block = new char[length];
32         ObjectFileHeader *header =
33                         reinterpret_cast<ObjectFileHeader *>(block);
34
35         unsigned long padding =
36                         reinterpret_cast<unsigned long>(block) % 16;
37         if (padding) {
38                 header = reinterpret_cast<ObjectFileHeader *>(
39                                 block + (16 - padding));
40         }
41
42         file.seekg(0, std::ios::beg);
43         file.read(reinterpret_cast<char *>(header), fileLength);
44
45         try {
46                 header->IntegrityCheck(fileLength);
47
48                 LoadExports(header->ident,
49                                 header->ExportsBegin(),
50                                 header->ExportsEnd());
51                 LoadExternals(header->ident,
52                                 header->ExternalsBegin(),
53                                 header->ExternalsEnd());
54                 LoadObjects(header->ident,
55                                 header->ObjectsBegin(),
56                                 header->ObjectsEnd());
57                 LoadArrays(header->ident,
58                                 header->ArraysBegin(),
59                                 header->ArraysEnd());
60         } catch (...) {
61                 delete[] block;
62                 throw;
63         }
64         objectFiles.insert(make_pair(filePath, block));
65 }
66
67 void Loader::LoadExports(char *src, Export *begin, Export *end) {
68         for (Export *i = begin; i < end; ++i) {
69                 string identifier(src + i->nameOffset);
70                 LoadedExport &exp(exports[identifier]);
71                 exp.typeId = i->typeId;
72                 exp.location = src + i->dataOffset;
73                 exports.insert(make_pair(identifier, exp));
74         }
75 }
76
77 void Loader::LoadExternals(char *src, External *begin, External *end) {
78         for (External *i = begin; i < end; ++i) {
79                 string identifier(src + i->nameOffset);
80                 map<string, LoadedExport>::const_iterator
81                                 exp(exports.find(identifier));
82                 if (exp == exports.end()) {
83                         throw std::runtime_error("undefined reference to "
84                                         + identifier);
85                 }
86                 const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
87                 char *dest = src + i->referenceOffset;
88                 if (i->inlined) {
89                         std::memcpy(dest, exp->second.location, td.Size());
90                 } else {
91                         std::memcpy(dest, &exp->second.location, sizeof(char *));
92                 }
93         }
94 }
95
96 void Loader::LoadObjects(char *src, Object *begin, Object *end) {
97         for (Object *i = begin; i < end; i = i->Next()) {
98                 const TypeDescription &td =
99                                 TypeDescription::Get(i->typeId);
100                 if (td.NeedsLinking()) {
101                         LoadObject(src, i->RawObject(), td);
102                 }
103         }
104 }
105
106 void Loader::LoadObject(char *src, char *object, const TypeDescription &td) {
107         for (TypeDescription::FieldIterator
108                         i(td.FieldsBegin()), end(td.FieldsEnd());
109                         i != end; ++i) {
110                 const FieldDescription &field = i->second;
111                 if (!field.IsReferenced() && !field.IsAggregate()) {
112                         continue;
113                 }
114                 char **dest(reinterpret_cast<char **>(object + field.Offset()));
115                 if (*dest) {
116                         *dest = src + *reinterpret_cast<unsigned int *>(dest);
117                 }
118         }
119 }
120
121 void Loader::LoadArrays(char *src, Array *begin, Array *end) {
122         for (Array *i = begin; i < end; i = i->Next()) {
123                 if (i->ref) {
124                         for (char *j = i->Data(), *end = i->Data() + i->size;
125                                         j < end; j += sizeof(void *)) {
126                                 *reinterpret_cast<char **>(j) =
127                                                 src + *reinterpret_cast<unsigned int *>(j);
128                         }
129                 } else {
130                         const TypeDescription &td = TypeDescription::Get(i->typeId);
131                         for (char *j = i->Data(), *end = i->Data() + i->size;
132                                         j < end; j += td.Size()) {
133                                 LoadObject(src, j, td);
134                         }
135                 }
136         }
137 }
138
139 }