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