Compare commits
24 Commits
78880e1c20
...
4c651d1b6f
Author | SHA1 | Date |
---|---|---|
BodgeMaster | 4c651d1b6f | |
BodgeMaster | e152c72a04 | |
BodgeMaster | 5d80ca801e | |
BodgeMaster | c245e8a5ca | |
BodgeMaster | 10d8cdae22 | |
BodgeMaster | b08a86f0b8 | |
BodgeMaster | c6ec0f6850 | |
BodgeMaster | 85fc73e015 | |
BodgeMaster | d2861b79ac | |
BodgeMaster | 9403da4ca0 | |
BodgeMaster | ad5bf1c41a | |
BodgeMaster | 7108e71b96 | |
Shwoomple | 26df433dc5 | |
BodgeMaster | 44716a55bb | |
BodgeMaster | fe7c763d06 | |
BodgeMaster | d392e080ca | |
BodgeMaster | 60a8ac9788 | |
Shwoomple | bc2255de6b | |
Shwoomple | e627714b44 | |
Shwoomple | 42b7e40f9d | |
Shwoomple | 9bda607649 | |
Shwoomple | 76dd30c45a | |
Shwoomple | f784948c3e | |
Shwoomple | d794bce288 |
|
@ -26,6 +26,7 @@ Build dependencies:
|
||||||
|
|
||||||
- bash
|
- bash
|
||||||
- a C++ 20 compiler
|
- a C++ 20 compiler
|
||||||
|
- GLFW with headers
|
||||||
|
|
||||||
Setup dependencies:
|
Setup dependencies:
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,14 @@ Data used to test the NBT library
|
||||||
`level.dat_decompressed`: The same data decompressed
|
`level.dat_decompressed`: The same data decompressed
|
||||||
|
|
||||||
|
|
||||||
|
## network_capture/
|
||||||
|
|
||||||
|
Network captures used to get an understanding of the protocol
|
||||||
|
|
||||||
|
`ping.pcapng`: WireShark capture of the multipayer screen server ping
|
||||||
|
`ping_decoded.txt`: Extracted TCP payloads from the network capture annotated with what’s happening
|
||||||
|
|
||||||
|
|
||||||
## unicode_data/
|
## unicode_data/
|
||||||
|
|
||||||
Files with unicode data
|
Files with unicode data
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -63,7 +63,7 @@ COMPILE_COMMANDS=(
|
||||||
"$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump"
|
"$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump"
|
||||||
"$CXX_WITH_FLAGS src/tools/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
|
"$CXX_WITH_FLAGS src/tools/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
|
||||||
"$CXX_WITH_FLAGS -pthread src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
|
"$CXX_WITH_FLAGS -pthread src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
|
||||||
"$CXX_WITH_FLAGS src/fossvg.cpp -I./include -Lbin/lib -l:cli.so -o bin/fossvg"
|
"$CXX_WITH_FLAGS src/fossvg.cpp -I./include -Lbin/lib -l:cli.so -lglfw -o bin/fossvg"
|
||||||
"$CXX_WITH_FLAGS src/fossvgd.cpp -I./include -Lbin/lib -l:cli.so -o bin/fossvgd"
|
"$CXX_WITH_FLAGS src/fossvgd.cpp -I./include -Lbin/lib -l:cli.so -o bin/fossvgd"
|
||||||
)
|
)
|
||||||
for command in ${!COMPILE_COMMANDS[@]}; do
|
for command in ${!COMPILE_COMMANDS[@]}; do
|
||||||
|
|
|
@ -25,6 +25,7 @@ remove .endianness
|
||||||
remove resources/check_endianness
|
remove resources/check_endianness
|
||||||
create_directory ./bin
|
create_directory ./bin
|
||||||
create_directory ./bin/lib
|
create_directory ./bin/lib
|
||||||
|
create_directory ./bin/lib/net
|
||||||
create_directory ./include
|
create_directory ./include
|
||||||
|
|
||||||
if uname -s | tr [:upper:] [:lower:] | grep cygwin >/dev/null; then
|
if uname -s | tr [:upper:] [:lower:] | grep cygwin >/dev/null; then
|
||||||
|
|
|
@ -39,6 +39,7 @@ COMPILE_COMMANDS=(
|
||||||
"$CXX_WITH_FLAGS src/test/nbt_tags.cpp -I./include -Lbin/lib -l:nbt.so -o bin/test/nbt_tags"
|
"$CXX_WITH_FLAGS src/test/nbt_tags.cpp -I./include -Lbin/lib -l:nbt.so -o bin/test/nbt_tags"
|
||||||
"$CXX_WITH_FLAGS src/test/nbt_size_helpers.cpp -I./include -Lbin/lib -l:nbt.so -o bin/test/nbt_size_helpers"
|
"$CXX_WITH_FLAGS src/test/nbt_size_helpers.cpp -I./include -Lbin/lib -l:nbt.so -o bin/test/nbt_size_helpers"
|
||||||
"$CXX_WITH_FLAGS src/test/file.cpp -I./include -Lbin/lib -l:file.so -o bin/test/file"
|
"$CXX_WITH_FLAGS src/test/file.cpp -I./include -Lbin/lib -l:file.so -o bin/test/file"
|
||||||
|
"$CXX_WITH_FLAGS src/test/varint.cpp -I./include -Lbin/lib -o bin/test/varint"
|
||||||
)
|
)
|
||||||
for command in ${!COMPILE_COMMANDS[@]}; do
|
for command in ${!COMPILE_COMMANDS[@]}; do
|
||||||
echo "${COMPILE_COMMANDS[command]}"
|
echo "${COMPILE_COMMANDS[command]}"
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include "./lib/cli.hpp"
|
#include "./lib/cli.hpp"
|
||||||
|
|
||||||
|
@ -25,6 +29,27 @@
|
||||||
#define EXIT_RUNTIME 1
|
#define EXIT_RUNTIME 1
|
||||||
#define EXIT_USAGE 2
|
#define EXIT_USAGE 2
|
||||||
|
|
||||||
|
//TODO: check the TODO above glfwInit() in void main()
|
||||||
|
// #### Callbacks ##############################################################
|
||||||
|
void cursorPositionCallback(GLFWwindow* window, double x, double y) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyCallback(GLFWwindow* window, int32_t key, int32_t scancode, int32_t action, int32_t mods) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void textInputCallback(GLFWwindow* window, uint32_t codepoint) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void cursorEnterLeaveCallback(GLFWwindow* window, int32_t entered) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseButtonCallback(GLFWwindow* window, int32_t button, int32_t action, int32_t mods) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollCallback(GLFWwindow* window, double x, double y) {
|
||||||
|
}
|
||||||
|
// #### End Callbacks ##########################################################
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
std::vector<CLI::Flag> flags;
|
std::vector<CLI::Flag> flags;
|
||||||
flags.push_back(CLI::Flag('h', "help", "print help and exit"));
|
flags.push_back(CLI::Flag('h', "help", "print help and exit"));
|
||||||
|
@ -63,5 +88,50 @@ int main(int argc, char* argv[]) {
|
||||||
return EXIT_USAGE;
|
return EXIT_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Find a better place for this
|
||||||
|
// Ideally, the window management and rendering portion of FOSS-VG should
|
||||||
|
// live in a library so it can be easily reloaded/restarted for things like
|
||||||
|
// switching from/to fullscreen. For now, I am going to put it here because
|
||||||
|
// I want to get it going before making it pretty.
|
||||||
|
{
|
||||||
|
if (!glfwInit()) {
|
||||||
|
return EXIT_RUNTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: allow to set startup window size using CLI options
|
||||||
|
uint32_t windowWidth = 1366;
|
||||||
|
uint32_t windowHeight = 768;
|
||||||
|
//TODO: add a version macro
|
||||||
|
// (for example Git commit hash passed on the compiler command line)
|
||||||
|
std::string windowTitle = "FOSS-VG";
|
||||||
|
|
||||||
|
// Apparently, this also allows to set things like whether the window is full-screen
|
||||||
|
GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, windowTitle.c_str(), nullptr, nullptr);
|
||||||
|
|
||||||
|
if (window == nullptr) {
|
||||||
|
return EXIT_RUNTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// What dis do? It was in a tutorial.
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
|
||||||
|
glfwSetCursorPosCallback(window, cursorPositionCallback);
|
||||||
|
glfwSetKeyCallback(window, keyCallback);
|
||||||
|
glfwSetCharCallback(window, textInputCallback);
|
||||||
|
glfwSetCursorEnterCallback(window, cursorEnterLeaveCallback);
|
||||||
|
glfwSetMouseButtonCallback(window, mouseButtonCallback);
|
||||||
|
glfwSetScrollCallback(window, scrollCallback);
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,6 @@ namespace CLI {
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgumentsParser::~ArgumentsParser() {
|
ArgumentsParser::~ArgumentsParser() {
|
||||||
//TODO: check that this actually runs
|
|
||||||
for (auto const& [shortName, flag]: this->flagsByShortName) {
|
for (auto const& [shortName, flag]: this->flagsByShortName) {
|
||||||
delete flag;
|
delete flag;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,9 @@ namespace ErrorCodes {
|
||||||
|
|
||||||
const uint8_t MIXED_TYPES = 12;
|
const uint8_t MIXED_TYPES = 12;
|
||||||
|
|
||||||
|
// when too much data is available
|
||||||
|
const uint8_t OVERFLOW = 13;
|
||||||
|
|
||||||
const uint8_t UNIMPLEMENTED = 254;
|
const uint8_t UNIMPLEMENTED = 254;
|
||||||
|
|
||||||
const uint8_t UNKNOWN = 255;
|
const uint8_t UNKNOWN = 255;
|
||||||
|
|
|
@ -65,6 +65,8 @@ void File::open(){
|
||||||
|
|
||||||
void File::close(){
|
void File::close(){
|
||||||
this->fileStream.close();
|
this->fileStream.close();
|
||||||
|
std::filesystem::path filePath = this->path;
|
||||||
|
this->size = ErrorOr<uint64_t>(std::filesystem::file_size(filePath));
|
||||||
this->isOpen = false;
|
this->isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +189,7 @@ ErrorOrVoid File::insertByte(uint8_t byte){
|
||||||
this->fileStream.seekg(0);
|
this->fileStream.seekg(0);
|
||||||
this->write(readData);
|
this->write(readData);
|
||||||
this->cursorPosition++;
|
this->cursorPosition++;
|
||||||
delete buffer;
|
delete[] buffer;
|
||||||
}catch(std::exception& e){
|
}catch(std::exception& e){
|
||||||
failure = true;
|
failure = true;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +211,7 @@ ErrorOrVoid File::insert(std::vector<uint8_t> data){
|
||||||
this->fileStream.seekg(0);
|
this->fileStream.seekg(0);
|
||||||
this->write(readData);
|
this->write(readData);
|
||||||
this->cursorPosition += data.size();
|
this->cursorPosition += data.size();
|
||||||
delete buffer;
|
delete[] buffer;
|
||||||
}catch(std::exception& e){
|
}catch(std::exception& e){
|
||||||
failure = true;
|
failure = true;
|
||||||
}
|
}
|
||||||
|
@ -225,15 +227,14 @@ ErrorOrVoid File::insertString(tiny_utf8::string string){
|
||||||
|
|
||||||
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
|
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
|
||||||
|
|
||||||
readData = tiny_utf8::string((char *) buffer);
|
readData = tiny_utf8::string((char *) buffer, 0, this->size.value);
|
||||||
readData.insert(readData.begin()+this->cursorPosition, string);
|
readData.insert(readData.begin()+this->cursorPosition, string);
|
||||||
|
|
||||||
this->fileStream.seekg(0);
|
this->fileStream.seekg(0);
|
||||||
|
|
||||||
//TODO: fix hack. tinyutf8 appends "_utf-8" when readData is assigned: tiny_utf8::string((char *) buffer);
|
this->writeString(readData);
|
||||||
this->writeString(readData.substr(0, readData.find("_utf-8")));
|
|
||||||
this->cursorPosition += string.size();
|
this->cursorPosition += string.size();
|
||||||
delete buffer;
|
delete[] buffer;
|
||||||
}catch(std::exception& e){
|
}catch(std::exception& e){
|
||||||
failure = true;
|
failure = true;
|
||||||
}
|
}
|
||||||
|
@ -256,14 +257,64 @@ ErrorOr<uint8_t> File::cutByte(){
|
||||||
std::filesystem::resize_file(this->path, readData.size());
|
std::filesystem::resize_file(this->path, readData.size());
|
||||||
this->fileStream.seekg(0);
|
this->fileStream.seekg(0);
|
||||||
this->write(readData);
|
this->write(readData);
|
||||||
this->cursorPosition++;
|
//this->cursorPosition++;
|
||||||
delete buffer;
|
delete[] buffer;
|
||||||
}catch(std::exception& e){
|
}catch(std::exception& e){
|
||||||
failure = true;
|
failure = true;
|
||||||
}
|
}
|
||||||
return failure ? ErrorOr<uint8_t>(true, ErrorCodes::UNKNOWN) : ErrorOr<uint8_t>(byte);
|
return failure ? ErrorOr<uint8_t>(true, ErrorCodes::UNKNOWN) : ErrorOr<uint8_t>(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<std::vector<uint8_t>> File::cut(uint64_t length){
|
||||||
|
bool failure = false;
|
||||||
|
std::vector<uint8_t> bytes;
|
||||||
|
|
||||||
|
try{
|
||||||
|
uint8_t* buffer = new uint8_t[this->size.value];
|
||||||
|
std::vector<uint8_t> readData;
|
||||||
|
|
||||||
|
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
|
||||||
|
readData = std::vector<uint8_t>(buffer, buffer+this->size.value);
|
||||||
|
|
||||||
|
bytes = std::vector<uint8_t>(readData.begin() + this->cursorPosition, readData.begin() + (this->cursorPosition + length));
|
||||||
|
readData.erase(readData.begin() + this->cursorPosition, readData.begin() + (this->cursorPosition + length));
|
||||||
|
|
||||||
|
std::filesystem::resize_file(this->path, readData.size());
|
||||||
|
this->fileStream.seekg(0);
|
||||||
|
this->write(readData);
|
||||||
|
//this->cursorPosition += length;
|
||||||
|
delete[] buffer;
|
||||||
|
}catch(std::exception& e){
|
||||||
|
failure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return failure ? ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::UNKNOWN) :ErrorOr<std::vector<uint8_t>>(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<tiny_utf8::string> File::cutString(uint64_t length){
|
||||||
|
bool failure = false;
|
||||||
|
tiny_utf8::string cutString;
|
||||||
|
try{
|
||||||
|
uint8_t* buffer = new uint8_t[this->size.value];
|
||||||
|
tiny_utf8::string readData;
|
||||||
|
|
||||||
|
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
|
||||||
|
readData = tiny_utf8::string((char *) buffer, 0, this->size.value);
|
||||||
|
|
||||||
|
cutString = readData.substr(this->cursorPosition, length);
|
||||||
|
|
||||||
|
std::filesystem::resize_file(this->path, readData.size()-cutString.size());
|
||||||
|
this->fileStream.seekg(0);
|
||||||
|
this->writeString(readData.substr(this->cursorPosition+length));
|
||||||
|
//this->cursorPosition += length;
|
||||||
|
delete[] buffer;
|
||||||
|
}catch(std::exception& e){
|
||||||
|
failure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return failure ? ErrorOr<tiny_utf8::string>(true, ErrorCodes::UNKNOWN) : ErrorOr<tiny_utf8::string>(cutString);
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<File*> File::open(std::string path, char mode, uint64_t startPosition){
|
ErrorOr<File*> File::open(std::string path, char mode, uint64_t startPosition){
|
||||||
if (!std::filesystem::exists(path) && (mode == 'r' || mode == 'm')) {
|
if (!std::filesystem::exists(path) && (mode == 'r' || mode == 'm')) {
|
||||||
return ErrorOr<File*>(true, ErrorCodes::FILE_NOT_FOUND, nullptr);
|
return ErrorOr<File*>(true, ErrorCodes::FILE_NOT_FOUND, nullptr);
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
// version 3 along with this program.
|
// version 3 along with this program.
|
||||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
//version 3 along with this program.
|
//version 3 along with this program.
|
||||||
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <tinyutf8/tinyutf8.h>
|
#include <tinyutf8/tinyutf8.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
|
|
@ -976,6 +976,20 @@ namespace NBT {
|
||||||
this->endPointer = new End();
|
this->endPointer = new End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<Compound*> Compound::constructWithData(tiny_utf8::string name, std::vector<Generic*> data) {
|
||||||
|
if (data.size() > 0) {
|
||||||
|
for (uint64_t i=0; i<data.size(); i++) {
|
||||||
|
if (data[i]->getTagType() == TagType::END && i != data.size()-1) {
|
||||||
|
return ErrorOr<Compound*>(true, ErrorCodes::NOT_ALLOWED, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data[data.size()-1]->getTagType() == TagType::END) {
|
||||||
|
return ErrorOr<Compound*>(new Compound(name, std::vector(data.begin(), data.end()-1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrorOr<Compound*>(new Compound(name, data));
|
||||||
|
}
|
||||||
|
|
||||||
Compound::~Compound() {
|
Compound::~Compound() {
|
||||||
for (uint64_t i=0; i<this->tags.size(); i++) {
|
for (uint64_t i=0; i<this->tags.size(); i++) {
|
||||||
delete this->tags.at(i);
|
delete this->tags.at(i);
|
||||||
|
@ -1342,7 +1356,7 @@ namespace NBT {
|
||||||
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextCompoundData.errorCode);
|
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextCompoundData.errorCode);
|
||||||
goto returnError;
|
goto returnError;
|
||||||
}
|
}
|
||||||
contents.push_back(new Tag::Compound("", nextCompoundData.value));
|
contents.push_back(reinterpret_cast<Tag::Generic*>(Tag::Compound::constructWithData("", nextCompoundData.value).value));
|
||||||
*processedDataSize += *containedDataSize;
|
*processedDataSize += *containedDataSize;
|
||||||
}
|
}
|
||||||
delete containedDataSize;
|
delete containedDataSize;
|
||||||
|
@ -1454,7 +1468,7 @@ namespace NBT {
|
||||||
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, compoundData.errorCode);
|
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, compoundData.errorCode);
|
||||||
goto returnNow;
|
goto returnNow;
|
||||||
}
|
}
|
||||||
tags.push_back(new Tag::Compound(tagName.value, compoundData.value));
|
tags.push_back(reinterpret_cast<Tag::Generic*>(Tag::Compound::constructWithData(tagName.value, compoundData.value).value));
|
||||||
*processedTagSize += (uint64_t) nameSize + 3;
|
*processedTagSize += (uint64_t) nameSize + 3;
|
||||||
}
|
}
|
||||||
currentPosition += *processedTagSize;
|
currentPosition += *processedTagSize;
|
||||||
|
|
|
@ -248,10 +248,10 @@ namespace NBT {
|
||||||
std::vector<Generic*> tags;
|
std::vector<Generic*> tags;
|
||||||
// built-in end tag
|
// built-in end tag
|
||||||
End* endPointer;
|
End* endPointer;
|
||||||
|
Compound(tiny_utf8::string name, std::vector<Generic*> data);
|
||||||
public:
|
public:
|
||||||
Compound();
|
Compound();
|
||||||
Compound(tiny_utf8::string name);
|
Compound(tiny_utf8::string name);
|
||||||
Compound(tiny_utf8::string name, std::vector<Generic*> data);
|
|
||||||
|
|
||||||
~Compound() override;
|
~Compound() override;
|
||||||
|
|
||||||
|
@ -262,6 +262,7 @@ namespace NBT {
|
||||||
ErrorOrVoid appendPointer(Generic* pointer);
|
ErrorOrVoid appendPointer(Generic* pointer);
|
||||||
ErrorOrVoid deleteElement(uint64_t position);
|
ErrorOrVoid deleteElement(uint64_t position);
|
||||||
uint64_t length();
|
uint64_t length();
|
||||||
|
static ErrorOr<Compound*> constructWithData(tiny_utf8::string name, std::vector<Generic*> data);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Int32Array: public Generic {
|
class Int32Array: public Generic {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
// BodgeMaster
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../../error.hpp"
|
||||||
|
|
||||||
|
namespace Position {
|
||||||
|
struct Location {
|
||||||
|
// 26 bit integer
|
||||||
|
int32_t x;
|
||||||
|
// 12 bit integer
|
||||||
|
int16_t y;
|
||||||
|
// 26 bit integer
|
||||||
|
int32_t z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location fromPosition(uint64_t position) {
|
||||||
|
Location location;
|
||||||
|
|
||||||
|
location.x = (int32_t) ((0xFFFFFFC000000000 & position) >> 38);
|
||||||
|
if (location.x >= 0x02000000) {
|
||||||
|
location.x -= 0x04000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.y = (int16_t) ((0x0000000000000FFF & position));
|
||||||
|
if (location.y >= 0x0800) {
|
||||||
|
location.y -= 0x1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.z = (int32_t) ((0x0000003FFFFFF000 & position) >> 12);
|
||||||
|
if (location.z >= 0x02000000) {
|
||||||
|
location.z -= 0x04000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Location> fromPosition(std::vector data, uint64_t initialPosition=0) {
|
||||||
|
if (inititalPosition >= data.size()) {
|
||||||
|
return ErrorOr<Location>(true, ErrorCodes::OUT_OF_BOUNDS);
|
||||||
|
}
|
||||||
|
if (initialPosition+7 >= data.size()) {
|
||||||
|
return ErrorOr<Location>(true, ErrorCodes::OVERRUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t deserialized = 0;
|
||||||
|
for (uint8_t i=0; i<8; i++) {
|
||||||
|
deserialized += (uint64_t) data[initialPosition+i] << i*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorOr<Location>(fromPosition(deserialized));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
// BodgeMaster, Shwoomple
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../../error.hpp"
|
||||||
|
|
||||||
|
namespace VarInt {
|
||||||
|
|
||||||
|
// up to 5 bytes, least significant byte first, most significant bit
|
||||||
|
// indicates whether the next byte is still part of the number
|
||||||
|
ErrorOr<int32_t> fromVar32(std::vector<uint8_t> data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) {
|
||||||
|
if (initialPosition >= data.size()) {
|
||||||
|
return ErrorOr<int32_t>(true, ErrorCodes::OUT_OF_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t returnValue = 0;
|
||||||
|
uint64_t currentPosition = initialPosition;
|
||||||
|
uint8_t bits = 0;
|
||||||
|
while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+4) {
|
||||||
|
returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits);
|
||||||
|
|
||||||
|
(*processedBytes)++;
|
||||||
|
bits += 7;
|
||||||
|
currentPosition++;
|
||||||
|
// check after increasing so we don't need to check outside the loop
|
||||||
|
if (currentPosition >= data.size()) {
|
||||||
|
return ErrorOr<int32_t>(true, ErrorCodes::OVERRUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (data[currentPosition] & 0b10000000) {
|
||||||
|
return ErrorOr<int32_t>(true, ErrorCodes::OVERFLOW);
|
||||||
|
}
|
||||||
|
returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits);
|
||||||
|
(*processedBytes)++;
|
||||||
|
|
||||||
|
return ErrorOr<int32_t>(returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// up to 10 bytes, least significant byte first, most significant bit
|
||||||
|
// indicates whether the next byte is still part of the number
|
||||||
|
ErrorOr<int64_t> fromVar64(std::vector<uint8_t> data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) {
|
||||||
|
if (initialPosition >= data.size()) {
|
||||||
|
return ErrorOr<int64_t>(true, ErrorCodes::OUT_OF_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t returnValue = 0;
|
||||||
|
uint64_t currentPosition = initialPosition;
|
||||||
|
uint8_t bits = 0;
|
||||||
|
while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+9) {
|
||||||
|
returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits);
|
||||||
|
|
||||||
|
(*processedBytes)++;
|
||||||
|
bits += 7;
|
||||||
|
currentPosition++;
|
||||||
|
// check after increasing so we don't need to check outside the loop
|
||||||
|
if (currentPosition >= data.size()) {
|
||||||
|
return ErrorOr<int64_t>(true, ErrorCodes::OVERRUN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data[currentPosition] & 0b10000000) {
|
||||||
|
return ErrorOr<int64_t>(true, ErrorCodes::OVERFLOW);
|
||||||
|
}
|
||||||
|
returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits);
|
||||||
|
(*processedBytes)++;
|
||||||
|
|
||||||
|
return ErrorOr<int64_t>(returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// appends to the vector
|
||||||
|
void toVar32(int32_t value, std::vector<uint8_t> &data) {
|
||||||
|
uint8_t nextByte;
|
||||||
|
uint8_t shift = 0;
|
||||||
|
// do something else after the 4th shift
|
||||||
|
while (shift < 4) {
|
||||||
|
if (shift>0 && value==0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextByte = value & 0b01111111;
|
||||||
|
|
||||||
|
value = (value >> 7) & 0x01FFFFFF;
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
|
||||||
|
if (value>0) {
|
||||||
|
nextByte = nextByte + 0b10000000;
|
||||||
|
}
|
||||||
|
data.push_back(nextByte);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (value>0) {
|
||||||
|
data.push_back(value & 0b00001111);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// appends to the vector
|
||||||
|
void toVar64(int64_t value, std::vector<uint8_t> &data) {
|
||||||
|
uint8_t nextByte;
|
||||||
|
uint8_t shift = 0;
|
||||||
|
// do something else after the 4th shift
|
||||||
|
while (shift < 9) {
|
||||||
|
if (shift>0 && value==0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextByte = value & 0b01111111;
|
||||||
|
|
||||||
|
value = (value >> 7) & 0x01FFFFFFFFFFFFFF;
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
if (value>0) {
|
||||||
|
nextByte = nextByte + 0b10000000;
|
||||||
|
}
|
||||||
|
data.push_back(nextByte);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (value>0) {
|
||||||
|
data.push_back(value & 0b00000001);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
// BodgeMaster
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Packet {
|
||||||
|
struct DataContainer {
|
||||||
|
uint32_t typeID;
|
||||||
|
std::vector<uint8_t> payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace TypeID {
|
||||||
|
// These are guessed names for what the package IDs could mean.
|
||||||
|
// Some package IDs are used multiple times. I assume the different
|
||||||
|
// connection states (handshaking, status, login, and play) play a role
|
||||||
|
// in identifying what kind of package has been received.
|
||||||
|
|
||||||
|
// State: handshaking
|
||||||
|
const uint32_t HANDSHAKE = 0;
|
||||||
|
|
||||||
|
// State: status
|
||||||
|
const uint32_t STATUS = 0;
|
||||||
|
const uint32_t PING = 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
@ -177,7 +177,39 @@ int main(){
|
||||||
tiny_utf8::string cutByteString = readFile->readString(readFile->size.value).value;
|
tiny_utf8::string cutByteString = readFile->readString(readFile->size.value).value;
|
||||||
readFile->close();
|
readFile->close();
|
||||||
|
|
||||||
|
ASSERT(modifyFile->cursorPosition == modifyFile->size.value);
|
||||||
ASSERT(cutByte.value == '.');
|
ASSERT(cutByte.value == '.');
|
||||||
ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple");
|
ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple");
|
||||||
std::cout << "Passed cut byte test." << std::endl;
|
std::cout << "Passed cut byte test." << std::endl;
|
||||||
|
|
||||||
|
modifyFile->open();
|
||||||
|
modifyFile->cursorPosition = 9;
|
||||||
|
ErrorOr<std::vector<uint8_t>> cutBytes = modifyFile->cut(18);
|
||||||
|
modifyFile->close();
|
||||||
|
|
||||||
|
readFile->open();
|
||||||
|
readFile->cursorPosition = 0;
|
||||||
|
tiny_utf8::string cutBytesString = readFile->readString(readFile->size.value).value;
|
||||||
|
readFile->close();
|
||||||
|
|
||||||
|
|
||||||
|
ASSERT(modifyFile->cursorPosition == 9);
|
||||||
|
ASSERT(cutBytes.value == std::vector<uint8_t>({' ', 'T', 'H', 'E', ' ', 'C', 'A', 'K', 'E', ' ', 'I', 'S', ' ','A', ' ', 'L', 'I', 'E'}))
|
||||||
|
ASSERT(cutBytesString == "Hallo, Hi, Ich bin Shwoomple");
|
||||||
|
std::cout << "Passed cut test." << std::endl;
|
||||||
|
|
||||||
|
modifyFile->open();
|
||||||
|
modifyFile->cursorPosition = 0;
|
||||||
|
ErrorOr<tiny_utf8::string> cutString = modifyFile->cutString(7);
|
||||||
|
modifyFile->close();
|
||||||
|
|
||||||
|
readFile->open();
|
||||||
|
readFile->cursorPosition = 0;
|
||||||
|
tiny_utf8::string cutReadString = readFile->readString(readFile->size.value).value;
|
||||||
|
readFile->close();
|
||||||
|
|
||||||
|
ASSERT(modifyFile->cursorPosition == 0);
|
||||||
|
ASSERT(cutString.value == "Hallo, ");
|
||||||
|
ASSERT(cutReadString == "Hi, Ich bin Shwoomple");
|
||||||
|
std::cout << "Passed cutString test." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -773,11 +773,16 @@ int main(){
|
||||||
NBT::Tag::Int8* pointer_2_1 = new NBT::Tag::Int8("entry_2_1", 28);
|
NBT::Tag::Int8* pointer_2_1 = new NBT::Tag::Int8("entry_2_1", 28);
|
||||||
NBT::Tag::Int8* pointer_2_2 = new NBT::Tag::Int8("entry_2_2", 45);
|
NBT::Tag::Int8* pointer_2_2 = new NBT::Tag::Int8("entry_2_2", 45);
|
||||||
NBT::Tag::Int8* pointer_2_3 = new NBT::Tag::Int8("entry_2_3", 78);
|
NBT::Tag::Int8* pointer_2_3 = new NBT::Tag::Int8("entry_2_3", 78);
|
||||||
|
NBT::Tag::Int8* pointer_invalid_0 = new NBT::Tag::Int8("ayya", 78);
|
||||||
|
NBT::Tag::Int16* pointer_invalid_1 = new NBT::Tag::Int16("ellohhh", 78);
|
||||||
std::vector<NBT::Tag::Generic*> listDataVector;
|
std::vector<NBT::Tag::Generic*> listDataVector;
|
||||||
listDataVector.push_back(pointer_2_0);
|
listDataVector.push_back(pointer_2_0);
|
||||||
listDataVector.push_back(pointer_2_1);
|
listDataVector.push_back(pointer_2_1);
|
||||||
listDataVector.push_back(pointer_2_2);
|
listDataVector.push_back(pointer_2_2);
|
||||||
listDataVector.push_back(pointer_2_3);
|
listDataVector.push_back(pointer_2_3);
|
||||||
|
std::vector<NBT::Tag::Generic*> invalidListDataVector;
|
||||||
|
invalidListDataVector.push_back(pointer_invalid_0);
|
||||||
|
invalidListDataVector.push_back(pointer_invalid_1);
|
||||||
|
|
||||||
NBT::Tag::List list_0 = NBT::Tag::List();
|
NBT::Tag::List list_0 = NBT::Tag::List();
|
||||||
ASSERT(list_0.serialize(&vector).isError);
|
ASSERT(list_0.serialize(&vector).isError);
|
||||||
|
@ -792,8 +797,9 @@ int main(){
|
||||||
NBT::Tag::Int16* pointer_invalid = new NBT::Tag::Int16("invalid", 400);
|
NBT::Tag::Int16* pointer_invalid = new NBT::Tag::Int16("invalid", 400);
|
||||||
resultError = list_1.appendPointer(pointer_invalid);
|
resultError = list_1.appendPointer(pointer_invalid);
|
||||||
ASSERT(resultError.isError && resultError.errorCode == ErrorCodes::INVALID_TYPE);
|
ASSERT(resultError.isError && resultError.errorCode == ErrorCodes::INVALID_TYPE);
|
||||||
//TODO: Check that constructing with a vector of mixed tags
|
ErrorOr<NBT::Tag::List*> invalid_list_or_error = NBT::Tag::List::constructWithData("list_invalid", invalidListDataVector);
|
||||||
// results in a clearly defined failure mode (issue #60)
|
ASSERT(invalid_list_or_error.isError);
|
||||||
|
ASSERT(invalid_list_or_error.errorCode == ErrorCodes::MIXED_TYPES);
|
||||||
ErrorOr<NBT::Tag::List*> list_2_or_error = NBT::Tag::List::constructWithData("list_2", listDataVector);
|
ErrorOr<NBT::Tag::List*> list_2_or_error = NBT::Tag::List::constructWithData("list_2", listDataVector);
|
||||||
ASSERT(!list_2_or_error.isError);
|
ASSERT(!list_2_or_error.isError);
|
||||||
NBT::Tag::List* list_2 = list_2_or_error.value;
|
NBT::Tag::List* list_2 = list_2_or_error.value;
|
||||||
|
@ -886,11 +892,24 @@ int main(){
|
||||||
compoundDataVector.push_back(new NBT::Tag::Int16("will be deleted", 0x1337));
|
compoundDataVector.push_back(new NBT::Tag::Int16("will be deleted", 0x1337));
|
||||||
compoundDataVector.push_back(new NBT::Tag::Int16("1", 0x1337));
|
compoundDataVector.push_back(new NBT::Tag::Int16("1", 0x1337));
|
||||||
compoundDataVector.push_back(new NBT::Tag::String("2", "Hello World!"));
|
compoundDataVector.push_back(new NBT::Tag::String("2", "Hello World!"));
|
||||||
|
std::vector<NBT::Tag::Generic*> invalidCompoundDataVector;
|
||||||
|
invalidCompoundDataVector.push_back(new NBT::Tag::End());
|
||||||
|
invalidCompoundDataVector.push_back(new NBT::Tag::End());
|
||||||
|
std::vector<NBT::Tag::Generic*> compoundDataVectorWithEnd;
|
||||||
|
compoundDataVectorWithEnd.push_back(new NBT::Tag::Int8("eeee", 25));
|
||||||
|
compoundDataVectorWithEnd.push_back(new NBT::Tag::End());
|
||||||
|
|
||||||
NBT::Tag::Compound compound_0 = NBT::Tag::Compound();
|
NBT::Tag::Compound compound_0 = NBT::Tag::Compound();
|
||||||
compound_0.name = "compound_0";
|
compound_0.name = "compound_0";
|
||||||
NBT::Tag::Compound compound_1 = NBT::Tag::Compound("compound_1");
|
NBT::Tag::Compound compound_1 = NBT::Tag::Compound("compound_1");
|
||||||
NBT::Tag::Compound compound_2 = NBT::Tag::Compound("compound_2", compoundDataVector);
|
ErrorOr<NBT::Tag::Compound*> invalid_compound_or_error = NBT::Tag::Compound::constructWithData("iiiiii", invalidCompoundDataVector);
|
||||||
|
ASSERT(invalid_compound_or_error.isError);
|
||||||
|
ASSERT(invalid_compound_or_error.errorCode == ErrorCodes::NOT_ALLOWED);
|
||||||
|
ErrorOr<NBT::Tag::Compound*> alternate_compound_or_error = NBT::Tag::Compound::constructWithData("iiiiii", compoundDataVectorWithEnd);
|
||||||
|
ASSERT(!alternate_compound_or_error.isError);
|
||||||
|
ErrorOr<NBT::Tag::Compound*> compound_2_or_error = NBT::Tag::Compound::constructWithData("compound_2", compoundDataVector);
|
||||||
|
ASSERT(!compound_2_or_error.isError);
|
||||||
|
NBT::Tag::Compound* compound_2 = compound_2_or_error.value;
|
||||||
|
|
||||||
ASSERT(!compound_1.appendPointer(new NBT::Tag::Int32("0", 69420)).isError);
|
ASSERT(!compound_1.appendPointer(new NBT::Tag::Int32("0", 69420)).isError);
|
||||||
ASSERT(!compound_1.appendPointer(new NBT::Tag::Int8("1", 1)).isError);
|
ASSERT(!compound_1.appendPointer(new NBT::Tag::Int8("1", 1)).isError);
|
||||||
|
@ -906,15 +925,15 @@ int main(){
|
||||||
resultNotAllowed = compound_1.setElementPointerAt(0, new NBT::Tag::End());
|
resultNotAllowed = compound_1.setElementPointerAt(0, new NBT::Tag::End());
|
||||||
ASSERT(resultNotAllowed.isError && resultNotAllowed.errorCode==ErrorCodes::NOT_ALLOWED);
|
ASSERT(resultNotAllowed.isError && resultNotAllowed.errorCode==ErrorCodes::NOT_ALLOWED);
|
||||||
ASSERT(compound_0.setElementPointerAt(1, new NBT::Tag::Int8()).isError && compound_0.setElementPointerAt(1, new NBT::Tag::Int8()).errorCode == ErrorCodes::OUT_OF_RANGE);
|
ASSERT(compound_0.setElementPointerAt(1, new NBT::Tag::Int8()).isError && compound_0.setElementPointerAt(1, new NBT::Tag::Int8()).errorCode == ErrorCodes::OUT_OF_RANGE);
|
||||||
ASSERT(!compound_2.deleteElement(1).isError);
|
ASSERT(!compound_2->deleteElement(1).isError);
|
||||||
ASSERT(compound_0.deleteElement(0).isError && compound_0.deleteElement(0).errorCode == ErrorCodes::NOT_ALLOWED);
|
ASSERT(compound_0.deleteElement(0).isError && compound_0.deleteElement(0).errorCode == ErrorCodes::NOT_ALLOWED);
|
||||||
ASSERT(compound_0.deleteElement(1).isError && compound_0.deleteElement(1).errorCode == ErrorCodes::OUT_OF_RANGE);
|
ASSERT(compound_0.deleteElement(1).isError && compound_0.deleteElement(1).errorCode == ErrorCodes::OUT_OF_RANGE);
|
||||||
ASSERT(compound_0.length() == 1);
|
ASSERT(compound_0.length() == 1);
|
||||||
ASSERT(compound_1.length() == 3);
|
ASSERT(compound_1.length() == 3);
|
||||||
ASSERT(compound_2.length() == 4);
|
ASSERT(compound_2->length() == 4);
|
||||||
compound_0.serialize(&vector);
|
compound_0.serialize(&vector);
|
||||||
compound_1.serialize(&vector);
|
compound_1.serialize(&vector);
|
||||||
compound_2.serialize(&vector);
|
compound_2->serialize(&vector);
|
||||||
ASSERT(vector.size() == 95);
|
ASSERT(vector.size() == 95);
|
||||||
ASSERT(
|
ASSERT(
|
||||||
vector.at( 0) == 10 &&
|
vector.at( 0) == 10 &&
|
||||||
|
@ -1016,7 +1035,7 @@ int main(){
|
||||||
vector.clear();
|
vector.clear();
|
||||||
compound_0.serializeWithoutHeader(&vector);
|
compound_0.serializeWithoutHeader(&vector);
|
||||||
compound_1.serializeWithoutHeader(&vector);
|
compound_1.serializeWithoutHeader(&vector);
|
||||||
compound_2.serializeWithoutHeader(&vector);
|
compound_2->serializeWithoutHeader(&vector);
|
||||||
ASSERT(vector.size() == 56);
|
ASSERT(vector.size() == 56);
|
||||||
ASSERT(
|
ASSERT(
|
||||||
vector.at( 0) == 0 &&
|
vector.at( 0) == 0 &&
|
||||||
|
|
|
@ -0,0 +1,287 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// Author(s):
|
||||||
|
// BodgeMaster, Shwoomple
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// version 3 along with this program.
|
||||||
|
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "assert.hpp"
|
||||||
|
#include "../lib/error.hpp"
|
||||||
|
#include "../lib/net/conversion/varint.hpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
std::cout << "VarInt tests" << std::endl;
|
||||||
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
// examples for numbers
|
||||||
|
//
|
||||||
|
// 32 Bit
|
||||||
|
// 0000 0000 0000 0000 0000 0000 0000 0000 = 0 -> 0000 0000
|
||||||
|
// 1111 1111 1111 1111 1111 1111 1111 1111 = -1 (unsigned int32 max) -> 1111 1111 1111 1111 1111 1111 1111 1111 0000 1111
|
||||||
|
// 0000 0000 0010 0100 0011 1101 1011 1101 = 2375101 -> 1011 1101 1111 1011 1001 0000 0000 0001
|
||||||
|
// 0000 0000 0000 0000 0001 0001 0001 0001 = 4369 -> 1001 0001 0010 0010
|
||||||
|
//
|
||||||
|
// 64 Bit
|
||||||
|
// 0010 0000 0001 0000 0000 0000 1010 0010 1010 1000 0010 0000 1101 0000 1001 0011 = 2310347307446489235 -> 1101 0011 1010 0001 1000 0011 1100 0001 1010 1010 1001 0100 1000 0000 1000 1000 0010 0000
|
||||||
|
// 1000 0000 0100 0000 0010 0000 0001 0000 0000 1000 0000 0100 0000 0010 0000 0001 = -9205322385119247871 -> 1000 0001 1000 0100 1001 0000 1100 0000 1000 0000 1000 0010 1000 1000 1010 0000 1000 0000 0000 0001
|
||||||
|
// 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 = -1 (unsigned int64 max) -> 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0000 0001
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> data = std::vector<uint8_t>();
|
||||||
|
uint8_t processedBytes;
|
||||||
|
ErrorOr<int32_t> result = VarInt::fromVar32(data, 0, &processedBytes);
|
||||||
|
ASSERT(result.isError);
|
||||||
|
ASSERT(result.errorCode == ErrorCodes::OUT_OF_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> data = { 0x84 };
|
||||||
|
uint8_t processedBytes;
|
||||||
|
ErrorOr<int32_t> result = VarInt::fromVar32(data, 0, &processedBytes);
|
||||||
|
ASSERT(result.isError);
|
||||||
|
ASSERT(result.errorCode == ErrorCodes::OVERRUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 };
|
||||||
|
uint8_t processedBytes;
|
||||||
|
ErrorOr<int32_t> result = VarInt::fromVar32(data, 0, &processedBytes);
|
||||||
|
ASSERT(result.isError);
|
||||||
|
ASSERT(result.errorCode == ErrorCodes::OVERFLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t zeroProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> zeroData;
|
||||||
|
zeroData.push_back(0);
|
||||||
|
ErrorOr<int32_t> zero = VarInt::fromVar32(zeroData, 0, &zeroProcessedBytes);
|
||||||
|
ASSERT(!zero.isError);
|
||||||
|
ASSERT(zero.value == 0);
|
||||||
|
ASSERT(zeroProcessedBytes == 1);
|
||||||
|
|
||||||
|
uint8_t minusOneProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> minusOneData;
|
||||||
|
minusOneData.push_back(255);
|
||||||
|
minusOneData.push_back(255);
|
||||||
|
minusOneData.push_back(255);
|
||||||
|
minusOneData.push_back(255);
|
||||||
|
minusOneData.push_back(15);
|
||||||
|
ErrorOr<int32_t> minusOne = VarInt::fromVar32(minusOneData, 0, &minusOneProcessedBytes);
|
||||||
|
ASSERT(!minusOne.isError);
|
||||||
|
ASSERT(minusOne.value == -1);
|
||||||
|
ASSERT(minusOneProcessedBytes == 5);
|
||||||
|
|
||||||
|
uint8_t smallProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> smallData;
|
||||||
|
// offset data by 3 to test initialPosition feature
|
||||||
|
smallData.push_back(0b10010001);
|
||||||
|
smallData.push_back(0b10010001);
|
||||||
|
smallData.push_back(0b10010001);
|
||||||
|
smallData.push_back(0b10010001);
|
||||||
|
smallData.push_back(0b00100010);
|
||||||
|
ErrorOr<int32_t> small = VarInt::fromVar32(smallData, 3, &smallProcessedBytes);
|
||||||
|
ASSERT(!small.isError);
|
||||||
|
ASSERT(small.value == 4369);
|
||||||
|
ASSERT(smallProcessedBytes == 2);
|
||||||
|
|
||||||
|
uint8_t bigProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> bigData;
|
||||||
|
bigData.push_back(0b10111101);
|
||||||
|
bigData.push_back(0b11111011);
|
||||||
|
bigData.push_back(0b10010000);
|
||||||
|
bigData.push_back(0b00000001);
|
||||||
|
ErrorOr<int32_t> big = VarInt::fromVar32(bigData, 0, &bigProcessedBytes);
|
||||||
|
ASSERT(!big.isError);
|
||||||
|
ASSERT(big.value == 2375101);
|
||||||
|
ASSERT(bigProcessedBytes == 4);
|
||||||
|
|
||||||
|
//TODO: test error conditions
|
||||||
|
|
||||||
|
std::cout << "Passed fromVar32 test." << std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> data = std::vector<uint8_t>();
|
||||||
|
uint8_t processedBytes;
|
||||||
|
ErrorOr<int64_t> result = VarInt::fromVar64(data, 0, &processedBytes);
|
||||||
|
ASSERT(result.isError);
|
||||||
|
ASSERT(result.errorCode == ErrorCodes::OUT_OF_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> data = { 0x84 };
|
||||||
|
uint8_t processedBytes;
|
||||||
|
ErrorOr<int64_t> result = VarInt::fromVar64(data, 0, &processedBytes);
|
||||||
|
ASSERT(result.isError);
|
||||||
|
ASSERT(result.errorCode == ErrorCodes::OVERRUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 };
|
||||||
|
uint8_t processedBytes;
|
||||||
|
ErrorOr<int64_t> result = VarInt::fromVar64(data, 0, &processedBytes);
|
||||||
|
ASSERT(result.isError);
|
||||||
|
ASSERT(result.errorCode == ErrorCodes::OVERFLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t zero64ProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> zero64Data;
|
||||||
|
zero64Data.push_back(0);
|
||||||
|
ErrorOr<int64_t> zero64 = VarInt::fromVar64(zero64Data, 0, &zero64ProcessedBytes);
|
||||||
|
ASSERT(!zero64.isError);
|
||||||
|
ASSERT(zero64.value == 0);
|
||||||
|
ASSERT(zero64ProcessedBytes == 1);
|
||||||
|
|
||||||
|
uint8_t minusOne64ProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> minusOne64Data;
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(255);
|
||||||
|
minusOne64Data.push_back(1);
|
||||||
|
ErrorOr<int64_t> minusOne64 = VarInt::fromVar64(minusOne64Data, 0, &minusOne64ProcessedBytes);
|
||||||
|
ASSERT(!minusOne64.isError);
|
||||||
|
ASSERT(minusOne64.value == -1);
|
||||||
|
ASSERT(minusOne64ProcessedBytes == 10);
|
||||||
|
|
||||||
|
// 0010 0000 0001 0000 0000 0000 1010 0010 1010 1000 0010 0000 1101 0000 1001 0011 = 2310347307446489235 -> 1101 0011 1010 0001 1000 0011 1100 0001 1010 1010 1001 0100 1000 0000 1000 1000 0010 0000
|
||||||
|
uint8_t small64ProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> small64Data;
|
||||||
|
// offset data by 3 to test initialPosition feature
|
||||||
|
small64Data.push_back(0b11010011);
|
||||||
|
small64Data.push_back(0b11010011);
|
||||||
|
small64Data.push_back(0b11010011);
|
||||||
|
small64Data.push_back(0b10010011);
|
||||||
|
small64Data.push_back(0b10100001);
|
||||||
|
small64Data.push_back(0b10000011);
|
||||||
|
small64Data.push_back(0b11000001);
|
||||||
|
small64Data.push_back(0b10101010);
|
||||||
|
small64Data.push_back(0b10010100);
|
||||||
|
small64Data.push_back(0b10000000);
|
||||||
|
small64Data.push_back(0b10001000);
|
||||||
|
small64Data.push_back(0b00100000);
|
||||||
|
ErrorOr<int64_t> small64 = VarInt::fromVar64(small64Data, 3, &small64ProcessedBytes);
|
||||||
|
ASSERT(!small64.isError);
|
||||||
|
ASSERT(small64.value == 2310347307446489235);
|
||||||
|
ASSERT(small64ProcessedBytes == 9);
|
||||||
|
|
||||||
|
// 1000 0000 0100 0000 0010 0000 0001 0000 0000 1000 0000 0100 0000 0010 0000 0001 = -9205322385119247871 -> 1000 0001 1000 0100 1001 0000 1100 0000 1000 0000 1000 0010 1000 1000 1010 0000 1000 0000 0000 0001
|
||||||
|
uint8_t big64ProcessedBytes = 0;
|
||||||
|
std::vector<uint8_t> big64Data;
|
||||||
|
big64Data.push_back(0b10000001);
|
||||||
|
big64Data.push_back(0b10000100);
|
||||||
|
big64Data.push_back(0b10010000);
|
||||||
|
big64Data.push_back(0b11000000);
|
||||||
|
big64Data.push_back(0b10000000);
|
||||||
|
big64Data.push_back(0b10000010);
|
||||||
|
big64Data.push_back(0b10001000);
|
||||||
|
big64Data.push_back(0b10100000);
|
||||||
|
big64Data.push_back(0b10000000);
|
||||||
|
big64Data.push_back(0b00000001);
|
||||||
|
ErrorOr<int64_t> big64 = VarInt::fromVar64(big64Data, 0, &big64ProcessedBytes);
|
||||||
|
ASSERT(!big64.isError);
|
||||||
|
ASSERT(big64.value == -9205322385119247871);
|
||||||
|
ASSERT(big64ProcessedBytes == 10);
|
||||||
|
|
||||||
|
//TODO: Test error conditions
|
||||||
|
|
||||||
|
std::cout << "Passed fromVar64 test." << std::endl;
|
||||||
|
|
||||||
|
// reversing all the previous tests
|
||||||
|
std::vector<uint8_t> dataDump;
|
||||||
|
|
||||||
|
VarInt::toVar32(0, dataDump);
|
||||||
|
ASSERT(dataDump[0] == 0);
|
||||||
|
|
||||||
|
VarInt::toVar32(-1, dataDump);
|
||||||
|
ASSERT(
|
||||||
|
dataDump[1]==255 &&
|
||||||
|
dataDump[2]==255 &&
|
||||||
|
dataDump[3]==255 &&
|
||||||
|
dataDump[4]==255 &&
|
||||||
|
dataDump[5]==15
|
||||||
|
);
|
||||||
|
|
||||||
|
VarInt::toVar32(4369, dataDump);
|
||||||
|
ASSERT(
|
||||||
|
dataDump[6]==0b10010001 &&
|
||||||
|
dataDump[7]==0b00100010
|
||||||
|
);
|
||||||
|
|
||||||
|
VarInt::toVar32(2375101, dataDump);
|
||||||
|
ASSERT(
|
||||||
|
dataDump[8]==0b10111101 &&
|
||||||
|
dataDump[9]==0b11111011 &&
|
||||||
|
dataDump[10]==0b10010000 &&
|
||||||
|
dataDump[11]==0b00000001
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "Passed toVar32 test." << std::endl;
|
||||||
|
|
||||||
|
VarInt::toVar64(0, dataDump);
|
||||||
|
ASSERT(dataDump[12]==0);
|
||||||
|
|
||||||
|
VarInt::toVar64(-1, dataDump);
|
||||||
|
ASSERT(
|
||||||
|
dataDump[13]==255 &&
|
||||||
|
dataDump[14]==255 &&
|
||||||
|
dataDump[15]==255 &&
|
||||||
|
dataDump[16]==255 &&
|
||||||
|
dataDump[17]==255 &&
|
||||||
|
dataDump[18]==255 &&
|
||||||
|
dataDump[19]==255 &&
|
||||||
|
dataDump[20]==255 &&
|
||||||
|
dataDump[21]==255 &&
|
||||||
|
dataDump[22]==1
|
||||||
|
);
|
||||||
|
|
||||||
|
VarInt::toVar64(2310347307446489235, dataDump);
|
||||||
|
ASSERT(
|
||||||
|
dataDump[23]==0b10010011 &&
|
||||||
|
dataDump[24]==0b10100001 &&
|
||||||
|
dataDump[25]==0b10000011 &&
|
||||||
|
dataDump[26]==0b11000001 &&
|
||||||
|
dataDump[27]==0b10101010 &&
|
||||||
|
dataDump[28]==0b10010100 &&
|
||||||
|
dataDump[29]==0b10000000 &&
|
||||||
|
dataDump[30]==0b10001000 &&
|
||||||
|
dataDump[31]==0b00100000
|
||||||
|
);
|
||||||
|
|
||||||
|
VarInt::toVar64(-9205322385119247871, dataDump);
|
||||||
|
ASSERT(
|
||||||
|
dataDump[32]==0b10000001 &&
|
||||||
|
dataDump[33]==0b10000100 &&
|
||||||
|
dataDump[34]==0b10010000 &&
|
||||||
|
dataDump[35]==0b11000000 &&
|
||||||
|
dataDump[36]==0b10000000 &&
|
||||||
|
dataDump[37]==0b10000010 &&
|
||||||
|
dataDump[38]==0b10001000 &&
|
||||||
|
dataDump[39]==0b10100000 &&
|
||||||
|
dataDump[40]==0b10000000 &&
|
||||||
|
dataDump[41]==0b00000001
|
||||||
|
)
|
||||||
|
|
||||||
|
std::cout << "Passed toVar64 test." << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue