From: Daniel Karbach Date: Sun, 17 Mar 2013 16:35:58 +0000 (+0100) Subject: ref and load images in l2o files X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=1970312e983541d32d4ff73c81b8d90156a7bb99;p=l2e.git ref and load images in l2o files --- diff --git a/src/loader/Compiler.cpp b/src/loader/Compiler.cpp index b583aab..96c0cc1 100644 --- a/src/loader/Compiler.cpp +++ b/src/loader/Compiler.cpp @@ -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::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::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::const_iterator + i(images.begin()), end(images.end()); + i != end; ++i) { + const string &path = intp.FindImage( + reinterpret_cast(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(&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(&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( - object + fd.Offset()); - if (!(*dest)) { - continue; - } - map::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( + object + fd.Offset()); + if (!(*dest)) { + continue; + } + if (fd.TypeId() == Interpreter::IMAGE_ID) { + images.insert(make_pair( + pos + fd.Offset(), *dest)); + } + map::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(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(destOffset); } } void Compiler::Write(ostream &out, const void *data, int amount) { out.write(reinterpret_cast(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; } } diff --git a/src/loader/Compiler.h b/src/loader/Compiler.h index 7afe633..2f89752 100644 --- a/src/loader/Compiler.h +++ b/src/loader/Compiler.h @@ -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 addressMap; + std::map images; }; diff --git a/src/loader/Interpreter.cpp b/src/loader/Interpreter.cpp index 51c6b9c..ecbb076 100644 --- a/src/loader/Interpreter.cpp +++ b/src/loader/Interpreter.cpp @@ -906,6 +906,17 @@ SDL_Surface *Interpreter::GetImage(const string &path) { } } +const string &Interpreter::FindImage(SDL_Surface *img) const { + for (std::map::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()); diff --git a/src/loader/Interpreter.h b/src/loader/Interpreter.h index 7eccab3..6b3835a 100644 --- a/src/loader/Interpreter.h +++ b/src/loader/Interpreter.h @@ -115,6 +115,7 @@ public: const std::map &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 &PostponedDefinitions() const { diff --git a/src/loader/Loader.cpp b/src/loader/Loader.cpp index 1e0050d..dbfbe31 100644 --- a/src/loader/Loader.cpp +++ b/src/loader/Loader.cpp @@ -5,6 +5,7 @@ #include #include #include +#include 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(src + i->destOffset); + std::map::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(object + field.Offset())); - if (*dest) { - *dest = src + *reinterpret_cast(dest); + 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); } } } @@ -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(j) = - src + *reinterpret_cast(j); + unsigned int offset = *reinterpret_cast(j); + if (offset) { + *reinterpret_cast(j) = src + offset; + } } } else { const TypeDescription &td = TypeDescription::Get(i->typeId); diff --git a/src/loader/Loader.h b/src/loader/Loader.h index 0a7f845..0839ecb 100644 --- a/src/loader/Loader.h +++ b/src/loader/Loader.h @@ -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 objectFiles; std::map exports; + std::map images; }; diff --git a/src/loader/ObjectFile.cpp b/src/loader/ObjectFile.cpp index 929b54a..7207eb0 100644 --- a/src/loader/ObjectFile.cpp +++ b/src/loader/ObjectFile.cpp @@ -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(this); return reinterpret_cast(data + exportsBegin); @@ -85,6 +89,16 @@ External *ObjectFileHeader::ExternalsEnd() { return reinterpret_cast(data + externalsEnd); } +Image *ObjectFileHeader::ImagesBegin() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + imagesBegin); +} + +Image *ObjectFileHeader::ImagesEnd() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + imagesEnd); +} + Object *ObjectFileHeader::ObjectsBegin() { char *data = reinterpret_cast(this); return reinterpret_cast(data + objectsBegin); diff --git a/src/loader/ObjectFile.h b/src/loader/ObjectFile.h index b497e34..98aff02 100644 --- a/src/loader/ObjectFile.h +++ b/src/loader/ObjectFile.h @@ -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 { diff --git a/src/loader/TypeDescription.cpp b/src/loader/TypeDescription.cpp index 1bb6c65..19974fb 100644 --- a/src/loader/TypeDescription.cpp +++ b/src/loader/TypeDescription.cpp @@ -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 { diff --git a/src/loader/TypeDescription.h b/src/loader/TypeDescription.h index fb1b078..7b74836 100644 --- a/src/loader/TypeDescription.h +++ b/src/loader/TypeDescription.h @@ -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 supertypes; int id; int size; - bool link; static std::map typeDescriptions; static std::map typeName2ID;