#include "Script.h"
+#include "../math/Vector.h"
+
namespace common {
Script::Script()
}
+
+unsigned int Script::Code::Size() const {
+ unsigned int size = sizeof(Code);
+ if (numParams == 0) {
+ return size;
+ }
+ unsigned int argSize = 0;
+ switch (type) {
+ default:
+ argSize = 0;
+ break;
+ case TYPE_ADDRESS:
+ argSize = sizeof(void *);
+ break;
+ case TYPE_INTEGER:
+ argSize = sizeof(int);
+ break;
+ case TYPE_VECTOR:
+ argSize = sizeof(math::Vector<int>);
+ break;
+ }
+ switch (numParams) {
+ case 3:
+ case 2:
+ if (reg2 == 7) {
+ size += argSize;
+ }
+ case 1:
+ if (reg1 == 7) {
+ size += argSize;
+ }
+ default:
+ break;
+ }
+ return size;
+}
+
}
Type type : 2;
unsigned int reg1 : 3;
unsigned int reg2 : 3;
+
+ unsigned int Size() const;
};
public:
#include "Interpreter.h"
#include "TypeDescription.h"
+#include "../common/Script.h"
#include <climits>
#include <cstring>
using std::make_pair;
using std::map;
using std::ostream;
+using std::pair;
using std::runtime_error;
using std::set;
using std::string;
fileHeader.arraysBegin = out.tellp();
WriteArrays(out);
fileHeader.arraysEnd = out.tellp();
+ fileHeader.scriptsBegin = out.tellp();
+ WriteScripts(out);
+ fileHeader.scriptsEnd = out.tellp();
out.seekp(0);
WriteHeader(out);
WriteExports(out);
Write(out, &object, sizeof(Object));
addressMap.insert(make_pair(*j, out.tellp()));
Write(out, *j, object.size);
+
+ if (td.TypeId() == Interpreter::SCRIPT_ID) {
+ common::Script *script = reinterpret_cast<common::Script *>(*j);
+ scripts.push_back(make_pair(const_cast<char *>(script->text), script->textlen));
+ }
}
}
}
}
}
+void Compiler::WriteScripts(ostream &out) {
+ for (vector<pair<const char *, unsigned int> >::const_iterator
+ i(scripts.begin()), end(scripts.end());
+ i != end; ++i) {
+ Script s;
+ s.size = i->second;
+ Write(out, &s, sizeof(Script));
+ addressMap.insert(make_pair(i->first, out.tellp()));
+ Write(out, i->first, s.size);
+ }
+}
+
void Compiler::PrepareExport(Export &exp, const string &str) {
const Interpreter::ParsedDefinition &dfn
out.seekg(out.tellp());
delete[] buffer;
}
+ Script script;
+ for (; out && out.tellg() < fileHeader.scriptsEnd;) {
+ out.read(reinterpret_cast<char *>(&script), sizeof(Script));
+ buffer = new char[script.size];
+ unsigned int pos = out.tellg();
+ out.read(buffer, script.size);
+ RelocateScript(buffer, script.size);
+ out.seekp(pos);
+ out.write(buffer, script.size);
+ out.seekg(out.tellp());
+ delete[] buffer;
+ }
}
void Compiler::RelocateArray(char *array, int size) {
}
}
+void Compiler::RelocateScript(char *text, unsigned int textlen) {
+ for (char *i = text, *end = text + textlen; i < end;) {
+ common::Script::Code *code =
+ reinterpret_cast<common::Script::Code *>(i);
+ if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) {
+ if (code->reg1 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ std::map<const void *, unsigned int>::const_iterator
+ found(addressMap.find(*reinterpret_cast<void **>(addr)));
+ if (found == addressMap.end()) {
+ throw std::runtime_error("unable to relocate script code");
+ }
+ *reinterpret_cast<unsigned int *>(addr) = found->second;
+ }
+
+ if (code->numParams > 1 && code->reg2 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ if (code->reg1 == 7) {
+ addr += sizeof(void *);
+ }
+ std::map<const void *, unsigned int>::const_iterator
+ found(addressMap.find(*reinterpret_cast<void **>(addr)));
+ if (found == addressMap.end()) {
+ throw std::runtime_error("unable to relocate script code");
+ }
+ *reinterpret_cast<unsigned int *>(addr) = found->second;
+ }
+ }
+ i += code->Size();
+ }
+}
+
void Compiler::Write(ostream &out, const void *data, int amount) {
out.write(reinterpret_cast<const char *>(data), amount);
#include <iosfwd>
#include <map>
#include <memory>
+#include <utility>
+#include <vector>
#include <SDL.h>
namespace loader {
void WriteExports(std::ostream &);
void WriteExternals(std::ostream &);
void WriteImages(std::ostream &);
+ void WriteScripts(std::ostream &);
void Relocate(std::iostream &);
void RelocateArray(char *, int size);
void Relocate(unsigned int pos, char *dest, const TypeDescription &);
+ void RelocateScript(char *, unsigned int);
void PrepareExport(Export &, const std::string &);
void PrepareExternal(External &, const Interpreter::PostponedDefinition &);
std::map<const void *, unsigned int> addressMap;
std::map<unsigned int, void *> images;
+ std::vector<std::pair<const char *, unsigned int> > scripts;
};
td.SetDescription("A signed integer.");
td.SetSize(sizeof(int));
}
- {;
+ {
TypeDescription &td(TypeDescription::Create(PATH_ID, "Path"));
td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location.");
td.SetSize(1);
td.AddSupertype(STRING_ID, 0);
}
{
+ Script s;
TypeDescription &td(TypeDescription::Create(SCRIPT_ID, "Script"));
td.SetDescription("Collection of commands that define a behaviour.");
td.SetSize(sizeof(Script));
+ td.AddField("text", FieldDescription(((char *)&s.text) - ((char *)&s), STRING_ID).SetAggregate());
}
{
TypeDescription &td(TypeDescription::Create(STRING_ID, "String"));
#include "Loader.h"
+#include "../common/Script.h"
+
#include <climits>
#include <cstring>
#include <fstream>
LoadImages(header->ident,
header->ImagesBegin(),
header->ImagesEnd());
+ LoadScripts(header->ident,
+ header->ScriptsBegin(),
+ header->ScriptsEnd());
InitObjects(
header->ObjectsBegin(),
}
}
+void Loader::LoadScripts(char *src, Script *begin, Script *end) {
+ for (Script *s = begin; s < end; s = s->Next()) {
+ for (char *i = s->Text(), *end = s->Text() + s->size; i < end;) {
+ common::Script::Code *code =
+ reinterpret_cast<common::Script::Code *>(i);
+ if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) {
+ if (code->reg1 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ unsigned int offset = *reinterpret_cast<unsigned int *>(addr);
+ if (offset) {
+ *reinterpret_cast<const char **>(addr) = src + offset;
+ }
+ }
+
+ if (code->numParams > 1 && code->reg2 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ if (code->reg1 == 7) {
+ addr += sizeof(void *);
+ }
+ unsigned int offset = *reinterpret_cast<unsigned int *>(addr);
+ if (offset) {
+ *reinterpret_cast<const char **>(addr) = src + offset;
+ }
+ }
+ }
+ i += code->Size();
+ }
+ }
+}
+
void Loader::InitObjects(Object *begin, Object *end) {
for (Object *i = begin; i < end; i = i->Next()) {
void LoadObjects(char *src, Object *begin, Object *end);
void LoadObject(char *src, char *dest, const TypeDescription &);
void LoadArrays(char *src, Array *begin, Array *end);
+ void LoadScripts(char *src, Script *begin, Script *end);
void InitObjects(Object *begin, Object *end);
void InitObject(char *object, const TypeDescription &);
, exportsEnd(0)
, externalsBegin(0)
, externalsEnd(0)
+, imagesBegin(0)
+, imagesEnd(0)
, objectsBegin(0)
, objectsEnd(0)
, arraysBegin(0)
-, arraysEnd(0) {
+, arraysEnd(0)
+, scriptsBegin(0)
+, scriptsEnd(0) {
ident[0] = 'L';
ident[1] = '2';
ident[2] = 'E';
return reinterpret_cast<Array *>(data + arraysEnd);
}
+Script *ObjectFileHeader::ScriptsBegin() {
+ char *data = reinterpret_cast<char *>(this);
+ return reinterpret_cast<Script *>(data + scriptsBegin);
+}
+
+Script *ObjectFileHeader::ScriptsEnd() {
+ char *data = reinterpret_cast<char *>(this);
+ return reinterpret_cast<Script *>(data + scriptsEnd);
+}
+
char *Object::RawObject() {
return reinterpret_cast<char *>(this) + sizeof(Object);
return reinterpret_cast<Array *>(Data() + size);
}
+char *Script::Text() {
+ return reinterpret_cast<char *>(this) + sizeof(Script);
+}
+
+Script *Script::Next() {
+ return reinterpret_cast<Script *>(Text() + size);
+}
+
}
Array *Next();
};
+struct Script {
+ unsigned int size;
+
+ char *Text();
+ Script *Next();
+};
+
struct ObjectFileHeader {
/// Has to be "L2E\n"
char ident[4];
unsigned int arraysBegin;
unsigned int arraysEnd;
+ /// File-relative offsets of the script section's begin
+ /// and end respectively.
+ /// Each script is an unsigned int with the length in
+ /// bytes followed by the script text.
+ unsigned int scriptsBegin;
+ unsigned int scriptsEnd;
+
ObjectFileHeader();
/// Check if there are any problems with the file header.
Object *ObjectsEnd();
Array *ArraysBegin();
Array *ArraysEnd();
+ Script *ScriptsBegin();
+ Script *ScriptsEnd();
private:
bool CheckSection(