]> git.localhorst.tv Git - l2e.git/commitdiff
new object file format in compiler
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 13 Mar 2013 18:07:19 +0000 (19:07 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 13 Mar 2013 18:07:19 +0000 (19:07 +0100)
13 files changed:
src/loader/Compiler.cpp
src/loader/Compiler.h
src/loader/Interpreter.cpp
src/loader/Interpreter.h
src/loader/Loader.cpp
src/loader/Loader.h
src/loader/ObjectFile.cpp
src/loader/ObjectFile.h
src/loader/PagedAllocator.cpp
src/loader/PagedAllocator.h
src/loader/TypeDescription.cpp
src/loader/TypeDescription.h
src/main.cpp

index 5575838b83f9664bcb2c21ecbca6f47ec17d8465..d122643fbedc7c29ddac0eef0ad6fb8d8fe53f3c 100644 (file)
@@ -1,26 +1,27 @@
-/*
- * Compiler.cpp
- *
- *  Created on: Sep 11, 2012
- *      Author: holy
- */
-
 #include "Compiler.h"
 
 #include "Interpreter.h"
+#include "TypeDescription.h"
 
 #include <climits>
 #include <cstring>
+#include <iostream>
 #include <map>
 #include <ostream>
 #include <set>
+#include <stdexcept>
 #include <string>
+#include <utility>
 #include <vector>
 
+using std::iostream;
+using std::make_pair;
 using std::map;
 using std::ostream;
+using std::runtime_error;
 using std::set;
 using std::string;
+using std::strlen;
 using std::vector;
 
 namespace loader {
@@ -28,151 +29,254 @@ namespace loader {
 Compiler::Compiler(const Interpreter &intp)
 : intp(intp)
 , cursor(0) {
-       int headerSize(sizeof(ObjectFileHeader) + (intp.Values().size() * sizeof(TypeOffset)));
-
-       fileHeader.exportsBegin = headerSize + Remaining(headerSize, 16);
-       fileHeader.exportsEnd = fileHeader.exportsBegin + (intp.ExportedIdentifiers().size() * sizeof(Export));
+       int headerSize(sizeof(ObjectFileHeader));
 
-       fileHeader.externalsBegin = fileHeader.exportsEnd + Remaining(fileHeader.exportsEnd, 16);
-       fileHeader.externalsEnd = fileHeader.externalsBegin + (intp.PostponedDefinitions().size() * sizeof(External));
-
-       fileHeader.exportStringsBegin = fileHeader.externalsEnd + Remaining(fileHeader.externalsEnd, 16);
-       fileHeader.exportStringsEnd = fileHeader.exportStringsBegin;
-       for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
-               fileHeader.exportStringsEnd += i->size() + 1;
-       }
+       fileHeader.exportsBegin = headerSize;
+       fileHeader.exportsEnd = fileHeader.exportsBegin
+                       + (intp.ExportedIdentifiers().size() * sizeof(Export));
 
-       fileHeader.externalStringsBegin = fileHeader.exportStringsEnd + Remaining(fileHeader.exportStringsEnd, 16);
-       fileHeader.externalStringsEnd = fileHeader.externalStringsBegin;
-       for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
-               fileHeader.externalStringsEnd += std::strlen(i->identifier) + 1;
-       }
-
-       fileHeader.imagesBegin = fileHeader.externalStringsEnd + Remaining(fileHeader.externalStringsEnd, 16);
-       fileHeader.imagesEnd = fileHeader.imagesBegin + (intp.Images().size() * sizeof(ImageProperties));
-       for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
-               fileHeader.imagesEnd += i->second->w * i->second->h * i->second->format->BytesPerPixel;
-       }
+       fileHeader.externalsBegin = fileHeader.exportsEnd;
+       fileHeader.externalsEnd = fileHeader.externalsBegin
+                       + (intp.PostponedDefinitions().size() * sizeof(External));
 
-       fileHeader.objectsBegin = fileHeader.imagesEnd + Remaining(fileHeader.imagesEnd, 16);
-       fileHeader.objectsEnd = fileHeader.objectsBegin;
-       for (map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
-               const TypeDescription &td(TypeDescription::Get(i->first));
-               objectOffsets[i->first] = fileHeader.objectsEnd;
-               fileHeader.objectsEnd += td.Size() * i->second.size();
-               fileHeader.objectsEnd += Remaining(fileHeader.objectsEnd, 16);
-       }
+       fileHeader.objectsBegin = fileHeader.externalsEnd
+                       + Remaining(fileHeader.externalsEnd, 16);
 }
 
-void Compiler::Write(ostream &out) {
-       WriteHeader(out);
+void Compiler::Write(iostream &out) {
+       ReserveHeader(out);
+       WriteObjects(out);
+       WriteOwnStrings(out);
+       fileHeader.objectsEnd = cursor;
        Pad(out, 16);
+       fileHeader.arraysBegin = cursor;
+       WriteArrays(out);
+       fileHeader.arraysEnd = cursor;
+       out.seekp(0);
+       cursor = 0;
+       WriteHeader(out);
        WriteExports(out);
-       Pad(out, 16);
        WriteExternals(out);
-       Pad(out, 16);
-       WriteExportStrings(out);
-       Pad(out, 16);
-       WriteExternalStrings(out);
-       Pad(out, 16);
-       WriteImages(out);
-       Pad(out, 16);
-       WriteObjects(out);
+       out.seekg(fileHeader.objectsBegin);
+       out.clear();
+       Relocate(out);
 }
 
+void Compiler::ReserveHeader(ostream &out) {
+       Fill(out, fileHeader.objectsBegin);
+}
 
 void Compiler::WriteHeader(ostream &out) {
-       Write(out, reinterpret_cast<const char *>(&fileHeader), sizeof(ObjectFileHeader));
-       for(map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
-               TypeOffset to;
-               to.typeId = i->first;
-               to.begin = GetTypeOffset(i->first);
-               to.end = to.begin + (i->second.size() * TypeDescription::Get(i->first).Size());
-               Write(out, reinterpret_cast<const char *>(&to), sizeof(TypeOffset));
+       Write(out, &fileHeader, sizeof(ObjectFileHeader));
+}
+
+void Compiler::WriteOwnStrings(ostream &out) {
+       for (set<string>::const_iterator
+                       i(intp.ExportedIdentifiers().begin()),
+                       end(intp.ExportedIdentifiers().end());
+                       i != end; ++i) {
+               addressMap.insert(make_pair(i->c_str(), cursor));
+               Object object;
+               object.typeId = Interpreter::STRING_ID;
+               object.size = i->size() + 1;
+               Write(out, &object, sizeof(Object));
+               Write(out, i->c_str(), object.size);
+       }
+       for(vector<Interpreter::PostponedDefinition>::const_iterator
+                       i(intp.PostponedDefinitions().begin()),
+                       end(intp.PostponedDefinitions().end());
+                       i != end; ++i) {
+               addressMap.insert(make_pair(
+                               i->identifier.c_str(), cursor));
+               Object object;
+               object.typeId = Interpreter::STRING_ID;
+               object.size = i->identifier.size() + 1;
+               Write(out, &object, sizeof(Object));
+               Write(out, i->identifier.c_str(), object.size);
        }
-       TypeOffset to;
-       to.typeId = 0;
-       to.begin = 0;
-       to.end = 0;
-       Write(out, reinterpret_cast<const char *>(&to), sizeof(TypeOffset));
 }
 
 void Compiler::WriteExports(ostream &out) {
-       int nameOffset(fileHeader.externalStringsBegin);
-       for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
-               const Interpreter::ParsedDefinition &dfn(intp.GetDefinition(*i));
+       for (set<string>::const_iterator
+                       i(intp.ExportedIdentifiers().begin()),
+                       end(intp.ExportedIdentifiers().end());
+                       i != end; ++i) {
                Export exp;
-               exp.nameOffset = nameOffset;
-               exp.typeId = dfn.type;
-               exp.dataOffset = ObjectOffset(dfn.type, dfn.id);
-               Write(out, reinterpret_cast<char *>(&exp), sizeof(Export));
-               nameOffset += i->size() + 1;
+               PrepareExport(exp, *i);
+               Write(out, &exp, sizeof(Export));
        }
 }
 
 void Compiler::WriteExternals(ostream &out) {
-       int nameOffset(fileHeader.exportStringsBegin);
-       for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
+       for(vector<Interpreter::PostponedDefinition>::const_iterator
+                       i(intp.PostponedDefinitions().begin()),
+                       end(intp.PostponedDefinitions().end());
+                       i != end; ++i) {
                External ext;
-               ext.nameOffset = nameOffset;
-               ext.referenceOffset = ReferenceOffset(i->type, i->id, i->offset);
-               ext.inlined = i->inlined ? 1 : 0;
-               Write(out, reinterpret_cast<char *>(&ext), sizeof(External));
-               nameOffset += std::strlen(i->identifier) + 1;
+               PrepareExternal(ext, *i);
+               Write(out, &ext, sizeof(External));
        }
 }
 
-void Compiler::WriteExportStrings(ostream &out) {
-       for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
-               Write(out, i->c_str(), i->size() + 1);
+void Compiler::WriteObjects(ostream &out) {
+       Pad(out, 16);
+       for (map<int, vector<void *> >::const_iterator
+                       i(intp.Values().begin()), end(intp.Values().end());
+                       i != end; ++i) {
+               const TypeDescription &td(TypeDescription::Get(i->first));
+               for (vector<void *>::const_iterator
+                               j(i->second.begin()), jend(i->second.end());
+                               j != jend; ++j) {
+                       Object object;
+                       PrepareObject(object, td, *j);
+                       Write(out, &object, sizeof(Object));
+                       Write(out, *j, object.size);
+               }
        }
 }
 
-void Compiler::WriteExternalStrings(ostream &out) {
-       for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
-               Write(out, i->identifier, std::strlen(i->identifier) + 1);
+void Compiler::WriteArrays(ostream &out) {
+       Pad(out, 16);
+       for (vector<Interpreter::Array>::const_iterator
+                       i(intp.Arrays().begin()), end(intp.Arrays().end());
+                       i != end; ++i) {
+               Array array;
+               array.size = i->size;
+               array.ref = i->ref;
+               Write(out, &array, sizeof(Array));
+               addressMap.insert(make_pair(i->data, cursor));
+               Write(out, i->data, array.size);
        }
 }
 
-void Compiler::WriteImages(ostream &out) {
-       for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
-               ImageProperties ip;
-               ip.flags = i->second->flags;
-               ip.width = i->second->w;
-               ip.height = i->second->h;
-               ip.depth = i->second->format->BitsPerPixel;
-               ip.pitch = i->second->pitch;
-               ip.rmask = i->second->format->Rmask;
-               ip.gmask = i->second->format->Gmask;
-               ip.bmask = i->second->format->Bmask;
-               ip.amask = i->second->format->Amask;
-               Write(out, reinterpret_cast<char *>(&ip), sizeof(ImageProperties));
-               SDL_LockSurface(i->second);
-               Write(out, reinterpret_cast<char *>(i->second->pixels), ip.width * ip.height * (ip.depth / CHAR_BIT + (ip.depth % CHAR_BIT ? 1 : 0)));
-               // TODO: store palette too?
-               SDL_UnlockSurface(i->second);
+
+void Compiler::PrepareExport(Export &exp, const string &str) {
+       const Interpreter::ParsedDefinition &dfn
+                       = intp.GetDefinition(str);
+       exp.nameOffset = addressMap[str.c_str()];
+       exp.typeId = dfn.type;
+       exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)];
+}
+
+void Compiler::PrepareExternal(
+               External &ext,
+               const Interpreter::PostponedDefinition &def) {
+       ext.nameOffset = addressMap[def.identifier.c_str()];
+       ext.referenceOffset = addressMap[def.object] + (def.dest - def.object);
+       ext.inlined = 0;
+       if (def.inlined) ext.inlined |= 1;
+       if (def.aggregate) ext.inlined |= 2;
+}
+
+void Compiler::PrepareObject(
+               Object &object,
+               const TypeDescription &td,
+               void *data) {
+       addressMap.insert(make_pair(data, cursor + sizeof(Object)));
+       object.typeId = td.TypeId();
+       switch (td.TypeId()) {
+               case Interpreter::STRING_ID:
+                       object.size = strlen(
+                                       reinterpret_cast<char *>(data)) + 1;
+                       break;
+               default:
+                       object.size = td.Size();
+                       break;
        }
 }
 
-void Compiler::WriteObjects(ostream &out) {
-       for (map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
-               const TypeDescription &td(TypeDescription::Get(i->first));
-               for (vector<void *>::const_iterator j(i->second.begin()), jend(i->second.end()); j != jend; ++j) {
-                       Write(out, reinterpret_cast<char *>(*j), td.Size());
+void Compiler::Relocate(iostream &out) {
+       int bufferSize = TypeDescription::GetMaxSize();
+       char *buffer = new char[bufferSize];
+       for (;out && out.tellg() < fileHeader.objectsEnd;) {
+               // 20785
+               Object object;
+               out.read(reinterpret_cast<char *>(&object), sizeof(Object));
+               const TypeDescription &td = TypeDescription::Get(object.typeId);
+               if (td.NeedsLinking()) {
+                       out.seekg(object.size, iostream::cur);
+                       continue;
+               }
+               unsigned int pos = out.tellg();
+               out.seekg(pos);
+               out.read(buffer, object.size);
+               Relocate(buffer, td);
+               out.seekp(pos);
+               out.write(buffer, object.size);
+               out.seekg(out.tellp());
+       }
+       delete[] buffer;
+       out.seekg(fileHeader.arraysBegin);
+       Array array;
+       for (; out && out.tellg() < fileHeader.arraysEnd;) {
+               out.read(reinterpret_cast<char *>(&array), sizeof(Array));
+               if (!array.ref) {
+                       out.seekg(array.size);
+                       continue;
                }
-               Pad(out, 16);
+               buffer = new char[array.size];
+               unsigned int pos = out.tellg();
+               out.seekg(pos);
+               out.read(buffer, array.size);
+               RelocateArray(buffer, array.size);
+               out.seekp(pos);
+               out.write(buffer, array.size);
+               out.seekg(out.tellp());
+               delete[] buffer;
        }
 }
 
+void Compiler::RelocateArray(char *array, int size) {
+       for (char *i = array, *end = array + size;
+                       i < end; i += sizeof(void *)) {
+               char **dest = reinterpret_cast<char **>(i);
+               map<const void *, unsigned int>::const_iterator
+                               entry(addressMap.find(*dest));
+               if (entry == addressMap.end()) {
+                       throw runtime_error("unable to relocate array member");
+               }
+               unsigned int destOffset = entry->second;
+               *dest = reinterpret_cast<char *>(destOffset);
+       }
+}
 
-void Compiler::Write(ostream &out, const char *data, int amount) {
-       out.write(data, amount);
+void Compiler::Relocate(char *object, const TypeDescription &td) {
+       for (TypeDescription::FieldIterator
+                       i(td.FieldsBegin()), end(td.FieldsEnd());
+                       i != end; ++i) {
+               const FieldDescription &fd = i->second;
+               if (!fd.IsAggregate() && !fd.IsReferenced()) {
+                       continue;
+               }
+               char **dest = reinterpret_cast<char **>(
+                               object + fd.Offset());
+               if (!(*dest)) {
+                       continue;
+               }
+               map<const void *, unsigned int>::const_iterator
+                               entry(addressMap.find(*dest));
+               if (entry == addressMap.end()) {
+                       throw runtime_error(string("unable to relocate field ")
+                                       + i->first + " in object of type " + td.TypeName());
+               }
+               unsigned int destOffset = entry->second;
+               *dest = reinterpret_cast<char *>(destOffset);
+       }
+}
+
+
+void Compiler::Write(ostream &out, const void *data, int amount) {
+       out.write(reinterpret_cast<const char *>(data), amount);
        cursor += amount;
 }
 
 void Compiler::Pad(ostream &out, int to) {
-       for (int remaining(Remaining(cursor, to)); remaining > 0; --remaining) {
-               out.put(0);
+       Fill(out, Remaining(cursor, to));
+}
+
+void Compiler::Fill(ostream &out, int count, char c) {
+       for (int remaining(count); remaining > 0; --remaining) {
+               out.put(c);
                ++cursor;
        }
 }
@@ -182,18 +286,4 @@ int Compiler::Remaining(int value, int alignment) {
        return (have > 0) ? (16 - have) : 0;
 }
 
-
-int Compiler::ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const {
-       return ObjectOffset(typeId, objectId) + fieldOffset;
-}
-
-int Compiler::ObjectOffset(int typeId, int objectId) const {
-       const TypeDescription &td(TypeDescription::Get(typeId));
-       return GetTypeOffset(typeId) + (td.Size() * objectId);
-}
-
-int Compiler::GetTypeOffset(int typeId) const {
-       return objectOffsets.at(typeId);
-}
-
 }
index ab26cea41e5ed955933c4a20e0598b9f1bbfc146..7afe633afd655db4434aaf283abbb32990785084 100644 (file)
@@ -1,14 +1,9 @@
-/*
- * Compiler.h
- *
- *  Created on: Sep 11, 2012
- *      Author: holy
- */
-
 #ifndef LOADER_COMPILER_H_
 #define LOADER_COMPILER_H_
 
+#include "Interpreter.h"
 #include "ObjectFile.h"
+#include "TypeDescription.h"
 
 #include <iosfwd>
 #include <map>
@@ -17,8 +12,6 @@
 
 namespace loader {
 
-class Interpreter;
-
 class Compiler {
 
 public:
@@ -29,36 +22,41 @@ private:
        Compiler &operator =(const Compiler &);
 
 public:
-       void Write(std::ostream &);
+       void Write(std::iostream &);
 
 private:
+       void ReserveHeader(std::ostream &);
+       void WriteObjects(std::ostream &);
+       void WriteOwnStrings(std::ostream &);
+       void WriteArrays(std::ostream &);
        void WriteHeader(std::ostream &);
        void WriteExports(std::ostream &);
        void WriteExternals(std::ostream &);
-       void WriteExportStrings(std::ostream &);
-       void WriteExternalStrings(std::ostream &);
-       void WriteImages(std::ostream &);
-       void WriteObjects(std::ostream &);
 
-       void Write(std::ostream &, const char *data, int amount);
+       void Relocate(std::iostream &);
+       void RelocateArray(char *, int size);
+       void Relocate(char *, const TypeDescription &);
+
+       void PrepareExport(Export &, const std::string &);
+       void PrepareExternal(External &, const Interpreter::PostponedDefinition &);
+       void PrepareObject(Object &, const TypeDescription &, void *);
+
+       void Write(std::ostream &, const void *data, int amount);
        void Pad(std::ostream &, int to);
+       void Fill(std::ostream &, int count, char c = '\0');
        static int Remaining(int value, int alignment);
 
-       int ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const;
-       int ObjectOffset(int typeId, int objectId) const;
-       int GetTypeOffset(int typeId) const;
-
 private:
        const Interpreter &intp;
 
-       int cursor;
+       unsigned int cursor;
 
        ObjectFileHeader fileHeader;
 
-       std::map<int, int> objectOffsets;
+       std::map<const void *, unsigned int> addressMap;
 
 };
 
 }
 
-#endif /* LOADER_COMPILER_H_ */
+#endif
index 8b54fc177913de18a1266f885cc8e959b6eb4eef..fc428cd8365e998ea37128ef23adf2ede9dbb716 100644 (file)
@@ -68,20 +68,64 @@ const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &id
        }
 }
 
+const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) const {
+       std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(identifier));
+       if (i != parsedDefinitions.end()) {
+               return i->second;
+       } else {
+               throw Error("access to undefined object " + identifier);
+       }
+}
+
 
-void *Interpreter::GetObject(int typeId, const std::string &name) {
-       std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
+void *Interpreter::GetObject(
+               int typeId,
+               const std::string &name) {
+       std::map<string, ParsedDefinition>::const_iterator
+                       i(parsedDefinitions.find(name));
        if (i != parsedDefinitions.end()) {
-               const TypeDescription &requested(TypeDescription::Get(typeId));
-               const TypeDescription &actual(TypeDescription::Get(i->second.type));
+               const TypeDescription &requested =
+                               TypeDescription::Get(typeId);
+               const TypeDescription &actual =
+                               TypeDescription::Get(i->second.type);
                if (requested.TypeId() == actual.TypeId()) {
                        return values[actual.TypeId()][i->second.id];
                } else if (actual.IsSubtypeOf(requested)) {
-                       char *sub(reinterpret_cast<char *>(values[actual.TypeId()][i->second.id]));
-                       std::ptrdiff_t offset(actual.SupertypeOffset(requested));
+                       char *sub = reinterpret_cast<char *>(
+                                       values[actual.TypeId()][i->second.id]);
+                       std::ptrdiff_t offset =
+                                       actual.SupertypeOffset(requested);
+                       return sub - offset;
+               } else {
+                       throw Error("cannot cast " + actual.TypeName()
+                                       + " to " + requested.TypeName());
+               }
+       } else {
+               throw Error("access to undefined object " + name);
+       }
+}
+
+const void *Interpreter::GetObject(
+               int typeId,
+               const std::string &name) const {
+       std::map<string, ParsedDefinition>::const_iterator
+                       i(parsedDefinitions.find(name));
+       if (i != parsedDefinitions.end()) {
+               const TypeDescription &requested =
+                               TypeDescription::Get(typeId);
+               const TypeDescription &actual =
+                               TypeDescription::Get(i->second.type);
+               if (requested.TypeId() == actual.TypeId()) {
+                       return values.at(actual.TypeId()).at(i->second.id);
+               } else if (actual.IsSubtypeOf(requested)) {
+                       char *sub = reinterpret_cast<char *>(
+                                       values.at(actual.TypeId()).at(i->second.id));
+                       std::ptrdiff_t offset =
+                                       actual.SupertypeOffset(requested);
                        return sub - offset;
                } else {
-                       throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName());
+                       throw Error("cannot cast " + actual.TypeName()
+                                       + " to " + requested.TypeName());
                }
        } else {
                throw Error("access to undefined object " + name);
@@ -287,11 +331,16 @@ void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyLis
                        if (fd.IsAggregate()) {
                                int arraySize(i->second->GetLiteral().ArraySize());
                                size_t memberSize = fd.IsReferenced() ? sizeof(char *) : fieldType.Size();
-                               char *aggregate = alloc.Alloc(arraySize * memberSize);
-                               char *iter = aggregate;
+                               Array array;
+                               array.size = arraySize * memberSize;
+                               array.data = alloc.Alloc(array.size);
+                               array.ref = fd.IsReferenced();
+                               arrays.push_back(array);
+                               char *iter = reinterpret_cast<char *>(array.data);
                                if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
                                        const vector<PropertyList *> &list(i->second->GetLiteral().GetPropertyLists());
-                                       for (vector<PropertyList *>::const_iterator j(list.begin()), end(list.end());
+                                       for (vector<PropertyList *>::const_iterator
+                                                       j(list.begin()), end(list.end());
                                                        j != end; ++j, iter += memberSize) {
                                                char *member;
                                                if (fd.IsReferenced()) {
@@ -329,11 +378,12 @@ void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyLis
                                                        *reinterpret_cast<void **>(iter)
                                                                        = GetObject(fd.TypeId(), *j);
                                                } else {
-                                                       Postpone(iter, *j, fd.TypeId(), false);
+                                                       Postpone(reinterpret_cast<char *>(array.data),
+                                                                       iter, *j, fd.TypeId(), false);
                                                }
                                        }
                                }
-                               std::memcpy(dest, &aggregate, sizeof(char *));
+                               std::memcpy(dest, &array.data, sizeof(char *));
                                dest += sizeof(char *);
                                std::memcpy(dest, &arraySize, sizeof(int));
                        } else if (i->second->IsLiteral() && !fd.IsReferenced()) {
@@ -355,7 +405,7 @@ void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyLis
                                }
                        }
                } else {
-                       Postpone(object, i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced(), fd.IsAggregate());
+                       Postpone(object, object + fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced(), fd.IsAggregate());
                }
        }
        td.Load(object);
@@ -861,16 +911,14 @@ bool Interpreter::CanLink(const Value &v) const {
 }
 
 void Interpreter::Postpone(
+               char *object,
                char *dest,
                const std::string &identifier,
                int type,
                bool inlined,
                bool aggregate) {
-       char *str(alloc.Alloc(identifier.size() + 1));
-       std::memcpy(str, identifier.c_str(), identifier.size());
-       str[identifier.size()] = '\0';
        postponedDefinitions.push_back(
-                       PostponedDefinition(dest, str, type, inlined, aggregate));
+                       PostponedDefinition(object, dest, identifier, type, inlined, aggregate));
 }
 
 
index 1a73d2dce69c54591354a2ae09fdd9234d03df91..3e9f661e56ccb53da7f5637315c5b1f5e5b9e1a4 100644 (file)
@@ -59,6 +59,7 @@ public:
        /// Error is thrown if the object is undefined or a cast
        /// was unsuccessful.
        void *GetObject(int typeId, const std::string &name);
+       const void *GetObject(int typeId, const std::string &name) const;
 
        /// Register the type descriptions of builtin types.
        /// This should be called before any interpretation (like
@@ -80,18 +81,21 @@ public:
        /// linked by its identifier.
        struct PostponedDefinition {
                PostponedDefinition(
+                               char *object,
                                char *dest,
-                               const char *identifier,
+                               const std::string &identifier,
                                int type,
                                bool inlined,
                                bool aggregate)
-               : dest(dest)
+               : object(object)
+               , dest(dest)
                , identifier(identifier)
                , type(type)
                , inlined(inlined)
                , aggregate(aggregate) { }
+               char *object;
                char *dest;
-               const char *identifier;
+               std::string identifier;
                int type;
                bool inlined;
                bool aggregate;
@@ -104,6 +108,7 @@ public:
        }
        /// Get the object definition for given identifier.
        const ParsedDefinition &GetDefinition(const std::string &identifier);
+       const ParsedDefinition &GetDefinition(const std::string &identifier) const;
        /// Get all images reference by he source.
        /// The returned map is indexed by filenames relative to
        /// the source file and contains ready-to-blit surfaces.
@@ -119,6 +124,14 @@ public:
        const std::map<int, std::vector<void *> > &Values() const {
                return values;
        }
+       struct Array {
+               void *data;
+               unsigned int size;
+               bool ref;
+       };
+       const std::vector<Array> &Arrays() const {
+               return arrays;
+       }
 
 private:
        /// Interpret given definition.
@@ -169,6 +182,7 @@ private:
        bool CanLink(const Value &) const;
        /// Defer linking of given object reference.
        void Postpone(
+                       char *object,
                        char *dest,
                        const std::string &identifier,
                        int type,
@@ -184,6 +198,7 @@ private:
        std::vector<PostponedDefinition> postponedDefinitions;
        std::map<std::string, SDL_Surface *> imageCache;
        std::map<int, std::vector<void *> > values;
+       std::vector<Array> arrays;
 
 };
 
index a1183f790f2b0b98af6bc90dd0c9c092e7413380..2403044ad20fb819a23fafc0b43c2ded125a317c 100644 (file)
@@ -1,10 +1,3 @@
-/*
- * Loader.cpp
- *
- *  Created on: Sep 13, 2012
- *      Author: holy
- */
-
 #include "Loader.h"
 
 #include <climits>
@@ -19,14 +12,10 @@ 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;
        }
 }
 
@@ -37,73 +26,59 @@ void Loader::Load(const std::string &filePath) {
        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());
+       } 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;
        }
 }
 
-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 {
@@ -112,50 +87,28 @@ void Loader::LinkExternals(LoadedObjectFile &object) {
        }
 }
 
-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::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);
                }
        }
 }
 
-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;
+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()) {
+                       continue;
+               }
                char **dest(reinterpret_cast<char **>(object + field.Offset()));
-               *dest = file.At(*reinterpret_cast<int *>(*dest));
+               if (*dest) {
+                       *dest = src + *reinterpret_cast<unsigned int *>(dest);
+               }
        }
 }
 
index 7717167e30361335b1cf1ac6478f5f39f6a7f8dc..cf7dd132a3e76b60c44464cb44aff5a0af82a6fd 100644 (file)
@@ -1,21 +1,14 @@
-/*
- * Loader.h
- *
- *  Created on: Sep 13, 2012
- *      Author: holy
- */
-
 #ifndef LOADER_LOADER_H_
 #define LOADER_LOADER_H_
 
 #include "ObjectFile.h"
 #include "TypeDescription.h"
 
-namespace loader {
-
 #include <map>
 #include <string>
-#include <vector>
+#include <SDL.h>
+
+namespace loader {
 
 class Loader {
 
@@ -27,18 +20,16 @@ public:
        void Load(const std::string &file);
 
 private:
-       void LoadHeader(LoadedObjectFile &);
-       void LoadExports(LoadedObjectFile &);
-       void LinkExternals(LoadedObjectFile &);
-       void LoadImages(LoadedObjectFile &);
-       void LinkObjects(LoadedObjectFile &);
-       void LinkObject(LoadedObjectFile &, const TypeDescription &, char *object);
+       void LoadExports(char *src, Export *begin, Export *end);
+       void LoadExternals(char *src, External *begin, External *end);
+       void LoadObjects(char *src, Object *begin, Object *end);
+       void LoadObject(char *src, char *dest, const TypeDescription &);
 
 private:
-       std::map<std::string, LoadedObjectFile> objectFiles;
+       std::map<std::string, char *> objectFiles;
        std::map<std::string, LoadedExport> exports;
 
 };
 
 }
-#endif /* LOADER_LOADER_H_ */
+#endif
index 4cb886223c80150216cdad339bdbc59312bcbafe..929b54a24025d01e57080593b37e28a5538a7ab7 100644 (file)
@@ -1,12 +1,10 @@
-/*
- * ObjectFile.cpp
- *
- *  Created on: Sep 15, 2012
- *      Author: holy
- */
-
 #include "ObjectFile.h"
 
+#include <stdexcept>
+
+using std::runtime_error;
+
+
 namespace loader {
 
 ObjectFileHeader::ObjectFileHeader()
@@ -15,40 +13,114 @@ ObjectFileHeader::ObjectFileHeader()
 , exportsEnd(0)
 , externalsBegin(0)
 , externalsEnd(0)
-, exportStringsBegin(0)
-, exportStringsEnd(0)
-, externalStringsBegin(0)
-, externalStringsEnd(0)
-, imagesBegin(0)
-, imagesEnd(0)
 , objectsBegin(0)
-, objectsEnd(0) {
+, objectsEnd(0)
+, arraysBegin(0)
+, arraysEnd(0) {
        ident[0] = 'L';
        ident[1] = '2';
        ident[2] = 'E';
        ident[3] = '\n';
 }
 
-LoadedObjectFile::LoadedObjectFile()
-: allocPtr(0)
-, fileHeader(0)
-, typeOffsetsBegin(0)
-, typeOffsetsEnd(0)
-, exportsBegin(0)
-, exportsEnd(0)
-, externalsBegin(0)
-, externalsEnd(0)
-, exportStringsBegin(0)
-, exportStringsEnd(0)
-, externalStringsBegin(0)
-, externalStringsEnd(0)
-, imagesBegin(0)
-, imagesEnd(0)
-, objectsBegin(0)
-, objectsEnd(0)
-, surfaces(0)
-, surfaceCount(0) {
+void ObjectFileHeader::IntegrityCheck(unsigned int fsize) const {
+       if (ident[0] != 'L'
+                       || ident[1] != '2'
+                       || ident[2] != 'E'
+                       || ident[3] != '\n') {
+               throw runtime_error("magic bytes mismatch");
+       }
+       if (versionId != FORMAT_ID) {
+               throw runtime_error("format ID mismatch");
+       }
+       if (exportsBegin < sizeof(ObjectFileHeader)
+                       || exportsBegin > fsize) {
+               throw runtime_error("exports section out of bounds");
+       }
+       if (exportsEnd < exportsBegin
+                       || exportsEnd > fsize
+                       || (exportsEnd - exportsBegin) % sizeof(Export) != 0) {
+               throw runtime_error("bogus exports section end");
+       }
+       if (externalsBegin < sizeof(ObjectFileHeader)
+                       || externalsBegin >= fsize) {
+               throw runtime_error("externals section out of bounds");
+       }
+       if (externalsEnd < externalsBegin
+                       || externalsEnd > fsize
+                       || (externalsEnd - externalsBegin) % sizeof(External) != 0) {
+               throw runtime_error("bogus externals section end");
+       }
+       if (objectsBegin < sizeof(ObjectFileHeader)
+                       || objectsBegin >= fsize
+                       || objectsEnd < objectsBegin
+                       || objectsEnd > fsize) {
+               throw runtime_error("objects section out of bounds");
+       }
+       if (arraysBegin < sizeof(ObjectFileHeader)
+                       || arraysBegin >= fsize
+                       || arraysEnd < arraysBegin
+                       || arraysEnd > fsize) {
+               throw runtime_error("arrays section out of bounds");
+       }
+}
+
+Export *ObjectFileHeader::ExportsBegin() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Export *>(data + exportsBegin);
+}
+
+Export *ObjectFileHeader::ExportsEnd() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Export *>(data + exportsEnd);
+}
+
+External *ObjectFileHeader::ExternalsBegin() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<External *>(data + externalsBegin);
+}
+
+External *ObjectFileHeader::ExternalsEnd() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<External *>(data + externalsEnd);
+}
+
+Object *ObjectFileHeader::ObjectsBegin() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Object *>(data + objectsBegin);
+}
+
+Object *ObjectFileHeader::ObjectsEnd() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Object *>(data + objectsEnd);
+}
+
+Array *ObjectFileHeader::ArraysBegin() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Array *>(data + arraysBegin);
+}
+
+Array *ObjectFileHeader::ArraysEnd() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Array *>(data + arraysEnd);
+}
+
+
+char *Object::RawObject() {
+       return reinterpret_cast<char *>(this) + sizeof(Object);
+}
+
+Object *Object::Next() {
+       return reinterpret_cast<Object *>(RawObject() + size);
+}
+
+
+char *Array::Data() {
+       return reinterpret_cast<char *>(this) + sizeof(Array);
+}
 
+Array *Array::Next() {
+       return reinterpret_cast<Array *>(Data() + size);
 }
 
 }
index 6a7d6773d6403016e7547e9bcf06c13ad4a15cc3..178180a2f8c3eafe27926766cfe25b0c8546482c 100644 (file)
@@ -1,10 +1,3 @@
-/*
- * ObjectFile.h
- *
- *  Created on: Sep 15, 2012
- *      Author: holy
- */
-
 #ifndef LOADER_OBJECTFILE_H_
 #define LOADER_OBJECTFILE_H_
 
 
 namespace loader {
 
-const int FORMAT_ID(1);
-
-struct ObjectFileHeader {
-       char ident[4];
-
-       int versionId;
-
-       int exportsBegin;
-       int exportsEnd;
-
-       int externalsBegin;
-       int externalsEnd;
-
-       int exportStringsBegin;
-       int exportStringsEnd;
-
-       int externalStringsBegin;
-       int externalStringsEnd;
-
-       int imagesBegin;
-       int imagesEnd;
-
-       int objectsBegin;
-       int objectsEnd;
-
-       ObjectFileHeader();
-};
-
-struct TypeOffset {
-       int typeId;
-       int begin;
-       int end;
-};
+const unsigned int FORMAT_ID = 2;
 
 struct Export {
-       int nameOffset;
-       int typeId;
-       int dataOffset;
+       /// Offset of the identifier in the file.
+       unsigned int nameOffset;
+       /// Type ID of referenced object.
+       unsigned int typeId;
+       /// File-offset of the object's actual data.
+       unsigned int dataOffset;
 };
 
 struct External {
-       int nameOffset;
-       int referenceOffset;
-       int inlined;
+       /// File-relative offset of the referenced object's
+       /// identifier.
+       unsigned int nameOffset;
+       /// Target position for linking/inlining.
+       unsigned int referenceOffset;
+       /// Nonzero if the object should be copied rather that
+       /// just writing a reference.
+       unsigned int inlined;
 };
 
-struct ImageProperties {
-       Uint32 flags;
-       int width;
-       int height;
-       int depth;
-       int pitch;
-       Uint32 rmask;
-       Uint32 gmask;
-       Uint32 bmask;
-       Uint32 amask;
+struct Object {
+       unsigned int typeId;
+       unsigned int size;
+       char *RawObject();
+       Object *Next();
 };
 
-struct LoadedObjectFile {
-       char *allocPtr;
-       ObjectFileHeader *fileHeader;
-
-       TypeOffset *typeOffsetsBegin;
-       TypeOffset *typeOffsetsEnd;
-
-       Export *exportsBegin;
-       Export *exportsEnd;
-
-       External *externalsBegin;
-       External *externalsEnd;
-
-       char *exportStringsBegin;
-       char *exportStringsEnd;
-
-       char *externalStringsBegin;
-       char *externalStringsEnd;
-
-       char *imagesBegin;
-       char *imagesEnd;
+struct Array {
+       unsigned int size;
+       bool ref;
+       char *Data();
+       Array *Next();
+};
 
-       char *objectsBegin;
-       char *objectsEnd;
+struct ObjectFileHeader {
+       /// Has to be "L2E\n"
+       char ident[4];
 
-       SDL_Surface **surfaces;
-       int surfaceCount;
+       /// Version ID of the object file format
+       /// For now it must match FORMAT_ID for the loader to be
+       /// able to read it.
+       /// Backwards compatibility might be implemented at some
+       /// point in the future, but don't bet on that ever
+       /// happening.
+       unsigned int versionId;
+
+       /// File-relative offsets of the export section's begin
+       /// and end respectively.
+       /// Exports are named and typed addresses within the
+       /// file. This is essentially an array of Export structs.
+       unsigned int exportsBegin;
+       unsigned int exportsEnd;
+
+       /// File-relative offsets of the externals section's
+       /// begin and end respectively.
+       /// Each external names an entity which must be linked in
+       /// for this object file to function properly. This is
+       /// essentially an array of External structs.
+       unsigned int externalsBegin;
+       unsigned int externalsEnd;
+
+       /// File-relative offsets of the objet section's begin
+       /// and end respectively.
+       /// Each object begins with its type ID followed by its
+       /// size and finally the raw object data.
+       /// All referecte type fields should contain either a
+       /// file-relative offset or zero to indicate a null
+       /// reference.
+       /// This can be sen as a linked list where the next
+       /// object for a node can be obtained by adding the size
+       /// of to int and the object to the current node's
+       /// address.
+       unsigned int objectsBegin;
+       unsigned int objectsEnd;
+
+       /// File-relative offsets of the array section's begin
+       /// and end respectively.
+       /// Each array consists of an unsigned integer indicating
+       /// its size followed by a boolean flag which is true if
+       /// the arrays consists of pointers followed by the data.
+       unsigned int arraysBegin;
+       unsigned int arraysEnd;
 
-       LoadedObjectFile();
+       ObjectFileHeader();
 
-       char *At(int offset) { return reinterpret_cast<char *>(fileHeader) + offset; }
+       /// Check if there are any problems with the file header.
+       /// Throws a std::runtime_error on failure.
+       void IntegrityCheck(unsigned int fileSize) const;
+       Export *ExportsBegin();
+       Export *ExportsEnd();
+       External *ExternalsBegin();
+       External *ExternalsEnd();
+       Object *ObjectsBegin();
+       Object *ObjectsEnd();
+       Array *ArraysBegin();
+       Array *ArraysEnd();
 };
 
 struct LoadedExport {
@@ -110,4 +112,4 @@ struct LoadedExport {
 
 }
 
-#endif /* LOADER_OBJECTFILE_H_ */
+#endif
index 77af8adb008e768e897372b4ec0b6def5570be64..464d9d1f4d9c96de0abd1b7503353285d909152e 100644 (file)
@@ -1,6 +1,10 @@
 #include "PagedAllocator.h"
 
+#include <stdexcept>
+
 using std::deque;
+using std::runtime_error;
+
 
 namespace loader {
 
@@ -32,6 +36,25 @@ char *PagedAllocator::Alloc(unsigned int size) {
        return chunk;
 }
 
+unsigned int PagedAllocator::PageOf(void *ptrIn) const {
+       char *ptr = reinterpret_cast<char *>(ptrIn);
+       unsigned int counter = 0;
+       for (deque<char *>::const_iterator i(pages.begin()), end(pages.end()); i != end; ++i, ++counter) {
+               if (ptr < *i) continue;
+               if (*i < ptr) return counter;
+       }
+       throw runtime_error("PagedAllocator::PageOf");
+}
+
+unsigned int PagedAllocator::PageOffsetOf(void *ptrIn) const {
+       char *ptr = reinterpret_cast<char *>(ptrIn);
+       for (deque<char *>::const_iterator i(pages.begin()), end(pages.end()); i != end; ++i) {
+               if (ptr < *i) continue;
+               if (*i < ptr) return ptr - *i;
+       }
+       throw runtime_error("PagedAllocator::PageOffsetOf");
+}
+
 unsigned int PagedAllocator::Free() const {
        return pageSize - (head - CurrentPage());
 }
index 13b79a49b68767d2eb790c4f81ee12840750d84b..b9922c446446c5bb64f492f365ee04f394d8ceea 100644 (file)
@@ -17,6 +17,9 @@ private:
 public:
        char *Alloc(unsigned int size);
 
+       unsigned int PageOf(void *) const;
+       unsigned int PageOffsetOf(void *) const;
+
 private:
        unsigned int Free() const;
        void NewPage();
index c6e5d7e876498bf5a7c0aae6713ce148f956dfaf..1bb6c6505309117000822b92135c616cfb1d92a3 100644 (file)
@@ -23,6 +23,9 @@ void TypeDescription::AddField(const std::string &n, const FieldDescription &f)
        } else {
                fields.insert(std::make_pair(n, f));
        }
+       if (f.IsReferenced() || f.IsAggregate()) {
+               link = true;
+       }
 }
 
 bool TypeDescription::HasField(const std::string &name) const {
@@ -107,6 +110,20 @@ const TypeDescription &TypeDescription::Get(int id) {
 }
 
 
+int TypeDescription::GetMaxSize() {
+       int max = 0;
+       for (map<int, TypeDescription>::const_iterator
+                       i(typeDescriptions.begin()),
+                       end(typeDescriptions.end());
+                       i != end; ++i) {
+               if (i->second.Size() > max) {
+                       max = i->second.Size();
+               }
+       }
+       return max;
+}
+
+
 void TypeDescription::WriteSourceWiki(std::ostream &out) {
        vector<string> types;
        for (map<int, TypeDescription>::const_iterator i(typeDescriptions.begin()), end(typeDescriptions.end()); i != end; ++i) {
index 262f76b9e9d79ff9bad507e31f5643ead1f4a606..fb1b07890a8fe57bff4b46d58e540d7734e583eb 100644 (file)
@@ -41,6 +41,7 @@ public:
        const FieldDescription &GetField(const std::string &name) const;
        void Construct(void *) const;
        void Load(void *) const;
+       bool NeedsLinking() const { return link; }
 
        void SetConstructor(void (*ctor)(void *)) { constructor = ctor; }
        void SetLoader(void (*ld)(void *)) { loader = ld; }
@@ -67,10 +68,12 @@ public:
        static int GetTypeId(const std::string &);
        static const TypeDescription &Get(int id);
 
+       static int GetMaxSize();
+
        static void WriteSourceWiki(std::ostream &);
 
 private:
-       TypeDescription(int id, const std::string &name) : constructor(0), loader(0), description(0), name(name), id(id), size(0) { }
+       TypeDescription(int id, const std::string &name) : constructor(0), loader(0), description(0), name(name), id(id), size(0), link(false) { }
 
 private:
        void (*constructor)(void *);
@@ -81,6 +84,7 @@ private:
        std::map<int, std::ptrdiff_t> supertypes;
        int id;
        int size;
+       bool link;
 
        static std::map<int, TypeDescription> typeDescriptions;
        static std::map<std::string, int> typeName2ID;
index bdde265098a54a10ab8881d1ff021d56a61c0716..73a9f16fff877eb6ddc013e6cd3b2b4f7e2169ee 100644 (file)
@@ -19,8 +19,6 @@
 #include "common/Script.h"
 #include "common/Spell.h"
 #include "common/Stats.h"
-#include "math/Fixed.h"
-#include "math/Vector.h"
 #include "graphics/CharSelect.h"
 #include "graphics/ComplexAnimation.h"
 #include "graphics/Font.h"
@@ -31,6 +29,7 @@
 #include "graphics/Sprite.h"
 #include "graphics/Texture.h"
 #include "loader/Caster.h"
+#include "loader/Compiler.h"
 #include "loader/Interpreter.h"
 #include "loader/Loader.h"
 #include "loader/ParsedSource.h"
@@ -42,6 +41,8 @@
 #include "map/MapState.h"
 #include "map/Tile.h"
 #include "map/Trigger.h"
+#include "math/Fixed.h"
+#include "math/Vector.h"
 #include "menu/Resources.h"
 #include "sdl/InitImage.h"
 #include "sdl/InitScreen.h"
@@ -67,10 +68,9 @@ using common::GameConfig;
 using common::GameState;
 using common::Hero;
 using common::Spell;
-using math::Fixed;
-using math::Vector;
 using graphics::Texture;
 using loader::Caster;
+using loader::Compiler;
 using loader::Interpreter;
 using loader::Loader;
 using loader::ParsedSource;
@@ -78,6 +78,8 @@ using loader::Parser;
 using loader::TypeDescription;
 using map::Entity;
 using map::MapState;
+using math::Fixed;
+using math::Vector;
 using sdl::InitImage;
 using sdl::InitScreen;
 using sdl::InitSDL;
@@ -158,6 +160,9 @@ int main(int argc, char **argv) {
                        }
                }
 
+               Interpreter intp(source);
+               intp.ReadSource();
+
                switch (args.GetRunLevel()) {
                        case Arguments::WRITE:
                        {
@@ -169,9 +174,14 @@ int main(int argc, char **argv) {
                                                break;
                                        }
                                        case 'o': {
-                                               std::ofstream outstream(args.OutfilePath());
+                                               std::fstream outstream(args.OutfilePath(), std::ios_base::out|std::ios_base::trunc);
+                                               outstream.flush();
+                                               outstream.close();
+                                               outstream.open(args.OutfilePath());
+                                               outstream.exceptions(std::ios_base::badbit|std::ios_base::failbit);
                                                Compiler(intp).Write(outstream);
                                                break;
+                                       }
                                        default: {
                                                throw std::runtime_error(string("don't know how to write file ") + args.OutfilePath());
                                        }
@@ -194,9 +204,6 @@ int main(int argc, char **argv) {
                                break;
                }
 
-               Interpreter intp(source);
-               intp.ReadSource();
-
                if (intp.PostponedDefinitions().size() > 0) {
                        for (vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
                                std::cerr << "missing definition of " << TypeDescription::Get(i->type).TypeName() << " " << i->identifier << std::endl;