#include "Loader.h"
+#include "../common/Script.h"
+
#include <climits>
#include <cstring>
#include <fstream>
+#include <ostream>
#include <stdexcept>
#include <utility>
+#include <SDL_image.h>
+using std::endl;
using std::make_pair;
using std::map;
+using std::ostream;
using std::string;
using std::vector;
LoadArrays(header->ident,
header->ArraysBegin(),
header->ArraysEnd());
+ LoadImages(header->ident,
+ header->ImagesBegin(),
+ header->ImagesEnd());
+ LoadScripts(header->ident,
+ header->ScriptsBegin(),
+ header->ScriptsEnd());
+
+ InitObjects(
+ header->ObjectsBegin(),
+ header->ObjectsEnd());
+ InitArrays(
+ header->ArraysBegin(),
+ header->ArraysEnd());
} catch (...) {
delete[] block;
throw;
}
objectFiles.insert(make_pair(filePath, block));
+
+ if (objectFiles.size() > 1) {
+ for (std::vector<MissingExternal>::iterator
+ i(unlinked.begin()); i != unlinked.end();) {
+ std::map<string, LoadedExport>::const_iterator
+ found(exports.find(i->identifier));
+ if (found != exports.end()) {
+ LinkExternal(*i, found->second);
+ i = unlinked.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ }
+}
+
+void Loader::LinkExternal(
+ const MissingExternal &ext,
+ const LoadedExport &exp) {
+ if (ext.typeId != exp.typeId) {
+ throw std::runtime_error("casting not implemented in loader");
+ }
+ const TypeDescription &td = TypeDescription::Get(ext.typeId);
+ if (ext.inlined) {
+ std::memcpy(ext.dest, exp.location, td.Size());
+ } else {
+ std::memcpy(ext.dest, &exp.location, sizeof(void *));
+ }
}
void Loader::LoadExports(char *src, Export *begin, Export *end) {
void Loader::LoadExternals(char *src, External *begin, External *end) {
for (External *i = begin; i < end; ++i) {
string identifier(src + i->nameOffset);
+ char *dest = src + i->referenceOffset;
+
map<string, LoadedExport>::const_iterator
exp(exports.find(identifier));
if (exp == exports.end()) {
- throw std::runtime_error("undefined reference to "
- + identifier);
+ MissingExternal m;
+ m.identifier = identifier;
+ m.dest = dest;
+ m.typeId = i->typeId;
+ m.inlined = i->inlined;
+ unlinked.push_back(m);
+ } else {
+ const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
+ if (i->inlined) {
+ std::memcpy(dest, exp->second.location, td.Size());
+ } else {
+ std::memcpy(dest, &exp->second.location, sizeof(char *));
+ }
}
- const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
- char *dest = src + i->referenceOffset;
- if (i->inlined) {
- std::memcpy(dest, exp->second.location, td.Size());
+ }
+}
+
+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 {
- std::memcpy(dest, &exp->second.location, sizeof(char *));
+ SDL_Surface *loaded = IMG_Load(path.c_str());
+ images.insert(make_pair(path, loaded));
+ *dest = loaded;
}
}
}
for (Object *i = begin; i < end; i = i->Next()) {
const TypeDescription &td =
TypeDescription::Get(i->typeId);
- if (td.NeedsLinking()) {
- LoadObject(src, i->RawObject(), td);
- }
+ LoadObject(src, i->RawObject(), td);
}
}
i(td.FieldsBegin()), end(td.FieldsEnd());
i != end; ++i) {
const FieldDescription &field = i->second;
- if (!field.IsReferenced() && !field.IsAggregate()) {
- continue;
- }
- char **dest(reinterpret_cast<char **>(object + field.Offset()));
- if (*dest) {
- *dest = src + *reinterpret_cast<unsigned int *>(dest);
+ 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) {
+ 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::LoadScripts(char *src, Script *begin, Script *end) {
+ for (Script *s = begin; s < end; s = s->Next()) {
+ for (char *i = s->Text(), *end = s->Text() + s->size; i < end;) {
+ common::Script::Code *code =
+ reinterpret_cast<common::Script::Code *>(i);
+ if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) {
+ if (code->reg1 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ unsigned int offset = *reinterpret_cast<unsigned int *>(addr);
+ if (offset) {
+ *reinterpret_cast<const char **>(addr) = src + offset;
+ }
+ }
+
+ if (code->numParams > 1 && code->reg2 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ if (code->reg1 == 7) {
+ addr += sizeof(void *);
+ }
+ unsigned int offset = *reinterpret_cast<unsigned int *>(addr);
+ if (offset) {
+ *reinterpret_cast<const char **>(addr) = src + offset;
+ }
+ }
+ }
+ i += code->Size();
+ }
+ }
+}
+
+
+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::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 += sizeof(void *)) {
- *reinterpret_cast<char **>(j) =
- src + *reinterpret_cast<unsigned int *>(j);
+ j < end; j += td.Size()) {
+ InitObject(j, td);
+ }
+ }
+}
+
+
+ostream &Loader::Dump(ostream &out) const {
+ out << "loaded objects" << endl;
+ out << "==============" << endl;
+
+ out << objectFiles.size() << " object files" << endl;
+ for (std::map<string, char *>::const_iterator
+ i(objectFiles.begin()), end(objectFiles.end());
+ i != end; ++i) {
+ out << " - " << i->first << endl;
+ }
+
+ out << exports.size() << " exports" << endl;
+ for (std::map<string, LoadedExport>::const_iterator
+ i(exports.begin()), end(exports.end());
+ i != end; ++i) {
+ const TypeDescription &td = TypeDescription::Get(i->second.typeId);
+ out << " - " << td.TypeName() << ' ' << i->first << endl;
+ }
+
+ out << images.size() << " images" << endl;
+ for (std::map<string, SDL_Surface *>::const_iterator
+ i(images.begin()), end(images.end());
+ i != end; ++i) {
+ out << " - " << i->first << endl;
+ }
+
+ out << unlinked.size() << " missing objects" << endl;
+ for (std::vector<MissingExternal>::const_iterator
+ i(unlinked.begin()), end(unlinked.end());
+ i != end; ++i) {
+ const TypeDescription &td = TypeDescription::Get(
+ i->typeId);
+ out << " - " << td.TypeName() << ' ';
+ if (!i->inlined) {
+ out << '*';
}
+ out << i->identifier << endl;
}
+
+ return out;
}
}