namespace loader {
Compiler::Compiler(const Interpreter &intp)
-: intp(intp)
-, cursor(0) {
+: intp(intp) {
int headerSize(sizeof(ObjectFileHeader));
fileHeader.exportsBegin = headerSize;
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) {
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) {
Object object;
PrepareObject(object, td, *j);
Write(out, &object, sizeof(Object));
+ addressMap.insert(make_pair(*j, out.tellp()));
Write(out, *j, object.size);
}
}
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
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:
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());
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;
}
}
}
}
-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;
}
}
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 &);
private:
const Interpreter &intp;
- unsigned int cursor;
-
ObjectFileHeader fileHeader;
std::map<const void *, unsigned int> addressMap;
+ std::map<unsigned int, void *> images;
};
}
}
+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());
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 {
#include <fstream>
#include <stdexcept>
#include <utility>
+#include <SDL_image.h>
using std::make_pair;
using std::map;
LoadArrays(header->ident,
header->ArraysBegin(),
header->ArraysEnd());
+ LoadImages(header->ident,
+ header->ImagesBegin(),
+ header->ImagesEnd());
} catch (...) {
delete[] block;
throw;
}
}
+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);
}
}
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);
}
}
}
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);
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);
private:
std::map<std::string, char *> objectFiles;
std::map<std::string, LoadedExport> exports;
+ std::map<std::string, SDL_Surface *> images;
};
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);
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);
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;
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
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 {
} else {
fields.insert(std::make_pair(n, f));
}
- if (f.IsReferenced() || f.IsAggregate()) {
- link = true;
- }
}
bool TypeDescription::HasField(const std::string &name) const {
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; }
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 *);
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;