Makes some stuff work

This commit is contained in:
zontreck 2024-07-30 22:30:55 -07:00
parent 43e16ce945
commit e5a3717e64
24 changed files with 2048 additions and 1 deletions

72
.vscode/settings.json vendored Normal file
View 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"
}
}

View file

@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 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_library(ac SHARED ${SOURCES})

40
src/nbt/Accountant.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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