From b5312aeb58bea3f00b16778245f988c4bb9569b8 Mon Sep 17 00:00:00 2001 From: Milan Suman <> Date: Wed, 20 Jul 2022 12:08:04 +0530 Subject: [PATCH] lib/nbt: implement readString NBT helper function --- scripts/build.sh | 2 +- scripts/test.sh | 2 +- src/lib/error.h++ | 3 +++ src/lib/javacompat.cpp | 14 ++++++++--- src/lib/javacompat.h++ | 4 +-- src/lib/nbt.cpp | 18 +++++++++++--- src/lib/nbt.h++ | 3 ++- src/test/javacompat.cpp | 2 +- src/test/nbt_helpers.cpp | 53 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 87 insertions(+), 14 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 0b981ea..e593d67 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -72,7 +72,7 @@ echo "Building tools..." mkdir -pv bin/tools # add compile commands to this array COMPILE_COMMANDS=( - "$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -Lbin/lib -l:nbt.so -o bin/tools/dumpnbt" + "$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I dependencies/tiny-utf8-4.4.3/include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/tools/dumpnbt" "$CXX_WITH_FLAGS src/tools/hexnet.cpp -Lbin/lib -l:cli.so -l:libsockpp.so -Idependencies/sockpp-0.7.1/include -o bin/tools/hexnet" ) for command in ${!COMPILE_COMMANDS[@]}; do diff --git a/scripts/test.sh b/scripts/test.sh index cc3aeb8..4a1c78f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -37,7 +37,7 @@ echo "Building tests..." # add compile commands to this array COMPILE_COMMANDS=( - "$CXX_WITH_FLAGS src/test/nbt_helpers.cpp -Lbin/lib -l:nbt.so -o bin/test/nbt_helpers" + "$CXX_WITH_FLAGS src/test/nbt_helpers.cpp -Idependencies/tiny-utf8-4.4.3/include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_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/javacompat.cpp -Idependencies/tiny-utf8-4.4.3/include -Lbin/lib -l:javacompat.so -o bin/test/javacompat" ) diff --git a/src/lib/error.h++ b/src/lib/error.h++ index 6364eb1..49b9d5c 100644 --- a/src/lib/error.h++ +++ b/src/lib/error.h++ @@ -81,4 +81,7 @@ namespace ErrorCodes { const uint8_t UNIMPLEMENTED = 254; const uint8_t UNKNOWN = 255; + + //mismatched size in java strings + const uint8_t MISMATCHEDSIZE = 6; } diff --git a/src/lib/javacompat.cpp b/src/lib/javacompat.cpp index b60bc88..6cb6c29 100644 --- a/src/lib/javacompat.cpp +++ b/src/lib/javacompat.cpp @@ -32,9 +32,13 @@ namespace JavaCompat { //FIXME: contrary to what I said, we need to explicitly pass the data // size because files could have been tampered with or corrupted - tiny_utf8::string importJavaString(uint8_t data[]) { + ErrorOr importJavaString(uint8_t data[], uint16_t size) { std::string stdString; - uint16_t size = static_cast(data[0])<<8 | static_cast(data[1]); + uint16_t encodedSize = static_cast(data[0])<<8 | static_cast(data[1]); + + if(encodedSize != size){ + return ErrorOr(true, ErrorCodes::MISMATCHEDSIZE); + } for(uint8_t i=2; i(tiny_utf8::string(stdString)); } ErrorOr> exportJavaString(tiny_utf8::string data) { @@ -54,6 +58,10 @@ namespace JavaCompat { std::vector output = std::vector(); std::string stdString = data.cpp_str(); + if(stdString.size() > 0xFFFF){ + return ErrorOr>(true, ErrorCodes::OVERRUN); + } + *size = (uint16_t) stdString.size(); //placeholder size bytes diff --git a/src/lib/javacompat.h++ b/src/lib/javacompat.h++ index c9eba00..5e9c7c3 100644 --- a/src/lib/javacompat.h++ +++ b/src/lib/javacompat.h++ @@ -18,8 +18,6 @@ #include namespace JavaCompat { - //FIXME: contrary to what I said, we need to explicitly pass the data - // size because files could have been tampered with or corrupted - tiny_utf8::string importJavaString(uint8_t data[]); + ErrorOr importJavaString(uint8_t data[], uint16_t size); ErrorOr> exportJavaString(tiny_utf8::string data); } diff --git a/src/lib/nbt.cpp b/src/lib/nbt.cpp index 0db2f97..1c76e2d 100644 --- a/src/lib/nbt.cpp +++ b/src/lib/nbt.cpp @@ -16,9 +16,12 @@ #include #include #include +#include #include "nbt.h++" #include "error.h++" +#include "javacompat.h++" + #include "../../.endianness" #ifdef FOSSVG_ENDIAN_BIG_WORD @@ -148,10 +151,17 @@ namespace NBT { // Maybe use a struct that holds decoded (de-Java-fied) string // data, decoded size, and original size? Original size is needed // so the parser knows where to continue. - //ErrorOr<> readString(uint8_t data[], uint64_t dataSize, uint64_t currentPosition) { - //TODO: implement - // return ErrorOr<>(""); - //} + ErrorOr readString(uint8_t data[], uint64_t dataSize, uint64_t currentPosition) { + if(dataSize > 0xFFFF){ + return ErrorOr(true, ErrorCodes::OVERRUN); + } + + ErrorOr output = JavaCompat::importJavaString(data+currentPosition, (uint16_t) dataSize); + if(output.isError){ + return ErrorOr(true, output.errorCode); + } + return output; + } ErrorOr> readInt32Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition) { // get size prefix diff --git a/src/lib/nbt.h++ b/src/lib/nbt.h++ index 6205f6d..58b9171 100644 --- a/src/lib/nbt.h++ +++ b/src/lib/nbt.h++ @@ -38,6 +38,7 @@ #include #include #include "error.h++" +#include namespace NBT { namespace helper { @@ -52,7 +53,7 @@ namespace NBT { // floating point number ErrorOr readFloat64(uint8_t data[], uint64_t dataSize, uint64_t currentPosition); ErrorOr> readInt8Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition); - //ErrorOr<> readString(uint8_t data[], uint64_t dataSize, uint64_t currentPosition); + ErrorOr readString(uint8_t data[], uint64_t dataSize, uint64_t currentPosition); ErrorOr> readInt32Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition); ErrorOr> readInt64Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition); diff --git a/src/test/javacompat.cpp b/src/test/javacompat.cpp index 49b1154..bce53cb 100644 --- a/src/test/javacompat.cpp +++ b/src/test/javacompat.cpp @@ -52,7 +52,7 @@ int main(){ return 2; } - tiny_utf8::string importedString = JavaCompat::importJavaString(reinterpret_cast(javaStdString.data())); + tiny_utf8::string importedString = JavaCompat::importJavaString(reinterpret_cast(javaStdString.data()), 0x75).value; std::streampos normalSize; std::string normalStdString; diff --git a/src/test/nbt_helpers.cpp b/src/test/nbt_helpers.cpp index b9733af..73885a2 100644 --- a/src/test/nbt_helpers.cpp +++ b/src/test/nbt_helpers.cpp @@ -16,11 +16,13 @@ #include #include #include +#include #include "assert.h++" #include "../lib/nbt.h++" #include "../lib/error.h++" +#include "../lib/javacompat.h++" int main(){ std::cout << "################################################################################" << std::endl; @@ -442,5 +444,56 @@ int main(){ std::cout << "Passed writeInt64 NBT helper test" << std::endl; + //readString test + char* nextChar = new char; + + //reading data from the java modified utf8 file + std::streampos javaSize; + std::string javaStdString; + const char* javaFilePath = "./resources/unicode_data/java-style_unicode"; + std::ifstream javaFile(javaFilePath, std::ios::in | std::ios::binary | std::ios::ate); + if(javaFile.is_open()){ + javaSize = javaFile.tellg(); + javaFile.seekg(0, std::ios::beg); + + for (int i=0; i(javaStdString.data()), 0x75, 0).value) + ASSERT(NBT::helper::readString(reinterpret_cast(javaStdString.data()), 0xFFFFF, 0).errorCode == ErrorCodes::OVERRUN); + ASSERT(NBT::helper::readString(reinterpret_cast(javaStdString.data()), 0xF, 0).errorCode == ErrorCodes::MISMATCHEDSIZE); + std::cout << "Passed readString NBT helper test." << std::endl; + return 0; }