--- /dev/null
+/*
+ * Loader.cpp
+ *
+ * Created on: Sep 13, 2012
+ * Author: holy
+ */
+
+#include "Loader.h"
+
+#include <climits>
+#include <cstring>
+#include <fstream>
+#include <stdexcept>
+
+using std::map;
+using std::string;
+using std::vector;
+
+namespace loader {
+
+Loader::~Loader() {
+ for(map<string, LoadedObjectFile>::const_iterator i(objectFiles.begin()), end(objectFiles.end()); i != end; ++i) {
+ if (i->second.surfaceCount) {
+ for (int j(0); j < i->second.surfaceCount; ++j) {
+ SDL_FreeSurface(i->second.surfaces[j]);
+ }
+ delete[] i->second.surfaces;
+ }
+ delete[] i->second.allocPtr;
+ }
+}
+
+
+void Loader::Load(const std::string &filePath) {
+ std::ifstream file(filePath.c_str());
+ file.seekg(0, std::ios::end);
+ int fileLength(file.tellg());
+ int length(fileLength + 15);
+
+ LoadedObjectFile &object(objectFiles[filePath]);
+ object.allocPtr = new char[length];
+
+ if (reinterpret_cast<unsigned long>(object.allocPtr) % 16) {
+ object.fileHeader = reinterpret_cast<ObjectFileHeader *>(object.allocPtr + (16 - (reinterpret_cast<unsigned long>(object.allocPtr) % 16)));
+ } else {
+ object.fileHeader = reinterpret_cast<ObjectFileHeader *>(object.allocPtr);
+ }
+
+ file.seekg(0, std::ios::beg);
+ file.read(reinterpret_cast<char *>(object.fileHeader), fileLength);
+
+ if (object.fileHeader->versionId != FORMAT_ID) {
+ throw std::runtime_error("mismatched version id of file " + filePath);
+ }
+
+ LoadHeader(object);
+ LoadExports(object);
+ LoadImages(object);
+ LinkObjects(object);
+ LinkExternals(object);
+}
+
+void Loader::LoadHeader(LoadedObjectFile &object) {
+ ObjectFileHeader *header(object.fileHeader);
+ char *charHeader(reinterpret_cast<char *>(header));
+
+ object.typeOffsetsBegin = reinterpret_cast<TypeOffset *>(charHeader + sizeof(ObjectFileHeader));
+ for (object.typeOffsetsEnd = object.typeOffsetsBegin; object.typeOffsetsEnd->begin != 0 && object.typeOffsetsEnd->end != 0; ++object.typeOffsetsEnd);
+
+ object.exportsBegin = reinterpret_cast<Export *>(charHeader + header->exportsBegin);
+ object.exportsEnd = reinterpret_cast<Export *>(charHeader + header->exportsEnd);
+
+ object.externalsBegin = reinterpret_cast<External *>(charHeader + header->externalsBegin);
+ object.externalsEnd = reinterpret_cast<External *>(charHeader + header->externalsEnd);
+
+ object.exportStringsBegin = charHeader + header->exportStringsBegin;
+ object.exportStringsEnd = charHeader + header->exportStringsEnd;
+
+ object.externalStringsBegin = charHeader + header->externalStringsBegin;
+ object.externalStringsEnd = charHeader + header->externalStringsEnd;
+
+ object.imagesBegin = charHeader + header->imagesBegin;
+ object.imagesEnd = charHeader + header->imagesEnd;
+
+ object.objectsBegin = charHeader + header->objectsBegin;
+ object.objectsEnd = charHeader + header->objectsEnd;
+}
+
+void Loader::LoadExports(LoadedObjectFile &object) {
+ for (Export *i(object.exportsBegin); i != object.exportsEnd; ++i) {
+ string identifier(object.At(i->nameOffset));
+ LoadedExport &exp(exports[identifier]);
+ exp.typeId = i->typeId;
+ exp.location = object.At(i->dataOffset);
+ }
+}
+
+void Loader::LinkExternals(LoadedObjectFile &object) {
+ for (External *i(object.externalsBegin); i != object.externalsEnd; ++i) {
+ string identifier(object.At(i->nameOffset));
+ map<string, LoadedExport>::const_iterator exp(exports.find(identifier));
+ if (exp == exports.end()) {
+ throw std::runtime_error("undefined reference to " + identifier);
+ }
+ const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
+ char *dest(object.At(i->referenceOffset));
+ if (i->inlined) {
+ std::memcpy(dest, exp->second.location, td.Size());
+ } else {
+ std::memcpy(dest, &exp->second.location, sizeof(char *));
+ }
+ }
+}
+
+void Loader::LoadImages(LoadedObjectFile &object) {
+ for (char *i(object.imagesBegin); i != object.imagesEnd;) {
+ ImageProperties *props(reinterpret_cast<ImageProperties *>(i));
+ i += sizeof(ImageProperties) + props->width * props->height * (props->depth / CHAR_BIT + (props->depth % CHAR_BIT ? 1 : 0));
+ ++object.surfaceCount;
+ }
+ if (object.surfaceCount == 0) return;
+
+ object.surfaces = new SDL_Surface *[object.surfaceCount];
+ int index(0);
+ for (char *i(object.imagesBegin); i != object.imagesEnd;) {
+ ImageProperties *props(reinterpret_cast<ImageProperties *>(i));
+ i += sizeof(ImageProperties);
+ SDL_Surface *image(SDL_CreateRGBSurfaceFrom(
+ i,
+ props->width,
+ props->height,
+ props->depth,
+ props->pitch,
+ props->rmask,
+ props->gmask,
+ props->bmask,
+ props->amask));
+ i += props->width * props->height * (props->depth / CHAR_BIT + (props->depth % CHAR_BIT ? 1 : 0));
+ object.surfaces[index] = image;
+ ++index;
+ }
+}
+
+void Loader::LinkObjects(LoadedObjectFile &object) {
+ for (TypeOffset *type(object.typeOffsetsBegin); type != object.typeOffsetsEnd; ++type) {
+ const TypeDescription &td(TypeDescription::Get(type->typeId));
+ for (int offset(type->begin); offset != type->end; offset += td.Size()) {
+ LinkObject(object, td, object.At(offset));
+ }
+ }
+}
+
+void Loader::LinkObject(LoadedObjectFile &file, const TypeDescription &td, char *object) {
+ for (TypeDescription::FieldIterator i(td.FieldsBegin()), end(td.FieldsEnd()); i != end; ++i) {
+ const FieldDescription &field(i->second);
+ if (!field.IsReferenced()) continue;
+ char **dest(reinterpret_cast<char **>(object + field.Offset()));
+ *dest = file.At(*reinterpret_cast<int *>(*dest));
+ }
+}
+
+}