]> git.localhorst.tv Git - l2e.git/blob - Loader.cpp
a1183f790f2b0b98af6bc90dd0c9c092e7413380
[l2e.git] / Loader.cpp
1 /*
2  * Loader.cpp
3  *
4  *  Created on: Sep 13, 2012
5  *      Author: holy
6  */
7
8 #include "Loader.h"
9
10 #include <climits>
11 #include <cstring>
12 #include <fstream>
13 #include <stdexcept>
14
15 using std::map;
16 using std::string;
17 using std::vector;
18
19 namespace loader {
20
21 Loader::~Loader() {
22         for(map<string, LoadedObjectFile>::const_iterator i(objectFiles.begin()), end(objectFiles.end()); i != end; ++i) {
23                 if (i->second.surfaceCount) {
24                         for (int j(0); j < i->second.surfaceCount; ++j) {
25                                 SDL_FreeSurface(i->second.surfaces[j]);
26                         }
27                         delete[] i->second.surfaces;
28                 }
29                 delete[] i->second.allocPtr;
30         }
31 }
32
33
34 void Loader::Load(const std::string &filePath) {
35         std::ifstream file(filePath.c_str());
36         file.seekg(0, std::ios::end);
37         int fileLength(file.tellg());
38         int length(fileLength + 15);
39
40         LoadedObjectFile &object(objectFiles[filePath]);
41         object.allocPtr = new char[length];
42
43         if (reinterpret_cast<unsigned long>(object.allocPtr) % 16) {
44                 object.fileHeader = reinterpret_cast<ObjectFileHeader *>(object.allocPtr + (16 - (reinterpret_cast<unsigned long>(object.allocPtr) % 16)));
45         } else {
46                 object.fileHeader = reinterpret_cast<ObjectFileHeader *>(object.allocPtr);
47         }
48
49         file.seekg(0, std::ios::beg);
50         file.read(reinterpret_cast<char *>(object.fileHeader), fileLength);
51
52         if (object.fileHeader->versionId != FORMAT_ID) {
53                 throw std::runtime_error("mismatched version id of file " + filePath);
54         }
55
56         LoadHeader(object);
57         LoadExports(object);
58         LoadImages(object);
59         LinkObjects(object);
60         LinkExternals(object);
61 }
62
63 void Loader::LoadHeader(LoadedObjectFile &object) {
64         ObjectFileHeader *header(object.fileHeader);
65         char *charHeader(reinterpret_cast<char *>(header));
66
67         object.typeOffsetsBegin = reinterpret_cast<TypeOffset *>(charHeader + sizeof(ObjectFileHeader));
68         for (object.typeOffsetsEnd = object.typeOffsetsBegin; object.typeOffsetsEnd->begin != 0 && object.typeOffsetsEnd->end != 0; ++object.typeOffsetsEnd);
69
70         object.exportsBegin = reinterpret_cast<Export *>(charHeader + header->exportsBegin);
71         object.exportsEnd = reinterpret_cast<Export *>(charHeader + header->exportsEnd);
72
73         object.externalsBegin = reinterpret_cast<External *>(charHeader + header->externalsBegin);
74         object.externalsEnd = reinterpret_cast<External *>(charHeader + header->externalsEnd);
75
76         object.exportStringsBegin = charHeader + header->exportStringsBegin;
77         object.exportStringsEnd = charHeader + header->exportStringsEnd;
78
79         object.externalStringsBegin = charHeader + header->externalStringsBegin;
80         object.externalStringsEnd = charHeader + header->externalStringsEnd;
81
82         object.imagesBegin = charHeader + header->imagesBegin;
83         object.imagesEnd = charHeader + header->imagesEnd;
84
85         object.objectsBegin = charHeader + header->objectsBegin;
86         object.objectsEnd = charHeader + header->objectsEnd;
87 }
88
89 void Loader::LoadExports(LoadedObjectFile &object) {
90         for (Export *i(object.exportsBegin); i != object.exportsEnd; ++i) {
91                 string identifier(object.At(i->nameOffset));
92                 LoadedExport &exp(exports[identifier]);
93                 exp.typeId = i->typeId;
94                 exp.location = object.At(i->dataOffset);
95         }
96 }
97
98 void Loader::LinkExternals(LoadedObjectFile &object) {
99         for (External *i(object.externalsBegin); i != object.externalsEnd; ++i) {
100                 string identifier(object.At(i->nameOffset));
101                 map<string, LoadedExport>::const_iterator exp(exports.find(identifier));
102                 if (exp == exports.end()) {
103                         throw std::runtime_error("undefined reference to " + identifier);
104                 }
105                 const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
106                 char *dest(object.At(i->referenceOffset));
107                 if (i->inlined) {
108                         std::memcpy(dest, exp->second.location, td.Size());
109                 } else {
110                         std::memcpy(dest, &exp->second.location, sizeof(char *));
111                 }
112         }
113 }
114
115 void Loader::LoadImages(LoadedObjectFile &object) {
116         for (char *i(object.imagesBegin); i != object.imagesEnd;) {
117                 ImageProperties *props(reinterpret_cast<ImageProperties *>(i));
118                 i += sizeof(ImageProperties) + props->width * props->height * (props->depth / CHAR_BIT + (props->depth % CHAR_BIT ? 1 : 0));
119                 ++object.surfaceCount;
120         }
121         if (object.surfaceCount == 0) return;
122
123         object.surfaces = new SDL_Surface *[object.surfaceCount];
124         int index(0);
125         for (char *i(object.imagesBegin); i != object.imagesEnd;) {
126                 ImageProperties *props(reinterpret_cast<ImageProperties *>(i));
127                 i += sizeof(ImageProperties);
128                 SDL_Surface *image(SDL_CreateRGBSurfaceFrom(
129                                 i,
130                                 props->width,
131                                 props->height,
132                                 props->depth,
133                                 props->pitch,
134                                 props->rmask,
135                                 props->gmask,
136                                 props->bmask,
137                                 props->amask));
138                 i += props->width * props->height * (props->depth / CHAR_BIT + (props->depth % CHAR_BIT ? 1 : 0));
139                 object.surfaces[index] = image;
140                 ++index;
141         }
142 }
143
144 void Loader::LinkObjects(LoadedObjectFile &object) {
145         for (TypeOffset *type(object.typeOffsetsBegin); type != object.typeOffsetsEnd; ++type) {
146                 const TypeDescription &td(TypeDescription::Get(type->typeId));
147                 for (int offset(type->begin); offset != type->end; offset += td.Size()) {
148                         LinkObject(object, td, object.At(offset));
149                 }
150         }
151 }
152
153 void Loader::LinkObject(LoadedObjectFile &file, const TypeDescription &td, char *object) {
154         for (TypeDescription::FieldIterator i(td.FieldsBegin()), end(td.FieldsEnd()); i != end; ++i) {
155                 const FieldDescription &field(i->second);
156                 if (!field.IsReferenced()) continue;
157                 char **dest(reinterpret_cast<char **>(object + field.Offset()));
158                 *dest = file.At(*reinterpret_cast<int *>(*dest));
159         }
160 }
161
162 }