]> git.localhorst.tv Git - l2e.git/blobdiff - src/loader/Loader.cpp
relocate scripts
[l2e.git] / src / loader / Loader.cpp
index 961ec7cff6d315dec5537338fe08ba8cfc0b9450..3c7f2bd5b3005611e6c41d93f0fc5f7b2895b96b 100644 (file)
@@ -1,14 +1,19 @@
 #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;
 
@@ -61,6 +66,9 @@ void Loader::Load(const std::string &filePath) {
                LoadImages(header->ident,
                                header->ImagesBegin(),
                                header->ImagesEnd());
+               LoadScripts(header->ident,
+                               header->ScriptsBegin(),
+                               header->ScriptsEnd());
 
                InitObjects(
                                header->ObjectsBegin(),
@@ -73,6 +81,34 @@ void Loader::Load(const std::string &filePath) {
                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) {
@@ -88,18 +124,24 @@ 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);
-               }
-               const TypeDescription &td(TypeDescription::Get(exp->second.typeId));
-               char *dest = src + i->referenceOffset;
-               if (i->inlined) {
-                       std::memcpy(dest, exp->second.location, td.Size());
+                       MissingExternal m;
+                       m.identifier = identifier;
+                       m.dest = dest;
+                       m.typeId = i->typeId;
+                       m.inlined = i->inlined;
+                       unlinked.push_back(m);
                } else {
-                       std::memcpy(dest, &exp->second.location, sizeof(char *));
+                       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 *));
+                       }
                }
        }
 }
@@ -166,6 +208,36 @@ void Loader::LoadArrays(char *src, Array *begin, Array *end) {
        }
 }
 
+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()) {
@@ -204,4 +276,47 @@ void Loader::InitArrays(Array *begin, Array *end) {
        }
 }
 
+
+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;
+}
+
 }