]> git.localhorst.tv Git - l2e.git/commitdiff
ref and load images in l2o files
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 17 Mar 2013 16:35:58 +0000 (17:35 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 17 Mar 2013 16:35:58 +0000 (17:35 +0100)
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/TypeDescription.cpp
src/loader/TypeDescription.h

index b583aabb298a46017fb87d23d1772e1e79fed12e..96c0cc1425b643a8068a7b5ff6c8e2ff3697069e 100644 (file)
@@ -27,8 +27,7 @@ using std::vector;
 namespace loader {
 
 Compiler::Compiler(const Interpreter &intp)
-: intp(intp)
-, cursor(0) {
+: intp(intp) {
        int headerSize(sizeof(ObjectFileHeader));
 
        fileHeader.exportsBegin = headerSize;
@@ -47,19 +46,23 @@ void Compiler::Write(iostream &out) {
        ReserveHeader(out);
        WriteObjects(out);
        WriteOwnStrings(out);
-       fileHeader.objectsEnd = cursor;
+       fileHeader.objectsEnd = out.tellp();
        Pad(out, 16);
-       fileHeader.arraysBegin = cursor;
+       fileHeader.arraysBegin = out.tellp();
        WriteArrays(out);
-       fileHeader.arraysEnd = cursor;
+       fileHeader.arraysEnd = out.tellp();
        out.seekp(0);
-       cursor = 0;
        WriteHeader(out);
        WriteExports(out);
        WriteExternals(out);
        out.seekg(fileHeader.objectsBegin);
        out.clear();
        Relocate(out);
+       fileHeader.imagesBegin = out.tellp();
+       WriteImages(out);
+       fileHeader.imagesEnd = out.tellp();
+       out.seekp(0);
+       WriteHeader(out);
 }
 
 void Compiler::ReserveHeader(ostream &out) {
@@ -79,21 +82,34 @@ void Compiler::WriteOwnStrings(ostream &out) {
                object.typeId = Interpreter::STRING_ID;
                object.size = i->size() + 1;
                Write(out, &object, sizeof(Object));
-               addressMap.insert(make_pair(i->c_str(), cursor));
+               addressMap.insert(make_pair(i->c_str(), out.tellp()));
                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));
+               addressMap.insert(make_pair(
+                               i->identifier.c_str(), out.tellp()));
                Write(out, i->identifier.c_str(), object.size);
        }
+       for (std::map<std::string, SDL_Surface *>::const_iterator
+                       i(intp.Images().begin()), end(intp.Images().end());
+                       i != end; ++i) {
+               addressMap.insert(make_pair(
+                               i->second, 0));
+               Object object;
+               object.typeId = Interpreter::STRING_ID;
+               object.size = i->first.size() + 1;
+               Write(out, &object, sizeof(Object));
+               addressMap.insert(make_pair(
+                               i->first.c_str(), out.tellp()));
+               Write(out, i->first.c_str(), object.size);
+       }
 }
 
 void Compiler::WriteExports(ostream &out) {
@@ -130,6 +146,7 @@ void Compiler::WriteObjects(ostream &out) {
                        Object object;
                        PrepareObject(object, td, *j);
                        Write(out, &object, sizeof(Object));
+                       addressMap.insert(make_pair(*j, out.tellp()));
                        Write(out, *j, object.size);
                }
        }
@@ -145,11 +162,24 @@ void Compiler::WriteArrays(ostream &out) {
                array.size = i->size;
                array.ref = i->ref;
                Write(out, &array, sizeof(Array));
-               addressMap.insert(make_pair(i->data, cursor));
+               addressMap.insert(make_pair(i->data, out.tellp()));
                Write(out, i->data, array.size);
        }
 }
 
+void Compiler::WriteImages(ostream &out) {
+       for (std::map<unsigned int, void *>::const_iterator
+                       i(images.begin()), end(images.end());
+                       i != end; ++i) {
+               const string &path = intp.FindImage(
+                               reinterpret_cast<SDL_Surface *>(i->second));
+               Image img;
+               img.pathOffset = addressMap.at(path.c_str());
+               img.destOffset = i->first;
+               Write(out, &img, sizeof(Image));
+       }
+}
+
 
 void Compiler::PrepareExport(Export &exp, const string &str) {
        const Interpreter::ParsedDefinition &dfn
@@ -173,7 +203,6 @@ 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:
@@ -190,18 +219,13 @@ 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);
+               Relocate(pos, buffer, td);
                out.seekp(pos);
                out.write(buffer, object.size);
                out.seekg(out.tellp());
@@ -211,23 +235,22 @@ void Compiler::Relocate(iostream &out) {
        Array array;
        for (; out && out.tellg() < fileHeader.arraysEnd;) {
                out.read(reinterpret_cast<char *>(&array), sizeof(Array));
+               buffer = new char[array.size];
+               unsigned int pos = out.tellg();
+               out.read(buffer, array.size);
                if (array.ref) {
-                       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;
                } else {
                        const TypeDescription &td = TypeDescription::Get(array.typeId);
-                       for (char *i = array.Data(), *end = array.Data() + array.size;
+                       for (char *i = buffer, *end = buffer + array.size;
                                        i < end; i += td.Size()) {
-                               Relocate(i, td);
+                               Relocate(pos + (i - buffer), i, td);
                        }
                }
+               out.seekp(pos);
+               out.write(buffer, array.size);
+               out.seekg(out.tellp());
+               delete[] buffer;
        }
 }
 
@@ -245,44 +268,52 @@ void Compiler::RelocateArray(char *array, int size) {
        }
 }
 
-void Compiler::Relocate(char *object, const TypeDescription &td) {
+void Compiler::Relocate(
+               unsigned int pos,
+               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());
+               if (fd.IsAggregate() || fd.IsReferenced()) {
+                       char **dest = reinterpret_cast<char **>(
+                                       object + fd.Offset());
+                       if (!(*dest)) {
+                               continue;
+                       }
+                       if (fd.TypeId() == Interpreter::IMAGE_ID) {
+                               images.insert(make_pair(
+                                               pos + fd.Offset(), *dest));
+                       }
+                       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);
+               } else {
+                       const TypeDescription &nestedType
+                                       = TypeDescription::Get(fd.TypeId());
+                       Relocate(pos + fd.Offset(), object + fd.Offset(), nestedType);
                }
-               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) {
-       Fill(out, Remaining(cursor, to));
+       Fill(out, Remaining(out.tellp(), to));
 }
 
 void Compiler::Fill(ostream &out, int count, char c) {
        for (int remaining(count); remaining > 0; --remaining) {
                out.put(c);
-               ++cursor;
        }
 }
 
index 7afe633afd655db4434aaf283abbb32990785084..2f89752690664d3a33426621cc33a3a4f8c92a30 100644 (file)
@@ -32,10 +32,11 @@ private:
        void WriteHeader(std::ostream &);
        void WriteExports(std::ostream &);
        void WriteExternals(std::ostream &);
+       void WriteImages(std::ostream &);
 
        void Relocate(std::iostream &);
        void RelocateArray(char *, int size);
-       void Relocate(char *, const TypeDescription &);
+       void Relocate(unsigned int pos, char *dest, const TypeDescription &);
 
        void PrepareExport(Export &, const std::string &);
        void PrepareExternal(External &, const Interpreter::PostponedDefinition &);
@@ -49,11 +50,10 @@ private:
 private:
        const Interpreter &intp;
 
-       unsigned int cursor;
-
        ObjectFileHeader fileHeader;
 
        std::map<const void *, unsigned int> addressMap;
+       std::map<unsigned int, void *> images;
 
 };
 
index 51c6b9ce3b2648d23310f00f015126f2f394e2d7..ecbb076224e225bad82cd92017c4db9d5caa33fc 100644 (file)
@@ -906,6 +906,17 @@ SDL_Surface *Interpreter::GetImage(const string &path) {
        }
 }
 
+const string &Interpreter::FindImage(SDL_Surface *img) const {
+       for (std::map<string, SDL_Surface *>::const_iterator
+                       i(imageCache.begin()), end(imageCache.end());
+                       i != end; ++i) {
+               if (i->second == img) {
+                       return i->first;
+               }
+       }
+       throw Error("unable to locate image");
+}
+
 
 bool Interpreter::CanLink(const Value &v) const {
        return v.IsLiteral() || source.IsDefined(v.GetIdentifier());
index 7eccab344bdc105cd50ddda63f65c80bb6c72690..6b3835a49ad3c270f2fc9530a71824fd6da6a577 100644 (file)
@@ -115,6 +115,7 @@ public:
        const std::map<std::string, SDL_Surface *> &Images() const {
                return imageCache;
        }
+       const std::string &FindImage(SDL_Surface *) const;
        /// Get all definitions that were postponed because they
        /// were not in the parsed source.
        const std::vector<PostponedDefinition> &PostponedDefinitions() const {
index 1e0050dbc022a64c1d7896428caad0b152dac2f0..dbfbe3186fdd93e8a508110c082753197778cc3c 100644 (file)
@@ -5,6 +5,7 @@
 #include <fstream>
 #include <stdexcept>
 #include <utility>
+#include <SDL_image.h>
 
 using std::make_pair;
 using std::map;
@@ -57,6 +58,9 @@ void Loader::Load(const std::string &filePath) {
                LoadArrays(header->ident,
                                header->ArraysBegin(),
                                header->ArraysEnd());
+               LoadImages(header->ident,
+                               header->ImagesBegin(),
+                               header->ImagesEnd());
        } catch (...) {
                delete[] block;
                throw;
@@ -93,13 +97,27 @@ void Loader::LoadExternals(char *src, External *begin, External *end) {
        }
 }
 
+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;
+               }
+       }
+}
+
 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);
        }
 }
 
@@ -108,12 +126,15 @@ 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()) {
-                       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);
                }
        }
 }
@@ -123,8 +144,10 @@ void Loader::LoadArrays(char *src, Array *begin, Array *end) {
                if (i->ref) {
                        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);
+                               unsigned int offset = *reinterpret_cast<unsigned int *>(j);
+                               if (offset) {
+                                       *reinterpret_cast<char **>(j) = src + offset;
+                               }
                        }
                } else {
                        const TypeDescription &td = TypeDescription::Get(i->typeId);
index 0a7f845e062d8f9861d22d2debf4ff5aa3471cb2..0839ecb3d3212a946c32303f35340fff803f6355 100644 (file)
@@ -24,6 +24,7 @@ public:
 private:
        void LoadExports(char *src, Export *begin, Export *end);
        void LoadExternals(char *src, External *begin, External *end);
+       void LoadImages(char *src, Image *begin, Image *end);
        void LoadObjects(char *src, Object *begin, Object *end);
        void LoadObject(char *src, char *dest, const TypeDescription &);
        void LoadArrays(char *src, Array *begin, Array *end);
@@ -31,6 +32,7 @@ private:
 private:
        std::map<std::string, char *> objectFiles;
        std::map<std::string, LoadedExport> exports;
+       std::map<std::string, SDL_Surface *> images;
 
 };
 
index 929b54a24025d01e57080593b37e28a5538a7ab7..7207eb0ed92eb66e52d252f605cb5e75c97d63be 100644 (file)
@@ -33,38 +33,42 @@ void ObjectFileHeader::IntegrityCheck(unsigned int fsize) const {
        if (versionId != FORMAT_ID) {
                throw runtime_error("format ID mismatch");
        }
-       if (exportsBegin < sizeof(ObjectFileHeader)
-                       || exportsBegin > fsize) {
+       if (!CheckSection(exportsBegin, exportsEnd, fsize)) {
                throw runtime_error("exports section out of bounds");
        }
-       if (exportsEnd < exportsBegin
-                       || exportsEnd > fsize
-                       || (exportsEnd - exportsBegin) % sizeof(Export) != 0) {
+       if ((exportsEnd - exportsBegin) % sizeof(Export) != 0) {
                throw runtime_error("bogus exports section end");
        }
-       if (externalsBegin < sizeof(ObjectFileHeader)
-                       || externalsBegin >= fsize) {
+       if (!CheckSection(externalsBegin, externalsEnd, fsize)) {
                throw runtime_error("externals section out of bounds");
        }
-       if (externalsEnd < externalsBegin
-                       || externalsEnd > fsize
-                       || (externalsEnd - externalsBegin) % sizeof(External) != 0) {
+       if ((externalsEnd - externalsBegin) % sizeof(External) != 0) {
                throw runtime_error("bogus externals section end");
        }
-       if (objectsBegin < sizeof(ObjectFileHeader)
-                       || objectsBegin >= fsize
-                       || objectsEnd < objectsBegin
-                       || objectsEnd > fsize) {
+       if (!CheckSection(imagesBegin, imagesEnd, fsize)) {
+               throw runtime_error("images section out of bounds");
+       }
+       if ((imagesEnd - imagesBegin) % sizeof(Image) != 0) {
+               throw runtime_error("bogus images section end");
+       }
+       if (!CheckSection(objectsBegin, objectsEnd, fsize)) {
                throw runtime_error("objects section out of bounds");
        }
-       if (arraysBegin < sizeof(ObjectFileHeader)
-                       || arraysBegin >= fsize
-                       || arraysEnd < arraysBegin
-                       || arraysEnd > fsize) {
+       if (!CheckSection(arraysBegin, arraysEnd, fsize)) {
                throw runtime_error("arrays section out of bounds");
        }
 }
 
+bool ObjectFileHeader::CheckSection(
+               unsigned int begin,
+               unsigned int end,
+               unsigned int fsize) const {
+       return begin >= sizeof(ObjectFileHeader)
+                       && begin < fsize
+                       && end >= begin
+                       && end <= fsize;
+}
+
 Export *ObjectFileHeader::ExportsBegin() {
        char *data = reinterpret_cast<char *>(this);
        return reinterpret_cast<Export *>(data + exportsBegin);
@@ -85,6 +89,16 @@ External *ObjectFileHeader::ExternalsEnd() {
        return reinterpret_cast<External *>(data + externalsEnd);
 }
 
+Image *ObjectFileHeader::ImagesBegin() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Image *>(data + imagesBegin);
+}
+
+Image *ObjectFileHeader::ImagesEnd() {
+       char *data = reinterpret_cast<char *>(this);
+       return reinterpret_cast<Image *>(data + imagesEnd);
+}
+
 Object *ObjectFileHeader::ObjectsBegin() {
        char *data = reinterpret_cast<char *>(this);
        return reinterpret_cast<Object *>(data + objectsBegin);
index b497e344b500ea45ba9fa4e80cbbbda1946c9629..98aff02918aaef733737fd2cc23765fd8f2d0ebc 100644 (file)
@@ -27,6 +27,14 @@ struct External {
        unsigned int inlined;
 };
 
+struct Image {
+       /// File-relative offset to the image's path string.
+       unsigned int pathOffset;
+       /// File-relative offset of the target position of the
+       /// image's reference.
+       unsigned int destOffset;
+};
+
 struct Object {
        unsigned int typeId;
        unsigned int size;
@@ -69,6 +77,12 @@ struct ObjectFileHeader {
        unsigned int externalsBegin;
        unsigned int externalsEnd;
 
+       /// File-relative offsets of the image section's begin and
+       /// end respectively.
+       /// Denotes an array of Image structs.
+       unsigned int imagesBegin;
+       unsigned int imagesEnd;
+
        /// File-relative offsets of the objet section's begin
        /// and end respectively.
        /// Each object begins with its type ID followed by its
@@ -100,10 +114,18 @@ struct ObjectFileHeader {
        Export *ExportsEnd();
        External *ExternalsBegin();
        External *ExternalsEnd();
+       Image *ImagesBegin();
+       Image *ImagesEnd();
        Object *ObjectsBegin();
        Object *ObjectsEnd();
        Array *ArraysBegin();
        Array *ArraysEnd();
+
+private:
+       bool CheckSection(
+                       unsigned int begin,
+                       unsigned int end,
+                       unsigned int fsize) const;
 };
 
 struct LoadedExport {
index 1bb6c6505309117000822b92135c616cfb1d92a3..19974fb52cced072a31509df6453cf84117f46d6 100644 (file)
@@ -23,9 +23,6 @@ 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 {
index fb1b07890a8fe57bff4b46d58e540d7734e583eb..7b7483624bfe1577979e5ff849405ab25e2fc65b 100644 (file)
@@ -41,7 +41,6 @@ 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; }
@@ -73,7 +72,7 @@ public:
        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), link(false) { }
+       TypeDescription(int id, const std::string &name) : constructor(0), loader(0), description(0), name(name), id(id), size(0) { }
 
 private:
        void (*constructor)(void *);
@@ -84,7 +83,6 @@ 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;