From d794bce28802ee742944fadfefbc4c91ec0a9f07 Mon Sep 17 00:00:00 2001 From: Shwoomple <> Date: Wed, 26 Oct 2022 19:18:11 +0530 Subject: [PATCH 01/21] lib/file.cpp: Implement cutByte function --- src/lib/file.cpp | 29 ++++++++++++++++++++++++++--- src/test/file.cpp | 16 ++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/lib/file.cpp b/src/lib/file.cpp index 4913361..92be7a5 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -187,7 +187,7 @@ ErrorOrVoid File::insertByte(uint8_t byte){ this->fileStream.seekg(0); this->write(readData); this->cursorPosition++; - + delete buffer; }catch(std::exception& e){ failure = true; } @@ -209,7 +209,7 @@ ErrorOrVoid File::insert(std::vector data){ this->fileStream.seekg(0); this->write(readData); this->cursorPosition += data.size(); - + delete buffer; }catch(std::exception& e){ failure = true; } @@ -233,13 +233,36 @@ ErrorOrVoid File::insertString(tiny_utf8::string string){ //TODO: fix hack. tinyutf8 appends "_utf-8" when readData is assigned: tiny_utf8::string((char *) buffer); this->writeString(readData.substr(0, readData.find("_utf-8"))); this->cursorPosition += string.size(); - + delete buffer; }catch(std::exception& e){ failure = true; } return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid(); } +ErrorOr File::cutByte(){ + bool failure = false; + uint8_t byte; + try{ + uint8_t* buffer = new uint8_t[this->size.value]; + std::vector readData; + + this->fileStream.read(reinterpret_cast(buffer), this->size.value); + readData = std::vector(buffer, buffer+this->size.value); + + byte = readData[this->cursorPosition]; + readData.erase(readData.begin() + this->cursorPosition); + + this->fileStream.seekg(0); + this->write(readData); + this->cursorPosition++; + delete buffer; + }catch(std::exception& e){ + failure = true; + } + return failure ? ErrorOr(true, ErrorCodes::UNKNOWN) : ErrorOr(byte); +} + ErrorOr File::open(std::string path, char mode, uint64_t startPosition){ if (!std::filesystem::exists(path) && (mode == 'r' || mode == 'm')) { return ErrorOr(true, ErrorCodes::FILE_NOT_FOUND, nullptr); diff --git a/src/test/file.cpp b/src/test/file.cpp index ad5dc5b..29613ef 100644 --- a/src/test/file.cpp +++ b/src/test/file.cpp @@ -123,6 +123,7 @@ int main(){ delete appendFile; + //test insert functions File *modifyFile; modifyFile = File::open("resources/writeTest", 'm').value; @@ -164,4 +165,19 @@ int main(){ ASSERT(modifyString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple."); std::cout << "Passed modify string test" << std::endl; + + //test cut functions + modifyFile->open(); + modifyFile->cursorPosition = modifyFile->size.value-1; + ErrorOr cutByte = modifyFile->cutByte(); + modifyFile->close(); + + readFile->open(); + readFile->cursorPosition = 0; + tiny_utf8::string cutByteString = readFile->readString(readFile->size.value).value; + readFile->close(); + + ASSERT(cutByte.value == '.'); + ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple"); + std::cout << "Passed cut byte test." << std::endl; } From f784948c3ebee5524de9d4c917dce093427b1913 Mon Sep 17 00:00:00 2001 From: Shwoomple <> Date: Sun, 30 Oct 2022 11:12:26 +0530 Subject: [PATCH 02/21] lib/file: fix cutByte filesize bug --- src/lib/file.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/file.cpp b/src/lib/file.cpp index 92be7a5..acb8e38 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -253,6 +253,7 @@ ErrorOr File::cutByte(){ byte = readData[this->cursorPosition]; readData.erase(readData.begin() + this->cursorPosition); + std::filesystem::resize_file(this->path, readData.size()); this->fileStream.seekg(0); this->write(readData); this->cursorPosition++; From 76dd30c45a91a3136f047b929dff602283be2af1 Mon Sep 17 00:00:00 2001 From: Shwoomple <> Date: Sat, 12 Nov 2022 10:58:27 +0530 Subject: [PATCH 03/21] lib/file:Fix issue #71 (Out of Bounds access) --- src/lib/file.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib/file.cpp b/src/lib/file.cpp index acb8e38..b5ca0c5 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -187,7 +187,7 @@ ErrorOrVoid File::insertByte(uint8_t byte){ this->fileStream.seekg(0); this->write(readData); this->cursorPosition++; - delete buffer; + delete[] buffer; }catch(std::exception& e){ failure = true; } @@ -209,7 +209,7 @@ ErrorOrVoid File::insert(std::vector data){ this->fileStream.seekg(0); this->write(readData); this->cursorPosition += data.size(); - delete buffer; + delete[] buffer; }catch(std::exception& e){ failure = true; } @@ -230,10 +230,9 @@ ErrorOrVoid File::insertString(tiny_utf8::string string){ this->fileStream.seekg(0); - //TODO: fix hack. tinyutf8 appends "_utf-8" when readData is assigned: tiny_utf8::string((char *) buffer); - this->writeString(readData.substr(0, readData.find("_utf-8"))); + this->writeString(readData); this->cursorPosition += string.size(); - delete buffer; + delete[] buffer; }catch(std::exception& e){ failure = true; } @@ -257,7 +256,7 @@ ErrorOr File::cutByte(){ this->fileStream.seekg(0); this->write(readData); this->cursorPosition++; - delete buffer; + delete[] buffer; }catch(std::exception& e){ failure = true; } From 9bda607649101e3364b4d4b53ed8b684c6d3641e Mon Sep 17 00:00:00 2001 From: Shwoomple <> Date: Sat, 12 Nov 2022 10:59:08 +0530 Subject: [PATCH 04/21] lib/file: Implement cut function. --- src/lib/file.cpp | 26 ++++++++++++++++++++++++++ src/test/file.cpp | 14 ++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/lib/file.cpp b/src/lib/file.cpp index b5ca0c5..bfdd245 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -263,6 +263,32 @@ ErrorOr File::cutByte(){ return failure ? ErrorOr(true, ErrorCodes::UNKNOWN) : ErrorOr(byte); } +ErrorOr> File::cut(uint64_t length){ + bool failure = false; + std::vector bytes; + + try{ + uint8_t* buffer = new uint8_t[this->size.value]; + std::vector readData; + + this->fileStream.read(reinterpret_cast(buffer), this->size.value); + readData = std::vector(buffer, buffer+this->size.value); + + bytes = std::vector(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>(true, ErrorCodes::UNKNOWN) :ErrorOr>(bytes); +} + ErrorOr File::open(std::string path, char mode, uint64_t startPosition){ if (!std::filesystem::exists(path) && (mode == 'r' || mode == 'm')) { return ErrorOr(true, ErrorCodes::FILE_NOT_FOUND, nullptr); diff --git a/src/test/file.cpp b/src/test/file.cpp index 29613ef..eddc358 100644 --- a/src/test/file.cpp +++ b/src/test/file.cpp @@ -180,4 +180,18 @@ int main(){ ASSERT(cutByte.value == '.'); ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple"); std::cout << "Passed cut byte test." << std::endl; + + modifyFile->open(); + modifyFile->cursorPosition = 9; + ErrorOr> cutBytes = modifyFile->cut(18); + modifyFile->close(); + + readFile->open(); + readFile->cursorPosition = 0; + tiny_utf8::string cutBytesString = readFile->readString(readFile->size.value).value; + readFile->close(); + + ASSERT(cutBytes.value == std::vector({' ', '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; } From bc2255de6b2ce0b8d19e49d6d1a29004f44d6e9f Mon Sep 17 00:00:00 2001 From: Shwoomple <> Date: Sat, 12 Nov 2022 11:51:43 +0530 Subject: [PATCH 05/21] lib/file: Fix issue #71 - Electric Boogaloo (Out of bounds access) Add size constraint to make sure string terminates at the correct length. Cygwin appears to not put null bytes to terminate string when reading from a file stream. --- src/lib/file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/file.cpp b/src/lib/file.cpp index bfdd245..15a0b45 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -225,7 +225,7 @@ ErrorOrVoid File::insertString(tiny_utf8::string string){ this->fileStream.read(reinterpret_cast(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); this->fileStream.seekg(0); From 60a8ac9788d6486d64769cc14b152b0f03813bed Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Fri, 25 Nov 2022 15:45:20 +0100 Subject: [PATCH 06/21] lib/nbt: Make constructor NBT::Tag::Compound::Compound(name, data) private MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The constructor has been made private and replaced with a static wrapper function to make constructing from invalid data impossible. If there is more than one end tag or an end tag isn’t at the end, an error will be returned. --- src/lib/nbt.cpp | 18 ++++++++++++++++-- src/lib/nbt.hpp | 3 ++- src/test/nbt_tags.cpp | 14 +++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/lib/nbt.cpp b/src/lib/nbt.cpp index f60a3ca..76aecbf 100644 --- a/src/lib/nbt.cpp +++ b/src/lib/nbt.cpp @@ -976,6 +976,20 @@ namespace NBT { this->endPointer = new End(); } + ErrorOr Compound::constructWithData(tiny_utf8::string name, std::vector data) { + if (data.size() > 0) { + for (uint64_t i=0; igetTagType() == TagType::END && i != data.size()-1) { + return ErrorOr(true, ErrorCodes::NOT_ALLOWED, nullptr); + } + } + if (data[data.size()-1]->getTagType() == TagType::END) { + return ErrorOr(new Compound(name, std::vector(data.begin(), data.end()-1))); + } + } + return ErrorOr(new Compound(name, data)); + } + Compound::~Compound() { for (uint64_t i=0; itags.size(); i++) { delete this->tags.at(i); @@ -1342,7 +1356,7 @@ namespace NBT { returnValue = ErrorOr>(true, nextCompoundData.errorCode); goto returnError; } - contents.push_back(new Tag::Compound("", nextCompoundData.value)); + contents.push_back(reinterpret_cast(Tag::Compound::constructWithData("", nextCompoundData.value).value)); *processedDataSize += *containedDataSize; } delete containedDataSize; @@ -1454,7 +1468,7 @@ namespace NBT { returnValue = ErrorOr>(true, compoundData.errorCode); goto returnNow; } - tags.push_back(new Tag::Compound(tagName.value, compoundData.value)); + tags.push_back(reinterpret_cast(Tag::Compound::constructWithData(tagName.value, compoundData.value).value)); *processedTagSize += (uint64_t) nameSize + 3; } currentPosition += *processedTagSize; diff --git a/src/lib/nbt.hpp b/src/lib/nbt.hpp index c0940e0..5a4e3a8 100644 --- a/src/lib/nbt.hpp +++ b/src/lib/nbt.hpp @@ -248,10 +248,10 @@ namespace NBT { std::vector tags; // built-in end tag End* endPointer; + Compound(tiny_utf8::string name, std::vector data); public: Compound(); Compound(tiny_utf8::string name); - Compound(tiny_utf8::string name, std::vector data); ~Compound() override; @@ -262,6 +262,7 @@ namespace NBT { ErrorOrVoid appendPointer(Generic* pointer); ErrorOrVoid deleteElement(uint64_t position); uint64_t length(); + static ErrorOr constructWithData(tiny_utf8::string name, std::vector data); }; class Int32Array: public Generic { diff --git a/src/test/nbt_tags.cpp b/src/test/nbt_tags.cpp index 1682c46..79e135c 100644 --- a/src/test/nbt_tags.cpp +++ b/src/test/nbt_tags.cpp @@ -890,7 +890,11 @@ int main(){ NBT::Tag::Compound compound_0 = NBT::Tag::Compound(); compound_0.name = "compound_0"; NBT::Tag::Compound compound_1 = NBT::Tag::Compound("compound_1"); - NBT::Tag::Compound compound_2 = NBT::Tag::Compound("compound_2", compoundDataVector); + //TODO: Check that constructing with a vector containing an end tag that + // isn’t at the end results in a clearly defined failure mode (issue #60) + ErrorOr 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::Int8("1", 1)).isError); @@ -906,15 +910,15 @@ int main(){ resultNotAllowed = compound_1.setElementPointerAt(0, new NBT::Tag::End()); 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_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(1).isError && compound_0.deleteElement(1).errorCode == ErrorCodes::OUT_OF_RANGE); ASSERT(compound_0.length() == 1); ASSERT(compound_1.length() == 3); - ASSERT(compound_2.length() == 4); + ASSERT(compound_2->length() == 4); compound_0.serialize(&vector); compound_1.serialize(&vector); - compound_2.serialize(&vector); + compound_2->serialize(&vector); ASSERT(vector.size() == 95); ASSERT( vector.at( 0) == 10 && @@ -1016,7 +1020,7 @@ int main(){ vector.clear(); compound_0.serializeWithoutHeader(&vector); compound_1.serializeWithoutHeader(&vector); - compound_2.serializeWithoutHeader(&vector); + compound_2->serializeWithoutHeader(&vector); ASSERT(vector.size() == 56); ASSERT( vector.at( 0) == 0 && From d392e080ca18e5b2bdd064fb79a2b8ac92a0573e Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Fri, 25 Nov 2022 17:07:35 +0100 Subject: [PATCH 07/21] test/nbt_tags: Add tests for constructing invalid lists/compounds --- src/test/nbt_tags.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/test/nbt_tags.cpp b/src/test/nbt_tags.cpp index 79e135c..90bd1b2 100644 --- a/src/test/nbt_tags.cpp +++ b/src/test/nbt_tags.cpp @@ -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_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_invalid_0 = new NBT::Tag::Int8("ayya", 78); + NBT::Tag::Int16* pointer_invalid_1 = new NBT::Tag::Int16("ellohhh", 78); std::vector listDataVector; listDataVector.push_back(pointer_2_0); listDataVector.push_back(pointer_2_1); listDataVector.push_back(pointer_2_2); listDataVector.push_back(pointer_2_3); + std::vector invalidListDataVector; + invalidListDataVector.push_back(pointer_invalid_0); + invalidListDataVector.push_back(pointer_invalid_1); NBT::Tag::List list_0 = NBT::Tag::List(); ASSERT(list_0.serialize(&vector).isError); @@ -792,8 +797,9 @@ int main(){ NBT::Tag::Int16* pointer_invalid = new NBT::Tag::Int16("invalid", 400); resultError = list_1.appendPointer(pointer_invalid); ASSERT(resultError.isError && resultError.errorCode == ErrorCodes::INVALID_TYPE); - //TODO: Check that constructing with a vector of mixed tags - // results in a clearly defined failure mode (issue #60) + ErrorOr invalid_list_or_error = NBT::Tag::List::constructWithData("list_invalid", invalidListDataVector); + ASSERT(invalid_list_or_error.isError); + ASSERT(invalid_list_or_error.errorCode == ErrorCodes::MIXED_TYPES); ErrorOr list_2_or_error = NBT::Tag::List::constructWithData("list_2", listDataVector); ASSERT(!list_2_or_error.isError); NBT::Tag::List* list_2 = list_2_or_error.value; @@ -886,12 +892,21 @@ int main(){ 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::String("2", "Hello World!")); + std::vector invalidCompoundDataVector; + invalidCompoundDataVector.push_back(new NBT::Tag::End()); + invalidCompoundDataVector.push_back(new NBT::Tag::End()); + std::vector 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(); compound_0.name = "compound_0"; NBT::Tag::Compound compound_1 = NBT::Tag::Compound("compound_1"); - //TODO: Check that constructing with a vector containing an end tag that - // isn’t at the end results in a clearly defined failure mode (issue #60) + ErrorOr 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 alternate_compound_or_error = NBT::Tag::Compound::constructWithData("iiiiii", compoundDataVectorWithEnd); + ASSERT(!alternate_compound_or_error.isError); ErrorOr 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; From fe7c763d06e6934248af25262dad7256f1771a8e Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Fri, 25 Nov 2022 22:14:53 +0100 Subject: [PATCH 08/21] lib/varint: Add VarInt library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minecraft uses 32-bit and 64-bit VarInt types to cut down on network usage. This library currently contains read functions for conversion to normal integers. Something seems to be wrong with the converter for 64-bit varints, can’t figure out what rn. --- scripts/test.sh | 1 + src/lib/error.hpp | 3 + src/lib/varint.hpp | 86 ++++++++++++++++++++++++ src/test/varint.cpp | 156 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 src/lib/varint.hpp create mode 100644 src/test/varint.cpp diff --git a/scripts/test.sh b/scripts/test.sh index 1b07a0b..5761e8f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -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_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/varint.cpp -I./include -Lbin/lib -o bin/test/varint" ) for command in ${!COMPILE_COMMANDS[@]}; do echo "${COMPILE_COMMANDS[command]}" diff --git a/src/lib/error.hpp b/src/lib/error.hpp index 54b341f..207b0ee 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -97,6 +97,9 @@ namespace ErrorCodes { 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 UNKNOWN = 255; diff --git a/src/lib/varint.hpp b/src/lib/varint.hpp new file mode 100644 index 0000000..a70abe4 --- /dev/null +++ b/src/lib/varint.hpp @@ -0,0 +1,86 @@ +// 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 +#include + +#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 fromVar32(std::vector data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) { + if (initialPosition > data.size()) { + return ErrorOr(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 + ((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(true, ErrorCodes::OVERRUN); + } + + } + if (data[currentPosition] & 0b10000000) { + return ErrorOr(true, ErrorCodes::OVERFLOW); + } + returnValue = returnValue + ((0b01111111 & data[currentPosition]) << bits); + (*processedBytes)++; + + return ErrorOr(returnValue); + } + + // up to 10 bytes, least significant byte first, most significant bit + // indicates whether the next byte is still part of the number + ErrorOr fromVar64(std::vector data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) { + if (initialPosition > data.size()) { + return ErrorOr(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 + ((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(true, ErrorCodes::OVERRUN); + } + } + if (data[currentPosition] & 0b10000000) { + return ErrorOr(true, ErrorCodes::OVERFLOW); + } + returnValue = returnValue + ((0b00000001 & data[currentPosition]) << bits); + (*processedBytes)++; + + return ErrorOr(returnValue); + } +} diff --git a/src/test/varint.cpp b/src/test/varint.cpp new file mode 100644 index 0000000..8a32424 --- /dev/null +++ b/src/test/varint.cpp @@ -0,0 +1,156 @@ +// 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 +#include +#include + +#include "assert.hpp" +#include "../lib/error.hpp" +#include "../lib/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 = 9241421688590303745 -> 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 + + uint8_t zeroProcessedBytes = 0; + std::vector zeroData; + zeroData.push_back(0); + ErrorOr zero = VarInt::fromVar32(zeroData, 0, &zeroProcessedBytes); + ASSERT(!zero.isError); + ASSERT(zero.value == 0); + ASSERT(zeroProcessedBytes == 1); + + uint8_t minusOneProcessedBytes = 0; + std::vector minusOneData; + minusOneData.push_back(255); + minusOneData.push_back(255); + minusOneData.push_back(255); + minusOneData.push_back(255); + minusOneData.push_back(15); + ErrorOr minusOne = VarInt::fromVar32(minusOneData, 0, &minusOneProcessedBytes); + ASSERT(!minusOne.isError); + ASSERT(minusOne.value == -1); + ASSERT(minusOneProcessedBytes == 5); + + uint8_t smallProcessedBytes = 0; + std::vector 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 small = VarInt::fromVar32(smallData, 3, &smallProcessedBytes); + ASSERT(!small.isError); + ASSERT(small.value == 4369); + ASSERT(smallProcessedBytes == 2); + + uint8_t bigProcessedBytes = 0; + std::vector bigData; + bigData.push_back(0b10111101); + bigData.push_back(0b11111011); + bigData.push_back(0b10010000); + bigData.push_back(0b00000001); + ErrorOr 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; + + uint8_t zero64ProcessedBytes = 0; + std::vector zero64Data; + zero64Data.push_back(0); + ErrorOr zero64 = VarInt::fromVar64(zero64Data, 0, &zero64ProcessedBytes); + ASSERT(!zero64.isError); + ASSERT(zero64.value == 0); + ASSERT(zero64ProcessedBytes == 1); + + uint8_t minusOne64ProcessedBytes = 0; + std::vector 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 minusOne64 = VarInt::fromVar64(minusOne64Data, 0, &minusOne64ProcessedBytes); + ASSERT(!minusOne64.isError); + //FIXME: We get -9 here, WTF? + //std::cout << minusOne64.value << std::endl; + //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 small64Data; + // offset data by 3 to test initialPosition feature + small64Data.push_back(0b11010011); + small64Data.push_back(0b11010011); + small64Data.push_back(0b11010011); + small64Data.push_back(0b11010011); + 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 small64 = VarInt::fromVar64(small64Data, 3, &small64ProcessedBytes); + //ASSERT(!small64.isError); + //std::cout << small64.value << std::endl; + //ASSERT(small64.value == 2310347307446489235); + //ASSERT(small64ProcessedBytes == 9); + + // 1000 0000 0100 0000 0010 0000 0001 0000 0000 1000 0000 0100 0000 0010 0000 0001 = 9241421688590303745 -> 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 big64Data; + big64Data.push_back(0b10111101); + big64Data.push_back(0b11111011); + big64Data.push_back(0b10010000); + big64Data.push_back(0b00000001); + //ErrorOr big64 = VarInt::fromVar64(big64Data, 0, &big64ProcessedBytes); + //ASSERT(!big64.isError); + //ASSERT(big64.value == 2375101); + //ASSERT(big64ProcessedBytes == 4); + + + return 0; +} From 44716a55bbfb733b521da2139a8f3718dd8239ac Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Sat, 26 Nov 2022 14:47:15 +0100 Subject: [PATCH 09/21] lib/varint: Fix fromVar64 function The problem was that I let the compiler assume data type widths. `1 << 63` is a 32 bit integer on x86_64-pc-linux-gnu. --- src/lib/varint.hpp | 8 ++++---- src/test/varint.cpp | 41 ++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/lib/varint.hpp b/src/lib/varint.hpp index a70abe4..4e4382e 100644 --- a/src/lib/varint.hpp +++ b/src/lib/varint.hpp @@ -34,7 +34,7 @@ namespace VarInt { uint64_t currentPosition = initialPosition; uint8_t bits = 0; while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+4) { - returnValue = returnValue + ((0b01111111 & data[currentPosition]) << bits); + returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; bits += 7; @@ -48,7 +48,7 @@ namespace VarInt { if (data[currentPosition] & 0b10000000) { return ErrorOr(true, ErrorCodes::OVERFLOW); } - returnValue = returnValue + ((0b01111111 & data[currentPosition]) << bits); + returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; return ErrorOr(returnValue); @@ -65,7 +65,7 @@ namespace VarInt { uint64_t currentPosition = initialPosition; uint8_t bits = 0; while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+9) { - returnValue = returnValue + ((0b01111111 & data[currentPosition]) << bits); + returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; bits += 7; @@ -78,7 +78,7 @@ namespace VarInt { if (data[currentPosition] & 0b10000000) { return ErrorOr(true, ErrorCodes::OVERFLOW); } - returnValue = returnValue + ((0b00000001 & data[currentPosition]) << bits); + returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits); (*processedBytes)++; return ErrorOr(returnValue); diff --git a/src/test/varint.cpp b/src/test/varint.cpp index 8a32424..90e70a7 100644 --- a/src/test/varint.cpp +++ b/src/test/varint.cpp @@ -39,7 +39,7 @@ int main() { // // 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 = 9241421688590303745 -> 1000 0001 1000 0100 1001 0000 1100 0000 1000 0000 1000 0010 1000 1000 1010 0000 1000 0000 0000 0001 + // 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 uint8_t zeroProcessedBytes = 0; @@ -112,9 +112,7 @@ int main() { minusOne64Data.push_back(1); ErrorOr minusOne64 = VarInt::fromVar64(minusOne64Data, 0, &minusOne64ProcessedBytes); ASSERT(!minusOne64.isError); - //FIXME: We get -9 here, WTF? - //std::cout << minusOne64.value << std::endl; - //ASSERT(minusOne64.value == -1); + 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 @@ -124,7 +122,7 @@ int main() { small64Data.push_back(0b11010011); 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); @@ -133,23 +131,32 @@ int main() { small64Data.push_back(0b10000000); small64Data.push_back(0b10001000); small64Data.push_back(0b00100000); - //ErrorOr small64 = VarInt::fromVar64(small64Data, 3, &small64ProcessedBytes); - //ASSERT(!small64.isError); - //std::cout << small64.value << std::endl; - //ASSERT(small64.value == 2310347307446489235); - //ASSERT(small64ProcessedBytes == 9); + ErrorOr 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 = 9241421688590303745 -> 1000 0001 1000 0100 1001 0000 1100 0000 1000 0000 1000 0010 1000 1000 1010 0000 1000 0000 0000 0001 + // 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 big64Data; - big64Data.push_back(0b10111101); - big64Data.push_back(0b11111011); + 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 big64 = VarInt::fromVar64(big64Data, 0, &big64ProcessedBytes); - //ASSERT(!big64.isError); - //ASSERT(big64.value == 2375101); - //ASSERT(big64ProcessedBytes == 4); + ErrorOr 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; return 0; From 26df433dc5dc02f32dd25dd60909cd88bd56dc12 Mon Sep 17 00:00:00 2001 From: Shwoomple <> Date: Sun, 4 Dec 2022 09:59:28 +0530 Subject: [PATCH 10/21] lib/file: Implement cutString function --- src/lib/file.cpp | 30 ++++++++++++++++++++++++++++-- src/test/file.cpp | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/lib/file.cpp b/src/lib/file.cpp index 15a0b45..c6ffb31 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -65,6 +65,8 @@ void File::open(){ void File::close(){ this->fileStream.close(); + std::filesystem::path filePath = this->path; + this->size = ErrorOr(std::filesystem::file_size(filePath)); this->isOpen = false; } @@ -255,7 +257,7 @@ ErrorOr File::cutByte(){ std::filesystem::resize_file(this->path, readData.size()); this->fileStream.seekg(0); this->write(readData); - this->cursorPosition++; + //this->cursorPosition++; delete[] buffer; }catch(std::exception& e){ failure = true; @@ -280,7 +282,7 @@ ErrorOr> File::cut(uint64_t length){ std::filesystem::resize_file(this->path, readData.size()); this->fileStream.seekg(0); this->write(readData); - this->cursorPosition += length; + //this->cursorPosition += length; delete[] buffer; }catch(std::exception& e){ failure = true; @@ -289,6 +291,30 @@ ErrorOr> File::cut(uint64_t length){ return failure ? ErrorOr>(true, ErrorCodes::UNKNOWN) :ErrorOr>(bytes); } +ErrorOr 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(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(true, ErrorCodes::UNKNOWN) : ErrorOr(cutString); +} + ErrorOr File::open(std::string path, char mode, uint64_t startPosition){ if (!std::filesystem::exists(path) && (mode == 'r' || mode == 'm')) { return ErrorOr(true, ErrorCodes::FILE_NOT_FOUND, nullptr); diff --git a/src/test/file.cpp b/src/test/file.cpp index eddc358..0cacab6 100644 --- a/src/test/file.cpp +++ b/src/test/file.cpp @@ -177,6 +177,7 @@ int main(){ tiny_utf8::string cutByteString = readFile->readString(readFile->size.value).value; readFile->close(); + ASSERT(modifyFile->cursorPosition == modifyFile->size.value); ASSERT(cutByte.value == '.'); ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple"); std::cout << "Passed cut byte test." << std::endl; @@ -191,7 +192,24 @@ int main(){ tiny_utf8::string cutBytesString = readFile->readString(readFile->size.value).value; readFile->close(); + + ASSERT(modifyFile->cursorPosition == 9); ASSERT(cutBytes.value == std::vector({' ', '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 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; } From 7108e71b9608002435fab0fe44a2d46506235972 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Tue, 20 Dec 2022 04:41:09 +0100 Subject: [PATCH 11/21] lib/varint: Add toVarN() functions --- src/lib/varint.hpp | 53 +++++++++++++++++++++++++++++++ src/test/varint.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/src/lib/varint.hpp b/src/lib/varint.hpp index 4e4382e..8feb23e 100644 --- a/src/lib/varint.hpp +++ b/src/lib/varint.hpp @@ -83,4 +83,57 @@ namespace VarInt { return ErrorOr(returnValue); } + + // appends to the vector + void toVar32(int32_t value, std::vector &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 &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); + } + } } diff --git a/src/test/varint.cpp b/src/test/varint.cpp index 90e70a7..2902f39 100644 --- a/src/test/varint.cpp +++ b/src/test/varint.cpp @@ -158,6 +158,82 @@ int main() { std::cout << "Passed fromVar64 test." << std::endl; + // reversing all the previous tests + std::vector 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; } From ad5bf1c41a88efb7c19c1cfc5010273effbc158d Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Tue, 20 Dec 2022 17:06:22 +0100 Subject: [PATCH 12/21] lib/cli: Remove completely useless TODO --- src/lib/cli.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/cli.cpp b/src/lib/cli.cpp index d5511ca..8956fef 100644 --- a/src/lib/cli.cpp +++ b/src/lib/cli.cpp @@ -202,7 +202,6 @@ namespace CLI { } ArgumentsParser::~ArgumentsParser() { - //TODO: check that this actually runs for (auto const& [shortName, flag]: this->flagsByShortName) { delete flag; } From 9403da4ca0bde0186a63be9da410bfa33dbb8a37 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Tue, 27 Dec 2022 15:44:05 +0100 Subject: [PATCH 13/21] lib/varint: Fix error handling for out of bounds access --- src/lib/varint.hpp | 8 ++++---- src/test/varint.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/lib/varint.hpp b/src/lib/varint.hpp index 8feb23e..f095a4e 100644 --- a/src/lib/varint.hpp +++ b/src/lib/varint.hpp @@ -26,7 +26,7 @@ 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 fromVar32(std::vector data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) { - if (initialPosition > data.size()) { + if (initialPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OUT_OF_RANGE); } @@ -40,7 +40,7 @@ namespace VarInt { bits += 7; currentPosition++; // check after increasing so we don't need to check outside the loop - if (currentPosition > data.size()) { + if (currentPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OVERRUN); } @@ -57,7 +57,7 @@ namespace VarInt { // up to 10 bytes, least significant byte first, most significant bit // indicates whether the next byte is still part of the number ErrorOr fromVar64(std::vector data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) { - if (initialPosition > data.size()) { + if (initialPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OUT_OF_RANGE); } @@ -71,7 +71,7 @@ namespace VarInt { bits += 7; currentPosition++; // check after increasing so we don't need to check outside the loop - if (currentPosition > data.size()) { + if (currentPosition >= data.size()) { return ErrorOr(true, ErrorCodes::OVERRUN); } } diff --git a/src/test/varint.cpp b/src/test/varint.cpp index 2902f39..c4acc1c 100644 --- a/src/test/varint.cpp +++ b/src/test/varint.cpp @@ -42,6 +42,30 @@ int main() { // 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 data = std::vector(); + uint8_t processedBytes; + ErrorOr result = VarInt::fromVar32(data, 0, &processedBytes); + ASSERT(result.isError); + ASSERT(result.errorCode == ErrorCodes::OUT_OF_RANGE); + } + + { + std::vector data = { 0x84 }; + uint8_t processedBytes; + ErrorOr result = VarInt::fromVar32(data, 0, &processedBytes); + ASSERT(result.isError); + ASSERT(result.errorCode == ErrorCodes::OVERRUN); + } + + { + std::vector data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 }; + uint8_t processedBytes; + ErrorOr result = VarInt::fromVar32(data, 0, &processedBytes); + ASSERT(result.isError); + ASSERT(result.errorCode == ErrorCodes::OVERFLOW); + } + uint8_t zeroProcessedBytes = 0; std::vector zeroData; zeroData.push_back(0); @@ -90,6 +114,30 @@ int main() { std::cout << "Passed fromVar32 test." << std::endl; + { + std::vector data = std::vector(); + uint8_t processedBytes; + ErrorOr result = VarInt::fromVar64(data, 0, &processedBytes); + ASSERT(result.isError); + ASSERT(result.errorCode == ErrorCodes::OUT_OF_RANGE); + } + + { + std::vector data = { 0x84 }; + uint8_t processedBytes; + ErrorOr result = VarInt::fromVar64(data, 0, &processedBytes); + ASSERT(result.isError); + ASSERT(result.errorCode == ErrorCodes::OVERRUN); + } + + { + std::vector data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 }; + uint8_t processedBytes; + ErrorOr result = VarInt::fromVar64(data, 0, &processedBytes); + ASSERT(result.isError); + ASSERT(result.errorCode == ErrorCodes::OVERFLOW); + } + uint8_t zero64ProcessedBytes = 0; std::vector zero64Data; zero64Data.push_back(0); From d2861b79ac41035ada703abb210cc32d70c0c15b Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Tue, 27 Dec 2022 16:24:59 +0100 Subject: [PATCH 14/21] lib/net/conversion/varint: move lib/varint here --- src/lib/{ => net/conversion}/varint.hpp | 2 +- src/test/varint.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/lib/{ => net/conversion}/varint.hpp (99%) diff --git a/src/lib/varint.hpp b/src/lib/net/conversion/varint.hpp similarity index 99% rename from src/lib/varint.hpp rename to src/lib/net/conversion/varint.hpp index f095a4e..17dcf44 100644 --- a/src/lib/varint.hpp +++ b/src/lib/net/conversion/varint.hpp @@ -19,7 +19,7 @@ #include #include -#include "error.hpp" +#include "../../error.hpp" namespace VarInt { diff --git a/src/test/varint.cpp b/src/test/varint.cpp index c4acc1c..e18ec1a 100644 --- a/src/test/varint.cpp +++ b/src/test/varint.cpp @@ -22,7 +22,7 @@ #include "assert.hpp" #include "../lib/error.hpp" -#include "../lib/varint.hpp" +#include "../lib/net/conversion/varint.hpp" int main() { From 85fc73e0151ca42deeb3d7d51e3fe3c4abee1a08 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Tue, 27 Dec 2022 17:28:11 +0100 Subject: [PATCH 15/21] lib/net/conversion/position.hpp: Add library Unit tests tbd --- src/lib/net/conversion/position.hpp | 68 +++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/lib/net/conversion/position.hpp diff --git a/src/lib/net/conversion/position.hpp b/src/lib/net/conversion/position.hpp new file mode 100644 index 0000000..05fc043 --- /dev/null +++ b/src/lib/net/conversion/position.hpp @@ -0,0 +1,68 @@ +// 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 +#include + +#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 fromPosition(std::vector data, uint64_t initialPosition=0) { + if (inititalPosition >= data.size()) { + return ErrorOr(true, ErrorCodes::OUT_OF_BOUNDS); + } + if (initialPosition+7 >= data.size()) { + return ErrorOr(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(fromPosition(deserialized)); + } +} From c6ec0f68501da2eff4be1e47fa37e5b2f4f4fcb0 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Tue, 27 Dec 2022 17:33:23 +0100 Subject: [PATCH 16/21] lib/net/conversion/position: Remove misattributed author Yeah, I just copied the header from somewhere else... --- src/lib/net/conversion/position.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/net/conversion/position.hpp b/src/lib/net/conversion/position.hpp index 05fc043..b5954bf 100644 --- a/src/lib/net/conversion/position.hpp +++ b/src/lib/net/conversion/position.hpp @@ -1,7 +1,7 @@ // Copyright 2022, FOSS-VG Developers and Contributers // // Author(s): -// BodgeMaster, Shwoomple +// 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 From b08a86f0b8b92e8355cabab9a894edc992aa1ad6 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Thu, 29 Dec 2022 03:28:18 +0100 Subject: [PATCH 17/21] resources: Add network capture of a server list ping --- resources/README.md | 8 + resources/network_capture/ping.pcapng | Bin 0 -> 3232 bytes resources/network_capture/ping_decoded.txt | 1434 ++++++++++++++++++++ 3 files changed, 1442 insertions(+) create mode 100644 resources/network_capture/ping.pcapng create mode 100644 resources/network_capture/ping_decoded.txt diff --git a/resources/README.md b/resources/README.md index ee5d485..15442a0 100644 --- a/resources/README.md +++ b/resources/README.md @@ -27,6 +27,14 @@ Data used to test the NBT library `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/ Files with unicode data diff --git a/resources/network_capture/ping.pcapng b/resources/network_capture/ping.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..fea0759635c565e83b265ae65be64ac6bb9a0e20 GIT binary patch literal 3232 zcmaKvTZ|i58OLWg*>saOw4t!sgi0L@4~d-E9(!gy-c}*w8DG}7wLQLWDx~pT?6K#5 zwH<=O6DUIJ3olefDlddb9{Pa9OIV4Ah(Lk1Kp>Hl2#JITREbh06#>ri24}Oo^plRx znd|TTzi)j0$48DHJ@QioLCUX(PcDG|KTl#2A(3_6mDE%9(BJ97NU- z*3(RZH_=mV#g?1_Z;wu+i3k~qqo;C;i~8GRlNUyOUlLK?*}i%fz8eOdFPy9Uq({J8 z7m>q=q?<7(fypE|e;C|x81&C0Uq%qquw67x5F~-}x`+-8$3-`(F5r zIfKhH)*;ZV@BqZS$B5%Mt_|)Kz!VEX*`@APYg@yP=*jXfPlnn|pA# z1;()LVdPhqW{h9%%UA`BlXHd%880KBEWNO^qQY(Pfj}PQ?$q|p%YVPif^)F#;gTzd zX53rPavvR?X@lJ5XSoY=Z95rTe_X!zzx?f~6`r{PYxTzJu3CLSUVn5HCMcq zA*1!PeHp6@k0bw@Gd_kozz^Z~M=pj$$q{VDbQMDntz8Vc(%22Hg|@EpoM-!r&#S0r zh!W~ZwlCR{t*c2i$7>R*@e|bcbktFeK%Jn9{Dv-#CBbvS0%6E9%A>MsnC1i(6=xJd zx31z_SJg6jlZM)o<$;ApjD#+o37INCk!%N|HGUjg!(wMbhOUCeAhZ?(*8$XdGBq7= z!PKw_Mn&Qw@ThILhG3|nwIo4-TV>u?1gIh;@-DxoXkfL9ntK1W9`8sbenx4fH|jyG znClxfhzi#nWSV_2%D}@k&Cp%YGZx>;OJKlen`)-ks^c9u-mA9pX06U-$0@5xhlBK} zkft)~`lzST1s%_I2bEfaqBS7{5CTnY)Wl(}Creh!^exiU#i;40Ohzh2EkD6){3y?* zB-QESM3D4^K2G(o#sfdCkt8+j)?Kzz+)(U|MlE2Xjm>nL z7g^bI8N;tII@akoTiPH>`h7$8(-My}X_BlEiVpgCix}9MX)wYqk+-;3i4g;b5i3y{ zt9MK-XlZP@P>J;zHCGI)#*}Nd(;L|~$qjPqz%@6?ioi_UrD0i#VO>h=#i)3y(~wI7 zYt?0=q;LbKRir2DWmoM?5@}K}6G^ty8Df?CFz8j|aw?V))UcT7=3^a!ZWcJAmQ!;U zm$s%pt>FD`QyqZk1#Hr&CaG)|=VQ4DLYOkLzsczPbVugG@ zN~UsnYoZ#yC`YkerI9Lws>kY9t!Wu)O)K@S4Z+XjMerG=eQwigPlj!pj92=~u+{5g zd_T8owYnpwNMaRbD)QZ|)Nr|C*~R4YxXk$FI88@eicu1#U0!K#l9P^+A*w-}Z;R{G ziq3WIwyJf*Qk<<yD_ZEmLft9}KvmF{!z#ZZ>c;whn7SWh{MMEMjJ(Lr1AeL5hvm zlUPP;DVsS?wVOVhi4j;)$a!qKUKy5)M2u5XeA_KbS**}V=JRwrVN?qw$EC`Apn5H7 zk}1eI?~JQdw^Cx07~l4)d5&xcQOzy~SW~J_0kJpS7&$x_C>^gqa9KZU)NLEbw5*iX z;&_%AO_^a&U(8v|(3hor(|ot$eM8$wE9W7-6cd6;gOP(P)iykLJa!Q^MR)w&ClN(PcGxnvAmX zcGipQekxg{;OaqV)NEtKc{Pn;LYKgL4cG169x?p(t8d;VEJx)24vdg3zhqbpB6?;-FbZ!c@7hp$@sdG7YG@XT*! ztS{_hrDm*S3y&>r?tL@X)73vv&@Z;^x{vxuBzB{1F@u=f82^!&>& literal 0 HcmV?d00001 diff --git a/resources/network_capture/ping_decoded.txt b/resources/network_capture/ping_decoded.txt new file mode 100644 index 0000000..6973220 --- /dev/null +++ b/resources/network_capture/ping_decoded.txt @@ -0,0 +1,1434 @@ +Connection established by client + +C→S Handshake +-- +13 Length: 19 +00 Packet type ID: 0 +f6 Protocol version: 758 (1.18.2) +05 +0c Host string: (length 12) minecraft.ip +6d m +69 i +6e n +65 e +63 c +72 r +61 a +66 f +74 t +2e . +69 i +70 p +63 Port: 25565 +dd +01 Next state: status + + +C→S Status request +-- +01 Length: 1 +00 Packet type ID: 0 + + +S→C Status response +-- +d9 Length: 1369 +0a +00 Packet type ID: 0 +d6 JSON payload: (length 1366) +0a +7b { +22 " +64 d +65 e +73 s +63 c +72 r +69 i +70 p +74 t +69 +6f +6e +22 +3a +7b +22 +74 +65 +78 +74 +22 +3a +22 +c2 +a7 +61 +53 +75 +72 +76 +69 +76 +61 +6c +20 +6d +6f +64 +65 +20 +73 +65 +72 +76 +65 +72 +2e +c2 +a7 +37 +20 +47 +61 +6d +65 +20 +6d +61 +79 +20 +72 +75 +6e +20 +73 +6c +6f +77 +6c +79 +20 +69 +66 +5c +6e +65 +78 +65 +63 +75 +74 +65 +64 +20 +6f +66 +66 +20 +61 +20 +66 +6c +6f +70 +70 +79 +20 +64 +69 +73 +6b +2e +20 +c2 +a7 +34 +c2 +a7 +6c +4d +6f +64 +65 +6d +20 +72 +65 +71 +75 +69 +72 +65 +64 +2e +22 +7d +2c +22 +70 +6c +61 +79 +65 +72 +73 +22 +3a +7b +22 +6d +61 +78 +22 +3a +31 +30 +2c +22 +6f +6e +6c +69 +6e +65 +22 +3a +30 +7d +2c +22 +76 +65 +72 +73 +69 +6f +6e +22 +3a +7b +22 +6e +61 +6d +65 +22 +3a +22 +31 +2e +31 +38 +2e +32 +22 +2c +22 +70 +72 +6f +74 +6f +63 +6f +6c +22 +3a +37 +35 +38 +7d +2c +22 +66 +61 +76 +69 +63 +6f +6e +22 +3a +22 +64 +61 +74 +61 +3a +69 +6d +61 +67 +65 +2f +70 +6e +67 +3b +62 +61 +73 +65 +36 +34 +2c +69 +56 +42 +4f +52 +77 +30 +4b +47 +67 +6f +41 +41 +41 +41 +4e +53 +55 +68 +45 +55 +67 +41 +41 +41 +45 +41 +41 +41 +41 +42 +41 +43 +41 +59 +41 +41 +41 +43 +71 +61 +58 +48 +65 +41 +41 +41 +44 +46 +55 +6c +45 +51 +56 +52 +34 +58 +74 +32 +62 +50 +57 +34 +55 +51 +52 +43 +46 +78 +39 +71 +55 +41 +2b +77 +42 +6b +4a +42 +38 +45 +6c +49 +6b +62 +6d +41 +4a +6e +34 +47 +59 +68 +4e +51 +33 +38 +41 +6d +63 +45 +42 +4f +52 +63 +41 +38 +4f +51 +64 +6a +51 +62 +66 +65 +71 +39 +70 +76 +71 +36 +75 +6e +64 +2f +70 +76 +39 +70 +43 +65 +4c +2f +71 +76 +33 +61 +6d +61 +6b +48 +53 +39 +65 +6c +73 +59 +34 +35 +77 +37 +75 +63 +67 +34 +38 +62 +78 +63 +77 +52 +53 +31 +59 +5a +79 +72 +2b +2b +37 +75 +6a +34 +59 +62 +63 +73 +66 +34 +77 +76 +42 +6d +36 +36 +38 +6a +59 +52 +74 +44 +4e +4b +4f +69 +72 +4f +54 +51 +77 +43 +2f +54 +5a +42 +42 +61 +64 +44 +66 +71 +74 +43 +6f +76 +4e +43 +6e +31 +58 +67 +55 +56 +6d +68 +2f +36 +76 +67 +6f +66 +76 +42 +65 +61 +34 +43 +42 +36 +36 +4e +35 +69 +6e +43 +42 +36 +32 +56 +35 +68 +72 +45 +7a +77 +6b +34 +71 +64 +61 +71 +53 +56 +4c +43 +64 +77 +73 +43 +64 +4e +2f +66 +31 +52 +58 +70 +6d +77 +56 +6d +44 +4d +4a +4e +30 +62 +43 +6c +47 +4b +2b +6c +6f +7a +53 +56 +57 +42 +4f +46 +57 +36 +53 +68 +47 +6c +68 +74 +70 +5a +36 +4e +63 +43 +7a +57 +4c +6a +4d +69 +30 +31 +59 +38 +6d +62 +30 +38 +32 +39 +58 +54 +66 +4c +63 +44 +71 +52 +66 +6f +4c +69 +53 +68 +43 +56 +4b +41 +79 +49 +4d +74 +6c +58 +79 +33 +42 +36 +63 +70 +33 +37 +44 +58 +58 +6a +31 +4e +52 +6a +77 +62 +50 +32 +66 +39 +30 +45 +63 +6c +2b +64 +33 +59 +48 +30 +58 +63 +41 +55 +4a +53 +35 +51 +47 +6c +47 +71 +53 +42 +71 +7a +76 +41 +69 +34 +67 +59 +55 +6c +68 +41 +79 +49 +63 +31 +79 +54 +50 +37 +38 +46 +46 +34 +61 +30 +47 +33 +4c +38 +63 +54 +35 +4c +68 +49 +31 +78 +50 +73 +55 +59 +50 +69 +68 +75 +51 +43 +71 +38 +31 +49 +43 +64 +4a +48 +4a +4e +31 +65 +6c +43 +6c +41 +54 +49 +34 +78 +62 +55 +4d +4c +68 +6e +57 +41 +4a +66 +35 +76 +58 +30 +30 +64 +57 +30 +44 +50 +4e +78 +4c +73 +56 +59 +48 +44 +74 +6b +71 +4e +43 +55 +44 +65 +52 +69 +61 +44 +53 +41 +4d +50 +62 +67 +42 +4c +6c +74 +46 +75 +2f +31 +4a +48 +48 +2f +36 +39 +47 +34 +56 +79 +6c +6f +76 +64 +66 +2f +31 +47 +4e +54 +39 +4d +65 +41 +41 +30 +52 +71 +51 +55 +71 +6f +42 +6d +6d +4c +67 +71 +4f +63 +76 +48 +34 +4b +6d +61 +67 +42 +76 +53 +5a +71 +57 +79 +6a +57 +41 +36 +32 +4e +67 +69 +6a +56 +62 +59 +31 +61 +67 +47 +5a +71 +56 +59 +6b +43 +4b +36 +31 +4e +69 +7a +64 +61 +59 +46 +65 +54 +74 +53 +4b +4d +74 +31 +66 +4d +78 +4d +43 +76 +4d +32 +41 +41 +2f +56 +69 +6f +4c +63 +7a +59 +61 +69 +57 +5a +36 +79 +58 +6f +45 +35 +50 +77 +57 +61 +57 +64 +49 +7a +4e +6e +53 +59 +72 +57 +6c +6d +59 +2b +65 +32 +44 +52 +4e +71 +54 +4d +6b +35 +75 +7a +4d +44 +65 +41 +36 +47 +5a +70 +7a +46 +75 +59 +73 +4f +7a +70 +43 +4a +49 +77 +70 +7a +61 +4c +38 +4a +39 +47 +72 +47 +35 +44 +43 +48 +2f +72 +72 +35 +2f +64 +71 +79 +70 +6d +55 +62 +47 +31 +41 +56 +4f +35 +73 +64 +5a +5a +58 +59 +51 +5a +64 +34 +38 +31 +43 +6e +51 +32 +62 +6c +47 +36 +4f +45 +6b +4d +77 +6f +4b +55 +63 +66 +73 +58 +71 +64 +54 +67 +32 +34 +50 +48 +68 +34 +79 +62 +52 +63 +4b +6b +65 +48 +37 +36 +64 +2f +54 +73 +2b +76 +79 +2f +48 +39 +58 +50 +4d +67 +46 +74 +6b +38 +50 +72 +66 +38 +44 +67 +61 +68 +68 +53 +6a +6f +79 +51 +74 +6c +6e +70 +54 +34 +70 +30 +49 +34 +61 +30 +47 +38 +45 +71 +6e +78 +4b +4b +31 +70 +54 +58 +41 +2f +38 +79 +4a +65 +30 +6b +49 +37 +31 +45 +6d +56 +69 +5a +47 +53 +6c +72 +55 +76 +44 +45 +30 +35 +31 +4b +63 +47 +75 +44 +42 +52 +4e +6a +4d +4b +35 +30 +53 +69 +39 +61 +57 +74 +4b +65 +46 +31 +4a +54 +37 +48 +48 +41 +57 +33 +6f +50 +4a +36 +53 +53 +39 +4d +61 +77 +6c +75 +56 +65 +79 +45 +4a +66 +34 +61 +73 +78 +50 +38 +59 +4e +4c +44 +37 +31 +61 +57 +75 +50 +48 +53 +36 +57 +77 +2f +6d +72 +4d +77 +31 +55 +65 +50 +7a +78 +4b +4b +62 +6a +4f +6b +73 +61 +53 +77 +69 +58 +75 +67 +68 +74 +44 +76 +2f +6f +52 +72 +72 +34 +31 +6d +46 +65 +46 +6d +32 +34 +46 +35 +6b +7a +43 +6a +62 +63 +43 +63 +35 +70 +77 +38 +39 +35 +68 +76 +6b +33 +77 +6b +4c +33 +43 +58 +45 +58 +77 +73 +4c +33 +42 +50 +42 +66 +42 +51 +2f +63 +43 +63 +31 +77 +46 +44 +35 +38 +64 +2b +71 +38 +43 +69 +38 +77 +4b +66 +56 +65 +46 +78 +57 +61 +44 +66 +70 +76 +41 +6f +72 +4e +41 +6e +38 +32 +68 +67 +56 +48 +51 +56 +31 +66 +63 +32 +42 +63 +6f +2b +38 +57 +6d +4a +39 +34 +4d +33 +54 +56 +6b +6e +75 +41 +61 +64 +46 +73 +4c +31 +74 +6b +46 +54 +76 +6e +65 +6f +59 +44 +6d +66 +7a +37 +2f +44 +32 +57 +46 +75 +32 +6e +76 +39 +37 +4b +38 +41 +41 +41 +41 +41 +45 +6c +46 +54 +6b +53 +75 +51 +6d +43 +43 +22 +7d } + + +C→S Ping +-- +09 Length: 9 +01 Packet type ID: 1 +00 64-bit integer payload: 56701 +00 +00 +00 +00 +00 +dd +7d + +S→C Pong +-- +09 Length: 9 +01 Packet type ID: 1 +00 64-bit integer payload: 56701 +00 +00 +00 +00 +00 +dd +7d + +Disconnect From 10d8cdae22b8b681f4f8250a29e0a4d61de78699 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Thu, 29 Dec 2022 03:31:56 +0100 Subject: [PATCH 18/21] lib/net/{client,server,packet}: Prepare for networking --- src/lib/net/client.cpp | 16 ++++++++++++++++ src/lib/net/client.hpp | 16 ++++++++++++++++ src/lib/net/packet.hpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/lib/net/server.cpp | 16 ++++++++++++++++ src/lib/net/server.hpp | 16 ++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 src/lib/net/client.cpp create mode 100644 src/lib/net/client.hpp create mode 100644 src/lib/net/packet.hpp create mode 100644 src/lib/net/server.cpp create mode 100644 src/lib/net/server.hpp diff --git a/src/lib/net/client.cpp b/src/lib/net/client.cpp new file mode 100644 index 0000000..143a4fc --- /dev/null +++ b/src/lib/net/client.cpp @@ -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 diff --git a/src/lib/net/client.hpp b/src/lib/net/client.hpp new file mode 100644 index 0000000..143a4fc --- /dev/null +++ b/src/lib/net/client.hpp @@ -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 diff --git a/src/lib/net/packet.hpp b/src/lib/net/packet.hpp new file mode 100644 index 0000000..9e270e6 --- /dev/null +++ b/src/lib/net/packet.hpp @@ -0,0 +1,41 @@ +// 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 + +#include +#include + +namespace Packet { + struct DataContainer { + uint32_t typeID; + std::vector 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; + } +} diff --git a/src/lib/net/server.cpp b/src/lib/net/server.cpp new file mode 100644 index 0000000..143a4fc --- /dev/null +++ b/src/lib/net/server.cpp @@ -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 diff --git a/src/lib/net/server.hpp b/src/lib/net/server.hpp new file mode 100644 index 0000000..143a4fc --- /dev/null +++ b/src/lib/net/server.hpp @@ -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 From c245e8a5ca8b0b3a7ab61e39146672bad340878a Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Fri, 30 Dec 2022 15:38:05 +0100 Subject: [PATCH 19/21] lib/{file,javacompat,net/conversion/position,net/conversion/varint,net/packet}: pragma once --- src/lib/file.hpp | 2 ++ src/lib/javacompat.hpp | 2 ++ src/lib/net/conversion/position.hpp | 2 ++ src/lib/net/conversion/varint.hpp | 2 ++ src/lib/net/packet.hpp | 2 ++ 5 files changed, 10 insertions(+) diff --git a/src/lib/file.hpp b/src/lib/file.hpp index c794d04..f739e57 100644 --- a/src/lib/file.hpp +++ b/src/lib/file.hpp @@ -16,6 +16,8 @@ // version 3 along with this program. // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html +#pragma once + #include #include #include diff --git a/src/lib/javacompat.hpp b/src/lib/javacompat.hpp index a8c054b..4121a76 100644 --- a/src/lib/javacompat.hpp +++ b/src/lib/javacompat.hpp @@ -13,6 +13,8 @@ //version 3 along with this program. //If not, see https://www.gnu.org/licenses/agpl-3.0.en.html +#pragma once + #include #include #include "error.hpp" diff --git a/src/lib/net/conversion/position.hpp b/src/lib/net/conversion/position.hpp index b5954bf..5540bde 100644 --- a/src/lib/net/conversion/position.hpp +++ b/src/lib/net/conversion/position.hpp @@ -16,6 +16,8 @@ // version 3 along with this program. // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html +#pragma once + #include #include diff --git a/src/lib/net/conversion/varint.hpp b/src/lib/net/conversion/varint.hpp index 17dcf44..16bfd4a 100644 --- a/src/lib/net/conversion/varint.hpp +++ b/src/lib/net/conversion/varint.hpp @@ -16,6 +16,8 @@ // version 3 along with this program. // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html +#pragma once + #include #include diff --git a/src/lib/net/packet.hpp b/src/lib/net/packet.hpp index 9e270e6..b600486 100644 --- a/src/lib/net/packet.hpp +++ b/src/lib/net/packet.hpp @@ -16,6 +16,8 @@ // version 3 along with this program. // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html +#pragma once + #include #include From 5d80ca801e03f5e687e522748cf7d8edae95b766 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Mon, 9 Jan 2023 20:38:13 +0100 Subject: [PATCH 20/21] scripts/clean: Recreate lib/net --- scripts/clean.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/clean.sh b/scripts/clean.sh index e4f54de..7b4d14b 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -25,6 +25,7 @@ remove .endianness remove resources/check_endianness create_directory ./bin create_directory ./bin/lib +create_directory ./bin/lib/net create_directory ./include ln -vs ../../dependencies/sockpp-0.7.1/build/libsockpp.so bin/lib/ From e152c72a04ae22cf23f018d2f433ce8fcf2ed431 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Mon, 9 Jan 2023 20:41:42 +0100 Subject: [PATCH 21/21] fossvg (client): Create window --- README.md | 1 + scripts/build.sh | 2 +- src/fossvg.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c62b51f..bea76d2 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Build dependencies: - bash - a C++ 20 compiler +- GLFW with headers Setup dependencies: diff --git a/scripts/build.sh b/scripts/build.sh index a5d13f8..c0fff03 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -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/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 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" ) for command in ${!COMPILE_COMMANDS[@]}; do diff --git a/src/fossvg.cpp b/src/fossvg.cpp index c2df751..8380b8c 100644 --- a/src/fossvg.cpp +++ b/src/fossvg.cpp @@ -18,6 +18,10 @@ #include #include +#include +#include + +#include #include "./lib/cli.hpp" @@ -25,6 +29,27 @@ #define EXIT_RUNTIME 1 #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[]) { std::vector flags; flags.push_back(CLI::Flag('h', "help", "print help and exit")); @@ -63,5 +88,50 @@ int main(int argc, char* argv[]) { 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; }