-/*
- * Loader.cpp
- *
- * Created on: Sep 13, 2012
- * Author: holy
- */
-
#include "Loader.h"
#include <climits>
#include <cstring>
#include <fstream>
#include <stdexcept>
+#include <utility>
+#include <SDL_image.h>
+using std::make_pair;
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;
+ for(map<string, char *>::const_iterator
+ i(objectFiles.begin()), end(objectFiles.end());
+ i != end; ++i) {
+ delete[] i->second;
}
}
int fileLength(file.tellg());
int length(fileLength + 15);
- LoadedObjectFile &object(objectFiles[filePath]);
- object.allocPtr = new char[length];
+ char *block = new char[length];
+ ObjectFileHeader *header =
+ reinterpret_cast<ObjectFileHeader *>(block);
- 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);
+ unsigned long padding =
+ reinterpret_cast<unsigned long>(block) % 16;
+ if (padding) {
+ header = reinterpret_cast<ObjectFileHeader *>(
+ block + (16 - padding));
}
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);
+ file.read(reinterpret_cast<char *>(header), fileLength);
+
+ try {
+ header->IntegrityCheck(fileLength);
+
+ LoadExports(header->ident,
+ header->ExportsBegin(),
+ header->ExportsEnd());
+ LoadExternals(header->ident,
+ header->ExternalsBegin(),
+ header->ExternalsEnd());
+ LoadObjects(header->ident,
+ header->ObjectsBegin(),
+ header->ObjectsEnd());
+ LoadArrays(header->ident,
+ header->ArraysBegin(),
+ header->ArraysEnd());
+ LoadImages(header->ident,
+ header->ImagesBegin(),
+ header->ImagesEnd());
+
+ InitObjects(
+ header->ObjectsBegin(),
+ header->ObjectsEnd());
+ InitArrays(
+ header->ArraysBegin(),
+ header->ArraysEnd());
+ } catch (...) {
+ delete[] block;
+ throw;
}
-
- LoadHeader(object);
- LoadExports(object);
- LoadImages(object);
- LinkObjects(object);
- LinkExternals(object);
+ objectFiles.insert(make_pair(filePath, block));
}
-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));
+void Loader::LoadExports(char *src, Export *begin, Export *end) {
+ for (Export *i = begin; i < end; ++i) {
+ string identifier(src + i->nameOffset);
LoadedExport &exp(exports[identifier]);
exp.typeId = i->typeId;
- exp.location = object.At(i->dataOffset);
+ exp.location = src + i->dataOffset;
+ exports.insert(make_pair(identifier, exp));
}
}
-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));
+void Loader::LoadExternals(char *src, External *begin, External *end) {
+ for (External *i = begin; i < end; ++i) {
+ string identifier(src + i->nameOffset);
+ map<string, LoadedExport>::const_iterator
+ exp(exports.find(identifier));
if (exp == exports.end()) {
- throw std::runtime_error("undefined reference to " + identifier);
+ throw std::runtime_error("undefined reference to "
+ + identifier);
}
const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
- char *dest(object.At(i->referenceOffset));
+ char *dest = src + i->referenceOffset;
if (i->inlined) {
std::memcpy(dest, exp->second.location, td.Size());
} else {
}
}
-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;
+void Loader::LoadImages(char *src, Image *begin, Image *end) {
+ for (Image *i = begin; i != end; ++i) {
+ const string path(src + i->pathOffset);
+ SDL_Surface **dest = reinterpret_cast<SDL_Surface **>(src + i->destOffset);
+ std::map<string, SDL_Surface *>::const_iterator
+ found(images.find(path));
+ if (found != images.end()) {
+ *dest = found->second;
+ } else {
+ SDL_Surface *loaded = IMG_Load(path.c_str());
+ images.insert(make_pair(path, loaded));
+ *dest = loaded;
+ }
}
- 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::LoadObjects(char *src, Object *begin, Object *end) {
+ for (Object *i = begin; i < end; i = i->Next()) {
+ const TypeDescription &td =
+ TypeDescription::Get(i->typeId);
+ LoadObject(src, i->RawObject(), td);
}
}
-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::LoadObject(char *src, char *object, const TypeDescription &td) {
+ for (TypeDescription::FieldIterator
+ i(td.FieldsBegin()), end(td.FieldsEnd());
+ i != end; ++i) {
+ const FieldDescription &field = i->second;
+ if (field.IsReferenced() || field.IsAggregate()) {
+ char **dest(reinterpret_cast<char **>(object + field.Offset()));
+ if (*dest) {
+ *dest = src + *reinterpret_cast<unsigned int *>(dest);
+ }
+ } else {
+ const TypeDescription &nestedType
+ = TypeDescription::Get(field.TypeId());
+ LoadObject(src, object + field.Offset(), nestedType);
+ }
+ }
+}
+
+void Loader::LoadArrays(char *src, Array *begin, Array *end) {
+ for (Array *i = begin; i < end; i = i->Next()) {
+ if (i->ref) {
+ for (char *j = i->Data(), *end = i->Data() + i->size;
+ j < end; j += sizeof(void *)) {
+ unsigned int offset = *reinterpret_cast<unsigned int *>(j);
+ if (offset) {
+ *reinterpret_cast<char **>(j) = src + offset;
+ }
+ }
+ } else {
+ const TypeDescription &td = TypeDescription::Get(i->typeId);
+ for (char *j = i->Data(), *end = i->Data() + i->size;
+ j < end; j += td.Size()) {
+ LoadObject(src, j, td);
+ }
+ }
+ }
+}
+
+
+void Loader::InitObjects(Object *begin, Object *end) {
+ for (Object *i = begin; i < end; i = i->Next()) {
+ const TypeDescription &td =
+ TypeDescription::Get(i->typeId);
+ InitObject(i->RawObject(), td);
+ }
+}
+
+void Loader::InitObject(char *object, const TypeDescription &td) {
+ td.Init(object);
+ td.Load(object);
+ for (TypeDescription::FieldIterator
+ i(td.FieldsBegin()), end(td.FieldsEnd());
+ i != end; ++i) {
+ const FieldDescription &field = i->second;
+ if (field.IsReferenced() || field.IsAggregate()) {
+ continue;
}
+ const TypeDescription &nestedType
+ = TypeDescription::Get(field.TypeId());
+ InitObject(object + field.Offset(), nestedType);
}
}
-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));
+void Loader::InitArrays(Array *begin, Array *end) {
+ for (Array *i = begin; i < end; i = i->Next()) {
+ if (i->ref) {
+ continue;
+ }
+ const TypeDescription &td = TypeDescription::Get(i->typeId);
+ for (char *j = i->Data(), *end = i->Data() + i->size;
+ j < end; j += td.Size()) {
+ InitObject(j, td);
+ }
}
}