Rework of ScriptResolver to binary handling. Now also serialises the type database to the stream, simplifying it's api.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2020-05-02 11:13:04 +02:00
parent 846580550a
commit bd77b58743
6 changed files with 221 additions and 37 deletions

View File

@@ -2,23 +2,30 @@
#define PKMNLIB_FILEBYTECODESTREAM_HPP
#include <angelscript.h>
#include <cstdio>
#include "IPkmnBinaryStream.hpp"
class FileByteCodeStream : public asIBinaryStream {
class FileByteCodeStream : public IPkmnBinaryStream {
private:
FILE* _file;
size_t _readPosition = 0;
public:
explicit FileByteCodeStream(FILE* file) : _file(file) {}
explicit FileByteCodeStream(FILE* file, size_t bound) : IPkmnBinaryStream(bound), _file(file) {}
int Write(const void* ptr, asUINT size) {
int Write(const void* ptr, asUINT size) override {
if (size == 0)
return 0;
return fwrite(ptr, size, 1, _file);
}
int Read(void* ptr, asUINT size) {
int Read(void* ptr, asUINT size) override {
if (size == 0)
return 0;
return fread(ptr, size, 1, _file);
if (_readPosition + size >= _angelScriptBound) {
size = _angelScriptBound - _readPosition;
}
auto diff = fread(ptr, size, 1, _file);
_readPosition += diff;
return diff;
}
};

View File

@@ -0,0 +1,111 @@
#ifndef PKMNLIB_IPKMNBINARYSTREAM_HPP
#define PKMNLIB_IPKMNBINARYSTREAM_HPP
#include <Arbutils/Collections/Dictionary.hpp>
#include <Arbutils/ConstString.hpp>
#include <CreatureLib/Battling/ScriptHandling/ScriptCategory.hpp>
#include <angelscript.h>
class IPkmnBinaryStream : public asIBinaryStream {
protected:
size_t _angelScriptBound;
IPkmnBinaryStream(size_t angelScriptBound) : _angelScriptBound(angelScriptBound) {}
public:
virtual void WriteTypes(const Dictionary<ScriptCategory, Dictionary<ConstString, AngelScriptTypeInfo*>>& types) {
// We serialize our types in the format
// "[category(byte)][name(str)]\2[decl(str)]\2[name(str)]\2[decl(str)]\1[category(byte)]...."
ScriptCategory categoryArr[1];
for (const auto& dic : types) {
// Write the category
categoryArr[0] = dic.first;
Write(categoryArr, sizeof(ScriptCategory));
for (const auto& inner : dic.second) {
// Write the script name
Write(inner.first.c_str(), sizeof(char) * inner.first.Length());
// Write the divider
Write("\2", sizeof(char));
// Write the declaration of the script
auto decl = inner.second->GetDecl();
Write(decl, sizeof(char) * strlen(decl));
// Write another divider.
Write("\2", sizeof(char));
}
// Write the divider between categories.
Write("\1", sizeof(char));
}
}
virtual Dictionary<ScriptCategory, Dictionary<ConstString, uint32_t>> ReadTypes() {
_angelScriptBound = SIZE_MAX;
Dictionary<ScriptCategory, Dictionary<ConstString, uint32_t>> types;
ScriptCategory categoryArr[1];
while (true) {
// Every inner database starts with the category, of known size. Read that.
auto read = Read(categoryArr, sizeof(ScriptCategory));
// If we haven't read anything, we are finished.
if (read == 0) {
break;
}
Dictionary<ConstString, uint32_t> innerDb;
// We don't know the sizes of the name and decl. Allocate 128 characters for them, as that should be enough.
char name[128];
char decl[128];
size_t pos = 0;
bool isDecl = false;
while (true) {
// Keep reading characters
char cArr[1];
Read(cArr, sizeof(char));
auto c = cArr[0];
// If we find a '\1' separator
if (c == '\1') {
// and if we were reading the decl
if (isDecl) {
// Insert the name and decl into the dictionary. Close off the decl with eof as well.
decl[pos] = '\0';
innerDb.Insert(Arbutils::CaseInsensitiveConstString(name),
Arbutils::CaseInsensitiveConstString::GetHash(decl));
}
// If we have found \1, we are done with the current category, so break.
break;
}
// If we find a '\2' separator, we need to toggle between writing to name and writing to decl. If we
// were writing a decl, also insert the name and decl into the dictionary.
if (c == '\2') {
if (isDecl) {
// Insert the name and decl into the dictionary. Close off the decl with eof as well.
decl[pos] = '\0';
innerDb.Insert(Arbutils::CaseInsensitiveConstString(name),
Arbutils::CaseInsensitiveConstString::GetHash(decl));
// Reset our position and toggle back to name.
pos = 0;
isDecl = false;
continue;
} else {
// Close of the name with eof, reset position and toggle to decl.
name[pos] = '\0';
pos = 0;
isDecl = true;
continue;
}
} else {
// If we haven't found any control character, just add the character to the thing we are writing to,
// and increment the position.
if (isDecl) {
decl[pos++] = c;
} else {
name[pos++] = c;
}
}
}
types.Insert(categoryArr[0], innerDb);
}
return types;
}
};
#endif // PKMNLIB_IPKMNBINARYSTREAM_HPP

View File

@@ -3,7 +3,7 @@
#include <angelscript.h>
#include <vector>
class MemoryByteCodeStream : public asIBinaryStream {
class MemoryByteCodeStream : public IPkmnBinaryStream {
private:
uint8_t* _out;
size_t _index = 0;
@@ -13,12 +13,15 @@ private:
#define MEM_STEPS 256
public:
MemoryByteCodeStream() : _out((uint8_t*)malloc(MEM_STEPS * sizeof(uint8_t))), _capacity(MEM_STEPS){};
MemoryByteCodeStream(uint8_t* in, size_t size) : _out(in), _size(size) {}
MemoryByteCodeStream()
: IPkmnBinaryStream(SIZE_MAX), _out((uint8_t*)malloc(MEM_STEPS * sizeof(uint8_t))), _capacity(MEM_STEPS){};
MemoryByteCodeStream(uint8_t* in, size_t size) : IPkmnBinaryStream(SIZE_MAX), _out(in), _size(size) {}
uint8_t* GetOut() const { return _out; }
size_t GetWrittenSize() const { return _size; }
void SetAngelScriptBound(size_t bound) noexcept { _angelScriptBound = bound; }
int Write(const void* ptr, asUINT size) final {
if (size == 0)
return 0;
@@ -38,6 +41,14 @@ public:
_size += size;
return size;
}
void WriteToPosition(const void* ptr, asUINT size, size_t position) {
auto start = reinterpret_cast<const uint8_t*>(ptr);
for (asUINT index = 0; index < size; index++) {
_out[position + index] = *(start + index);
}
}
int Read(void* ptr, asUINT size) final {
if (size == 0)
return 0;