Compare commits
22 Commits
3ba4171da3
...
c9ec524db1
Author | SHA1 | Date |
---|---|---|
BodgeMaster | c9ec524db1 | |
BodgeMaster | 73ae58e522 | |
BodgeMaster | acc19ae100 | |
BodgeMaster | 149285c357 | |
BodgeMaster | 0c92bdf8fd | |
BodgeMaster | 86f1ef596f | |
BodgeMaster | 027f324f03 | |
BodgeMaster | 7a2c1d7d57 | |
BodgeMaster | 6fecb2cdb7 | |
BodgeMaster | e882a09099 | |
BodgeMaster | 748c91c375 | |
BodgeMaster | f5d85da98c | |
BodgeMaster | 396b9673fd | |
BodgeMaster | 68fbf3ae20 | |
BodgeMaster | 4363432025 | |
BodgeMaster | 5400790e78 | |
BodgeMaster | c7dd5471dd | |
BodgeMaster | 8048dc8891 | |
BodgeMaster | a1f16e6f6b | |
Shwoomple | cb7b5ddba7 | |
Shwoomple | e0648720bb | |
Shwoomple | ebcf436a18 |
|
@ -33,7 +33,7 @@ fi
|
||||||
|
|
||||||
# `.cpp` files in src/lib will be automatically picked up and compiled into
|
# `.cpp` files in src/lib will be automatically picked up and compiled into
|
||||||
# dynamically linked libraries.
|
# dynamically linked libraries.
|
||||||
echo "Building libs..."
|
echo ">>> Building libs..."
|
||||||
create_directory bin/lib
|
create_directory bin/lib
|
||||||
for lib in $(find ./src/lib -name "*.cpp"); do
|
for lib in $(find ./src/lib -name "*.cpp"); do
|
||||||
COMPILE_COMMAND="$CXX_WITH_FLAGS -I ./include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib"
|
COMPILE_COMMAND="$CXX_WITH_FLAGS -I ./include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib"
|
||||||
|
@ -55,7 +55,7 @@ wait
|
||||||
# How to run a tool: specify the library path to use for the dynamic linker
|
# How to run a tool: specify the library path to use for the dynamic linker
|
||||||
# when running a program
|
# when running a program
|
||||||
# Example: LD_LIBRARY_PATH=bin/lib bin/tools/dumpnbt
|
# Example: LD_LIBRARY_PATH=bin/lib bin/tools/dumpnbt
|
||||||
echo "Building tools..."
|
echo ">>> Building tools..."
|
||||||
create_directory bin/tools
|
create_directory bin/tools
|
||||||
# add compile commands to this array
|
# add compile commands to this array
|
||||||
COMPILE_COMMANDS=(
|
COMPILE_COMMANDS=(
|
||||||
|
|
|
@ -15,6 +15,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
|
||||||
|
|
||||||
|
echo ">>> Cleaning build files..."
|
||||||
|
|
||||||
source scripts/lib.sh
|
source scripts/lib.sh
|
||||||
|
|
||||||
remove ./bin
|
remove ./bin
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
source scripts/lib.sh
|
source scripts/lib.sh
|
||||||
|
|
||||||
echo "Checking download cache for unneeded or corrupted files..."
|
echo ">>> Checking download cache for unneeded or corrupted files..."
|
||||||
for file in $(ls .download_cache); do
|
for file in $(ls .download_cache); do
|
||||||
#TODO: remove if unknown shasum
|
#TODO: remove if unknown shasum
|
||||||
if grep $file scripts/setup_project.sh >/dev/null 2>&1; then
|
if grep $file scripts/setup_project.sh >/dev/null 2>&1; then
|
||||||
|
@ -32,7 +32,8 @@ for file in $(ls .download_cache); do
|
||||||
rm ".download_cache/$file"
|
rm ".download_cache/$file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
echo ""
|
echo "
|
||||||
|
>>> Cleaning dependencies..."
|
||||||
|
|
||||||
remove ./dependencies
|
remove ./dependencies
|
||||||
create_directory ./dependencies
|
create_directory ./dependencies
|
||||||
|
|
|
@ -72,9 +72,7 @@ function download {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Cleaning build files..."
|
|
||||||
scripts/clean.sh
|
scripts/clean.sh
|
||||||
echo "Cleaning dependencies..."
|
|
||||||
scripts/clean_dependencies.sh
|
scripts/clean_dependencies.sh
|
||||||
|
|
||||||
set -e # failures are not acceptable here
|
set -e # failures are not acceptable here
|
||||||
|
@ -82,20 +80,21 @@ create_directory dependencies/tmp
|
||||||
download https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f
|
download https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f
|
||||||
download https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.7.1.tar.gz dependencies/tmp/sockpp.tar.gz 2e023528bebbd2ac083fc91fbe6d5c4158c3336bedbcff48f594f3b28f53b940
|
download https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.7.1.tar.gz dependencies/tmp/sockpp.tar.gz 2e023528bebbd2ac083fc91fbe6d5c4158c3336bedbcff48f594f3b28f53b940
|
||||||
|
|
||||||
echo -n "Extracting tiny-utf8... "
|
echo -n ">>> Extracting tiny-utf8... "
|
||||||
gzip -d dependencies/tmp/tiny-utf8.tar.gz
|
gzip -d dependencies/tmp/tiny-utf8.tar.gz
|
||||||
tar -xf dependencies/tmp/tiny-utf8.tar -C dependencies
|
tar -xf dependencies/tmp/tiny-utf8.tar -C dependencies
|
||||||
echo "done."
|
echo "done"
|
||||||
|
|
||||||
echo -n "Extracting sockpp... "
|
echo -n ">>> Extracting sockpp... "
|
||||||
gzip -d dependencies/tmp/sockpp.tar.gz
|
gzip -d dependencies/tmp/sockpp.tar.gz
|
||||||
tar -xf dependencies/tmp/sockpp.tar -C dependencies
|
tar -xf dependencies/tmp/sockpp.tar -C dependencies
|
||||||
echo "done."
|
echo "done"
|
||||||
echo -n "Building sockpp... "
|
|
||||||
|
echo ">>> Building sockpp... "
|
||||||
pushd dependencies/sockpp-0.7.1/ >/dev/null 2>&1
|
pushd dependencies/sockpp-0.7.1/ >/dev/null 2>&1
|
||||||
cmake -Bbuild .
|
cmake -Bbuild .
|
||||||
cmake --build build
|
cmake --build build
|
||||||
popd >/dev/null 2>&1
|
popd >/dev/null 2>&1
|
||||||
echo "done."
|
|
||||||
|
|
||||||
|
echo ">>> Cleaning up..."
|
||||||
remove dependencies/tmp
|
remove dependencies/tmp
|
||||||
|
|
|
@ -25,16 +25,20 @@ else
|
||||||
fi
|
fi
|
||||||
echo "$LD_LIBRARY_PATH"
|
echo "$LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
echo ">>> Cleaning tests..."
|
||||||
|
remove bin/test
|
||||||
create_directory bin/test
|
create_directory bin/test
|
||||||
|
|
||||||
echo "Building tests..."
|
echo ">>> Building tests..."
|
||||||
|
|
||||||
# add compile commands to this array
|
# add compile commands to this array
|
||||||
COMPILE_COMMANDS=(
|
COMPILE_COMMANDS=(
|
||||||
"$CXX_WITH_FLAGS src/test/nbt_helpers.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_helpers"
|
"$CXX_WITH_FLAGS src/test/nbt_read_write_helpers.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_read_write_helpers"
|
||||||
"$CXX_WITH_FLAGS src/test/cli_argument_parser.cpp -Lbin/lib -l:cli.so -o bin/test/cli_argument_parser"
|
"$CXX_WITH_FLAGS src/test/cli_argument_parser.cpp -Lbin/lib -l:cli.so -o bin/test/cli_argument_parser"
|
||||||
"$CXX_WITH_FLAGS src/test/javacompat.cpp -I./include -Lbin/lib -l:javacompat.so -o bin/test/javacompat"
|
"$CXX_WITH_FLAGS src/test/javacompat.cpp -I./include -Lbin/lib -l:javacompat.so -o bin/test/javacompat"
|
||||||
"$CXX_WITH_FLAGS src/test/nbt_writestring_failure_mode.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_writestring_failure_mode"
|
"$CXX_WITH_FLAGS src/test/nbt_write_string_failure_mode.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_write_string_failure_mode"
|
||||||
|
"$CXX_WITH_FLAGS src/test/nbt_tags.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_tags"
|
||||||
|
"$CXX_WITH_FLAGS src/test/nbt_size_helpers.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_size_helpers"
|
||||||
)
|
)
|
||||||
for command in ${!COMPILE_COMMANDS[@]}; do
|
for command in ${!COMPILE_COMMANDS[@]}; do
|
||||||
echo "${COMPILE_COMMANDS[command]}"
|
echo "${COMPILE_COMMANDS[command]}"
|
||||||
|
@ -44,9 +48,15 @@ done
|
||||||
|
|
||||||
wait
|
wait
|
||||||
|
|
||||||
echo "Running tests..."
|
echo ">>> Running tests..."
|
||||||
|
|
||||||
|
# explicitly allow commands to fail at this stage
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
for test in $(ls bin/test); do
|
for test in $(ls bin/test); do
|
||||||
bin/test/$test
|
bin/test/$test
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for test in $(ls scripts/test); do
|
||||||
|
scripts/test/$test
|
||||||
|
done
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
echo "################################################################################
|
||||||
|
Testing hexnet
|
||||||
|
################################################################################"
|
||||||
|
|
||||||
|
echo "Test not yet implemented."
|
||||||
|
#TODO: implement unit test after merging back with master
|
|
@ -44,6 +44,4 @@ if [ -f "$PROJECT_BASE_DIR/.localenv.bashrc" ]; then
|
||||||
source "$PROJECT_BASE_DIR/.localenv.bashrc"
|
source "$PROJECT_BASE_DIR/.localenv.bashrc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unset PROJECT_BASE_DIR
|
|
||||||
|
|
||||||
echo "done."
|
echo "done."
|
||||||
|
|
|
@ -258,5 +258,66 @@ namespace CLI {
|
||||||
// argument is not present, but this is not an error -> false, NOT_PRESENT, ""
|
// argument is not present, but this is not an error -> false, NOT_PRESENT, ""
|
||||||
else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string(""));
|
else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||||
}
|
}
|
||||||
//std::string ArgumentsParser::getUsage();
|
|
||||||
|
std::string ArgumentsParser::getUsage(){
|
||||||
|
std::string usageString = "";
|
||||||
|
if (this->description != "") {
|
||||||
|
usageString += "Help: " + this->programName + "\n\n\t" + this->description + "\n\n";
|
||||||
|
}
|
||||||
|
usageString += "Usage: " + this->programName + " ";
|
||||||
|
|
||||||
|
if(!this->flagsByShortName.empty()){
|
||||||
|
usageString += "[-";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& [key, value]: this->flagsByShortName){
|
||||||
|
usageString.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this->flagsByShortName.empty()){
|
||||||
|
usageString += "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& [key, value]: this->optionsByShortName){
|
||||||
|
usageString += "[-";
|
||||||
|
usageString.push_back(key);
|
||||||
|
usageString += " " + value->placeholder + "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& argument: this->arguments){
|
||||||
|
usageString += argument.placeholder + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
usageString.push_back('\n');
|
||||||
|
|
||||||
|
if(!this->flagsByShortName.empty()){
|
||||||
|
usageString += "\nFlags:\n";
|
||||||
|
|
||||||
|
for(const auto& [key, value]: this->flagsByShortName){
|
||||||
|
usageString += "\t-";
|
||||||
|
usageString.push_back(key);
|
||||||
|
usageString += ", --" + value->longName + "\n\t\t" + value->description + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this->optionsByShortName.empty()){
|
||||||
|
usageString += "\nOptions:\n";
|
||||||
|
|
||||||
|
for(const auto& [key, value]: this->optionsByShortName){
|
||||||
|
usageString += "\t-";
|
||||||
|
usageString.push_back(key);
|
||||||
|
usageString += " " + value->placeholder + ", --" + value->longName + "=" + value->placeholder + "\n\t\t" + value->description + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this->arguments.empty()){
|
||||||
|
usageString += "\nArguments:\n";
|
||||||
|
|
||||||
|
for(const auto& argument: this->arguments){
|
||||||
|
usageString += "\t" + argument.placeholder + "\n\t\t" + argument.description + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return usageString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
// Copyright 2022, FOSS-VG Developers and Contributers
|
|
||||||
//
|
|
||||||
// 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 <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "error.hpp"
|
|
||||||
|
|
||||||
namespace CLI {
|
|
||||||
|
|
||||||
struct Flag {
|
|
||||||
char shortName;
|
|
||||||
std::string longName;
|
|
||||||
// used for automatic usage generation
|
|
||||||
std::string description;
|
|
||||||
|
|
||||||
bool present;
|
|
||||||
|
|
||||||
Flag();
|
|
||||||
Flag(char shortName, std::string longName, std::string description);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Option {
|
|
||||||
char shortName;
|
|
||||||
std::string longName;
|
|
||||||
// used for automatic usage generation
|
|
||||||
std::string description;
|
|
||||||
std::string placeholder; // the "COUNT" in "ping [-c <COUNT>] <HOST>"
|
|
||||||
|
|
||||||
bool present;
|
|
||||||
std::string value;
|
|
||||||
|
|
||||||
Option();
|
|
||||||
Option(char shortName, std::string longName, std::string placeholder, std::string description);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Argument {
|
|
||||||
// used for automatic usage generation
|
|
||||||
std::string description;
|
|
||||||
std::string placeholder; // the "HOST" in "ping [-c <COUNT>] <HOST>"
|
|
||||||
|
|
||||||
bool present;
|
|
||||||
std::string value;
|
|
||||||
|
|
||||||
Argument();
|
|
||||||
Argument(std::string placeholder, std::string description);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ArgumentsParser {
|
|
||||||
private:
|
|
||||||
std::map<char, Flag*> flagsByShortName;
|
|
||||||
std::map<std::string, Flag*> flagsByLongName;
|
|
||||||
std::map<char, Option*> optionsByShortName;
|
|
||||||
std::map<std::string, Option*> optionsByLongName;
|
|
||||||
std::vector<Argument> arguments;
|
|
||||||
std::string description;
|
|
||||||
std::string additionalInfo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::string programName;
|
|
||||||
bool wrongUsage;
|
|
||||||
std::vector<std::string> wrongUsageMessages;
|
|
||||||
|
|
||||||
// using int here bc that's how main() is defined
|
|
||||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments);
|
|
||||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description);
|
|
||||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description, std::string additionalInfo);
|
|
||||||
~ArgumentsParser();
|
|
||||||
|
|
||||||
ErrorOr<bool> getFlag(char shortName);
|
|
||||||
ErrorOr<bool> getFlag(std::string longName);
|
|
||||||
ErrorOr<std::string> getArgument(std::vector<CLI::Argument>::size_type position);
|
|
||||||
ErrorOr<std::string> getOption(char shortName);
|
|
||||||
ErrorOr<std::string> getOption(std::string longName);
|
|
||||||
|
|
||||||
std::string getUsage();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -78,10 +78,12 @@ namespace ErrorCodes {
|
||||||
// when dealing with maps
|
// when dealing with maps
|
||||||
const uint8_t UNKNOWN_KEY = 5;
|
const uint8_t UNKNOWN_KEY = 5;
|
||||||
|
|
||||||
|
//mismatched size in java strings
|
||||||
|
const uint8_t MISMATCHEDSIZE = 6;
|
||||||
|
|
||||||
|
const uint8_t NOT_YET_KNOWN = 7;
|
||||||
|
|
||||||
const uint8_t UNIMPLEMENTED = 254;
|
const uint8_t UNIMPLEMENTED = 254;
|
||||||
|
|
||||||
const uint8_t UNKNOWN = 255;
|
const uint8_t UNKNOWN = 255;
|
||||||
|
|
||||||
//mismatched size in java strings
|
|
||||||
const uint8_t MISMATCHEDSIZE = 6;
|
|
||||||
}
|
}
|
||||||
|
|
152
src/lib/nbt.cpp
152
src/lib/nbt.cpp
|
@ -370,6 +370,151 @@ namespace NBT {
|
||||||
writeInt64(destination, data[i]);
|
writeInt64(destination, data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME: instead of blindly passing the error code upwards, choose
|
||||||
|
// one that is applicable to the situation (for example replace
|
||||||
|
// OUT_OF_RANGE with OVERRUN where appropriate)
|
||||||
|
//
|
||||||
|
// The total size in bytes
|
||||||
|
//
|
||||||
|
// Does not work for compound tags and lists. This is an intended
|
||||||
|
// feature as compound tags and lists need to be dealt with
|
||||||
|
// separately to avoid unnecessarily long and complex code.
|
||||||
|
//
|
||||||
|
// Regardinng lists specifically: The size of some lists can can
|
||||||
|
// be determined easily by looking at the contained data type and
|
||||||
|
// size information but cases like string lists or compound lists
|
||||||
|
// are significantly more difficult to deal with. Parsing their
|
||||||
|
// contents requires special attention anyway due the tag headers
|
||||||
|
// of contained tags being absent so they may as well get their
|
||||||
|
// own function for this as well.
|
||||||
|
ErrorOr<uint64_t> totalTagSize(uint8_t data[], uint64_t dataSize, uint64_t currentPosition) {
|
||||||
|
uint8_t nextTag;
|
||||||
|
if (dataSize <= currentPosition) {
|
||||||
|
return ErrorOr<uint64_t>(true, ErrorCodes::OVERRUN);
|
||||||
|
} else {
|
||||||
|
nextTag = data[currentPosition];
|
||||||
|
}
|
||||||
|
// deal with compound tags and lists separately
|
||||||
|
if (nextTag == TagType::COMPOUND || nextTag == TagType::LIST) return ErrorOr<uint64_t>(true, ErrorCodes::NOT_YET_KNOWN);
|
||||||
|
// deal with end tag before trying to access the name
|
||||||
|
if (nextTag == TagType::END) return ErrorOr<uint64_t>(1);
|
||||||
|
|
||||||
|
ErrorOr<int16_t> nameSize = helper::readInt16(data, dataSize, currentPosition+1);
|
||||||
|
if (nameSize.isError) {
|
||||||
|
return ErrorOr<uint64_t>(true, nameSize.errorCode);
|
||||||
|
}
|
||||||
|
// add type byte and name size bytes
|
||||||
|
uint64_t prefixSize = (uint64_t) nameSize.value + 3;
|
||||||
|
switch (nextTag) {
|
||||||
|
case TagType::INT8:
|
||||||
|
return ErrorOr<uint64_t>(prefixSize+1);
|
||||||
|
case TagType::INT16:
|
||||||
|
return ErrorOr<uint64_t>(prefixSize+2);
|
||||||
|
case TagType::INT32:
|
||||||
|
return ErrorOr<uint64_t>(prefixSize+4);
|
||||||
|
case TagType::INT64:
|
||||||
|
return ErrorOr<uint64_t>(prefixSize+8);
|
||||||
|
case TagType::FLOAT:
|
||||||
|
return ErrorOr<uint64_t>(prefixSize+4);
|
||||||
|
case TagType::DOUBLE:
|
||||||
|
return ErrorOr<uint64_t>(prefixSize+8);
|
||||||
|
case TagType::INT8_ARRAY: {
|
||||||
|
ErrorOr<int32_t> arrayLength = helper::readInt32(data, dataSize, currentPosition+prefixSize);
|
||||||
|
if (arrayLength.isError) {
|
||||||
|
return ErrorOr<uint64_t>(true, arrayLength.errorCode);
|
||||||
|
}
|
||||||
|
return ErrorOr<uint64_t>((uint64_t) arrayLength.value + prefixSize + 4);
|
||||||
|
}
|
||||||
|
case TagType::STRING: {
|
||||||
|
ErrorOr<int16_t> stringSize = helper::readInt16(data, dataSize, currentPosition+prefixSize);
|
||||||
|
if (stringSize.isError) {
|
||||||
|
return ErrorOr<uint64_t>(true, stringSize.errorCode);
|
||||||
|
}
|
||||||
|
return ErrorOr<uint64_t>((uint64_t) stringSize.value + prefixSize + 2);
|
||||||
|
}
|
||||||
|
case TagType::INT32_ARRAY: {
|
||||||
|
ErrorOr<int32_t> arrayLength = helper::readInt32(data, dataSize, currentPosition+prefixSize);
|
||||||
|
if (arrayLength.isError) {
|
||||||
|
return ErrorOr<uint64_t>(true, arrayLength.errorCode);
|
||||||
|
}
|
||||||
|
return ErrorOr<uint64_t>((uint64_t) arrayLength.value*4 + prefixSize + 4);
|
||||||
|
}
|
||||||
|
case TagType::INT64_ARRAY: {
|
||||||
|
ErrorOr<int32_t> arrayLength = helper::readInt32(data, dataSize, currentPosition+prefixSize);
|
||||||
|
if (arrayLength.isError) {
|
||||||
|
return ErrorOr<uint64_t>(true, arrayLength.errorCode);
|
||||||
|
}
|
||||||
|
return ErrorOr<uint64_t>((uint64_t) arrayLength.value*8 + prefixSize + 4);
|
||||||
|
}
|
||||||
|
// unknown tag or parsing error
|
||||||
|
default:
|
||||||
|
return ErrorOr<uint64_t>(true, ErrorCodes::UNKNOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: instead of blindly passing the error code upwards, choose
|
||||||
|
// one that is applicable to the situation (for example replace
|
||||||
|
// OUT_OF_RANGE with OVERRUN where appropriate)
|
||||||
|
//
|
||||||
|
// Length is the number of stored elements, not to be confused with size
|
||||||
|
// which is the size in bytes.
|
||||||
|
ErrorOr<int32_t> containedDataLength(uint8_t data[], uint64_t dataSize, uint64_t currentPosition){
|
||||||
|
|
||||||
|
uint8_t nextTag;
|
||||||
|
if (dataSize <= currentPosition) {
|
||||||
|
return ErrorOr<int32_t>(true, ErrorCodes::OVERRUN);
|
||||||
|
} else {
|
||||||
|
nextTag = data[currentPosition];
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with compound tags separately
|
||||||
|
if (nextTag == TagType::COMPOUND) {
|
||||||
|
return ErrorOr<int32_t>(true, ErrorCodes::NOT_YET_KNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with end tag before trying to access the name
|
||||||
|
if (nextTag == TagType::END) {
|
||||||
|
return ErrorOr<int32_t>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tags that only ever hold one value
|
||||||
|
if (nextTag == TagType::INT8 || nextTag == TagType::INT16 || nextTag == TagType::INT32 || nextTag == TagType::INT64 || nextTag == TagType::FLOAT || nextTag == TagType::DOUBLE) {
|
||||||
|
return ErrorOr<int32_t>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<int16_t> nameSize = helper::readInt16(data, dataSize, currentPosition+1);
|
||||||
|
if (nameSize.isError) {
|
||||||
|
return ErrorOr<int32_t>(true, nameSize.errorCode);
|
||||||
|
}
|
||||||
|
// add type byte and name size bytes
|
||||||
|
uint64_t prefixSize = (uint64_t) nameSize.value + 3;
|
||||||
|
switch (nextTag) {
|
||||||
|
case TagType::INT8_ARRAY: {
|
||||||
|
return helper::readInt32(data, dataSize, currentPosition+prefixSize);
|
||||||
|
}
|
||||||
|
case TagType::STRING: {
|
||||||
|
ErrorOr<int16_t> stringSize = helper::readInt16(data, dataSize, currentPosition+prefixSize);
|
||||||
|
if (stringSize.isError) {
|
||||||
|
return ErrorOr<int32_t>(true, stringSize.errorCode);
|
||||||
|
}
|
||||||
|
return ErrorOr<int32_t>((int32_t) stringSize.value);
|
||||||
|
}
|
||||||
|
case TagType::LIST: {
|
||||||
|
// add an additional byte for the contained data type
|
||||||
|
return helper::readInt32(data, dataSize, currentPosition+prefixSize+1);
|
||||||
|
}
|
||||||
|
case TagType::INT32_ARRAY: {
|
||||||
|
return helper::readInt32(data, dataSize, currentPosition+prefixSize);
|
||||||
|
}
|
||||||
|
case TagType::INT64_ARRAY: {
|
||||||
|
return helper::readInt32(data, dataSize, currentPosition+prefixSize);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// unknown tag or parsing error
|
||||||
|
return ErrorOr<int32_t>(true, ErrorCodes::UNKNOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tag constructors
|
//Tag constructors
|
||||||
|
@ -424,9 +569,10 @@ namespace NBT {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateRawNBTData(uint8_t data[], uint64_t dataSize){
|
bool validateRawNBTData(uint8_t data[], uint64_t dataSize, uint64_t initialPosition){
|
||||||
//state machine?
|
//TODO: find out the size of the next tag
|
||||||
//TODO: implement
|
//TODO: consume tag
|
||||||
|
//TODO: recurse if tag compound and return if tag end
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,25 @@ namespace NBT {
|
||||||
void writeInt32Array(std::vector<uint8_t>* destination, int32_t data[], uint32_t dataSize);
|
void writeInt32Array(std::vector<uint8_t>* destination, int32_t data[], uint32_t dataSize);
|
||||||
void writeInt64Array(std::vector<uint8_t>* destination, std::vector<int64_t> data);
|
void writeInt64Array(std::vector<uint8_t>* destination, std::vector<int64_t> data);
|
||||||
void writeInt64Array(std::vector<uint8_t>* destination, int64_t data[], uint32_t dataSize);
|
void writeInt64Array(std::vector<uint8_t>* destination, int64_t data[], uint32_t dataSize);
|
||||||
|
|
||||||
|
ErrorOr<uint64_t> totalTagSize(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||||
|
ErrorOr<int32_t> containedDataLength(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace TagType {
|
||||||
|
const uint8_t END = 0;
|
||||||
|
const uint8_t INT8 = 1;
|
||||||
|
const uint8_t INT16 = 2;
|
||||||
|
const uint8_t INT32 = 3;
|
||||||
|
const uint8_t INT64 = 4;
|
||||||
|
const uint8_t FLOAT = 5;
|
||||||
|
const uint8_t DOUBLE = 6;
|
||||||
|
const uint8_t INT8_ARRAY = 7;
|
||||||
|
const uint8_t STRING = 8;
|
||||||
|
const uint8_t LIST = 9;
|
||||||
|
const uint8_t COMPOUND = 10;
|
||||||
|
const uint8_t INT32_ARRAY= 11;
|
||||||
|
const uint8_t INT64_ARRAY= 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Generic parent class to make declaration easier
|
//Generic parent class to make declaration easier
|
||||||
|
@ -94,5 +113,5 @@ namespace NBT {
|
||||||
bool validate(uint8_t data[]);
|
bool validate(uint8_t data[]);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool validateRawNBTData(uint8_t data[], int length);
|
bool validateRawNBTData(uint8_t data[], int length, uint64_t initialPosition=0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,4 +15,4 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#define ASSERT(truth) if ((truth)); else { std::cout << "Assertion failed: " << #truth << std::endl; return 1; }
|
#define ASSERT(truth) if ((truth)); else { std::cout << "On line " << __LINE__ << ": Assertion failed: " << #truth << std::endl; return 1; }
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "################################################################################" << std::endl;
|
std::cout << "################################################################################" << std::endl;
|
||||||
std::cout << "CLI argument parser tests" << std::endl;
|
std::cout << "CLI argument parsing tests" << std::endl;
|
||||||
std::cout << "################################################################################" << std::endl;
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
|
||||||
// Valid parameter test ############################################
|
// Valid parameter test ############################################
|
||||||
|
@ -636,5 +636,115 @@ int main() {
|
||||||
delete[] tooManyArgumentsTestParameterList;
|
delete[] tooManyArgumentsTestParameterList;
|
||||||
std::cout << "Passed too many arguments test." << std::endl;
|
std::cout << "Passed too many arguments test." << std::endl;
|
||||||
|
|
||||||
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
std::cout << "CLI argument parser help tests" << std::endl;
|
||||||
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
|
||||||
|
// normal usage with all types of CLI input ########################
|
||||||
|
std::vector<CLI::Flag> helpTestFlags;
|
||||||
|
helpTestFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||||
|
helpTestFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||||
|
|
||||||
|
std::vector<CLI::Option> helpTestOptions;
|
||||||
|
helpTestOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||||
|
helpTestOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||||
|
|
||||||
|
std::vector<CLI::Argument> helpTestArguments;
|
||||||
|
helpTestArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||||
|
helpTestArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||||
|
|
||||||
|
const char** helpTestCommand = new const char*[1];
|
||||||
|
helpTestCommand[0] = "universecreator";
|
||||||
|
CLI::ArgumentsParser helpTestParser = CLI::ArgumentsParser(1, helpTestCommand, helpTestFlags, helpTestOptions, helpTestArguments, "Create a universe with a banana and an apple.");
|
||||||
|
|
||||||
|
ASSERT(helpTestParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||||
|
std::cout << "Passed normal usage test." << std::endl;
|
||||||
|
|
||||||
|
// no description ##################################################
|
||||||
|
std::vector<CLI::Flag> usageOnlyTestFlags;
|
||||||
|
usageOnlyTestFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||||
|
usageOnlyTestFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||||
|
|
||||||
|
std::vector<CLI::Option> usageOnlyTestOptions;
|
||||||
|
usageOnlyTestOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||||
|
usageOnlyTestOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||||
|
|
||||||
|
std::vector<CLI::Argument> usageOnlyTestArguments;
|
||||||
|
usageOnlyTestArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||||
|
usageOnlyTestArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||||
|
|
||||||
|
const char** usageOnlyTestCommand = new const char*[1];
|
||||||
|
usageOnlyTestCommand[0] = "universecreator";
|
||||||
|
CLI::ArgumentsParser usageOnlyTestParser = CLI::ArgumentsParser(1, usageOnlyTestCommand, usageOnlyTestFlags, usageOnlyTestOptions, usageOnlyTestArguments);
|
||||||
|
|
||||||
|
ASSERT(usageOnlyTestParser.getUsage() == "Usage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||||
|
std::cout << "Passed normal usage without description test." << std::endl;
|
||||||
|
|
||||||
|
// no flags ########################################################
|
||||||
|
std::vector<CLI::Flag> noFlagsFlags;
|
||||||
|
|
||||||
|
std::vector<CLI::Option> noFlagsOptions;
|
||||||
|
noFlagsOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||||
|
noFlagsOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||||
|
|
||||||
|
std::vector<CLI::Argument> noFlagsArguments;
|
||||||
|
noFlagsArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||||
|
noFlagsArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||||
|
|
||||||
|
const char** noFlagsCommand = new const char*[1];
|
||||||
|
noFlagsCommand[0] = "universecreator";
|
||||||
|
CLI::ArgumentsParser noFlagsParser = CLI::ArgumentsParser(1, noFlagsCommand, noFlagsFlags, noFlagsOptions, noFlagsArguments, "Create a universe with a banana and an apple.");
|
||||||
|
|
||||||
|
ASSERT(noFlagsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||||
|
|
||||||
|
// no options ######################################################
|
||||||
|
std::vector<CLI::Flag> noOptionsFlags;
|
||||||
|
noOptionsFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||||
|
noOptionsFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||||
|
|
||||||
|
std::vector<CLI::Option> noOptionsOptions;
|
||||||
|
|
||||||
|
std::vector<CLI::Argument> noOptionsArguments;
|
||||||
|
noOptionsArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||||
|
noOptionsArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||||
|
|
||||||
|
const char** noOptionsCommand = new const char*[1];
|
||||||
|
noOptionsCommand[0] = "universecreator";
|
||||||
|
CLI::ArgumentsParser noOptionsParser = CLI::ArgumentsParser(1, noOptionsCommand, noOptionsFlags, noOptionsOptions, noOptionsArguments, "Create a universe with a banana and an apple.");
|
||||||
|
|
||||||
|
ASSERT(noOptionsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||||
|
|
||||||
|
// no arguments ####################################################
|
||||||
|
std::vector<CLI::Flag> noArgumentsFlags;
|
||||||
|
noArgumentsFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||||
|
noArgumentsFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||||
|
|
||||||
|
std::vector<CLI::Option> noArgumentsOptions;
|
||||||
|
noArgumentsOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||||
|
noArgumentsOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||||
|
|
||||||
|
std::vector<CLI::Argument> noArgumentsArguments;
|
||||||
|
|
||||||
|
const char** noArgumentsCommand = new const char*[1];
|
||||||
|
noArgumentsCommand[0] = "universecreator";
|
||||||
|
CLI::ArgumentsParser noArgumentsParser = CLI::ArgumentsParser(1, noArgumentsCommand, noArgumentsFlags, noArgumentsOptions, noArgumentsArguments, "Create a universe with a banana and an apple.");
|
||||||
|
|
||||||
|
ASSERT(noArgumentsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n");
|
||||||
|
std::cout << "Passed absent section usage test." << std::endl;
|
||||||
|
|
||||||
|
// no CLI input ####################################################
|
||||||
|
std::vector<CLI::Flag> noCLIFlags;
|
||||||
|
|
||||||
|
std::vector<CLI::Option> noCLIOptions;
|
||||||
|
|
||||||
|
std::vector<CLI::Argument> noCLIArguments;
|
||||||
|
|
||||||
|
const char** noCLICommand = new const char*[1];
|
||||||
|
noCLICommand[0] = "universecreator";
|
||||||
|
CLI::ArgumentsParser noCLIParser = CLI::ArgumentsParser(1, noCLICommand, noCLIFlags, noCLIOptions, noCLIArguments, "Create a universe with a banana and an apple.");
|
||||||
|
|
||||||
|
ASSERT(noCLIParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator \n");
|
||||||
|
std::cout << "Passed no CLI input usage test." << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
std::cout << "################################################################################" << std::endl;
|
std::cout << "################################################################################" << std::endl;
|
||||||
std::cout << "NBT helper tests" << std::endl;
|
std::cout << "NBT read/write helper tests" << std::endl;
|
||||||
std::cout << "################################################################################" << std::endl;
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
|
||||||
// used for all integer tests
|
// used for all integer tests
|
||||||
|
@ -524,15 +524,5 @@ int main(){
|
||||||
|
|
||||||
std::cout << "Passed writeString NBT helper test." << std::endl;
|
std::cout << "Passed writeString NBT helper test." << std::endl;
|
||||||
|
|
||||||
//Byte tag constructor test
|
|
||||||
uint8_t bytetest[] = {0x01, 0x00, 0x02, 0x68, 0x69, 0x32};
|
|
||||||
NBT::Byte byte = NBT::Byte(bytetest);
|
|
||||||
|
|
||||||
ASSERT(byte.tagType == 1);
|
|
||||||
ASSERT(byte.nameSize == 2);
|
|
||||||
ASSERT(byte.content = 0x32);
|
|
||||||
ASSERT(byte.name == tiny_utf8::string("hi"));
|
|
||||||
|
|
||||||
std::cout << "Passed Byte Tag constructor test." << std::endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// 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 "assert.hpp"
|
||||||
|
|
||||||
|
#include "../lib/nbt.hpp"
|
||||||
|
#include "../lib/error.hpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout
|
||||||
|
<< "################################################################################\n"
|
||||||
|
<< "NBT size helper tests\n"
|
||||||
|
<< "################################################################################"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
// a full copy of /resources/NBT_data/simple_nbt
|
||||||
|
//
|
||||||
|
// This contains all tag types. It is most likely not suitable for
|
||||||
|
// tests chasing edge cases as it is - as the name says - really
|
||||||
|
// basic NBT data.
|
||||||
|
uint8_t simpleNBTData[] = {
|
||||||
|
0x0a, 0x00, 0x00, 0x08, 0x00, 0x3e, 0x53, 0x70,
|
||||||
|
0x61, 0x63, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64,
|
||||||
|
0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c,
|
||||||
|
0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74,
|
||||||
|
0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20,
|
||||||
|
0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20,
|
||||||
|
0x69, 0x6e, 0x20, 0x74, 0x61, 0x67, 0x20, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x73, 0x2c, 0x20, 0x72, 0x69,
|
||||||
|
0x67, 0x68, 0x74, 0x3f, 0x00, 0x16, 0x49, 0x64,
|
||||||
|
0x6b, 0x2e, 0x20, 0x4c, 0x65, 0x74, 0xe2, 0x80,
|
||||||
|
0x99, 0x73, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20,
|
||||||
|
0x6f, 0x75, 0x74, 0x2e, 0x0a, 0x00, 0x08, 0x63,
|
||||||
|
0x6f, 0x6d, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x03,
|
||||||
|
0x00, 0x0b, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x6e,
|
||||||
|
0x75, 0x6d, 0x62, 0x65, 0x72, 0xd3, 0x07, 0x23,
|
||||||
|
0x41, 0x08, 0x00, 0x09, 0x73, 0x6f, 0x6d, 0x65,
|
||||||
|
0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x0c, 0x65,
|
||||||
|
0x61, 0x74, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6f,
|
||||||
|
0x6b, 0x69, 0x65, 0x00, 0x06, 0x00, 0x06, 0x64,
|
||||||
|
0x6f, 0x75, 0x62, 0x6c, 0x65, 0x41, 0x23, 0x07,
|
||||||
|
0xd3, 0x4e, 0xfd, 0x07, 0xf1, 0x05, 0x00, 0x05,
|
||||||
|
0x66, 0x6c, 0x6f, 0x61, 0x74, 0x42, 0x0d, 0x12,
|
||||||
|
0x43, 0x02, 0x00, 0x05, 0x69, 0x6e, 0x74, 0x31,
|
||||||
|
0x36, 0x07, 0xd0, 0x03, 0x00, 0x05, 0x69, 0x6e,
|
||||||
|
0x74, 0x33, 0x32, 0x00, 0x9a, 0x21, 0x12, 0x0b,
|
||||||
|
0x00, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f,
|
||||||
|
0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x00,
|
||||||
|
0x04, 0x17, 0xbf, 0xe8, 0x3c, 0x00, 0x00, 0xa8,
|
||||||
|
0xfb, 0x7f, 0xff, 0xff, 0xff, 0x61, 0x72, 0x72,
|
||||||
|
0x61, 0x04, 0x00, 0x05, 0x69, 0x6e, 0x74, 0x36,
|
||||||
|
0x34, 0x00, 0x00, 0x00, 0xbc, 0x97, 0xde, 0x9e,
|
||||||
|
0x3e, 0x0c, 0x00, 0x0b, 0x69, 0x6e, 0x74, 0x36,
|
||||||
|
0x34, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00,
|
||||||
|
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x03, 0xa8, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x67, 0xe7, 0xbd, 0x7f, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0x00, 0x00, 0xab, 0xd8, 0x00,
|
||||||
|
0x00, 0xab, 0xd8, 0x00, 0x0b, 0x12, 0x21, 0x00,
|
||||||
|
0x79, 0x61, 0x72, 0x01, 0x00, 0x04, 0x69, 0x6e,
|
||||||
|
0x74, 0x38, 0x64, 0x07, 0x00, 0x0a, 0x69, 0x6e,
|
||||||
|
0x74, 0x38, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79,
|
||||||
|
0x00, 0x00, 0x00, 0x08, 0x71, 0x35, 0x77, 0x62,
|
||||||
|
0x54, 0x64, 0xf5, 0x32, 0x09, 0x00, 0x09, 0x6c,
|
||||||
|
0x69, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x38,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x05, 0x41, 0x60, 0x4e,
|
||||||
|
0x7f, 0xfa, 0x09, 0x00, 0x0c, 0x6c, 0x69, 0x73,
|
||||||
|
0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
|
||||||
|
0x73, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06,
|
||||||
|
0x50, 0x61, 0x63, 0x6d, 0x61, 0x6e, 0x00, 0x03,
|
||||||
|
0x61, 0x74, 0x65, 0x00, 0x03, 0x61, 0x6c, 0x6c,
|
||||||
|
0x00, 0x03, 0x74, 0x68, 0x65, 0x00, 0x04, 0x64,
|
||||||
|
0x6f, 0x74, 0x73, 0x00, 0x02, 0x73, 0x6f, 0x00,
|
||||||
|
0x03, 0x6e, 0x6f, 0x77, 0x00, 0x06, 0x68, 0x65,
|
||||||
|
0xe2, 0x80, 0x99, 0x73, 0x00, 0x06, 0x63, 0x6f,
|
||||||
|
0x6d, 0x69, 0x6e, 0x67, 0x00, 0x03, 0x66, 0x6f,
|
||||||
|
0x72, 0x00, 0x03, 0x74, 0x68, 0x65, 0x00, 0x06,
|
||||||
|
0x77, 0x6f, 0x72, 0x64, 0x73, 0x2e, 0x08, 0x00,
|
||||||
|
0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
|
||||||
|
0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
|
||||||
|
0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00
|
||||||
|
};
|
||||||
|
uint64_t simpleNBTDataSize = 478;
|
||||||
|
|
||||||
|
//##################################################################
|
||||||
|
// Basic valid data tests
|
||||||
|
//##################################################################
|
||||||
|
// const uint8_t END = 0;
|
||||||
|
ErrorOr<uint64_t> totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x93);
|
||||||
|
ErrorOr<int32_t> dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x93);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 1);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 0);
|
||||||
|
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 477);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 477);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 1);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 0);
|
||||||
|
|
||||||
|
//const uint8_t INT8 = 1;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x133);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x133);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 8);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
//const uint8_t INT16 = 2;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xb1);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xb1);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 10);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
//const uint8_t INT32 = 3;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xbb);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xbb);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 12);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x67);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x67);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 18);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
//const uint8_t INT64 = 4;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xe9);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xe9);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 16);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
//const uint8_t FLOAT = 5;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xa5);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xa5);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 12);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
//const uint8_t DOUBLE = 6;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x94);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x94);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 17);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 1);
|
||||||
|
|
||||||
|
//const uint8_t INT8_ARRAY = 7;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x13b);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x13b);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 25);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 8);
|
||||||
|
|
||||||
|
//const uint8_t STRING = 8;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x1c6);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x1c6);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 23);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 12);
|
||||||
|
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x79);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x79);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 26);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 12);
|
||||||
|
|
||||||
|
//const uint8_t LIST = 9;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x154);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x154);
|
||||||
|
|
||||||
|
ASSERT(totalSize.isError);
|
||||||
|
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 5);
|
||||||
|
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x16a);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x16a);
|
||||||
|
|
||||||
|
ASSERT(totalSize.isError);
|
||||||
|
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 12);
|
||||||
|
|
||||||
|
//const uint8_t COMPOUND = 10;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x5c);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x5c);
|
||||||
|
|
||||||
|
ASSERT(totalSize.isError);
|
||||||
|
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||||
|
ASSERT(dataLength.isError);
|
||||||
|
ASSERT(dataLength.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||||
|
|
||||||
|
//const uint8_t INT32_ARRAY= 11;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xc7);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xc7);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 34);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 4);
|
||||||
|
|
||||||
|
//const uint8_t INT64_ARRAY= 12;
|
||||||
|
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xf9);
|
||||||
|
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xf9);
|
||||||
|
|
||||||
|
ASSERT(!totalSize.isError);
|
||||||
|
ASSERT(totalSize.value == 58);
|
||||||
|
ASSERT(!dataLength.isError);
|
||||||
|
ASSERT(dataLength.value == 5);
|
||||||
|
|
||||||
|
std::cout << "Passed simple valid data test." << std::endl;
|
||||||
|
|
||||||
|
//TODO: add tests for errors and edge cases
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||||
|
//
|
||||||
|
// 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 <fstream>
|
||||||
|
|
||||||
|
#include "assert.hpp"
|
||||||
|
|
||||||
|
#include "../lib/nbt.hpp"
|
||||||
|
#include "../lib/error.hpp"
|
||||||
|
#include "../lib/javacompat.hpp"
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
std::cout << "NBT object tests" << std::endl;
|
||||||
|
std::cout << "################################################################################" << std::endl;
|
||||||
|
|
||||||
|
//Byte tag constructor test
|
||||||
|
uint8_t bytetest[] = {0x01, 0x00, 0x02, 0x68, 0x69, 0x32};
|
||||||
|
NBT::Byte byte = NBT::Byte(bytetest);
|
||||||
|
|
||||||
|
ASSERT(byte.tagType == 1);
|
||||||
|
ASSERT(byte.nameSize == 2);
|
||||||
|
ASSERT(byte.content = 0x32);
|
||||||
|
ASSERT(byte.name == tiny_utf8::string("hi"));
|
||||||
|
|
||||||
|
std::cout << "Passed Byte Tag constructor test." << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <sockpp/tcp_acceptor.h>
|
#include <sockpp/tcp_acceptor.h>
|
||||||
|
#include <sockpp/tcp6_acceptor.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
@ -40,8 +41,11 @@ int64_t mtu = 1500;
|
||||||
std::string host;
|
std::string host;
|
||||||
in_port_t port;
|
in_port_t port;
|
||||||
sockpp::tcp_socket* tcpSocket;
|
sockpp::tcp_socket* tcpSocket;
|
||||||
|
sockpp::tcp6_socket* tcp6Socket;
|
||||||
sockpp::tcp_acceptor tcpAcceptor;
|
sockpp::tcp_acceptor tcpAcceptor;
|
||||||
|
sockpp::tcp6_acceptor tcp6Acceptor;
|
||||||
std::mutex tcpSocketMutex;
|
std::mutex tcpSocketMutex;
|
||||||
|
std::mutex tcp6SocketMutex;
|
||||||
std::mutex consoleMutex;
|
std::mutex consoleMutex;
|
||||||
// used for coordinated graceful exit across threads
|
// used for coordinated graceful exit across threads
|
||||||
bool exitProgram = false;
|
bool exitProgram = false;
|
||||||
|
@ -50,12 +54,20 @@ void signalHandler(int signal) {
|
||||||
exitProgram = true;
|
exitProgram = true;
|
||||||
// if still waiting for incoming connection, stop waiting
|
// if still waiting for incoming connection, stop waiting
|
||||||
tcpAcceptor.shutdown();
|
tcpAcceptor.shutdown();
|
||||||
|
tcp6Acceptor.shutdown();
|
||||||
// tell sockpp to close TCP socket if open because it blocks when trying
|
// tell sockpp to close TCP socket if open because it blocks when trying
|
||||||
// to read and there is no data
|
// to read and there is no data
|
||||||
if (*tcpSocket) {
|
|
||||||
|
if (tcpSocket != nullptr && *tcpSocket) {
|
||||||
// Intentionally not using the mutex here
|
// Intentionally not using the mutex here
|
||||||
|
std::cout << "test\n";
|
||||||
tcpSocket->shutdown(SHUT_RD);
|
tcpSocket->shutdown(SHUT_RD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tcp6Socket != nullptr && *tcp6Socket) {
|
||||||
|
// Intentionally not using the mutex here
|
||||||
|
tcp6Socket->shutdown(SHUT_RD);
|
||||||
|
}
|
||||||
//TODO: figure out if - and how - this applies to UDP
|
//TODO: figure out if - and how - this applies to UDP
|
||||||
|
|
||||||
// Priority is to finish up all unfinished business that can be finished up.
|
// Priority is to finish up all unfinished business that can be finished up.
|
||||||
|
@ -64,32 +76,71 @@ void signalHandler(int signal) {
|
||||||
consoleMutex.lock();
|
consoleMutex.lock();
|
||||||
std::cerr << "Received signal " << signal << ", shutting down." << std::endl;
|
std::cerr << "Received signal " << signal << ", shutting down." << std::endl;
|
||||||
consoleMutex.unlock();
|
consoleMutex.unlock();
|
||||||
|
std::exit(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void readFromTCPSocket(sockpp::tcp_socket* socket, int64_t mtu) {
|
void readFromTCPSocket(sockpp::tcp_socket* socket, int64_t mtu) {
|
||||||
ssize_t numBytes;
|
ssize_t numBytes;
|
||||||
uint8_t buffer[mtu];
|
uint8_t buffer[mtu];
|
||||||
tcpSocketMutex.lock();
|
tcpSocketMutex.lock();
|
||||||
while (!exitProgram && (numBytes = socket->read(buffer, sizeof(buffer))) > 0) {
|
while (!exitProgram && (numBytes = socket->read(buffer, sizeof(buffer))) > 0) {
|
||||||
tcpSocketMutex.unlock();
|
|
||||||
consoleMutex.lock();
|
|
||||||
for (ssize_t i=0; i<numBytes; i++) {
|
|
||||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i];
|
|
||||||
}
|
|
||||||
std::cout.flush();
|
|
||||||
consoleMutex.unlock();
|
|
||||||
tcpSocketMutex.lock();
|
|
||||||
}
|
|
||||||
tcpSocketMutex.unlock();
|
tcpSocketMutex.unlock();
|
||||||
consoleMutex.lock();
|
consoleMutex.lock();
|
||||||
std::cerr << std::endl << "Connection closed." << std::endl;
|
for (ssize_t i=0; i<numBytes; i++) {
|
||||||
|
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i];
|
||||||
|
}
|
||||||
|
std::cout.flush();
|
||||||
consoleMutex.unlock();
|
consoleMutex.unlock();
|
||||||
|
tcpSocketMutex.lock();
|
||||||
|
}
|
||||||
|
tcpSocketMutex.unlock();
|
||||||
|
consoleMutex.lock();
|
||||||
|
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||||
|
consoleMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFromTCP6Socket(sockpp::tcp6_socket* socket, int64_t mtu){
|
||||||
|
ssize_t numBytes;
|
||||||
|
uint8_t buffer[mtu];
|
||||||
|
tcp6SocketMutex.lock();
|
||||||
|
while (!exitProgram && (numBytes = socket->read(buffer, sizeof(buffer))) > 0) {
|
||||||
|
tcp6SocketMutex.unlock();
|
||||||
|
consoleMutex.lock();
|
||||||
|
for (ssize_t i=0; i<numBytes; i++) {
|
||||||
|
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i];
|
||||||
|
}
|
||||||
|
std::cout.flush();
|
||||||
|
consoleMutex.unlock();
|
||||||
|
tcp6SocketMutex.lock();
|
||||||
|
}
|
||||||
|
tcp6SocketMutex.unlock();
|
||||||
|
consoleMutex.lock();
|
||||||
|
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||||
|
consoleMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToTCPSocket(sockpp::tcp_socket* socket){
|
||||||
|
while (!exitProgram) {
|
||||||
|
//TODO: Implement locking/unlocking/threading shenanigans
|
||||||
|
}
|
||||||
|
consoleMutex.lock();
|
||||||
|
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||||
|
consoleMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToTCP6Socket(sockpp::tcp6_socket* socket){
|
||||||
|
while (!exitProgram) {
|
||||||
|
//TODO: Implement locking/unlocking/threading shenanigans
|
||||||
|
}
|
||||||
|
consoleMutex.lock();
|
||||||
|
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||||
|
consoleMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]){
|
int main(int argc, char* argv[]){
|
||||||
|
|
||||||
signal(SIGINT, signalHandler);
|
std::signal(SIGINT, signalHandler);
|
||||||
signal(SIGTERM, signalHandler);
|
std::signal(SIGTERM, signalHandler);
|
||||||
|
|
||||||
std::vector<CLI::Flag> flags;
|
std::vector<CLI::Flag> flags;
|
||||||
flags.push_back(CLI::Flag('4', "ipv4", "use IPv4, defaults to both when -4 and -6 are omitted, otherwise uses what is specified"));
|
flags.push_back(CLI::Flag('4', "ipv4", "use IPv4, defaults to both when -4 and -6 are omitted, otherwise uses what is specified"));
|
||||||
|
@ -98,84 +149,142 @@ int main(int argc, char* argv[]){
|
||||||
flags.push_back(CLI::Flag('u', "udp", "use UDP, defaults to both when -t and -u are omitted, otherwise uses what is specified"));
|
flags.push_back(CLI::Flag('u', "udp", "use UDP, defaults to both when -t and -u are omitted, otherwise uses what is specified"));
|
||||||
flags.push_back(CLI::Flag('n', "no-color", "disable coloring the output (intended for terminals that don't work well with color escape sequences)"));
|
flags.push_back(CLI::Flag('n', "no-color", "disable coloring the output (intended for terminals that don't work well with color escape sequences)"));
|
||||||
flags.push_back(CLI::Flag('e', "echo-back", "echo input back to stdout"));
|
flags.push_back(CLI::Flag('e', "echo-back", "echo input back to stdout"));
|
||||||
|
flags.push_back(CLI::Flag('h', "help", "print this information and exit"));
|
||||||
|
flags.push_back(CLI::Flag('l', "license", "print license information and exit"));
|
||||||
|
|
||||||
std::vector<CLI::Option> options;
|
std::vector<CLI::Option> options;
|
||||||
options.push_back(CLI::Option('c', "connect", "HOST", "connect to HOST, listen for incoming connections if omitted"));
|
options.push_back(CLI::Option('c', "connect", "HOST", "connect to HOST, listen for incoming connections if omitted"));
|
||||||
options.push_back(CLI::Option('m', "mtu-optimize", "MTU", "Optimize for a specific maximum transfer unit by reading MTU bytes at a time."));
|
options.push_back(CLI::Option('m', "mtu-optimize", "MTU", "Optimize for a specific maximum transfer unit by reading MTU bytes at a time."));
|
||||||
options.push_back(CLI::Option(
|
options.push_back(CLI::Option(
|
||||||
'p', "print-prefixes", "TCPv4i:UDPv4i:TCPv6i:UDPv6i:TCPv4o:UDPv4o:TCPv6o:UDPv6o",
|
'p', "print-prefixes", "TCPin:UDPin:TCPout:UDPout",
|
||||||
"override default prefixes for output (defaults to spaces + coloring the output or \"t4:u4:t6:u6:T4:U4:T6:U6\" in no-color mode)"
|
"override default prefixes for output (defaults to spaces + coloring the output or \"t:u:T:U\" in no-color mode)"
|
||||||
));
|
));
|
||||||
options.push_back(CLI::Option(
|
options.push_back(CLI::Option(
|
||||||
'i', "input-prefixes", "TCP:UDP:IPv4:IPv6",
|
'i', "input-prefixes", "TCP:UDP",
|
||||||
"override default prefixes for input (defaults to \"t:u:4:6\")"
|
"override default prefixes for input (defaults to \"t:u\")"
|
||||||
));
|
));
|
||||||
|
|
||||||
std::vector<CLI::Argument> arguments;
|
std::vector<CLI::Argument> arguments;
|
||||||
arguments.push_back(CLI::Argument("PORT", "the port to use"));
|
arguments.push_back(CLI::Argument("PORT", "the port to use"));
|
||||||
|
|
||||||
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments);
|
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary tcp/udp connections in hex format.");
|
||||||
|
|
||||||
|
if (cliParser.getFlag("help").value){
|
||||||
|
std::cout << cliParser.getUsage() << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
if (cliParser.getFlag("license").value){
|
||||||
|
std::cout
|
||||||
|
<< "Copyright 2022, FOSS-VG Developers and Contributers\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "Hexnet is part of the FOSS-VG development tool suite.\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "This program is free software: you can redistribute it and/or modify it\n"
|
||||||
|
<< "under the terms of the GNU Affero General Public License as published\n"
|
||||||
|
<< "by the Free Software Foundation, version 3.\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "This program is distributed in the hope that it will be useful,\n"
|
||||||
|
<< "but WITHOUT ANY WARRANTY; without even the implied\n"
|
||||||
|
<< "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||||
|
<< "See the GNU Affero General Public License for more details.\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "You should have received a copy of the GNU Affero General Public License\n"
|
||||||
|
<< "version 3 along with this program.\n"
|
||||||
|
<< "If not, see https://www.gnu.org/licenses/agpl-3.0.en.html"
|
||||||
|
<< std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (cliParser.wrongUsage) {
|
if (cliParser.wrongUsage) {
|
||||||
//TODO: spit out usage information generated by the parser
|
std::cout << cliParser.getUsage() << std::endl;
|
||||||
return EXIT_USAGE;
|
return EXIT_USAGE;
|
||||||
}
|
}
|
||||||
if (cliParser.getFlag('4').value || cliParser.getFlag('6').value) {
|
if (cliParser.getFlag("ipv4").value || cliParser.getFlag("ipv6").value) {
|
||||||
ipv4 = cliParser.getFlag('4').value;
|
ipv4 = cliParser.getFlag("ipv4").value;
|
||||||
ipv6 = cliParser.getFlag('6').value;
|
ipv6 = cliParser.getFlag("ipv4").value;
|
||||||
}
|
}
|
||||||
if (cliParser.getFlag('t').value || cliParser.getFlag('u').value) {
|
if (cliParser.getFlag("tcp").value || cliParser.getFlag("udp").value) {
|
||||||
tcp = cliParser.getFlag('t').value;
|
tcp = cliParser.getFlag("tcp").value;
|
||||||
udp = cliParser.getFlag('u').value;
|
udp = cliParser.getFlag("udp").value;
|
||||||
}
|
}
|
||||||
if (cliParser.getOption('c').errorCode == ErrorCodes::NOT_PRESENT) {
|
if (cliParser.getOption('c').errorCode == ErrorCodes::NOT_PRESENT) {
|
||||||
listenMode = true;
|
listenMode = true;
|
||||||
}
|
}
|
||||||
if (cliParser.getOption('m').errorCode == ErrorCodes::SUCCESS) {
|
if (cliParser.getOption("mtu-optimize").errorCode == ErrorCodes::SUCCESS) {
|
||||||
mtu = std::stol(cliParser.getOption('m').value);
|
mtu = std::stol(cliParser.getOption("mtu-optimize").value);
|
||||||
}
|
}
|
||||||
host = cliParser.getOption('c').value;
|
host = cliParser.getOption("connect").value;
|
||||||
//FIXME: use a function that returns a fixed-width data type instead,
|
//FIXME: use a function that returns a fixed-width data type instead,
|
||||||
// ensure that the given value is a valid port
|
// ensure that the given value is a valid port
|
||||||
port = (in_port_t) std::stoi(cliParser.getArgument(0).value);
|
port = (in_port_t) std::stoi(cliParser.getArgument(0).value);
|
||||||
|
|
||||||
if (listenMode) {
|
if (listenMode) {
|
||||||
if (ipv6) {
|
|
||||||
std::cerr << "IPv6 support is not implented yet." << std::endl;
|
|
||||||
return EXIT_UNIMPLEMENTED;
|
|
||||||
}
|
|
||||||
if (udp) {
|
if (udp) {
|
||||||
std::cerr << "UDP support is not implemented yet." << std::endl;
|
std::cerr << "UDP support is not implemented yet." << std::endl;
|
||||||
return EXIT_UNIMPLEMENTED;
|
return EXIT_UNIMPLEMENTED;
|
||||||
}
|
}
|
||||||
std::cerr << "Listening on port " << port << "." << std::endl;
|
|
||||||
|
|
||||||
sockpp::socket_initializer socketInitializer;
|
if (ipv6) {
|
||||||
tcpAcceptor = sockpp::tcp_acceptor(port);
|
//std::cerr << "IPv6 support is not implented yet." << std::endl;
|
||||||
|
//return EXIT_UNIMPLEMENTED;
|
||||||
|
std::cerr << "Listening on port " << port << "." << std::endl;
|
||||||
|
sockpp::socket_initializer socketInitializer;
|
||||||
|
tcp6Acceptor = sockpp::tcp6_acceptor(port);
|
||||||
|
|
||||||
if (!tcpAcceptor) {
|
if(!tcp6Acceptor){
|
||||||
std::cerr << "Error while creating TCP acceptor: " << tcpAcceptor.last_error_str() << std::endl;
|
std::cerr << "Error while creating TCP6 acceptor: " << tcp6Acceptor.last_error_str() << std::endl;
|
||||||
return EXIT_RUNTIME;
|
return EXIT_RUNTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockpp::inet6_address peer;
|
||||||
|
tcp6Socket = new sockpp::tcp6_socket();
|
||||||
|
*tcp6Socket = tcp6Acceptor.accept(&peer);
|
||||||
|
|
||||||
|
std::cerr << "Incoming connection from " << peer << std::endl;
|
||||||
|
|
||||||
|
if (!(*tcp6Socket)) {
|
||||||
|
std::cerr << "Error on incoming connection: " << tcp6Acceptor.last_error_str() << std::endl;
|
||||||
|
delete tcp6Socket;
|
||||||
|
return EXIT_RUNTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread threadReadFromTCP6 = std::thread(readFromTCP6Socket, tcp6Socket, mtu);
|
||||||
|
threadReadFromTCP6.join();
|
||||||
|
|
||||||
|
delete tcp6Socket;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
sockpp::inet_address peer;
|
if(ipv4){
|
||||||
tcpSocket = new sockpp::tcp_socket();
|
std::cerr << "Listening on port " << port << "." << std::endl;
|
||||||
*tcpSocket = tcpAcceptor.accept(&peer);
|
|
||||||
|
|
||||||
std::cerr << "Incoming connection from " << peer << std::endl;
|
sockpp::socket_initializer socketInitializer;
|
||||||
|
tcpAcceptor = sockpp::tcp_acceptor(port);
|
||||||
|
|
||||||
|
if (!tcpAcceptor) {
|
||||||
|
std::cerr << "Error while creating TCP acceptor: " << tcpAcceptor.last_error_str() << std::endl;
|
||||||
|
return EXIT_RUNTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockpp::inet_address peer;
|
||||||
|
tcpSocket = new sockpp::tcp_socket();
|
||||||
|
*tcpSocket = tcpAcceptor.accept(&peer);
|
||||||
|
|
||||||
|
std::cerr << "Incoming connection from " << peer << std::endl;
|
||||||
|
|
||||||
|
if (!(*tcpSocket)) {
|
||||||
|
std::cerr << "Error on incoming connection: " << tcpAcceptor.last_error_str() << std::endl;
|
||||||
|
delete tcpSocket;
|
||||||
|
return EXIT_RUNTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread threadReadFromTCP = std::thread(readFromTCPSocket, tcpSocket, mtu);
|
||||||
|
threadReadFromTCP.join();
|
||||||
|
|
||||||
if (!(*tcpSocket)) {
|
|
||||||
std::cerr << "Error on incoming connection: " << tcpAcceptor.last_error_str() << std::endl;
|
|
||||||
delete tcpSocket;
|
delete tcpSocket;
|
||||||
return EXIT_RUNTIME;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread threadReadTCP = std::thread(readFromTCPSocket, tcpSocket, mtu);
|
|
||||||
threadReadTCP.join();
|
|
||||||
|
|
||||||
delete tcpSocket;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Client mode is not implemented yet." << std::endl;
|
std::cerr << "Client mode is not implemented yet." << std::endl;
|
||||||
return EXIT_UNIMPLEMENTED;
|
return EXIT_UNIMPLEMENTED;
|
||||||
|
|
Loading…
Reference in New Issue