Makes some stuff work
This commit is contained in:
parent
43e16ce945
commit
e5a3717e64
24 changed files with 2048 additions and 1 deletions
72
.vscode/settings.json
vendored
Normal file
72
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"vector": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"array": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"bit": "cpp",
|
||||||
|
"*.tcc": "cpp",
|
||||||
|
"bitset": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"charconv": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"compare": "cpp",
|
||||||
|
"concepts": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"system_error": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"format": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"numbers": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"print": "cpp",
|
||||||
|
"span": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"stop_token": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"text_encoding": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"typeinfo": "cpp",
|
||||||
|
"variant": "cpp",
|
||||||
|
"__bit_reference": "cpp",
|
||||||
|
"__locale": "cpp",
|
||||||
|
"__threading_support": "cpp",
|
||||||
|
"__verbose_abort": "cpp",
|
||||||
|
"execution": "cpp",
|
||||||
|
"ios": "cpp",
|
||||||
|
"locale": "cpp",
|
||||||
|
"queue": "cpp",
|
||||||
|
"stack": "cpp"
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
# Add source files
|
# Add source files
|
||||||
file(GLOB SOURCES "src/utils/*.cpp" "src/nbt/*.cpp")
|
file(GLOB SOURCES "src/utils/*.cpp" "src/types/*.cpp")
|
||||||
|
|
||||||
# Add an shared library target
|
# Add an shared library target
|
||||||
add_library(ac SHARED ${SOURCES})
|
add_library(ac SHARED ${SOURCES})
|
||||||
|
|
40
src/nbt/Accountant.cpp
Normal file
40
src/nbt/Accountant.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "Accountant.h"
|
||||||
|
#include "Tag.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace nbt;
|
||||||
|
using namespace libac;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
int NBTAccountant::_prettyIndex = 0;
|
||||||
|
|
||||||
|
void NBTAccountant::printRead(const Tag &tag)
|
||||||
|
{
|
||||||
|
tag.prettyPrint(_prettyIndex, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NBTAccountant::visitTag()
|
||||||
|
{
|
||||||
|
_prettyIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NBTAccountant::leaveTag(const Tag &tag)
|
||||||
|
{
|
||||||
|
// Assuming Tag has virtual methods to check its type or a `getType` method
|
||||||
|
if (dynamic_cast<const CompoundTag *>(&tag) || dynamic_cast<const ListTag *>(&tag))
|
||||||
|
{
|
||||||
|
if (const CompoundTag *ct = dynamic_cast<const CompoundTag *>(&tag))
|
||||||
|
{
|
||||||
|
ct->endPrettyPrint(_prettyIndex);
|
||||||
|
}
|
||||||
|
else if (const ListTag *lt = dynamic_cast<const ListTag *>(&tag))
|
||||||
|
{
|
||||||
|
lt->endPrettyPrint(_prettyIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_prettyIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
21
src/nbt/Accountant.h
Normal file
21
src/nbt/Accountant.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef NBTACCOUNTANT_H
|
||||||
|
#define NBTACCOUNTANT_H
|
||||||
|
|
||||||
|
#include "Tag.h" // Assuming this includes definitions for Tag, CompoundTag, and ListTag
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
class NBTAccountant
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void printRead(const Tag &tag);
|
||||||
|
static void visitTag();
|
||||||
|
static void leaveTag(const Tag &tag);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int _prettyIndex;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NBTACCOUNTANT_H
|
104
src/nbt/ByteArrayTag.cpp
Normal file
104
src/nbt/ByteArrayTag.cpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "ByteArrayTag.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
ByteArrayTag::ByteArrayTag() : Tag()
|
||||||
|
{
|
||||||
|
// Default constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayTag::ByteArrayTag(const std::vector<uint8_t> &value) : Tag(), value(value)
|
||||||
|
{
|
||||||
|
// Constructor with initial value
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteArrayTag::readValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
int len = data.readInt();
|
||||||
|
value.clear();
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
value.push_back(data.readByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteArrayTag::writeValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
data.writeInt(static_cast<int>(value.size()));
|
||||||
|
for (int i : value)
|
||||||
|
{
|
||||||
|
data.writeByte(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType ByteArrayTag::getTagType() const
|
||||||
|
{
|
||||||
|
return TagType::ByteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic ByteArrayTag::getValue() const
|
||||||
|
{
|
||||||
|
return dynamic(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteArrayTag::setValue(const dynamic &val)
|
||||||
|
{
|
||||||
|
value = val.get<vector<uint8_t>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteArrayTag::prettyPrint(int indent, bool recurse) const
|
||||||
|
{
|
||||||
|
std::cout << std::setw(indent) << std::setfill('\t') << ""
|
||||||
|
<< Tag::getCanonicalName(getTagType()) << ": [";
|
||||||
|
for (size_t i = 0; i < value.size(); i++)
|
||||||
|
{
|
||||||
|
std::cout << value[i];
|
||||||
|
if (i < value.size() - 1)
|
||||||
|
{
|
||||||
|
std::cout << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteArrayTag::writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const
|
||||||
|
{
|
||||||
|
builder << (isList ? std::string(indent, '\t') : "") << "[B; ";
|
||||||
|
for (size_t i = 0; i < value.size(); i++)
|
||||||
|
{
|
||||||
|
builder << value[i] << "B";
|
||||||
|
if (i < value.size() - 1)
|
||||||
|
{
|
||||||
|
builder << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteArrayTag::readStringifiedValue(StringReader &reader)
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
reader.expect('[');
|
||||||
|
reader.expect('B');
|
||||||
|
reader.expect(';');
|
||||||
|
value.clear();
|
||||||
|
|
||||||
|
while (reader.peek() != ']')
|
||||||
|
{
|
||||||
|
uint8_t num = stoi(reader.readNumber());
|
||||||
|
value.push_back(num);
|
||||||
|
|
||||||
|
reader.expect('b');
|
||||||
|
|
||||||
|
if (reader.peek() == ',')
|
||||||
|
reader.next();
|
||||||
|
}
|
||||||
|
reader.expect(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/nbt/ByteArrayTag.h
Normal file
37
src/nbt/ByteArrayTag.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef BYTEARRAYTAG_H
|
||||||
|
#define BYTEARRAYTAG_H
|
||||||
|
|
||||||
|
#include "Tag.h"
|
||||||
|
#include "../utils/ByteLayer.h" // Assuming ByteLayer is a class you have
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
class ByteArrayTag : public Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteArrayTag();
|
||||||
|
ByteArrayTag(const std::vector<uint8_t> &value);
|
||||||
|
|
||||||
|
// Override functions from the Tag class
|
||||||
|
void readValue(ByteLayer &data) override;
|
||||||
|
void writeValue(ByteLayer &data) override;
|
||||||
|
TagType getTagType() const override;
|
||||||
|
dynamic getValue() const;
|
||||||
|
void setValue(const dynamic &val) override;
|
||||||
|
void prettyPrint(int indent, bool recurse) const override;
|
||||||
|
void writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const override;
|
||||||
|
void readStringifiedValue(StringReader &reader) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<uint8_t> value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BYTEARRAYTAG_H
|
66
src/nbt/ByteTag.cpp
Normal file
66
src/nbt/ByteTag.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "ByteTag.h"
|
||||||
|
#include "../utils/ByteLayer.h"
|
||||||
|
#include "../utils/StringBuilder.h"
|
||||||
|
#include "../utils/StringReader.h"
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
ByteTag::ByteTag() : Tag(), value(0)
|
||||||
|
{
|
||||||
|
// Default constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteTag::ByteTag(int value) : Tag(), value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteTag::readValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
value = data.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteTag::writeValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
data.writeByte(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType ByteTag::getTagType() const
|
||||||
|
{
|
||||||
|
return TagType::Byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic ByteTag::getValue() const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteTag::setValue(const dynamic &val)
|
||||||
|
{
|
||||||
|
value = val.get<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteTag::prettyPrint(int indent, bool recurse) const
|
||||||
|
{
|
||||||
|
std::cout << std::setw(indent) << std::setfill('\t') << ""
|
||||||
|
<< Tag::getCanonicalName(getTagType()) << ": " << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteTag::writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const
|
||||||
|
{
|
||||||
|
builder << (isList ? std::string(indent, '\t') : "") << value << "b";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteTag::readStringifiedValue(StringReader &reader)
|
||||||
|
{
|
||||||
|
std::string val = reader.readNumber();
|
||||||
|
value = stoi(val);
|
||||||
|
|
||||||
|
reader.expect('b');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/nbt/ByteTag.h
Normal file
37
src/nbt/ByteTag.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef BYTETAG_H
|
||||||
|
#define BYTETAG_H
|
||||||
|
|
||||||
|
#include "Tag.h"
|
||||||
|
#include <string>
|
||||||
|
#include "../utils/ByteLayer.h"
|
||||||
|
#include "../utils/StringBuilder.h"
|
||||||
|
#include "../utils/StringReader.h"
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
class ByteTag : public Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteTag();
|
||||||
|
ByteTag(int value);
|
||||||
|
~ByteTag();
|
||||||
|
|
||||||
|
// Override functions from the Tag class
|
||||||
|
void readValue(ByteLayer &data) override;
|
||||||
|
void writeValue(ByteLayer &data) override;
|
||||||
|
TagType getTagType() const override;
|
||||||
|
dynamic getValue() const override;
|
||||||
|
void setValue(const dynamic &val) override;
|
||||||
|
void prettyPrint(int indent, bool recurse) const override;
|
||||||
|
void writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const override;
|
||||||
|
void readStringifiedValue(StringReader &reader) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BYTETAG_H
|
62
src/nbt/DoubleTag.cpp
Normal file
62
src/nbt/DoubleTag.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "DoubleTag.h"
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
DoubleTag::DoubleTag() : Tag(), value(0.0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleTag::DoubleTag(double val) : Tag(), value(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleTag::readValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
value = data.readDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleTag::writeValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
data.writeDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType DoubleTag::getTagType() const
|
||||||
|
{
|
||||||
|
return TagType::Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic DoubleTag::getValue() const
|
||||||
|
{
|
||||||
|
return dynamic(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleTag::setValue(const dynamic &val)
|
||||||
|
{
|
||||||
|
value = val.get<double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleTag::prettyPrint(int indent, bool recurse) const
|
||||||
|
{
|
||||||
|
cout << setw(indent) << setfill('\t') << Tag::getCanonicalName(getTagType()) << ": " << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleTag::writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const
|
||||||
|
{
|
||||||
|
builder << (isList ? std::string(indent, '\t') : "") << value << "d";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleTag::readStringifiedValue(StringReader &reader)
|
||||||
|
{
|
||||||
|
double val = stod(reader.readNumber());
|
||||||
|
value = val;
|
||||||
|
|
||||||
|
reader.expect('d');
|
||||||
|
}
|
||||||
|
}
|
30
src/nbt/DoubleTag.h
Normal file
30
src/nbt/DoubleTag.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef DOUBLE_TAG_H
|
||||||
|
#define DOUBLE_TAG_H
|
||||||
|
|
||||||
|
#include "Tag.h"
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
class DoubleTag : public Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DoubleTag();
|
||||||
|
DoubleTag(double val);
|
||||||
|
~DoubleTag();
|
||||||
|
|
||||||
|
// Function overrides
|
||||||
|
void readValue(ByteLayer &data) override;
|
||||||
|
void writeValue(ByteLayer &data) override;
|
||||||
|
TagType getTagType() const override;
|
||||||
|
dynamic getValue() const override;
|
||||||
|
void setValue(const dynamic &val) override;
|
||||||
|
void prettyPrint(int indent, bool recurse) const override;
|
||||||
|
void writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const override;
|
||||||
|
void readStringifiedValue(StringReader &reader) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
59
src/nbt/EndTag.cpp
Normal file
59
src/nbt/EndTag.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include "EndTag.h"
|
||||||
|
#include "Tag.h" // Ensure you include the Tag class header
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip> // For std::setw if needed
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
EndTag::EndTag() : Tag()
|
||||||
|
{
|
||||||
|
// Constructor implementation if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTag::~EndTag(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTag::readValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
// Implementation here
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTag::writeValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
// Implementation here
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType EndTag::getTagType() const
|
||||||
|
{
|
||||||
|
return TagType::End;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTag::setValue(const dynamic &val)
|
||||||
|
{
|
||||||
|
// Implementation here
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic EndTag::getValue() const
|
||||||
|
{
|
||||||
|
// Implementation here
|
||||||
|
return new dynamic(new string("")); // Return appropriate value
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTag::prettyPrint(int indent, bool recurse) const
|
||||||
|
{
|
||||||
|
std::cout << std::setw(indent) << std::setfill('\t') << "" << Tag::getCanonicalName(getTagType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTag::writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const
|
||||||
|
{
|
||||||
|
// Implementation here
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTag::readStringifiedValue(StringReader &reader)
|
||||||
|
{
|
||||||
|
// Implementation here
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
src/nbt/EndTag.h
Normal file
29
src/nbt/EndTag.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef ENDTAG_H
|
||||||
|
#define ENDTAG_H
|
||||||
|
|
||||||
|
#include "Tag.h"
|
||||||
|
#include "../utils/ByteLayer.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
class EndTag : public Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EndTag();
|
||||||
|
~EndTag();
|
||||||
|
|
||||||
|
// Override functions from the Tag class
|
||||||
|
void readValue(ByteLayer &data) override;
|
||||||
|
void writeValue(ByteLayer &data) override;
|
||||||
|
TagType getTagType() const override;
|
||||||
|
void setValue(const dynamic &val) override;
|
||||||
|
dynamic getValue() const override;
|
||||||
|
void prettyPrint(int indent, bool recurse) const override;
|
||||||
|
void writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const override;
|
||||||
|
void readStringifiedValue(StringReader &reader) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
62
src/nbt/FloatTag.cpp
Normal file
62
src/nbt/FloatTag.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "FloatTag.h"
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
FloatTag::FloatTag() : Tag(), value(0.0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatTag::FloatTag(float val) : Tag(), value(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatTag::readValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
value = data.readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatTag::writeValue(ByteLayer &data)
|
||||||
|
{
|
||||||
|
data.writeFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType FloatTag::getTagType() const
|
||||||
|
{
|
||||||
|
return TagType::Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic FloatTag::getValue() const
|
||||||
|
{
|
||||||
|
return dynamic(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatTag::setValue(const dynamic &val)
|
||||||
|
{
|
||||||
|
value = val.get<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatTag::prettyPrint(int indent, bool recurse) const
|
||||||
|
{
|
||||||
|
cout << setw(indent) << setfill('\t') << Tag::getCanonicalName(getTagType()) << ": " << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatTag::writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const
|
||||||
|
{
|
||||||
|
builder << (isList ? std::string(indent, '\t') : "") << value << "f";
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatTag::readStringifiedValue(StringReader &reader)
|
||||||
|
{
|
||||||
|
float val = stof(reader.readNumber());
|
||||||
|
value = val;
|
||||||
|
|
||||||
|
reader.expect('f');
|
||||||
|
}
|
||||||
|
}
|
30
src/nbt/FloatTag.h
Normal file
30
src/nbt/FloatTag.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef FLOAT_TAG_H
|
||||||
|
#define FLOAT_TAG_H
|
||||||
|
|
||||||
|
#include "Tag.h"
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
class FloatTag : public Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FloatTag();
|
||||||
|
FloatTag(float val);
|
||||||
|
~FloatTag();
|
||||||
|
|
||||||
|
// Function overrides
|
||||||
|
void readValue(ByteLayer &data) override;
|
||||||
|
void writeValue(ByteLayer &data) override;
|
||||||
|
TagType getTagType() const override;
|
||||||
|
dynamic getValue() const override;
|
||||||
|
void setValue(const dynamic &val) override;
|
||||||
|
void prettyPrint(int indent, bool recurse) const override;
|
||||||
|
void writeStringifiedValue(StringBuilder &builder, int indent, bool isList) const override;
|
||||||
|
void readStringifiedValue(StringReader &reader) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
255
src/nbt/Tag.cpp
Normal file
255
src/nbt/Tag.cpp
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
#include "Tag.h"
|
||||||
|
#include "EndTag.h"
|
||||||
|
#include <cctype>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "../utils/ByteLayer.h"
|
||||||
|
#include "../utils/StringBuilder.h"
|
||||||
|
#include "../utils/StringReader.h"
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
std::shared_ptr<Tag> Tag::readNamedTag(ByteLayer &data)
|
||||||
|
{
|
||||||
|
int type = data.readByte();
|
||||||
|
switch (static_cast<TagType>(type))
|
||||||
|
{
|
||||||
|
case TagType::End:
|
||||||
|
return std::make_shared<EndTag>();
|
||||||
|
case TagType::Byte:
|
||||||
|
// handle other cases similarly
|
||||||
|
default:
|
||||||
|
// default handling
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tag::shouldQuoteName()
|
||||||
|
{
|
||||||
|
std::string key = getKey();
|
||||||
|
if (key.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
for (char digit : key)
|
||||||
|
{
|
||||||
|
if (letters.find(digit) != std::string::npos)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tag::shouldQuote(const std::string &value)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
for (char digit : value)
|
||||||
|
{
|
||||||
|
if (letters.find(digit) != std::string::npos)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tag::writeNamedTag(Tag &tag, ByteLayer &data)
|
||||||
|
{
|
||||||
|
data.writeByte(tag.getType());
|
||||||
|
if (tag.getType() != static_cast<int>(TagType::End))
|
||||||
|
{
|
||||||
|
data.writeString(tag.getKey());
|
||||||
|
tag.writeValue(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Tag> Tag::readStringifiedNamedTag(StringReader &string)
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
if (string.peek() == '{' || string.peek() == '[')
|
||||||
|
{
|
||||||
|
name = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = string.readString();
|
||||||
|
string.expect(':');
|
||||||
|
}
|
||||||
|
TagType type = Tag::getStringifiedTagType(string);
|
||||||
|
std::shared_ptr<Tag> tag = makeTagOfType(type);
|
||||||
|
tag->setKey(name);
|
||||||
|
tag->readStringifiedValue(string);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tag::writeStringifiedNamedTag(Tag &tag, StringBuilder &builder, int indents)
|
||||||
|
{
|
||||||
|
if (tag.getType() != (int)TagType::End)
|
||||||
|
{
|
||||||
|
if (tag.getKey().empty())
|
||||||
|
{
|
||||||
|
builder << std::string(indents, '\t');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tag.shouldQuoteName())
|
||||||
|
{
|
||||||
|
builder << std::string(indents, '\t') << "\"" << tag.getKey() << "\": ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder << std::string(indents, '\t') << tag.getKey() << ": ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tag.writeStringifiedValue(builder, indents + 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Tag::getCanonicalName(TagType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TagType::String:
|
||||||
|
return "TAG_String";
|
||||||
|
case TagType::List:
|
||||||
|
return "TAG_List";
|
||||||
|
case TagType::LongArray:
|
||||||
|
return "TAG_LongArray";
|
||||||
|
case TagType::Long:
|
||||||
|
return "TAG_Long";
|
||||||
|
case TagType::IntArray:
|
||||||
|
return "TAG_IntArray";
|
||||||
|
case TagType::Int:
|
||||||
|
return "TAG_Int";
|
||||||
|
case TagType::Compound:
|
||||||
|
return "TAG_Compound";
|
||||||
|
case TagType::ByteArray:
|
||||||
|
return "TAG_ByteArray";
|
||||||
|
case TagType::Byte:
|
||||||
|
return "TAG_Byte";
|
||||||
|
case TagType::Double:
|
||||||
|
return "TAG_Double";
|
||||||
|
case TagType::Float:
|
||||||
|
return "TAG_Float";
|
||||||
|
case TagType::Short:
|
||||||
|
return "TAG_Short";
|
||||||
|
case TagType::End:
|
||||||
|
return "TAG_End";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType Tag::getStringifiedTagType(StringReader &str)
|
||||||
|
{
|
||||||
|
str.startSeek();
|
||||||
|
TagType ret = TagType::End;
|
||||||
|
bool isNumber = true;
|
||||||
|
bool isAlpha = true; // Is digits only
|
||||||
|
|
||||||
|
while (str.canRead() && ret == TagType::End)
|
||||||
|
{
|
||||||
|
char val = str.next();
|
||||||
|
val = std::toupper(val); // Convert to uppercase
|
||||||
|
|
||||||
|
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
if (alphabet.find(val) == std::string::npos)
|
||||||
|
{
|
||||||
|
isAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (val)
|
||||||
|
{
|
||||||
|
case '{':
|
||||||
|
ret = TagType::Compound;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
{
|
||||||
|
// Check for a type Prefix
|
||||||
|
std::string X = str.readUntil(';');
|
||||||
|
std::transform(X.begin(), X.end(), X.begin(), ::toupper); // Convert to uppercase
|
||||||
|
if (X == "B")
|
||||||
|
{
|
||||||
|
ret = TagType::ByteArray;
|
||||||
|
}
|
||||||
|
else if (X == "I")
|
||||||
|
{
|
||||||
|
ret = TagType::IntArray;
|
||||||
|
}
|
||||||
|
else if (X == "L")
|
||||||
|
{
|
||||||
|
ret = TagType::LongArray;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = TagType::List;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'B':
|
||||||
|
ret = TagType::Byte;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
ret = TagType::Double;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
ret = TagType::Float;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
ret = TagType::Int;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
ret = TagType::Long;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
ret = TagType::Short;
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
ret = TagType::String;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
case '\n':
|
||||||
|
if (str.getSeeked() >= 1)
|
||||||
|
ret = TagType::String;
|
||||||
|
if (isNumber)
|
||||||
|
ret = TagType::Int;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!str.isDigit(val))
|
||||||
|
{
|
||||||
|
if (isNumber)
|
||||||
|
isNumber = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str.endSeek();
|
||||||
|
if (!isNumber && isAlpha)
|
||||||
|
ret = TagType::String;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
129
src/nbt/Tag.h
Normal file
129
src/nbt/Tag.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#ifndef LIBNBT_TAG_H
|
||||||
|
#define LIBNBT_TAG_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include "../utils/ByteLayer.h"
|
||||||
|
#include "../utils/StringBuilder.h"
|
||||||
|
#include "../utils/StringReader.h"
|
||||||
|
#include "../types/dynamic.h"
|
||||||
|
|
||||||
|
using namespace libac;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace nbt
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class TagType
|
||||||
|
{
|
||||||
|
End = 0,
|
||||||
|
Byte = 1,
|
||||||
|
Short = 2,
|
||||||
|
Int = 3,
|
||||||
|
Long = 4,
|
||||||
|
Float = 5,
|
||||||
|
Double = 6,
|
||||||
|
ByteArray = 7,
|
||||||
|
String = 8,
|
||||||
|
List = 9,
|
||||||
|
Compound = 10,
|
||||||
|
IntArray = 11,
|
||||||
|
LongArray = 12
|
||||||
|
|
||||||
|
};
|
||||||
|
class Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Tag() = default;
|
||||||
|
|
||||||
|
int getType() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(getTagType());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual TagType getTagType() const = 0;
|
||||||
|
|
||||||
|
bool hasParent() const
|
||||||
|
{
|
||||||
|
return _parentTag != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TagType getStringifiedTagType(StringReader &str);
|
||||||
|
|
||||||
|
void updateParent(std::shared_ptr<Tag> tag)
|
||||||
|
{
|
||||||
|
if (tag == nullptr)
|
||||||
|
{
|
||||||
|
_parentTag.reset();
|
||||||
|
setParentTagType(TagType::End);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_parentTag = tag;
|
||||||
|
setParentTagType(tag->getTagType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Tag> getParent() const
|
||||||
|
{
|
||||||
|
return _parentTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType getParentTagType() const
|
||||||
|
{
|
||||||
|
return _parentTagType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setParentTagType(TagType type)
|
||||||
|
{
|
||||||
|
_parentTagType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void writeValue(ByteLayer &data) const = 0;
|
||||||
|
virtual void readValue(ByteLayer &data) = 0;
|
||||||
|
|
||||||
|
std::string getKey() const
|
||||||
|
{
|
||||||
|
return _key.empty() ? "" : _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setKey(const std::string &key)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void writeStringifiedValue(StringBuilder &stream, int indent, bool isList) const = 0;
|
||||||
|
virtual void readStringifiedValue(StringReader &reader) = 0;
|
||||||
|
virtual void writeValue(ByteLayer &data);
|
||||||
|
virtual void setValue(const dynamic &val);
|
||||||
|
virtual void prettyPrint(int indent, bool recurse) const;
|
||||||
|
virtual void readStringifiedValue(StringReader &reader);
|
||||||
|
virtual dynamic getValue() const;
|
||||||
|
virtual void setValue(int val);
|
||||||
|
|
||||||
|
virtual bool equals(const Tag &other) const
|
||||||
|
{
|
||||||
|
return getType() == other.getType() && getKey() == other.getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Tag> readNamedTag(ByteLayer &data);
|
||||||
|
static void writeNamedTag(Tag &tag, ByteLayer &data);
|
||||||
|
static std::shared_ptr<Tag> readStringifiedNamedTag(StringReader &string);
|
||||||
|
static void writeStringifiedNamedTag(Tag &tag, StringBuilder &builder, int indents);
|
||||||
|
|
||||||
|
static std::shared_ptr<Tag> makeTagOfType(TagType type);
|
||||||
|
|
||||||
|
static std::string getCanonicalName(TagType type);
|
||||||
|
bool shouldQuoteName();
|
||||||
|
static bool shouldQuote(const string &value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<Tag> _parentTag;
|
||||||
|
TagType _parentTagType = TagType::End;
|
||||||
|
std::string _key;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
139
src/types/dynamic.cpp
Normal file
139
src/types/dynamic.cpp
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#include <string>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "dynamic.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
dynamic::dynamic(T y)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<T, char>)
|
||||||
|
{
|
||||||
|
Type = 1;
|
||||||
|
x.c = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, unsigned char>)
|
||||||
|
{
|
||||||
|
Type = 2;
|
||||||
|
x.uc = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, short>)
|
||||||
|
{
|
||||||
|
Type = 3;
|
||||||
|
x.s = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, long>)
|
||||||
|
{
|
||||||
|
Type = 4;
|
||||||
|
x.l = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, int>)
|
||||||
|
{
|
||||||
|
Type = 5;
|
||||||
|
x.i = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, float>)
|
||||||
|
{
|
||||||
|
Type = 6;
|
||||||
|
x.f = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, double>)
|
||||||
|
{
|
||||||
|
Type = 7;
|
||||||
|
x.d = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, std::string>)
|
||||||
|
{
|
||||||
|
Type = 8;
|
||||||
|
x.str = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, uint8_t>)
|
||||||
|
{
|
||||||
|
Type = 9;
|
||||||
|
x.u8 = y;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v < T, vector<uint8_t>)
|
||||||
|
{
|
||||||
|
Type = 10;
|
||||||
|
x.u8l = y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(!std::is_same_v<T, T>, "Unsupported type for dynamic");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T dynamic::get() const
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<T, char> && Type == 1)
|
||||||
|
{
|
||||||
|
return x.c;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, unsigned char> && Type == 2)
|
||||||
|
{
|
||||||
|
return x.uc;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, short> && Type == 3)
|
||||||
|
{
|
||||||
|
return x.s;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, long> && Type == 4)
|
||||||
|
{
|
||||||
|
return x.l;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, int> && Type == 5)
|
||||||
|
{
|
||||||
|
return x.i;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, float> && Type == 6)
|
||||||
|
{
|
||||||
|
return x.f;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, double> && Type == 7)
|
||||||
|
{
|
||||||
|
return x.d;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, std::string> && Type == 8)
|
||||||
|
{
|
||||||
|
return x.str;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, uint8_t> && Type == 9)
|
||||||
|
{
|
||||||
|
return x.u8;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, vector<uint8_t>> && Type == 10)
|
||||||
|
{
|
||||||
|
return x.u8l;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Type mismatch or unsupported type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template dynamic::dynamic(char);
|
||||||
|
template dynamic::dynamic(unsigned char);
|
||||||
|
template dynamic::dynamic(short);
|
||||||
|
template dynamic::dynamic(long);
|
||||||
|
template dynamic::dynamic(int);
|
||||||
|
template dynamic::dynamic(float);
|
||||||
|
template dynamic::dynamic(double);
|
||||||
|
template dynamic::dynamic(std::string);
|
||||||
|
template dynamic::dynamic(uint8_t);
|
||||||
|
template dynamic::dynamic(vector<uint8_t>);
|
||||||
|
|
||||||
|
template char dynamic::get<char>() const;
|
||||||
|
template unsigned char dynamic::get<unsigned char>() const;
|
||||||
|
template short dynamic::get<short>() const;
|
||||||
|
template long dynamic::get<long>() const;
|
||||||
|
template int dynamic::get<int>() const;
|
||||||
|
template float dynamic::get<float>() const;
|
||||||
|
template double dynamic::get<double>() const;
|
||||||
|
template std::string dynamic::get<std::string>() const;
|
||||||
|
template uint8_t dynamic::get<uint8_t>() const;
|
||||||
|
template vector<uint8_t> dynamic::get<vector<uint8_t>>() const;
|
||||||
|
}
|
44
src/types/dynamic.h
Normal file
44
src/types/dynamic.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef DYNAMIC_H
|
||||||
|
#define DYNAMIC_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
|
||||||
|
union all
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
unsigned char uc;
|
||||||
|
short s;
|
||||||
|
long l;
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
string str;
|
||||||
|
uint8_t u8;
|
||||||
|
vector<uint8_t> u8l;
|
||||||
|
};
|
||||||
|
|
||||||
|
class dynamic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~dynamic();
|
||||||
|
|
||||||
|
char Type;
|
||||||
|
all x;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
dynamic(T y);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T get() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
433
src/utils/ByteLayer.cpp
Normal file
433
src/utils/ByteLayer.cpp
Normal file
|
@ -0,0 +1,433 @@
|
||||||
|
#include "ByteLayer.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <random>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
|
||||||
|
void ByteLayer::ensureCapacity(size_t additionalBytes)
|
||||||
|
{
|
||||||
|
size_t requiredCapacity = position + additionalBytes;
|
||||||
|
if (requiredCapacity > byteBuffer.size())
|
||||||
|
{
|
||||||
|
byteBuffer.resize(requiredCapacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeInt(int value)
|
||||||
|
{
|
||||||
|
ensureCapacity(4);
|
||||||
|
std::memcpy(&byteBuffer[position], &value, 4);
|
||||||
|
position += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeDouble(double value)
|
||||||
|
{
|
||||||
|
ensureCapacity(8);
|
||||||
|
std::memcpy(&byteBuffer[position], &value, 8);
|
||||||
|
position += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeString(const std::string &value)
|
||||||
|
{
|
||||||
|
writeShort(static_cast<int16_t>(value.size()));
|
||||||
|
ensureCapacity(value.size());
|
||||||
|
std::memcpy(&byteBuffer[position], value.data(), value.size());
|
||||||
|
position += value.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteLayer::readInt()
|
||||||
|
{
|
||||||
|
if (position + 4 > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
int value;
|
||||||
|
std::memcpy(&value, &byteBuffer[position], 4);
|
||||||
|
position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ByteLayer::readDouble()
|
||||||
|
{
|
||||||
|
if (position + 8 > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
double value;
|
||||||
|
std::memcpy(&value, &byteBuffer[position], 8);
|
||||||
|
position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ByteLayer::readString()
|
||||||
|
{
|
||||||
|
int16_t length = readShort();
|
||||||
|
if (position + length > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
std::string value(reinterpret_cast<char *>(&byteBuffer[position]), length);
|
||||||
|
position += length;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeIntZigZag(int value)
|
||||||
|
{
|
||||||
|
int zigzag = (value << 1) ^ (value >> 31);
|
||||||
|
writeInt(zigzag);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteLayer::readIntZigZag()
|
||||||
|
{
|
||||||
|
int zigzag = readInt();
|
||||||
|
return (zigzag >> 1) ^ -(zigzag & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeByte(uint8_t value)
|
||||||
|
{
|
||||||
|
ensureCapacity(1);
|
||||||
|
byteBuffer[position] = value;
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeUnsignedByte(uint8_t value)
|
||||||
|
{
|
||||||
|
ensureCapacity(1);
|
||||||
|
byteBuffer[position] = value;
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ByteLayer::readByte()
|
||||||
|
{
|
||||||
|
if (position >= byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
return byteBuffer[position++];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ByteLayer::readUnsignedByte()
|
||||||
|
{
|
||||||
|
return readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeVarInt(int value)
|
||||||
|
{
|
||||||
|
while ((value & ~0x7F) != 0)
|
||||||
|
{
|
||||||
|
writeByte((value & 0x7F) | 0x80);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
writeByte(value & 0x7F);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteLayer::readVarInt()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
uint8_t byte;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byte = readByte();
|
||||||
|
result |= (byte & 0x7F) << shift;
|
||||||
|
shift += 7;
|
||||||
|
} while (byte & 0x80);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeVarIntNoZigZag(int value)
|
||||||
|
{
|
||||||
|
while ((value & ~0x7F) != 0)
|
||||||
|
{
|
||||||
|
writeByte((value & 0x7F) | 0x80);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
writeByte(value & 0x7F);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteLayer::readVarIntNoZigZag()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
uint8_t byte;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byte = readByte();
|
||||||
|
result |= (byte & 0x7F) << shift;
|
||||||
|
shift += 7;
|
||||||
|
} while (byte & 0x80);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeShort(int16_t value)
|
||||||
|
{
|
||||||
|
ensureCapacity(2);
|
||||||
|
std::memcpy(&byteBuffer[position], &value, 2);
|
||||||
|
position += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t ByteLayer::readShort()
|
||||||
|
{
|
||||||
|
if (position + 2 > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
int16_t value;
|
||||||
|
std::memcpy(&value, &byteBuffer[position], 2);
|
||||||
|
position += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeFloat(float value)
|
||||||
|
{
|
||||||
|
ensureCapacity(4);
|
||||||
|
std::memcpy(&byteBuffer[position], &value, 4);
|
||||||
|
position += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ByteLayer::readFloat()
|
||||||
|
{
|
||||||
|
if (position + 4 > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
float value;
|
||||||
|
std::memcpy(&value, &byteBuffer[position], 4);
|
||||||
|
position += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeTagName(const std::string &name)
|
||||||
|
{
|
||||||
|
writeShort(static_cast<int16_t>(name.size()));
|
||||||
|
ensureCapacity(name.size());
|
||||||
|
std::memcpy(&byteBuffer[position], name.data(), name.size());
|
||||||
|
position += name.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ByteLayer::readTagName()
|
||||||
|
{
|
||||||
|
int16_t length = readShort();
|
||||||
|
if (position + length > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
std::string name(reinterpret_cast<char *>(&byteBuffer[position]), length);
|
||||||
|
position += length;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::resetPosition()
|
||||||
|
{
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::clear()
|
||||||
|
{
|
||||||
|
resetPosition();
|
||||||
|
byteBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeToFile(const std::string &filePath)
|
||||||
|
{
|
||||||
|
std::ofstream file(filePath, std::ios::binary);
|
||||||
|
if (!file)
|
||||||
|
throw std::runtime_error("Unable to open file for writing");
|
||||||
|
file.write(reinterpret_cast<const char *>(byteBuffer.data()), byteBuffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::readFromFile(const std::string &filePath)
|
||||||
|
{
|
||||||
|
std::ifstream file(filePath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file)
|
||||||
|
throw std::runtime_error("Unable to open file for reading");
|
||||||
|
std::streamsize size = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
byteBuffer.resize(size);
|
||||||
|
if (!file.read(reinterpret_cast<char *>(byteBuffer.data()), size))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Error reading file");
|
||||||
|
}
|
||||||
|
resetPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::doCompress()
|
||||||
|
{
|
||||||
|
uLongf compressedSize = compressBound(byteBuffer.size());
|
||||||
|
std::vector<uint8_t> compressedData(compressedSize);
|
||||||
|
if (compress(compressedData.data(), &compressedSize, byteBuffer.data(), byteBuffer.size()) != Z_OK)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Compression failed");
|
||||||
|
}
|
||||||
|
compressedData.resize(compressedSize);
|
||||||
|
byteBuffer = std::move(compressedData);
|
||||||
|
position = byteBuffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::doDecompress()
|
||||||
|
{
|
||||||
|
uLongf decompressedSize = byteBuffer.size() * 4; // Rough estimate
|
||||||
|
std::vector<uint8_t> decompressedData(decompressedSize);
|
||||||
|
if (uncompress(decompressedData.data(), &decompressedSize, byteBuffer.data(), byteBuffer.size()) != Z_OK)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Decompression failed");
|
||||||
|
}
|
||||||
|
decompressedData.resize(decompressedSize);
|
||||||
|
byteBuffer = std::move(decompressedData);
|
||||||
|
position = byteBuffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeLong(int64_t value)
|
||||||
|
{
|
||||||
|
ensureCapacity(8);
|
||||||
|
std::memcpy(&byteBuffer[position], &value, 8);
|
||||||
|
position += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeUnsignedLong(uint64_t value)
|
||||||
|
{
|
||||||
|
ensureCapacity(8);
|
||||||
|
std::memcpy(&byteBuffer[position], &value, 8);
|
||||||
|
position += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ByteLayer::readLong()
|
||||||
|
{
|
||||||
|
if (position + 8 > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
int64_t value;
|
||||||
|
std::memcpy(&value, &byteBuffer[position], 8);
|
||||||
|
position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ByteLayer::readUnsignedLong()
|
||||||
|
{
|
||||||
|
if (position + 8 > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
uint64_t value;
|
||||||
|
std::memcpy(&value, &byteBuffer[position], 8);
|
||||||
|
position += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeVarLongNoZigZag(uint64_t value)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if ((value & ~0x7F) == 0)
|
||||||
|
{
|
||||||
|
writeByte(static_cast<uint8_t>(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writeByte((value & 0x7F) | 0x80);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeVarLongZigZag(int64_t value)
|
||||||
|
{
|
||||||
|
value = (value << 1) ^ (value >> 63);
|
||||||
|
writeVarLongNoZigZag(static_cast<uint64_t>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeLongZigZag(int64_t value)
|
||||||
|
{
|
||||||
|
value = (value << 1) ^ (value >> 63);
|
||||||
|
writeLong(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ByteLayer::readVarLongNoZigZag()
|
||||||
|
{
|
||||||
|
uint64_t result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
uint8_t byte;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byte = readByte();
|
||||||
|
result |= (static_cast<uint64_t>(byte & 0x7F) << shift);
|
||||||
|
shift += 7;
|
||||||
|
} while (byte & 0x80);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ByteLayer::readVarLongZigZag()
|
||||||
|
{
|
||||||
|
uint64_t zigzag = readVarLongNoZigZag();
|
||||||
|
return static_cast<int64_t>((zigzag >> 1) ^ -(zigzag & 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ByteLayer::readLongZigZag()
|
||||||
|
{
|
||||||
|
int64_t value = readLong();
|
||||||
|
return (value >> 1) ^ -(value & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::writeBytes(const std::vector<uint8_t> &bytes)
|
||||||
|
{
|
||||||
|
ensureCapacity(bytes.size());
|
||||||
|
std::memcpy(&byteBuffer[position], bytes.data(), bytes.size());
|
||||||
|
position += bytes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ByteLayer::readBytes(size_t num)
|
||||||
|
{
|
||||||
|
if (position + num > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Read past buffer end");
|
||||||
|
std::vector<uint8_t> result(byteBuffer.begin() + position, byteBuffer.begin() + position + num);
|
||||||
|
position += num;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::setBit(size_t position, uint8_t maskToSet)
|
||||||
|
{
|
||||||
|
if (position >= byteBuffer.size())
|
||||||
|
throw std::out_of_range("Position out of range");
|
||||||
|
seek(position);
|
||||||
|
uint8_t current = readUnsignedByte();
|
||||||
|
seek(position);
|
||||||
|
writeUnsignedByte(current | maskToSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::clearBit(size_t position, uint8_t maskToClear)
|
||||||
|
{
|
||||||
|
if (position >= byteBuffer.size())
|
||||||
|
throw std::out_of_range("Position out of range");
|
||||||
|
seek(position);
|
||||||
|
uint8_t current = readUnsignedByte();
|
||||||
|
seek(position);
|
||||||
|
writeUnsignedByte(current & ~maskToClear);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteLayer::checkBit(size_t position, uint8_t mask)
|
||||||
|
{
|
||||||
|
if (position >= byteBuffer.size())
|
||||||
|
return false;
|
||||||
|
seek(position);
|
||||||
|
uint8_t current = readUnsignedByte();
|
||||||
|
return (current & mask) == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ByteLayer::getBit(size_t position)
|
||||||
|
{
|
||||||
|
if (position >= byteBuffer.size())
|
||||||
|
return 0;
|
||||||
|
seek(position);
|
||||||
|
return readUnsignedByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::seek(size_t newPosition)
|
||||||
|
{
|
||||||
|
if (newPosition > byteBuffer.size())
|
||||||
|
throw std::out_of_range("Seek past buffer end");
|
||||||
|
position = newPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::unsetSetBit(size_t position, uint8_t maskToClear, uint8_t maskToSet)
|
||||||
|
{
|
||||||
|
clearBit(position, maskToClear);
|
||||||
|
setBit(position, maskToSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteLayer::insertRandomBytes(size_t count)
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 rng(rd());
|
||||||
|
std::uniform_int_distribution<uint8_t> dist(0, 255);
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
writeByte(dist(rng));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
92
src/utils/ByteLayer.h
Normal file
92
src/utils/ByteLayer.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#ifndef BYTELAYER_H
|
||||||
|
#define BYTELAYER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <bitset>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <zlib.h> // For compression and decompression
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
class ByteLayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteLayer() : position(0) {}
|
||||||
|
|
||||||
|
size_t getLength() const
|
||||||
|
{
|
||||||
|
return byteBuffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getCurrentPosition() const
|
||||||
|
{
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> getBytes() const
|
||||||
|
{
|
||||||
|
return std::vector<uint8_t>(byteBuffer.begin(), byteBuffer.begin() + position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeInt(int value);
|
||||||
|
void writeDouble(double value);
|
||||||
|
void writeString(const std::string &value);
|
||||||
|
int readInt();
|
||||||
|
double readDouble();
|
||||||
|
std::string readString();
|
||||||
|
void writeIntZigZag(int value);
|
||||||
|
int readIntZigZag();
|
||||||
|
void writeByte(uint8_t value);
|
||||||
|
void writeUnsignedByte(uint8_t value);
|
||||||
|
uint8_t readByte();
|
||||||
|
uint8_t readUnsignedByte();
|
||||||
|
void writeVarInt(int value);
|
||||||
|
int readVarInt();
|
||||||
|
void writeVarIntNoZigZag(int value);
|
||||||
|
int readVarIntNoZigZag();
|
||||||
|
void writeShort(int16_t value);
|
||||||
|
int16_t readShort();
|
||||||
|
void writeFloat(float value);
|
||||||
|
float readFloat();
|
||||||
|
void writeTagName(const std::string &name);
|
||||||
|
std::string readTagName();
|
||||||
|
void resetPosition();
|
||||||
|
void clear();
|
||||||
|
void writeToFile(const std::string &filePath);
|
||||||
|
void readFromFile(const std::string &filePath);
|
||||||
|
void doCompress();
|
||||||
|
void doDecompress();
|
||||||
|
void writeLong(int64_t value);
|
||||||
|
void writeUnsignedLong(uint64_t value);
|
||||||
|
int64_t readLong();
|
||||||
|
uint64_t readUnsignedLong();
|
||||||
|
void writeVarLongNoZigZag(uint64_t value);
|
||||||
|
void writeVarLongZigZag(int64_t value);
|
||||||
|
void writeLongZigZag(int64_t value);
|
||||||
|
uint64_t readVarLongNoZigZag();
|
||||||
|
int64_t readVarLongZigZag();
|
||||||
|
int64_t readLongZigZag();
|
||||||
|
void writeBytes(const std::vector<uint8_t> &bytes);
|
||||||
|
std::vector<uint8_t> readBytes(size_t num);
|
||||||
|
void setBit(size_t position, uint8_t maskToSet);
|
||||||
|
void clearBit(size_t position, uint8_t maskToClear);
|
||||||
|
bool checkBit(size_t position, uint8_t mask);
|
||||||
|
uint8_t getBit(size_t position);
|
||||||
|
void seek(size_t position);
|
||||||
|
void unsetSetBit(size_t position, uint8_t maskToClear, uint8_t maskToSet);
|
||||||
|
void insertRandomBytes(size_t count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> byteBuffer;
|
||||||
|
size_t position;
|
||||||
|
|
||||||
|
void ensureCapacity(size_t additionalBytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BYTELAYER_H
|
65
src/utils/StringBuilder.cpp
Normal file
65
src/utils/StringBuilder.cpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include "StringBuilder.h"
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
|
||||||
|
StringBuilder::StringBuilder() : buffer() {}
|
||||||
|
|
||||||
|
bool StringBuilder::isEmpty() const
|
||||||
|
{
|
||||||
|
return buffer.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringBuilder::append(const std::string &value)
|
||||||
|
{
|
||||||
|
buffer.append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringBuilder::clear()
|
||||||
|
{
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringBuilder::toString() const
|
||||||
|
{
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload operator<< for std::string
|
||||||
|
StringBuilder& StringBuilder::operator<<(const std::string& value) {
|
||||||
|
append(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload operator<< for C-style strings
|
||||||
|
StringBuilder& StringBuilder::operator<<(const char* value) {
|
||||||
|
append(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload operator<< for single characters
|
||||||
|
StringBuilder& StringBuilder::operator<<(char value) {
|
||||||
|
buffer += value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload operator<< for integers
|
||||||
|
StringBuilder& StringBuilder::operator<<(int value) {
|
||||||
|
std::stringstream oss;
|
||||||
|
oss << value;
|
||||||
|
append(oss.str());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload operator<< for doubles
|
||||||
|
StringBuilder& StringBuilder::operator<<(double value) {
|
||||||
|
std::stringstream oss;
|
||||||
|
oss << value;
|
||||||
|
append(oss.str());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
31
src/utils/StringBuilder.h
Normal file
31
src/utils/StringBuilder.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef STRINGBUILDER_H
|
||||||
|
#define STRINGBUILDER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
|
||||||
|
class StringBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringBuilder();
|
||||||
|
|
||||||
|
bool isEmpty() const;
|
||||||
|
void append(const std::string &value);
|
||||||
|
void clear();
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
|
// Overload operator<< to append strings and other types
|
||||||
|
StringBuilder& operator<<(const std::string& value);
|
||||||
|
StringBuilder& operator<<(const char* value);
|
||||||
|
StringBuilder& operator<<(char value);
|
||||||
|
StringBuilder& operator<<(int value);
|
||||||
|
StringBuilder& operator<<(double value);
|
||||||
|
private:
|
||||||
|
std::string buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // STRINGBUILDER_H
|
168
src/utils/StringReader.cpp
Normal file
168
src/utils/StringReader.cpp
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
#include "StringReader.h"
|
||||||
|
#include <cctype>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
StringReader::StringReader(const std::string &buffer)
|
||||||
|
: _buffer(buffer), _position(0), _lastPosition(0), _quotedString(false) {}
|
||||||
|
|
||||||
|
// Check if there's more to read
|
||||||
|
bool StringReader::canRead() const
|
||||||
|
{
|
||||||
|
return _position < _buffer.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of characters seeked
|
||||||
|
int StringReader::getSeeked() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(_lastPosition - _position);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the next character
|
||||||
|
char StringReader::next()
|
||||||
|
{
|
||||||
|
if (canRead())
|
||||||
|
{
|
||||||
|
skipWhitespace();
|
||||||
|
return _buffer[_position++];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::out_of_range("End of buffer reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek the next character without advancing the position
|
||||||
|
char StringReader::peek() const
|
||||||
|
{
|
||||||
|
if (_position < _buffer.length())
|
||||||
|
{
|
||||||
|
return _buffer[_position];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::out_of_range("End of buffer reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip any whitespace characters
|
||||||
|
void StringReader::skipWhitespace()
|
||||||
|
{
|
||||||
|
if (_quotedString)
|
||||||
|
return; // We need whitespace for strings
|
||||||
|
while (canRead() && isWhitespace(peek()))
|
||||||
|
{
|
||||||
|
_position++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a character is whitespace
|
||||||
|
bool StringReader::isWhitespace(char c) const
|
||||||
|
{
|
||||||
|
return std::isspace(static_cast<unsigned char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read until a specific character is found
|
||||||
|
std::string StringReader::readUntil(char stopChar)
|
||||||
|
{
|
||||||
|
std::ostringstream result;
|
||||||
|
while (canRead() && peek() != stopChar)
|
||||||
|
{
|
||||||
|
result << next();
|
||||||
|
}
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string enclosed in double quotes
|
||||||
|
std::string StringReader::readQuotedString()
|
||||||
|
{
|
||||||
|
_quotedString = true;
|
||||||
|
if (next() != '"')
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Expected double quotes at the start of a string");
|
||||||
|
}
|
||||||
|
std::ostringstream result;
|
||||||
|
while (canRead())
|
||||||
|
{
|
||||||
|
char c = next();
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result << c;
|
||||||
|
}
|
||||||
|
_quotedString = false;
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a number (int or double)
|
||||||
|
std::string StringReader::readNumber()
|
||||||
|
{
|
||||||
|
std::ostringstream result;
|
||||||
|
while (canRead() && (isDigit(peek()) || peek() == '.' || peek() == '-'))
|
||||||
|
{
|
||||||
|
result << next();
|
||||||
|
}
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a character is a digit
|
||||||
|
bool StringReader::isDigit(char c) const
|
||||||
|
{
|
||||||
|
return std::isdigit(static_cast<unsigned char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read an unquoted string (used for keys in SNBT)
|
||||||
|
std::string StringReader::readUnquotedString()
|
||||||
|
{
|
||||||
|
std::ostringstream result;
|
||||||
|
while (canRead() &&
|
||||||
|
!isWhitespace(peek()) &&
|
||||||
|
peek() != ':' &&
|
||||||
|
peek() != ',' &&
|
||||||
|
peek() != '{' &&
|
||||||
|
peek() != '}' &&
|
||||||
|
peek() != '[' &&
|
||||||
|
peek() != ']')
|
||||||
|
{
|
||||||
|
result << next();
|
||||||
|
}
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringReader::readString()
|
||||||
|
{
|
||||||
|
if (peek() == '"')
|
||||||
|
{
|
||||||
|
return readQuotedString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return readUnquotedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a specific character and throw an exception if it's not found
|
||||||
|
void StringReader::expect(char expectedChar)
|
||||||
|
{
|
||||||
|
if (std::tolower(next()) != std::tolower(expectedChar))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("Expected ") + expectedChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringReader::startSeek()
|
||||||
|
{
|
||||||
|
_lastPosition = _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringReader::endSeek()
|
||||||
|
{
|
||||||
|
_position = _lastPosition;
|
||||||
|
_lastPosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
src/utils/StringReader.h
Normal file
42
src/utils/StringReader.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef STRINGREADER_H
|
||||||
|
#define STRINGREADER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace libac
|
||||||
|
{
|
||||||
|
|
||||||
|
class StringReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit StringReader(const std::string &buffer);
|
||||||
|
|
||||||
|
bool canRead() const;
|
||||||
|
int getSeeked() const;
|
||||||
|
char next();
|
||||||
|
char peek() const;
|
||||||
|
std::string readUntil(char stopChar);
|
||||||
|
std::string readQuotedString();
|
||||||
|
std::string readNumber();
|
||||||
|
std::string readUnquotedString();
|
||||||
|
std::string readString();
|
||||||
|
void expect(char expectedChar);
|
||||||
|
void startSeek();
|
||||||
|
void endSeek();
|
||||||
|
bool isDigit(char c) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void skipWhitespace();
|
||||||
|
bool isWhitespace(char c) const;
|
||||||
|
|
||||||
|
std::string _buffer;
|
||||||
|
size_t _position;
|
||||||
|
size_t _lastPosition;
|
||||||
|
bool _quotedString;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // STRINGREADER_H
|
Loading…
Add table
Add a link
Reference in a new issue