X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=src%2Floader%2FLoader.cpp;h=3c7f2bd5b3005611e6c41d93f0fc5f7b2895b96b;hb=b20681c1bf555c337b15796b3910d0d48488b102;hp=2403044ad20fb819a23fafc0b43c2ded125a317c;hpb=8c8061a4f8b88410d6d93c039afe6affc4b69cf2;p=l2e.git diff --git a/src/loader/Loader.cpp b/src/loader/Loader.cpp index 2403044..3c7f2bd 100644 --- a/src/loader/Loader.cpp +++ b/src/loader/Loader.cpp @@ -1,11 +1,19 @@ #include "Loader.h" +#include "../common/Script.h" + #include #include #include +#include #include +#include +#include +using std::endl; +using std::make_pair; using std::map; +using std::ostream; using std::string; using std::vector; @@ -52,11 +60,55 @@ void Loader::Load(const std::string &filePath) { LoadObjects(header->ident, header->ObjectsBegin(), header->ObjectsEnd()); + 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::iterator + i(unlinked.begin()); i != unlinked.end();) { + std::map::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) { @@ -65,24 +117,47 @@ void Loader::LoadExports(char *src, Export *begin, Export *end) { LoadedExport &exp(exports[identifier]); exp.typeId = i->typeId; exp.location = src + i->dataOffset; + exports.insert(make_pair(identifier, exp)); } } 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::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(src + i->destOffset); + std::map::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; } } } @@ -91,9 +166,7 @@ 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); - if (td.NeedsLinking()) { - LoadObject(src, i->RawObject(), td); - } + LoadObject(src, i->RawObject(), td); } } @@ -102,14 +175,148 @@ void Loader::LoadObject(char *src, char *object, const TypeDescription &td) { i(td.FieldsBegin()), end(td.FieldsEnd()); i != end; ++i) { const FieldDescription &field = i->second; - if (!field.IsReferenced() && !field.IsAggregate()) { + if (field.IsReferenced() || field.IsAggregate()) { + char **dest(reinterpret_cast(object + field.Offset())); + if (*dest) { + *dest = src + *reinterpret_cast(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(j); + if (offset) { + *reinterpret_cast(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(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(addr); + if (offset) { + *reinterpret_cast(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(addr); + if (offset) { + *reinterpret_cast(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; } - char **dest(reinterpret_cast(object + field.Offset())); - if (*dest) { - *dest = src + *reinterpret_cast(dest); + 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); } } } + +ostream &Loader::Dump(ostream &out) const { + out << "loaded objects" << endl; + out << "==============" << endl; + + out << objectFiles.size() << " object files" << endl; + for (std::map::const_iterator + i(objectFiles.begin()), end(objectFiles.end()); + i != end; ++i) { + out << " - " << i->first << endl; + } + + out << exports.size() << " exports" << endl; + for (std::map::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::const_iterator + i(images.begin()), end(images.end()); + i != end; ++i) { + out << " - " << i->first << endl; + } + + out << unlinked.size() << " missing objects" << endl; + for (std::vector::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; +} + }