Compare commits

...

4 Commits

Author SHA1 Message Date
BodgeMaster b53999a548 tools/arraydump: Remove a debugging message that I accidentally left in 2022-10-08 08:32:02 +02:00
BodgeMaster 379903d751 tools/baseconvert: New tool
This tool allows for easy conversion between relevant bases
for unsigned numbers.

You may be able to coerce it into converting signed numbers into
unsigned numbers if you know how, though that is not an officially
supported use case (aka that’s using UB in the STL).
2022-10-08 08:29:01 +02:00
BodgeMaster 17792ec5bf lib/cli: Implement the "Additional Info" feature 2022-10-08 08:27:48 +02:00
BodgeMaster 9ce35b5c6b test/nbt_tags: Implement more tests 2022-10-08 08:25:57 +02:00
7 changed files with 398 additions and 6 deletions

View File

@ -61,6 +61,7 @@ create_directory bin/tools
COMPILE_COMMANDS=( COMPILE_COMMANDS=(
"$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -l:cli.so -o bin/tools/dumpnbt" "$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -l:cli.so -o bin/tools/dumpnbt"
"$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump" "$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump"
"$CXX_WITH_FLAGS src/tools/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
#"$CXX_WITH_FLAGS src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet" #"$CXX_WITH_FLAGS src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
) )
for command in ${!COMPILE_COMMANDS[@]}; do for command in ${!COMPILE_COMMANDS[@]}; do

22
scripts/test/baseconvert.sh Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
echo "================================================================================"
echo -n "Testing \`baseconvert\`... "
[ $(baseconvert -d "0xFFFFFFFFFFFFFFFF") = "18446744073709551615" ] \
&& [ $(baseconvert -x "0xFFFFFFFFFFFFFFFF") = "0xffffffffffffffff" ] \
&& [ $(baseconvert -o "0xFFFFFFFFFFFFFFFF") = "01777777777777777777777" ] \
&& [ $(baseconvert -b "0xFFFFFFFFFFFFFFFF") = "0b1111111111111111111111111111111111111111111111111111111111111111" ] \
&& [ $(baseconvert -x "0XFFFFFFFFFFFFFFFF") = "0xffffffffffffffff" ] \
&& [ $(baseconvert -d "0") = "0" ] \
&& [ $(baseconvert -x "0") = "0x0" ] \
&& [ $(baseconvert -o "0") = "0" ] \
&& [ $(baseconvert -b "0") = "0b0" ] \
&& [ $(baseconvert -b "4") = "0b100" ] \
&& [ $(baseconvert -x "07777" ) = "0xfff" ] \
&& [ $(baseconvert -x "0o7777" ) = "0xfff" ] \
&& [ $(baseconvert -x "0O7777" ) = "0xfff" ] \
&& [ $(baseconvert -o "0b1000" ) = "010" ] \
&& [ $(baseconvert -o "0B1000" ) = "010" ] \
&& echo "PASS" \
|| echo "FAIL"
echo "================================================================================"

View File

@ -1,5 +1,8 @@
// Copyright 2022, FOSS-VG Developers and Contributers // Copyright 2022, FOSS-VG Developers and Contributers
// //
// Author(s):
// BodgeMaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it // 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 // under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3. // by the Free Software Foundation, version 3.
@ -318,6 +321,10 @@ namespace CLI {
} }
} }
if (this->additionalInfo != "") {
usageString += "\nAdditional Info:\n\n\t" + this->additionalInfo + "\n";
}
return usageString; return usageString;
} }
} }

View File

@ -746,5 +746,19 @@ int main() {
ASSERT(noCLIParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator \n"); 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; std::cout << "Passed no CLI input usage test." << std::endl;
// additional info test ############################################
std::vector<CLI::Flag> additionalInfoCLIFlags;
std::vector<CLI::Option> additionalInfoCLIOptions;
std::vector<CLI::Argument> additionalInfoCLIArguments;
const char** additionalInfoCLICommand = new const char*[1];
additionalInfoCLICommand[0] = "universecreator";
CLI::ArgumentsParser additionalInfoCLIParser = CLI::ArgumentsParser(1, additionalInfoCLICommand, additionalInfoCLIFlags, additionalInfoCLIOptions, additionalInfoCLIArguments, "Create a universe with a banana and an apple.", "Rick Astley was here.");
ASSERT(additionalInfoCLIParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator \n\nAdditional Info:\n\n\tRick Astley was here.\n");
std::cout << "Passed additional info test." << std::endl;
return 0; return 0;
} }

View File

@ -37,6 +37,9 @@ int main(){
ASSERT(generic.serialize(&vector).errorCode == ErrorCodes::INVALID_TYPE); ASSERT(generic.serialize(&vector).errorCode == ErrorCodes::INVALID_TYPE);
ASSERT(generic.serializeWithoutHeader(&vector).isError); ASSERT(generic.serializeWithoutHeader(&vector).isError);
ASSERT(generic.serializeWithoutHeader(&vector).errorCode == ErrorCodes::INVALID_TYPE); ASSERT(generic.serializeWithoutHeader(&vector).errorCode == ErrorCodes::INVALID_TYPE);
// Normally, at this point, we would discard the vector as garbage.
// In this case, the assertions below exist to test the common
// serializer code.
ASSERT(vector.size() == 6); ASSERT(vector.size() == 6);
ASSERT( ASSERT(
vector.at(0) == 255 && vector.at(0) == 255 &&
@ -46,6 +49,8 @@ int main(){
vector.at(4) == 0 && vector.at(4) == 0 &&
vector.at(5) == 0 vector.at(5) == 0
); );
generic.name = tiny_utf8::string(std::string(0x10000, 'E'));
ASSERT(generic.serialize(&vector).isError && generic.serialize(&vector).errorCode == ErrorCodes::OVERRUN);
vector.clear(); vector.clear();
std::cout << "Passed Generic (super type) test." << std::endl; std::cout << "Passed Generic (super type) test." << std::endl;
@ -68,7 +73,6 @@ int main(){
ASSERT(!int8_0.serialize(&vector).isError); ASSERT(!int8_0.serialize(&vector).isError);
ASSERT(!int8_1.serialize(&vector).isError); ASSERT(!int8_1.serialize(&vector).isError);
ASSERT(vector.size() == 20); ASSERT(vector.size() == 20);
std::cout << (int) vector.at(9) << std::endl;
ASSERT( ASSERT(
vector.at( 0) == 1 && vector.at( 0) == 1 &&
vector.at( 1) == 0 && vector.at( 1) == 0 &&
@ -112,10 +116,225 @@ int main(){
vector.clear(); vector.clear();
std::cout << "Passed Int8 test." << std::endl; std::cout << "Passed Int8 test." << std::endl;
//NBT::Tag::Int16 int16_0 = NBT::Tag::Int16(); NBT::Tag::Int16 int16_0 = NBT::Tag::Int16();
//int16_0.name = "int16_0"; int16_0.name = "int16_0";
//int16_0.setValue(32767); int16_0.setValue(-32768);
//TODO: Check that we actually get overrun when trying to store a name that's too long NBT::Tag::Int16 int16_1 = NBT::Tag::Int16("int16_1", 32767);
ASSERT(int16_0.getValue() == -0x8000);
ASSERT(int16_1.getValue() == 0x7FFF);
ASSERT(int16_0.getTagType() == 2 && int16_1.getTagType() == 2);
ASSERT(!int16_0.serialize(&vector).isError);
ASSERT(!int16_1.serialize(&vector).isError);
ASSERT(vector.size() == 24);
ASSERT(
vector.at( 0) == 2 &&
vector.at( 1) == 0 &&
vector.at( 2) == 7 &&
vector.at( 3) == 'i' &&
vector.at( 4) == 'n' &&
vector.at( 5) == 't' &&
vector.at( 6) == '1' &&
vector.at( 7) == '6' &&
vector.at( 8) == '_' &&
vector.at( 9) == '0' &&
vector.at(10) == 0x80 &&
vector.at(11) == 0x00 &&
vector.at(12) == 2 &&
vector.at(13) == 0 &&
vector.at(14) == 7 &&
vector.at(15) == 'i' &&
vector.at(16) == 'n' &&
vector.at(17) == 't' &&
vector.at(18) == '1' &&
vector.at(19) == '6' &&
vector.at(20) == '_' &&
vector.at(21) == '1' &&
vector.at(22) == 0x7F &&
vector.at(23) == 0xFF
);
vector.clear();
int16_0.name = "";
ASSERT(!int16_0.serialize(&vector).isError);
ASSERT(vector.size() == 5);
ASSERT(
vector.at(0) == 2 &&
vector.at(1) == 0 &&
vector.at(2) == 0 &&
vector.at(3) == 0x80 &&
vector.at(4) == 0
);
vector.clear();
ASSERT(!int16_0.serializeWithoutHeader(&vector).isError);
ASSERT(!int16_1.serializeWithoutHeader(&vector).isError);
ASSERT(vector.size() == 4);
ASSERT(
vector.at(0) == 0x80 &&
vector.at(1) == 0 &&
vector.at(2) == 0x7F &&
vector.at(3) == 0xFF
);
vector.clear();
std::cout << "Passed Int16 test." << std::endl;
NBT::Tag::Int32 int32_0 = NBT::Tag::Int32();
int32_0.name = "int32_0";
int32_0.setValue(-2147483648);
NBT::Tag::Int32 int32_1 = NBT::Tag::Int32("int32_1", 2147483647);
ASSERT(int32_0.getValue() == (int32_t) -0x80000000);
ASSERT(int32_1.getValue() == 0x7FFFFFFF);
ASSERT(int32_0.getTagType() == 3 && int32_1.getTagType() == 3);
ASSERT(!int32_0.serialize(&vector).isError);
ASSERT(!int32_1.serialize(&vector).isError);
ASSERT(vector.size() == 28);
ASSERT(
vector.at( 0) == 3 &&
vector.at( 1) == 0 &&
vector.at( 2) == 7 &&
vector.at( 3) == 'i' &&
vector.at( 4) == 'n' &&
vector.at( 5) == 't' &&
vector.at( 6) == '3' &&
vector.at( 7) == '2' &&
vector.at( 8) == '_' &&
vector.at( 9) == '0' &&
vector.at(10) == 0x80 &&
vector.at(11) == 0x00 &&
vector.at(12) == 0x00 &&
vector.at(13) == 0x00 &&
vector.at(14) == 3 &&
vector.at(15) == 0 &&
vector.at(16) == 7 &&
vector.at(17) == 'i' &&
vector.at(18) == 'n' &&
vector.at(19) == 't' &&
vector.at(20) == '3' &&
vector.at(21) == '2' &&
vector.at(22) == '_' &&
vector.at(23) == '1' &&
vector.at(24) == 0x7F &&
vector.at(25) == 0xFF &&
vector.at(26) == 0xFF &&
vector.at(27) == 0xFF
);
vector.clear();
int32_0.name = "";
ASSERT(!int32_0.serialize(&vector).isError);
ASSERT(vector.size() == 7);
ASSERT(
vector.at(0) == 3 &&
vector.at(1) == 0 &&
vector.at(2) == 0 &&
vector.at(3) == 0x80 &&
vector.at(4) == 0 &&
vector.at(5) == 0 &&
vector.at(6) == 0
);
vector.clear();
ASSERT(!int32_0.serializeWithoutHeader(&vector).isError);
ASSERT(!int32_1.serializeWithoutHeader(&vector).isError);
ASSERT(vector.size() == 8);
ASSERT(
vector.at(0) == 0x80 &&
vector.at(1) == 0 &&
vector.at(2) == 0 &&
vector.at(3) == 0 &&
vector.at(4) == 0x7F &&
vector.at(5) == 0xFF &&
vector.at(6) == 0xFF &&
vector.at(7) == 0xFF
);
vector.clear();
std::cout << "Passed Int32 test." << std::endl;
NBT::Tag::Int64 int64_0 = NBT::Tag::Int64();
int64_0.name = "int64_0";
int64_0.setValue(-9223372036854775808);
NBT::Tag::Int64 int64_1 = NBT::Tag::Int64("int64_1", 9223372036854775807);
ASSERT(int64_0.getValue() == (int64_t) -0x8000000000000000);
ASSERT(int64_1.getValue() == 0x7FFFFFFFFFFFFFFF);
ASSERT(int64_0.getTagType() == 4 && int64_1.getTagType() == 4);
ASSERT(!int64_0.serialize(&vector).isError);
ASSERT(!int64_1.serialize(&vector).isError);
ASSERT(vector.size() == 36);
ASSERT(
vector.at( 0) == 4 &&
vector.at( 1) == 0 &&
vector.at( 2) == 7 &&
vector.at( 3) == 'i' &&
vector.at( 4) == 'n' &&
vector.at( 5) == 't' &&
vector.at( 6) == '6' &&
vector.at( 7) == '4' &&
vector.at( 8) == '_' &&
vector.at( 9) == '0' &&
vector.at(10) == 0x80 &&
vector.at(11) == 0x00 &&
vector.at(12) == 0x00 &&
vector.at(13) == 0x00 &&
vector.at(14) == 0x00 &&
vector.at(15) == 0x00 &&
vector.at(16) == 0x00 &&
vector.at(17) == 0x00 &&
vector.at(18) == 4 &&
vector.at(19) == 0 &&
vector.at(20) == 7 &&
vector.at(21) == 'i' &&
vector.at(22) == 'n' &&
vector.at(23) == 't' &&
vector.at(24) == '6' &&
vector.at(25) == '4' &&
vector.at(26) == '_' &&
vector.at(27) == '1' &&
vector.at(28) == 0x7F &&
vector.at(29) == 0xFF &&
vector.at(30) == 0xFF &&
vector.at(31) == 0xFF &&
vector.at(32) == 0xFF &&
vector.at(33) == 0xFF &&
vector.at(34) == 0xFF &&
vector.at(35) == 0xFF
);
vector.clear();
int64_0.name = "";
ASSERT(!int64_0.serialize(&vector).isError);
ASSERT(vector.size() == 11);
ASSERT(
vector.at( 0) == 4 &&
vector.at( 1) == 0 &&
vector.at( 2) == 0 &&
vector.at( 3) == 0x80 &&
vector.at( 4) == 0 &&
vector.at( 5) == 0 &&
vector.at( 6) == 0 &&
vector.at( 7) == 0 &&
vector.at( 8) == 0 &&
vector.at( 9) == 0 &&
vector.at(10) == 0
);
vector.clear();
ASSERT(!int64_0.serializeWithoutHeader(&vector).isError);
ASSERT(!int64_1.serializeWithoutHeader(&vector).isError);
ASSERT(vector.size() == 16);
ASSERT(
vector.at( 0) == 0x80 &&
vector.at( 1) == 0 &&
vector.at( 2) == 0 &&
vector.at( 3) == 0 &&
vector.at( 4) == 0 &&
vector.at( 5) == 0 &&
vector.at( 6) == 0 &&
vector.at( 7) == 0 &&
vector.at( 8) == 0x7F &&
vector.at( 9) == 0xFF &&
vector.at(10) == 0xFF &&
vector.at(11) == 0xFF &&
vector.at(12) == 0xFF &&
vector.at(13) == 0xFF &&
vector.at(14) == 0xFF &&
vector.at(15) == 0xFF
);
vector.clear();
std::cout << "Passed Int64 test." << std::endl;
return 0; return 0;
} }

View File

@ -41,7 +41,6 @@ int main(int argc, char* argv[]) {
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Dump files as C++ array literals"); CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Dump files as C++ array literals");
if (cliParser.getFlag("help").value) { if (cliParser.getFlag("help").value) {
std::cout << "I was here" << std::endl;
std::cout << cliParser.getUsage() << std::endl; std::cout << cliParser.getUsage() << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

130
src/tools/baseconvert.cpp Normal file
View File

@ -0,0 +1,130 @@
// 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 <bitset>
#include <cstdint>
#include <iostream>
#include <vector>
#include "../lib/cli.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
int main(int argc, char* argv[]) {
std::vector<CLI::Flag> flags;
flags.push_back(CLI::Flag('x', "hexadecimal", "base 16"));
flags.push_back(CLI::Flag('o', "octal", "base 8"));
flags.push_back(CLI::Flag('b', "binary", "base 2"));
flags.push_back(CLI::Flag('d', "decimal", "base 10"));
flags.push_back(CLI::Flag('h', "help", "print help and exit"));
flags.push_back(CLI::Flag('l', "license", "print license information and exit"));
std::vector<CLI::Option> options;
std::vector<CLI::Argument> arguments;
arguments.push_back(CLI::Argument("NUMBER", "the number to convert"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Convert numbers between predefined bases", "This only works for unsigned numbers.\n\tBaseConvert understands the prefixes 0x, 0b, 0o, and 0 in input numbers.");
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"
<< "BaseConvert 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) {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_USAGE;
}
std::string numberString = cliParser.getArgument(0).value;
uint8_t base = 10;
uint64_t* number = new uint64_t;
if (numberString == "") {
std::cerr << "Empty string is not a valid number." << std::endl;
return EXIT_RUNTIME;
}
if (numberString[0] == '0') {
if (numberString.substr(0, 2)=="0x" || numberString.substr(0, 2)=="0X") {
base = 16;
numberString = numberString.substr(2, numberString.length()-2);
} else if (numberString.substr(0, 2)=="0b" || numberString.substr(0, 2)=="0B") {
base = 2;
numberString = numberString.substr(2, numberString.length()-2);
} else if (numberString.substr(0, 2)=="0o" || numberString.substr(0, 2)=="0O") {
base = 8;
numberString = numberString.substr(2, numberString.length()-2);
} else {
base = 8;
}
}
*number = std::stoull(numberString, nullptr, base);
if (cliParser.getFlag("hexadecimal").value) {
std::cout << "0x" << std::hex << *number << std::endl;
} else if (cliParser.getFlag("octal").value) {
*number==0? std::cout << "0" << std::endl : std::cout << "0" << std::oct << *number << std::endl;
} else if (cliParser.getFlag("binary").value) {
std::bitset<64> bitset = std::bitset<64>(*number);
bool foundFirstBit = false;
std::cout << "0b";
for (uint8_t i=0; i<64; i++) {
if (bitset[63-i]) {
std::cout << "1";
foundFirstBit = true;
} else if (foundFirstBit) {
std::cout << "0";
}
}
if (!foundFirstBit) {
std::cout << "0";
}
std::cout << std::endl;
} else if (cliParser.getFlag("decimal").value) {
std::cout << *number << std::endl;
} else {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_USAGE;
}
delete number;
return EXIT_SUCCESS;
}