Compare commits

..

183 Commits

Author SHA1 Message Date
BodgeMaster 53173dd7c7 lib/zlibutil, tools/zlibutil: moving things around
This includes the following changes:
- Move the data type wrangling into the lib to make it easier to use
- Put the functions into their own `zlib` namespace
- Use ErrorOr instead of exceptions
- Error codes for compression/decompression
2024-06-10 06:29:30 +02:00
BodgeMaster 8482194b01 build system: update build commands for libs
I forgot this after changing the build system when resolving merge conflicts.
2024-06-08 23:59:55 +02:00
BodgeMaster 229392a7fe test/zlibutil: update to match changes in zlibutil, increase reliability
The following changes have been made:
- The test has been adjusted to zlibutil's changed behavior.
- The output of zlibutil isn’t checked against static data, instead it hands
  the compressed file to another decompressor. This was done because the exact
  output can change with updates to zlib itself (this appears to have happened
  in my case).
- The new test works with random data, reducing the likelihood of false passes.
- The new decompression test works with its own file for the same reason.
2024-06-08 15:59:03 +02:00
BodgeMaster a48c4dcd33 tools/zlibutil: Change CLI to act more like other compression utilities
Compression is now the implied default action, decompress with the -d flag.
2024-06-08 15:10:38 +02:00
BodgeMaster a787a89493 resources/region_files: add a zlib compressed chunk 2024-06-08 15:09:14 +02:00
BodgeMaster b9006cc6ea Build system: start moving the download handler to its own file 2024-06-08 15:09:14 +02:00
BodgeMaster eb8db35615 scripts/lib: Fix a bug in the `remove` function 2024-06-08 15:09:14 +02:00
BodgeMaster 9dd4489141 test/hexnet: remove useless (unimplemented) test 2024-06-08 15:08:37 +02:00
BodgeMaster d1c855857c Code style guidelines and resources/README: Minor documentation changes 2024-06-08 15:07:26 +02:00
BodgeMaster 8f8d51f459 lib/net/*: Move stuff around
I did this months ago with the intention to finally start implementing networking....
Yeah, that definitely panned out.

Also, Git is drunk with how it says files have been renamed, they’re just empty apart from the license notice.
2024-06-08 15:07:26 +02:00
BodgeMaster 8b13f72acc tools: Add zlibutil
Third time's the charm...
Editing this commit again to resolve merge conflicts.
- Bodge

Splitting one of Joca’s commits by topic - Bodge

Add zlibutil.cpp and zlib to the project's dependencies. - Joca
2024-06-08 15:06:50 +02:00
Joca 6ef1d401bb lib: Add zlibutil library and test script 2024-05-12 17:24:58 -03:00
Joca 1bcc5eae64 tools: Add ZLIBUTIL
Add zlibutil.cpp and zlib to the project's dependencies.
2024-03-12 22:37:09 -03:00
BodgeMaster 97b844c6d1 build system: add support for building shaders to SPIRV binaries
This adds the following to the project:
- glslc from Google’s shaderc
- src/shaders directory
- shaders are now built as part of the `build` command
- forcefully remove some files during the setup process and when cleaning
2024-01-07 20:07:33 +01:00
BodgeMaster 20857cb8c5 build system (setup_project): Comment out seemingly useless workarounds 2023-06-18 07:53:35 +02:00
BodgeMaster abc5491192 Update sockpp to version 0.8.1
This supposedly fixes a bunch of things, we’ll see...
2023-06-18 07:01:10 +02:00
BodgeMaster ad54f0a012 test/dumpnbt: Move expected output out of the script, also add another test
What was I thinking!?
2023-06-18 03:37:19 +02:00
BodgeMaster ae71322ba1 lib/nbt: Fix #80 2023-06-18 03:17:20 +02:00
BodgeMaster 01e5f5eaac lib/region: Start working on region file parser
Something is fishy with dumpnbt or lib/nbt.
Attempting to dump the extracted chunk fails, but external tools
do manage to parse it.
2023-05-29 14:47:19 +02:00
BodgeMaster 6112da2e6f lib/game: Start working on game internals
Btw: I lost the game.
2023-01-27 03:32:43 +01:00
BodgeMaster b07d6e2ff6 fossvg (client): Clean up GLFW-related code
- add some Vulkan-specific things to deal with GLFW
- get rid of useless warnings
- allow to set window size from the command line

The Window size is fixed for now because that will hopefully make
things easier in the strt. I intend to have a resizable window
in the future but getting things going is more important.
2023-01-27 01:20:29 +01:00
BodgeMaster 4247bd295a fossvg (client): Commit to using Vulkan
I have decided that we are going to use Vulkan for this. Hopefully, it works out.
This commit removes some OpenGL-specific things and adds Vulkan to the build command line.
2023-01-27 01:20:29 +01:00
BodgeMaster 4c651d1b6f Merge branch 'master' into cygwin 2023-01-09 21:54:23 +01:00
BodgeMaster e152c72a04 fossvg (client): Create window 2023-01-09 20:43:49 +01:00
BodgeMaster 5d80ca801e scripts/clean: Recreate lib/net 2023-01-09 20:38:13 +01:00
BodgeMaster c245e8a5ca lib/{file,javacompat,net/conversion/position,net/conversion/varint,net/packet}: pragma once 2022-12-30 15:38:33 +01:00
BodgeMaster 10d8cdae22 lib/net/{client,server,packet}: Prepare for networking 2022-12-29 03:31:56 +01:00
BodgeMaster b08a86f0b8 resources: Add network capture of a server list ping 2022-12-29 03:28:18 +01:00
BodgeMaster c6ec0f6850 lib/net/conversion/position: Remove misattributed author
Yeah, I just copied the header from somewhere else...
2022-12-27 17:34:16 +01:00
BodgeMaster 85fc73e015 lib/net/conversion/position.hpp: Add library
Unit tests tbd
2022-12-27 17:28:11 +01:00
BodgeMaster d2861b79ac lib/net/conversion/varint: move lib/varint here 2022-12-27 16:24:59 +01:00
BodgeMaster 9403da4ca0 lib/varint: Fix error handling for out of bounds access 2022-12-27 15:44:05 +01:00
BodgeMaster ad5bf1c41a lib/cli: Remove completely useless TODO 2022-12-20 17:06:22 +01:00
BodgeMaster 7108e71b96 lib/varint: Add toVarN() functions 2022-12-20 04:41:09 +01:00
Shwoomple 26df433dc5 lib/file: Implement cutString function 2022-12-04 09:59:28 +05:30
BodgeMaster 44716a55bb lib/varint: Fix fromVar64 function
The problem was that I let the compiler assume data type widths.
`1 << 63` is a 32 bit integer on x86_64-pc-linux-gnu.
2022-11-26 14:50:02 +01:00
BodgeMaster fe7c763d06 lib/varint: Add VarInt library
Minecraft uses 32-bit and 64-bit VarInt types to cut down on network usage.
This library currently contains read functions for conversion to normal integers.

Something seems to be wrong with the converter for 64-bit varints,
can’t figure out what rn.
2022-11-25 22:19:49 +01:00
BodgeMaster d392e080ca test/nbt_tags: Add tests for constructing invalid lists/compounds 2022-11-25 17:07:35 +01:00
BodgeMaster 60a8ac9788 lib/nbt: Make constructor NBT::Tag::Compound::Compound(name, data) private
The constructor has been made private and replaced with a static wrapper
function to make constructing from invalid data impossible.

If there is more than one end tag or an end tag isn’t at the end,
an error will be returned.
2022-11-25 15:52:24 +01:00
Shwoomple bc2255de6b lib/file: Fix issue #71 - Electric Boogaloo (Out of bounds access)
Add size constraint to make sure string terminates at the correct
length. Cygwin appears to not put null bytes to terminate string when
reading from a file stream.
2022-11-12 11:51:43 +05:30
Shwoomple e627714b44 lib/file: Implement cut function. 2022-11-12 06:36:04 +01:00
Shwoomple 42b7e40f9d lib/file:Fix issue #71 (Out of Bounds access) 2022-11-12 06:36:04 +01:00
Shwoomple 9bda607649 lib/file: Implement cut function. 2022-11-12 10:59:08 +05:30
Shwoomple 76dd30c45a lib/file:Fix issue #71 (Out of Bounds access) 2022-11-12 10:58:27 +05:30
BodgeMaster 78880e1c20 setupenv: Fix spelling
Yeah, really important commit, I know.
2022-10-31 17:56:11 +01:00
BodgeMaster 1d899db889 scripts/clean: Add a link with the original file name of cygsockpp-0.dll
Otherwise, the dynamic linker complains that it can’t find the file.
2022-10-31 17:56:11 +01:00
BodgeMaster 3cc91ae33d Build system: Get sockpp to build on Cygwin
This is probably not the last time this issue needs attention
as it *builds* on Cygwin with these workarounds, but it doesn’t *work*
on Cygwin...
2022-10-31 17:56:11 +01:00
Shwoomple 63e1749ad1 lib/file: fix cutByte filesize bug 2022-10-31 17:23:02 +01:00
Shwoomple ea8e806366 lib/file.cpp: Implement cutByte function 2022-10-31 17:23:02 +01:00
BodgeMaster 18a9517370 Build system: Start working on Cygwin support 2022-10-30 19:39:46 +01:00
BodgeMaster cd93f4c4c6 gitignore: Ignore endianness check on Cygwin 2022-10-30 17:19:55 +01:00
Shwoomple f784948c3e lib/file: fix cutByte filesize bug 2022-10-30 16:10:33 +00:00
Shwoomple d794bce288 lib/file.cpp: Implement cutByte function 2022-10-30 16:10:33 +00:00
BodgeMaster 99c8f562d6 setupenv: Fix wrong path 2022-10-30 06:10:04 +01:00
BodgeMaster 57a86cba47 setupenv: Add workaround for LD_LIBRARY_PATH on Cygwin 2022-10-30 05:56:34 +01:00
BodgeMaster 5ff8a871ad lib/javacompat: Make this a header library
Cygwin build issues were caused by lib/nbt impleicitly linking against this
2022-10-30 04:55:58 +01:00
BodgeMaster e0994e5db8 resources/java/netty-tests: Add maven project
This is going to be used for figuring out how Netty operates
and whether we should just make our own version or port the
existing Netty to C++ and use it as a dependency or whether
we even need it at all.
2022-10-30 03:17:25 +01:00
BodgeMaster 80c8a46ab2 Documentation and resources: Updates and minor clean-up 2022-10-30 02:53:56 +02:00
BodgeMaster 4abb1f223c lib/nbt: Lists can no longer be constructed from invalid sets of data
The constructor `NBT::Tag::List::List(tiny_utf8::string, std::vector<NBT::Tag::Generic*>)`
is now private and has a wrapper function `NBT::Tag::List::constructWithData(tiny_utf8::string, std::vector<NBT::Tag::Generic*>)`
that performs a sanity check on the data it is given.
2022-10-28 04:08:06 +02:00
BodgeMaster 4da50d3c6b test/dumpnbt: Add unit test (fixing #63) 2022-10-28 02:45:52 +02:00
BodgeMaster c9b56d4d7f tools/dumpnbt: Remove unused CLI flag 2022-10-28 02:45:25 +02:00
BodgeMaster 7bccaca7b9 fossvg and fossvgd: Add stub programs for client and server 2022-10-28 01:53:20 +02:00
BodgeMaster f6b965040d tools/hexnet: Compile with POSIX threads
Because apparently that’s not the default on NetBSD for some reason.
2022-10-23 03:06:48 +02:00
BodgeMaster b5c18cd0de tools/hexnet: Implement bi-directional communication 2022-10-23 01:48:47 +02:00
BodgeMaster a1ba08b7db tools/hexnet: Shut down connections when gracefully handling signals 2022-10-23 01:47:44 +02:00
BodgeMaster 1d7e98d0b3 tools/hexnet: Implement function for reading bytes from stdin 2022-10-23 01:45:59 +02:00
BodgeMaster a7e07d2c3c tools/hexnet: Implement UDP support (and minor refactoring) 2022-10-22 18:51:29 +02:00
BodgeMaster 7ae843039c tools/hexnet: Implement TCP v6 handler, rename readFromTCPSocket to readFromTCP 2022-10-22 01:18:44 +02:00
BodgeMaster 5574cdb4bf tools/hexnet: Don’t confuse users 2022-10-22 01:02:00 +02:00
BodgeMaster 89cfb9d850 tools/hexnet: Reduce redundant code 2022-10-21 23:01:03 +02:00
BodgeMaster f681c54c82 tools/hexnet: Reimplement TCP server, implement TCP client
Both can only receive at the moment as we still don’t handle input.
2022-10-21 23:01:03 +02:00
BodgeMaster ee0ebb273c tools/hexnet: Add instructions for setting up TTY 2022-10-21 23:01:03 +02:00
Shwoomple 8dea1f2d31 lib/file: Implement modify functions 2022-10-20 15:12:15 +05:30
Shwoomple c825c73afd lib/file: Implement insertByte function 2022-10-20 13:02:15 +05:30
Shwoomple e7711a3d59 commit merge 2022-10-20 10:27:48 +05:30
Shwoomple e7ce6f5cd4 lib/file: Fix write function bugs 2022-10-20 10:27:00 +05:30
BodgeMaster ee9b5d4f67 tools/hexnet: Add command line parser back
Reimplementation has started.
2022-10-19 15:26:38 +02:00
BodgeMaster b84130344d tools/hexnet: Starting over 2022-10-19 15:26:38 +02:00
BodgeMaster 25d7806f6d lib/nbt: Fix memory leak in case of parsing error 2022-10-19 15:26:38 +02:00
Shwoomple 6e57a86338 lib/file: Implement write functions 2022-10-19 10:43:23 +05:30
Shwoomple c54eb48887 lib/file: Implement writeByte function 2022-10-18 20:57:02 +05:30
BodgeMaster c14504ce0b tools/dumpnbt: Display empty lists correctly 2022-10-17 07:02:36 +02:00
BodgeMaster 92cf81c1b4 tools/dumpnbt: Implement basic functionality.
FINALLY!!! :^)
2022-10-17 06:40:56 +02:00
BodgeMaster df35243ee9 lib/nbt: Add NBT::Tag::List::getContainedType()
Supid oversight, easily work-aroundable,
but it doesn’t hurt and was easy to implement
2022-10-17 06:39:42 +02:00
BodgeMaster 36dcf0a0f5 resources/dumpnbt_output_format: Give end tags header and payload information 2022-10-17 06:37:16 +02:00
BodgeMaster 93fdcb7b65 resources: Add a file with examples for possible dumpnbt output
This may be useful for future unit tests.
I did this because I had no fucking idea how to implement drawing
the tree. I still have no fucking idea.

I hope there are no errors in there. If there are any, we’ll
find out when writing the relevant unit tests.
2022-10-16 07:40:55 +02:00
BodgeMaster 8d2f3f2fa5 tools/dumpnbt: Switch from using the validator to using the parser, update some strings 2022-10-16 07:40:00 +02:00
BodgeMaster cdc23e7468 lib/nbt: Implement parser 2022-10-15 23:05:26 +02:00
BodgeMaster e9bfb6eeee resources/NBT_data: Add two files that are valid NBT by our extended spec
Since we allow loose tags to be valid NBT data, this is valid NBT by our spec.
This isn’t valid by Mojang’s spec.
2022-10-15 21:41:32 +02:00
BodgeMaster 8b62ec9c88 lib/nbt: Get rid of that ugly #define return hack
Instead of doing #define return, the boolean returnValue is set and
a goto statement is used to get to the code that does what the macro
used to do.
2022-10-15 18:55:58 +02:00
BodgeMaster ca0af3306f test/nbt_tags: Implement Int64Array test
My arm hurts.
My back huts.
Man, that was exhausting.
Finally done.
2022-10-14 22:58:59 +02:00
BodgeMaster 9b21dfaee5 test/nbt_tags: Implement Int32Array test 2022-10-14 22:33:57 +02:00
BodgeMaster 996154fbbc lib/nbt: Return the correct error code from soem functions for i32 arrays. 2022-10-14 22:33:32 +02:00
BodgeMaster 77dd79398f test/nbt_tags: Test compound serialization 2022-10-14 21:46:55 +02:00
BodgeMaster fd5fe3967f test/nbt_tags: Partially implement compound test 2022-10-14 20:33:43 +02:00
BodgeMaster 374466f26c lib/nbt: Fix not actually returning from Compound::setElementPointerAt in the do nothing case 2022-10-14 20:01:47 +02:00
BodgeMaster 3b56a52085 lib/nbt: Fix a memory leak 2022-10-14 19:22:05 +02:00
BodgeMaster 7be73f86d4 lib/nbt: Prevent addition of additional end tags to compounds 2022-10-14 18:33:05 +02:00
BodgeMaster 71834e1018 lib/nbt: Build an end tag object into compound tag objects to prevent creation of endless compounds 2022-10-14 18:08:49 +02:00
BodgeMaster ccce564219 lib/error: Add NOT_ALLOWED 2022-10-14 17:39:00 +02:00
BodgeMaster 53279c6905 lib/error: Clean up comments 2022-10-14 17:30:35 +02:00
BodgeMaster f8dd10d301 test/nbt_tags: Finish test implementation for NBT::Tag::List 2022-10-13 11:34:57 +02:00
BodgeMaster 6672a4f149 test/nbt_tags: Implement string test and partial list test 2022-10-09 10:29:28 +02:00
BodgeMaster d5ce50a4a9 lib/nbt: Fix a potential memory leak 2022-10-09 10:18:20 +02:00
BodgeMaster f0092b78d3 lib/nbt: Make list serielizer return an error when serializing a list with no contained type set 2022-10-08 23:35:21 +02:00
BodgeMaster b1ba33b39f test/nbt_tags: Implement unit tests for Float, Double, and Int8Array 2022-10-08 12:56:13 +02:00
BodgeMaster 833c09e2da lib/nbt: Fix a bug caused by having two return statements swapped 2022-10-08 12:54:05 +02:00
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
BodgeMaster be08a97275 tesst/nbt_tags: Choose a more sensible value for int8_0 2022-10-06 20:46:50 +02:00
BodgeMaster 6bdf99c897 test/nbt_tags: Implement tests for the first three tag types 2022-10-06 11:10:51 +02:00
BodgeMaster 936def1a65 lib/nbt: move a comment (yes, very important commit) 2022-10-06 11:09:58 +02:00
BodgeMaster 3cc1222de9 lib/nbt: Fix a bug in NBT::Helper::writeString()
Writing a string to a byte vector would result in it being replaced
with one holding only the string.
2022-10-06 10:21:59 +02:00
BodgeMaster ecf3b14b5a test/nbt_tags: I have no clue what’s going on here.
Committing so I can debug at my PC.
2022-10-06 09:59:48 +02:00
BodgeMaster 8da758becd scripts/test/arraydump: Add test 2022-10-05 06:26:41 +02:00
BodgeMaster 1e5051b503 setupenv: Remove check for xxd
`xxd` is no longer needed as arraydump has been rewritten in C++
2022-10-05 05:31:37 +02:00
BodgeMaster 3b4c125ca2 tools/arraydump: Reimplement in C++ 2022-10-05 05:26:04 +02:00
BodgeMaster 4cb1206839 lib/file: Fix isOpen not being set properly when closing and reopening; add destructor 2022-10-05 05:02:58 +02:00
BodgeMaster 39c5940200 lib/file: Fix a potential memory leak created by yours truly 2022-10-05 04:50:41 +02:00
BodgeMaster f3e03710f6 lib/file: Ensure a file is actually open before attempting to read 2022-10-05 04:07:46 +02:00
BodgeMaster 72fc923839 lib/nbt: remove now useless comment 2022-10-05 04:02:32 +02:00
BodgeMaster 5059bd0193 lib/file: change File::eof to a function
This is just way easier to implement and less messy.
2022-10-05 04:01:18 +02:00
BodgeMaster 8bb633f118 lib/error and lib/file: reassign code 9 to FILE_NOT_OPEN
These are not exceptions so we don’t need multiple variants of
generic error in case someone wants to catch it somewhere
up the call stack.

It’s okay to use UNKNOWN for generic errors where we don’t know
exactly what happened.
2022-10-05 03:48:05 +02:00
BodgeMaster ec44ac9531 lib/file: Check if there are enough bytes left to read 2022-10-05 03:46:42 +02:00
BodgeMaster 341b4c187e lib/file: Fix (potential) memory leaks 2022-10-05 03:30:01 +02:00
BodgeMaster 79650e390e lib/nbt: Implement the rest of the functions outline in the header
This concludes the implementation of the in-memory NBT representation.
This is still all untested code so it might just blow up in your face.
The next step will be writing tests (and probably a lot of cursing and
debugging)...
2022-10-05 01:12:38 +02:00
BodgeMaster 2d2b67373c lib/nbt: Yesterday’s progress of implementing more of the functions in the header 2022-10-04 02:39:58 +02:00
BodgeMaster 4c4366f7e6 lib/nbt: Partially update documentation to current terminology.
Would probably be better if it were moved to doc/ and completely rewritten.
2022-10-02 07:48:03 +02:00
BodgeMaster 4ef1d2c44f lib/nbt: Split serializer into two components
One for serializing full tags and one for serializing tags without
their header.

The former is what used to be `toRawData` - though a bunch of
duplicated code has been removed by just moving it to the Generic
type class instead of having an implementation on the sub-classes.

The latter is useful for serializing lists.

The previous warning that all of this is untested still applies.
2022-10-02 07:47:12 +02:00
Shwoomple 5920d1d004 commit merge 2022-10-02 08:42:33 +05:30
Shwoomple 056c1e6b11 lib/file.cpp: fix read fubctions. 2022-10-02 08:38:39 +05:30
BodgeMaster 8b1491c311 lib/nbt: Add missing class prefix to function names 2022-10-01 04:57:45 +02:00
BodgeMaster fc2caf3bc0 lib/nbt: Implement more member functions for tag types 2022-10-01 04:51:53 +02:00
BodgeMaster 89baeebc65 lib/file: Switch to using pointers for passing File objects around 2022-09-30 20:10:28 +02:00
Shwoomple c204aa7d76 lib/file.cpp:Fix exception warnings 2022-09-30 22:41:55 +05:30
BodgeMaster 09503d3dc7 lib/file: Remove accidentally included C header 2022-09-30 18:31:49 +02:00
BodgeMaster 9fb06c998e scripts/build: Temporarily comment out hexnet 2022-09-30 18:31:20 +02:00
BodgeMaster aa97154474 lib/error: Remove misplaced code fragment
brea
2022-09-30 18:09:23 +02:00
BodgeMaster 9abfd9e5a9 setupenv: Move sourcing the local environment before FOSS-VG environment adjustments 2022-09-30 17:55:17 +02:00
Shwoomple 150ce826ba complete merge 2022-09-30 11:03:05 +05:30
Shwoomple 3449e3b9c4 lib/file: Implement broken file functions 2022-09-30 11:02:46 +05:30
Charlie Root 213d28a9b8 setupenv: Fix syntax errors 2022-09-30 06:13:38 +02:00
Shwoomple c1d7801436 complete merge 2022-09-28 08:22:09 +05:30
Shwoomple 9610f4a4a2 lib/file: implement open function 2022-09-28 08:21:39 +05:30
BodgeMaster 434c976cc5 lib/nbt: Continue implementing in-memory NBT tag data types
This is still all unvalidated work.
For all I know it might cause your computer to burst into flames,
grow an arm and a leg and an eye, and attack you with a sword.
But probably, it will just not work and I will realize that sleepy
past me was a fucking idiot (as always).
2022-09-28 03:43:54 +02:00
BodgeMaster 47fd1f8970 test/nbt_read_write_helpers: Change unnecessarily long string to be just one above the allowed size 2022-09-26 23:53:53 +02:00
BodgeMaster 10b1d9fa0c lib/nbt: Start implementing NBT data types, make NBT::Helper::writeString() return an error instead of aborting the program
The former is finally some progress on getting NBT going,
though at this point it is all unvalidated work.
For all I know it might cause your computer to burst into flames,
grow an arm and a leg and an eye, and attack you with a sword.
But probably, it won’t do that and instead start working after I
have debugged it so much that I wish I could attack my PC with a sword.

The latter is the implementation of a change I prepared in a previous commit
when i added ErrorOrVoid.
2022-09-26 03:11:44 +02:00
Shwoomple e8d41efeef lib/error.hpp: fix merge conflicts 2022-09-19 16:21:25 +05:30
Shwoomple 508b5e67e7 lib/error.hpp: add file errors 2022-09-19 16:19:52 +05:30
BodgeMaster 398321e415 test/nbt*: Replace NBT::helper with NBT::Helper
Yes, I forgot to run the test suite before committing.
This is why we need CI.
2022-09-19 11:47:29 +02:00
BodgeMaster 53878c3e2b lib/nbt: Start implementing the in-memory data structure for NBT 2022-09-15 06:06:47 +02:00
BodgeMaster ad291ee77d lib/nbt: Capitalize NBT::Helper because I feel like it 2022-09-15 02:00:07 +02:00
BodgeMaster 6149418f52 Add a level.dat to test the NBT parser on. 2022-09-15 01:51:51 +02:00
BodgeMaster ac12bcf865 Makefile: Finally get rid of this as we don't need it.
A makefile may be added back when we are preparing distribution but
it’s a long road until then.
2022-09-15 01:06:59 +02:00
BodgeMaster 8b92d24ab9 setupenv: Add dependency check 2022-09-11 10:11:17 +02:00
BodgeMaster aab91a2523 lib/nbt: Fix NBT::validateRawNBTData() and NBT::validateRawListContents closing #52 and #53 2022-09-11 09:14:32 +02:00
BodgeMaster 58b1199e38 lib/javacompat: Fixed JavaCompat::importJavaString() hanging when trying to import long strings
This was caused by an integer overflow due to using a too small data type in a counter variable.
2022-09-11 09:08:08 +02:00
Shwoomple 48f8a7dcf2 tools/hexnet: start implementing console input 2022-08-30 00:52:06 +05:30
BodgeMaster 209d0828b4 tools/hexnet: un-comment problematic sections 2022-08-29 21:06:54 +02:00
BodgeMaster b4d4ce77b2 tools/dumpnbt: better variable name and exit when data is invalid 2022-08-29 21:02:36 +02:00
BodgeMaster ee5048331c tools/dumpnbt: start implementing a preliminary version
for use until the full NBT library is in place...
2022-08-28 13:59:31 +02:00
BodgeMaster 629c999336 lib/nbt: Return correct error code from read functions (fixes #17) 2022-08-27 22:35:10 +02:00
BodgeMaster cdd17045d1 test/nbt_read_write_helpers: add more tests according to issue #43 2022-08-27 20:10:29 +02:00
BodgeMaster bb40f6553e tools/hexnet: comment sections out temporarily to get rid of compile errors
Doesn’t compile on Void x86_32 glibc. This will need to be investigated.
I just wanted to get rid of the errors while working on other issues.

Compile command:
ccache g++ -std=c++20 -Wall -Wextra src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet
2022-08-27 11:50:36 +02:00
BodgeMaster a9759e3bc2 lib/file: Clarify what the functions do, take cursor position into account for cut functions and add missing cut function 2022-08-24 01:38:44 +02:00
BodgeMaster ab1164557d lib/file: Write header
I hope I didn’t forget anything. Not exactly capable of thinking rn.
2022-08-24 01:27:34 +02:00
BodgeMaster 1b8819ffe5 lib/error: Add ErrorOrVoid
This allows for error propagation on functions that would otherwise
not return anything.
2022-08-24 01:21:38 +02:00
BodgeMaster 4934a78aaa lib/error: Move definitions of constructors of ErrorOr<> inside class definition. 2022-08-24 01:19:59 +02:00
BodgeMaster 327ad9a9b5 Copyright Notice: Add authors section 2022-08-23 23:24:29 +02:00
BodgeMaster bddab2e9f8 setupenv: Add tool directories to PATH, be more verbose
No more `bin/tools/hexnet -4t 9000`. Just `hexnet -4t 9000` now.
2022-08-16 13:55:42 +02:00
BodgeMaster 017c8a61f8 scripts/tools/arraydump: New tool added
Never again will you need to manually convert binary data into an array!
This tool does it for you! Get it now for only $99! Limited availability!

To process data from stdin / a pipe, just pass `-` as the file name.
2022-08-16 13:40:50 +02:00
BodgeMaster 5272636cb8 test/nbt_read_write_helpers: fix unit tests for readString() 2022-08-15 13:30:53 +02:00
BodgeMaster 91d16ea451 test/javacompat: add test for mismatched size 2022-08-15 12:24:03 +02:00
BodgeMaster a1fc0ce4b4 lib/nbt: Fix a possible buffer overflow in readString() 2022-08-15 12:02:58 +02:00
Shwoomple ca7b121c4d tools/hexnet: Implement udp partially. 2022-08-15 15:07:33 +05:30
BodgeMaster 25bec4c587 lib/nbt: Validator: Fix bytes not being added up correctly in multiple places 2022-08-15 10:51:50 +02:00
BodgeMaster 589cf1ddaf lib/nbt: NBT validator: Fix wrong function declaration in the header, fix not using the currentPosition variable when accessing data 2022-08-15 09:53:06 +02:00
BodgeMaster 884a5239c6 lib/nbt: fix a bug in NBT::helper::readString() which caused it to asuume that dataSize is the size of the string 2022-08-15 09:51:46 +02:00
BodgeMaster 9190cad80d lib/nbt: finish implementation of validateRawNBTData() and fix a critical macro-induced bug
I did a `#define return` and then tried to `if () return;` everywhere...
2022-08-15 08:50:07 +02:00
BodgeMaster a862590370 lib/nbt: Start implementing the NBT validator
In theory, this is it. It’s just missing the portion that deals with lists
and unit tests. Both will each likely require similar effort to this.
2022-08-15 05:20:05 +02:00
BodgeMaster 3995e97f03 lib/javacompat: Make the endianness error message refer to the correct function 2022-08-15 02:07:00 +02:00
86 changed files with 15376 additions and 764 deletions

8
.gitignore vendored
View File

@ -14,12 +14,20 @@
# ignore endianness check
/.endianness
/resources/check_endianness
/resources/check_endianness.exe
# Java bytecode
*.class
# Maven's build files
/resources/java/netty-tests/target/
# ignore nano's temp files
*.swp
# Ignore sublime text project files.
*.sublime-*
#vscode
.vscode
writeTest

View File

@ -1,12 +0,0 @@
all: build
build:
bash ./scripts/build.sh
clean:
bash ./scripts/clean.sh
mrproper:
bash ./scripts/clean.sh
bash ./scripts/clean_dependencies.sh
setup:
bash ./scripts/setup_project.sh
test:
bash ./scripts/test.sh

View File

@ -14,8 +14,8 @@ Immediate goals:
- [ ] send a surface to stand on
- [ ] handle chat
- NBT library
- [ ] parse NBT
- [ ] decode and encode data
- [x] parse NBT
- [x] decode and encode data
## Project Setup Instructions
@ -26,6 +26,7 @@ Build dependencies:
- bash
- a C++ 20 compiler
- GLFW with headers
Setup dependencies:

View File

@ -22,10 +22,8 @@ each file.
Don't use excessive comments, use descriptive names instead.
There is no such thing as too long names (within reason, of course).
Don't have comments that go beyond 80 characters per line, preferably
slightly less.
Put comments on their own lines.
Format comments to improve readability, don't have long single-line comments.
Indent by four spaces.

View File

@ -1,5 +1,8 @@
Copyright <year>, FOSS-VG Developers and Contributers
Author(s):
<names or pseudonyms here>
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.

Binary file not shown.

View File

@ -0,0 +1,122 @@
[0: Compound]:
|Header: 3 bytes
|Payload: 232 bytes
|Total: 235 bytes
|Length: 4
|
|[3: List] int8 arrays:
| |Header: 14 bytes
| |Payload: 29 bytes
| |Total: 43 bytes
| |Contained Type: Array of 8 Bit Integers
| |Length: 3
| |
| |[22: Array of 8 Bit Integers]:
| | |Payload: 8 bytes
| | |Total: 8 bytes
| | |Length: 4
| | 'Values:
| | |13
| | |37
| | |52
| | '81
| |
| |[30: Array of 8 Bit Integers]:
| | |Payload: 8 bytes
| | |Total: 8 bytes
| | |Length: 4
| | 'Values:
| | |80
| | |0
| | |81
| | '35
| |
| '[38: Array of 8 Bit Integers]:
| |Payload: 8 bytes
| |Total: 8 bytes
| |Length: 4
| 'Values:
| |0
| |0
| |34
| '-65
|
|
|[46: List] int32 arrays:
| |Header: 15 bytes
| |Payload: 97 bytes
| |Total: 112 bytes
| |Contained Type: Array of 32 Bit Integers
| |Length: 3
| |
| |[66: Array of 32 Bit Integers]:
| | |Payload: 16 bytes
| | |Total: 16 bytes
| | |Length: 3
| | 'Values:
| | |13859
| | |7677676
| | '1337
| |
| |[82: Array of 32 Bit Integers]:
| | |Payload: 68 bytes
| | |Total: 68 bytes
| | |Length: 16
| | 'Values:
| | |1
| | |2
| | |4
| | |8
| | |16
| | |32
| | |64
| | |128
| | |256
| | |512
| | |1024
| | |2048
| | |4096
| | |8192
| | |16384
| | '32768
| |
| '[150: Array of 32 Bit Integers]:
| |Payload: 8 bytes
| |Total: 8 bytes
| |Length: 1
| 'Values:
| '-100000
|
|
|[158: List] int64 arrays:
| |Header: 15 bytes
| |Payload: 61 bytes
| |Total: 76 bytes
| |Contained Type: Array of 64 Bit Integers
| |Length: 2
| |
| |[178: Array of 64 Bit Integers]:
| | |Payload: 28 bytes
| | |Total: 28 bytes
| | |Length: 3
| | 'Values:
| | |9999999998
| | |0
| | '77777666666666
| |
| '[206: Array of 64 Bit Integers]:
| |Payload: 28 bytes
| |Total: 28 bytes
| |Length: 3
| 'Values:
| |-2141414141414141
| |7680
| '900
|
|
'[234: End]:
|Header: 1 byte
|Payload: 0 bytes
'Total: 1 byte

Binary file not shown.

View File

@ -0,0 +1,6 @@
[0: 64 Bit Integer] test:
|Header: 7 bytes
|Payload: 8 bytes
|Total: 15 bytes
'Value: 9223372036854775807

Binary file not shown.

View File

@ -0,0 +1,12 @@
[0: 64 Bit Integer] test:
|Header: 7 bytes
|Payload: 8 bytes
|Total: 15 bytes
'Value: 9223372036854775807
[15: 32 Bit Integer] int32:
|Header: 8 bytes
|Payload: 4 bytes
|Total: 12 bytes
'Value: 1866009202

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,592 @@
[0: Compound]:
|Header: 3 bytes
|Payload: 792 bytes
|Total: 795 bytes
|Length: 3
|
|[3: List] 60:
| |Header: 5 bytes
| |Payload: 222 bytes
| |Total: 227 bytes
| |Contained Type: List
| |Length: 5
| |
| |[13: List]:
| | |Payload: 81 bytes
| | |Total: 81 bytes
| | |Contained Type: String
| | |Length: 3
| | |
| | |[18: String]:
| | | |Payload: 18 bytes
| | | |Total: 18 bytes
| | | 'Value: Du bist so dumm,
| | |
| | |[36: String]:
| | | |Payload: 38 bytes
| | | |Total: 38 bytes
| | | 'Value: Du wirfst nen Stein aufn Boden
| | |
| | '[74: String]:
| | |Payload: 20 bytes
| | |Total: 20 bytes
| | 'Value: und triffst nicht.
| |
| |
| |[94: List]:
| | |Payload: 12 bytes
| | |Total: 12 bytes
| | |Contained Type: 8 Bit Integer
| | |Length: 7
| | |
| | |[99: 8 Bit Integer]:
| | | |Payload: 1 byte
| | | |Total: 1 byte
| | | 'Value: 115
| | |
| | |[100: 8 Bit Integer]:
| | | |Payload: 1 byte
| | | |Total: 1 byte
| | | 'Value: 35
| | |
| | |[101: 8 Bit Integer]:
| | | |Payload: 1 byte
| | | |Total: 1 byte
| | | 'Value: 7
| | |
| | |[102: 8 Bit Integer]:
| | | |Payload: 1 byte
| | | |Total: 1 byte
| | | 'Value: -3
| | |
| | |[103: 8 Bit Integer]:
| | | |Payload: 1 byte
| | | |Total: 1 byte
| | | 'Value: 56
| | |
| | |[104: 8 Bit Integer]:
| | | |Payload: 1 byte
| | | |Total: 1 byte
| | | 'Value: 105
| | |
| | '[105: 8 Bit Integer]:
| | |Payload: 1 byte
| | |Total: 1 byte
| | 'Value: 125
| |
| |
| |[106: List]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | |Contained Type: End
| | 'Length: 0
| |
| |[111: List]:
| | |Payload: 77 bytes
| | |Total: 77 bytes
| | |Contained Type: Compound
| | |Length: 3
| | |
| | |[116: Compound]:
| | | |Payload: 6 bytes
| | | |Total: 6 bytes
| | | |Length: 2
| | | |
| | | |[116: 8 Bit Integer] 3:
| | | | |Header: 4 bytes
| | | | |Payload: 1 byte
| | | | |Total: 5 bytes
| | | | 'Value: 105
| | | |
| | | '[121: End]:
| | | |Header: 1 byte
| | | |Payload: 0 bytes
| | | 'Total: 1 byte
| | |
| | |
| | |[122: Compound]:
| | | |Payload: 38 bytes
| | | |Total: 38 bytes
| | | |Length: 3
| | | |
| | | |[122: String] 600:
| | | | |Header: 6 bytes
| | | | |Payload: 5 bytes
| | | | |Total: 11 bytes
| | | | 'Value: 800
| | | |
| | | |[133: List] cookie:
| | | | |Header: 9 bytes
| | | | |Payload: 17 bytes
| | | | |Total: 26 bytes
| | | | |Contained Type: String
| | | | |Length: 3
| | | | |
| | | | |[147: String]:
| | | | | |Payload: 5 bytes
| | | | | |Total: 5 bytes
| | | | | 'Value: eat
| | | | |
| | | | |[152: String]:
| | | | | |Payload: 4 bytes
| | | | | |Total: 4 bytes
| | | | | 'Value: it
| | | | |
| | | | '[156: String]:
| | | | |Payload: 3 bytes
| | | | |Total: 3 bytes
| | | | 'Value: !
| | | |
| | | |
| | | '[159: End]:
| | | |Header: 1 byte
| | | |Payload: 0 bytes
| | | 'Total: 1 byte
| | |
| | |
| | '[160: Compound]:
| | |Payload: 28 bytes
| | |Total: 28 bytes
| | |Length: 2
| | |
| | |[160: Compound]:
| | | |Header: 3 bytes
| | | |Payload: 24 bytes
| | | |Total: 27 bytes
| | | |Length: 2
| | | |
| | | |[163: Compound] e:
| | | | |Header: 4 bytes
| | | | |Payload: 19 bytes
| | | | |Total: 23 bytes
| | | | |Length: 3
| | | | |
| | | | |[167: 32 Bit Integer] a:
| | | | | |Header: 4 bytes
| | | | | |Payload: 4 bytes
| | | | | |Total: 8 bytes
| | | | | 'Value: 544502633
| | | | |
| | | | |[175: Compound] f:
| | | | | |Header: 4 bytes
| | | | | |Payload: 6 bytes
| | | | | |Total: 10 bytes
| | | | | |Length: 2
| | | | | |
| | | | | |[179: Compound] o:
| | | | | | |Header: 4 bytes
| | | | | | |Payload: 1 byte
| | | | | | |Total: 5 bytes
| | | | | | |Length: 1
| | | | | | |
| | | | | | '[183: End]:
| | | | | | |Header: 1 byte
| | | | | | |Payload: 0 bytes
| | | | | | 'Total: 1 byte
| | | | | |
| | | | | |
| | | | | '[184: End]:
| | | | | |Header: 1 byte
| | | | | |Payload: 0 bytes
| | | | | 'Total: 1 byte
| | | | |
| | | | |
| | | | '[185: End]:
| | | | |Header: 1 byte
| | | | |Payload: 0 bytes
| | | | 'Total: 1 byte
| | | |
| | | |
| | | '[186: End]:
| | | |Header: 1 byte
| | | |Payload: 0 bytes
| | | 'Total: 1 byte
| | |
| | |
| | '[187: End]:
| | |Header: 1 byte
| | |Payload: 0 bytes
| | 'Total: 1 byte
| |
| |
| |
| '[188: List]:
| |Payload: 42 bytes
| |Total: 42 bytes
| |Contained Type: List
| |Length: 2
| |
| |[193: List]:
| | |Payload: 20 bytes
| | |Total: 20 bytes
| | |Contained Type: String
| | |Length: 5
| | |
| | |[198: String]:
| | | |Payload: 3 bytes
| | | |Total: 3 bytes
| | | 'Value: a
| | |
| | |[201: String]:
| | | |Payload: 3 bytes
| | | |Total: 3 bytes
| | | 'Value: b
| | |
| | |[204: String]:
| | | |Payload: 3 bytes
| | | |Total: 3 bytes
| | | 'Value: c
| | |
| | |[207: String]:
| | | |Payload: 3 bytes
| | | |Total: 3 bytes
| | | 'Value: d
| | |
| | '[210: String]:
| | |Payload: 3 bytes
| | |Total: 3 bytes
| | 'Value: e
| |
| |
| '[213: List]:
| |Payload: 17 bytes
| |Total: 17 bytes
| |Contained Type: 32 Bit Integer
| |Length: 3
| |
| |[218: 32 Bit Integer]:
| | |Payload: 4 bytes
| | |Total: 4 bytes
| | 'Value: 457829
| |
| |[222: 32 Bit Integer]:
| | |Payload: 4 bytes
| | |Total: 4 bytes
| | 'Value: 300
| |
| '[226: 32 Bit Integer]:
| |Payload: 4 bytes
| |Total: 4 bytes
| 'Value: 60
|
|
|
|
|[230: Compound] compound_level_1:
| |Header: 19 bytes
| |Payload: 545 bytes
| |Total: 564 bytes
| |Length: 5
| |
| |[249: List] 100:
| | |Header: 6 bytes
| | |Payload: 291 bytes
| | |Total: 297 bytes
| | |Contained Type: Compound
| | |Length: 4
| | |
| | |[260: Compound]:
| | | |Payload: 6 bytes
| | | |Total: 6 bytes
| | | |Length: 2
| | | |
| | | |[260: 8 Bit Integer] 3:
| | | | |Header: 4 bytes
| | | | |Payload: 1 byte
| | | | |Total: 5 bytes
| | | | 'Value: 3
| | | |
| | | '[265: End]:
| | | |Header: 1 byte
| | | |Payload: 0 bytes
| | | 'Total: 1 byte
| | |
| | |
| | |[266: Compound]:
| | | |Payload: 125 bytes
| | | |Total: 125 bytes
| | | |Length: 4
| | | |
| | | |[266: Array of 8 Bit Integers] 600:
| | | | |Header: 6 bytes
| | | | |Payload: 16 bytes
| | | | |Total: 22 bytes
| | | | |Length: 12
| | | | 'Values:
| | | | |69
| | | | |36
| | | | |67
| | | | |66
| | | | |40
| | | | |-121
| | | | |98
| | | | |-46
| | | | |21
| | | | |101
| | | | |104
| | | | '97
| | | |
| | | |[288: 64 Bit Integer] eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee:
| | | | |Header: 85 bytes
| | | | |Payload: 8 bytes
| | | | |Total: 93 bytes
| | | | 'Value: 317827579944
| | | |
| | | |[381: 16 Bit Integer] nose:
| | | | |Header: 7 bytes
| | | | |Payload: 2 bytes
| | | | |Total: 9 bytes
| | | | 'Value: 12547
| | | |
| | | '[390: End]:
| | | |Header: 1 byte
| | | |Payload: 0 bytes
| | | 'Total: 1 byte
| | |
| | |
| | |[391: Compound]:
| | | |Payload: 154 bytes
| | | |Total: 154 bytes
| | | |Length: 3
| | | |
| | | |[391: List] 681:
| | | | |Header: 6 bytes
| | | | |Payload: 8 bytes
| | | | |Total: 14 bytes
| | | | |Contained Type: 8 Bit Integer
| | | | |Length: 3
| | | | |
| | | | |[402: 8 Bit Integer]:
| | | | | |Payload: 1 byte
| | | | | |Total: 1 byte
| | | | | 'Value: 3
| | | | |
| | | | |[403: 8 Bit Integer]:
| | | | | |Payload: 1 byte
| | | | | |Total: 1 byte
| | | | | 'Value: 3
| | | | |
| | | | '[404: 8 Bit Integer]:
| | | | |Payload: 1 byte
| | | | |Total: 1 byte
| | | | 'Value: 5
| | | |
| | | |
| | | |[405: Compound] moar:
| | | | |Header: 7 bytes
| | | | |Payload: 132 bytes
| | | | |Total: 139 bytes
| | | | |Length: 2
| | | | |
| | | | |[412: Compound] nesting:
| | | | | |Header: 10 bytes
| | | | | |Payload: 121 bytes
| | | | | |Total: 131 bytes
| | | | | |Length: 2
| | | | | |
| | | | | |[422: Compound] go:
| | | | | | |Header: 5 bytes
| | | | | | |Payload: 115 bytes
| | | | | | |Total: 120 bytes
| | | | | | |Length: 2
| | | | | | |
| | | | | | |[427: Compound] brrrrr:
| | | | | | | |Header: 9 bytes
| | | | | | | |Payload: 105 bytes
| | | | | | | |Total: 114 bytes
| | | | | | | |Length: 7
| | | | | | | |
| | | | | | | |[436: 16 Bit Integer] anyway:
| | | | | | | | |Header: 9 bytes
| | | | | | | | |Payload: 2 bytes
| | | | | | | | |Total: 11 bytes
| | | | | | | | 'Value: 12547
| | | | | | | |
| | | | | | | |[447: List] data:
| | | | | | | | |Header: 7 bytes
| | | | | | | | |Payload: 21 bytes
| | | | | | | | |Total: 28 bytes
| | | | | | | | |Contained Type: 32 Bit Integer
| | | | | | | | |Length: 4
| | | | | | | | |
| | | | | | | | |[459: 32 Bit Integer]:
| | | | | | | | | |Payload: 4 bytes
| | | | | | | | | |Total: 4 bytes
| | | | | | | | | 'Value: 10
| | | | | | | | |
| | | | | | | | |[463: 32 Bit Integer]:
| | | | | | | | | |Payload: 4 bytes
| | | | | | | | | |Total: 4 bytes
| | | | | | | | | 'Value: 808464643
| | | | | | | | |
| | | | | | | | |[467: 32 Bit Integer]:
| | | | | | | | | |Payload: 4 bytes
| | | | | | | | | |Total: 4 bytes
| | | | | | | | | 'Value: 645
| | | | | | | | |
| | | | | | | | '[471: 32 Bit Integer]:
| | | | | | | | |Payload: 4 bytes
| | | | | | | | |Total: 4 bytes
| | | | | | | | 'Value: 1337
| | | | | | | |
| | | | | | | |
| | | | | | | |[475: 8 Bit Integer] here:
| | | | | | | | |Header: 7 bytes
| | | | | | | | |Payload: 1 byte
| | | | | | | | |Total: 8 bytes
| | | | | | | | 'Value: 3
| | | | | | | |
| | | | | | | |[483: Double] is:
| | | | | | | | |Header: 5 bytes
| | | | | | | | |Payload: 8 bytes
| | | | | | | | |Total: 13 bytes
| | | | | | | | 'Value: 7.29293e-304
| | | | | | | |
| | | | | | | |[496: 32 Bit Integer] so:
| | | | | | | | |Header: 5 bytes
| | | | | | | | |Payload: 4 bytes
| | | | | | | | |Total: 9 bytes
| | | | | | | | 'Value: 808464643
| | | | | | | |
| | | | | | | |[505: Array of 32 Bit Integers] some:
| | | | | | | | |Header: 7 bytes
| | | | | | | | |Payload: 28 bytes
| | | | | | | | |Total: 35 bytes
| | | | | | | | |Length: 6
| | | | | | | | 'Values:
| | | | | | | | |3865431
| | | | | | | | |230597146
| | | | | | | | |2147483647
| | | | | | | | |-1870208349
| | | | | | | | |-1195067710
| | | | | | | | '-2031966525
| | | | | | | |
| | | | | | | '[540: End]:
| | | | | | | |Header: 1 byte
| | | | | | | |Payload: 0 bytes
| | | | | | | 'Total: 1 byte
| | | | | | |
| | | | | | |
| | | | | | '[541: End]:
| | | | | | |Header: 1 byte
| | | | | | |Payload: 0 bytes
| | | | | | 'Total: 1 byte
| | | | | |
| | | | | |
| | | | | '[542: End]:
| | | | | |Header: 1 byte
| | | | | |Payload: 0 bytes
| | | | | 'Total: 1 byte
| | | | |
| | | | |
| | | | '[543: End]:
| | | | |Header: 1 byte
| | | | |Payload: 0 bytes
| | | | 'Total: 1 byte
| | | |
| | | |
| | | '[544: End]:
| | | |Header: 1 byte
| | | |Payload: 0 bytes
| | | 'Total: 1 byte
| | |
| | |
| | '[545: Compound]:
| | |Payload: 1 byte
| | |Total: 1 byte
| | |Length: 1
| | |
| | '[545: End]:
| | |Header: 1 byte
| | |Payload: 0 bytes
| | 'Total: 1 byte
| |
| |
| |
| |[546: Compound] compound_level_2a:
| | |Header: 20 bytes
| | |Payload: 1 byte
| | |Total: 21 bytes
| | |Length: 1
| | |
| | '[566: End]:
| | |Header: 1 byte
| | |Payload: 0 bytes
| | 'Total: 1 byte
| |
| |
| |[567: Compound] compound_level_2b:
| | |Header: 20 bytes
| | |Payload: 191 bytes
| | |Total: 211 bytes
| | |Length: 3
| | |
| | |[587: Float] 300:
| | | |Header: 6 bytes
| | | |Payload: 4 bytes
| | | |Total: 10 bytes
| | | 'Value: 1.89896e+28
| | |
| | |[597: List] 900:
| | | |Header: 6 bytes
| | | |Payload: 174 bytes
| | | |Total: 180 bytes
| | | |Contained Type: String
| | | |Length: 6
| | | |
| | | |[608: String]:
| | | | |Payload: 7 bytes
| | | | |Total: 7 bytes
| | | | 'Value: aaaaa
| | | |
| | | |[615: String]:
| | | | |Payload: 30 bytes
| | | | |Total: 30 bytes
| | | | 'Value: bbbbbbbbbbbbbbbbbbbbbbbbbbbb
| | | |
| | | |[645: String]:
| | | | |Payload: 6 bytes
| | | | |Total: 6 bytes
| | | | 'Value: nose
| | | |
| | | |[651: String]:
| | | | |Payload: 13 bytes
| | | | |Total: 13 bytes
| | | | 'Value: hello there
| | | |
| | | |[664: String]:
| | | | |Payload: 37 bytes
| | | | |Total: 37 bytes
| | | | 'Value: Eat more bricks, theyre healthy.
| | | |
| | | '[701: String]:
| | | |Payload: 76 bytes
| | | |Total: 76 bytes
| | | 'Value: ŧ€æ ̣←¶ĸæ↓ŧŧþ€ł„ ̣€æ€“¢↓ø→ł¶€¶„ŋ
| | |
| | |
| | '[777: End]:
| | |Header: 1 byte
| | |Payload: 0 bytes
| | 'Total: 1 byte
| |
| |
| |[778: List] eeeeeee:
| | |Header: 10 bytes
| | |Payload: 5 bytes
| | |Total: 15 bytes
| | |Contained Type: End
| | 'Length: 0
| |
| '[793: End]:
| |Header: 1 byte
| |Payload: 0 bytes
| 'Total: 1 byte
|
|
'[794: End]:
|Header: 1 byte
|Payload: 0 bytes
'Total: 1 byte

View File

@ -0,0 +1,78 @@
[0: Compound]:
|Header: 3 bytes
|Payload: 2395 bytes
|Total: 2398 bytes
|Length: 2
|
|[3: List] servers:
| |Header: 10 bytes
| |Payload: 2384 bytes
| |Total: 2394 bytes
| |Contained Type: Compound
| |Length: 2
| |
| |[18: Compound]:
| | |Payload: 1184 bytes
| | |Total: 1184 bytes
| | |Length: 4
| | |
| | |[18: String] ip:
| | | |Header: 5 bytes
| | | |Payload: 14 bytes
| | | |Total: 19 bytes
| | | 'Value: minecraft.ip
| | |
| | |[37: String] name:
| | | |Header: 7 bytes
| | | |Payload: 20 bytes
| | | |Total: 27 bytes
| | | 'Value: Survival0 Internal
| | |
| | |[64: String] icon:
| | | |Header: 7 bytes
| | | |Payload: 1130 bytes
| | | |Total: 1137 bytes
| | | 'Value: iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAADFUlEQVR4Xt2bPW4UQRCFx9qUA+wBkJB8ElIkbmAJn4GYhNQ38AmcEBORcA8OQdjQbfeq9pvq6und/pv9pCeL/qv3amakHS9elsY45w7ucg48bxcwRS1YZyr++7uj4Ybcsf4wvBm668jYRtDNKOirOTQwC/TZBBadDfqtCovNCn1XgUVmh/6vgofvBea4CB66N5inCB62V5hrEzwk4qdaqSVLCdwsCdN/f1RXpmwVmDMJN0bClGK+lozSVWBOFW6ShGlhtpZ6NcCzWLjMi01Y8mb0829XTfLcDqRfoLiShCVKAyIMtlXy3B6cp37DXXj1NRjwbP2f90Ecl+d3YH0XcAUJS5QGlGqSBqzvAi4gYUlhAyIc1yTP78FF4a0G3L8cT5LhI1xPsUYPihuQCq81ICdJHJN1elClATI4xbUMLhnWAJf5vX00dW0DPNxLsVYHDtkqNCUDeRiaDSAMPbgBLltFu/1JHH/69G4Vylovdf/1GNT9MeAA0RqQUqoBmmLgqOcvH4KmagBvSZqWyjWA62NgijVbY1agGZqVYkCK61NizdaYFeTtSKMt1fMxMCvM2AA/VioLczYaiWZ6yXoE5PwWaWdIzNnSYrWlmY+e2DRNqTMk5uzMDeA6GZpzFuYsOzpCJIwpzaL8J9GrG5DCH/rr5/dqypmUbG1AVO5sdZZXYQZd481CnQ2blG6OEkMwoKUcfsXqdTg24PHh4ybRcKkeH76d/Ts+vy/H9XPMgFtk8Prf8DgahhSjoyQtlnpT4p0I4a0G8EqnxKK1pTXA/8yJe0kI71EmViZGSlrUvDE051KcGuDBRNjMK50Si9aWtKeF1JT7HHAW3oPJ6SS9MawluVeyEJf4asxP8YNLD71aWuPHS6Ww/mrMw1UePzxKKbjOksaSwiXughtDv/oRrr41mFeFm24F5kzCjbcCc5pw895hvk3wkL3CXEXwsL3BPBfBQ/cCc1wFD58d+q8Ci8wKfVeFxWaDfpvAorNAn82hgVHQV1fc2Bco+8WmJ94M3TVknuAadFsL1tkFTvneoYDmfz7/D2WFu2nv97K8AAAAAElFTkSuQmCC
| | |
| | '[1201: End]:
| | |Header: 1 byte
| | |Payload: 0 bytes
| | 'Total: 1 byte
| |
| |
| '[1202: Compound]:
| |Payload: 1195 bytes
| |Total: 1195 bytes
| |Length: 4
| |
| |[1202: String] ip:
| | |Header: 5 bytes
| | |Payload: 25 bytes
| | |Total: 30 bytes
| | 'Value: lostcave.ddnss.de:45539
| |
| |[1232: String] name:
| | |Header: 7 bytes
| | |Payload: 20 bytes
| | |Total: 27 bytes
| | 'Value: Survival0 External
| |
| |[1259: String] icon:
| | |Header: 7 bytes
| | |Payload: 1130 bytes
| | |Total: 1137 bytes
| | 'Value: iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAADFUlEQVR4Xt2bPW4UQRCFx9qUA+wBkJB8ElIkbmAJn4GYhNQ38AmcEBORcA8OQdjQbfeq9pvq6und/pv9pCeL/qv3amakHS9elsY45w7ucg48bxcwRS1YZyr++7uj4Ybcsf4wvBm668jYRtDNKOirOTQwC/TZBBadDfqtCovNCn1XgUVmh/6vgofvBea4CB66N5inCB62V5hrEzwk4qdaqSVLCdwsCdN/f1RXpmwVmDMJN0bClGK+lozSVWBOFW6ShGlhtpZ6NcCzWLjMi01Y8mb0829XTfLcDqRfoLiShCVKAyIMtlXy3B6cp37DXXj1NRjwbP2f90Ecl+d3YH0XcAUJS5QGlGqSBqzvAi4gYUlhAyIc1yTP78FF4a0G3L8cT5LhI1xPsUYPihuQCq81ICdJHJN1elClATI4xbUMLhnWAJf5vX00dW0DPNxLsVYHDtkqNCUDeRiaDSAMPbgBLltFu/1JHH/69G4Vylovdf/1GNT9MeAA0RqQUqoBmmLgqOcvH4KmagBvSZqWyjWA62NgijVbY1agGZqVYkCK61NizdaYFeTtSKMt1fMxMCvM2AA/VioLczYaiWZ6yXoE5PwWaWdIzNnSYrWlmY+e2DRNqTMk5uzMDeA6GZpzFuYsOzpCJIwpzaL8J9GrG5DCH/rr5/dqypmUbG1AVO5sdZZXYQZd481CnQ2blG6OEkMwoKUcfsXqdTg24PHh4ybRcKkeH76d/Ts+vy/H9XPMgFtk8Prf8DgahhSjoyQtlnpT4p0I4a0G8EqnxKK1pTXA/8yJe0kI71EmViZGSlrUvDE051KcGuDBRNjMK50Si9aWtKeF1JT7HHAW3oPJ6SS9MawluVeyEJf4asxP8YNLD71aWuPHS6Ww/mrMw1UePzxKKbjOksaSwiXughtDv/oRrr41mFeFm24F5kzCjbcCc5pw895hvk3wkL3CXEXwsL3BPBfBQ/cCc1wFD58d+q8Ci8wKfVeFxWaDfpvAorNAn82hgVHQV1fc2Bco+8WmJ94M3TVknuAadFsL1tkFTvneoYDmfz7/D2WFu2nv97K8AAAAAElFTkSuQmCC
| |
| '[2396: End]:
| |Header: 1 byte
| |Payload: 0 bytes
| 'Total: 1 byte
|
|
|
'[2397: End]:
|Header: 1 byte
|Payload: 0 bytes
'Total: 1 byte

View File

@ -0,0 +1,223 @@
[0: Compound]:
|Header: 3 bytes
|Payload: 475 bytes
|Total: 478 bytes
|Length: 15
|
|[3: String] Spaces and special characters are allowed in tag names, right?:
| |Header: 65 bytes
| |Payload: 24 bytes
| |Total: 89 bytes
| 'Value: Idk. Lets find out.
|
|[92: Compound] compound:
| |Header: 11 bytes
| |Payload: 45 bytes
| |Total: 56 bytes
| |Length: 3
| |
| |[103: 32 Bit Integer] some_number:
| | |Header: 14 bytes
| | |Payload: 4 bytes
| | |Total: 18 bytes
| | 'Value: -754506943
| |
| |[121: String] some_text:
| | |Header: 12 bytes
| | |Payload: 14 bytes
| | |Total: 26 bytes
| | 'Value: eat a cookie
| |
| '[147: End]:
| |Header: 1 byte
| |Payload: 0 bytes
| 'Total: 1 byte
|
|
|[148: Double] double:
| |Header: 9 bytes
| |Payload: 8 bytes
| |Total: 17 bytes
| 'Value: 623594
|
|[165: Float] float:
| |Header: 8 bytes
| |Payload: 4 bytes
| |Total: 12 bytes
| 'Value: 35.2678
|
|[177: 16 Bit Integer] int16:
| |Header: 8 bytes
| |Payload: 2 bytes
| |Total: 10 bytes
| 'Value: 2000
|
|[187: 32 Bit Integer] int32:
| |Header: 8 bytes
| |Payload: 4 bytes
| |Total: 12 bytes
| 'Value: 10101010
|
|[199: Array of 32 Bit Integers] int32_array:
| |Header: 14 bytes
| |Payload: 20 bytes
| |Total: 34 bytes
| |Length: 4
| 'Values:
| |398452796
| |43259
| |2147483647
| '1634890337
|
|[233: 64 Bit Integer] int64:
| |Header: 8 bytes
| |Payload: 8 bytes
| |Total: 16 bytes
| 'Value: 810001800766
|
|[249: Array of 64 Bit Integers] int64_array:
| |Header: 14 bytes
| |Payload: 44 bytes
| |Total: 58 bytes
| |Length: 5
| 'Values:
| |239865
| |23586749
| |9223372036854775807
| |188944201329624
| '3116157694992754
|
|[307: 8 Bit Integer] int8:
| |Header: 7 bytes
| |Payload: 1 byte
| |Total: 8 bytes
| 'Value: 100
|
|[315: Array of 8 Bit Integers] int8_array:
| |Header: 13 bytes
| |Payload: 12 bytes
| |Total: 25 bytes
| |Length: 8
| 'Values:
| |113
| |53
| |119
| |98
| |84
| |100
| |-11
| '50
|
|[340: List] list_int8:
| |Header: 12 bytes
| |Payload: 10 bytes
| |Total: 22 bytes
| |Contained Type: 8 Bit Integer
| |Length: 5
| |
| |[357: 8 Bit Integer]:
| | |Payload: 1 byte
| | |Total: 1 byte
| | 'Value: 65
| |
| |[358: 8 Bit Integer]:
| | |Payload: 1 byte
| | |Total: 1 byte
| | 'Value: 96
| |
| |[359: 8 Bit Integer]:
| | |Payload: 1 byte
| | |Total: 1 byte
| | 'Value: 78
| |
| |[360: 8 Bit Integer]:
| | |Payload: 1 byte
| | |Total: 1 byte
| | 'Value: 127
| |
| '[361: 8 Bit Integer]:
| |Payload: 1 byte
| |Total: 1 byte
| 'Value: -6
|
|
|[362: List] list_strings:
| |Header: 15 bytes
| |Payload: 77 bytes
| |Total: 92 bytes
| |Contained Type: String
| |Length: 12
| |
| |[382: String]:
| | |Payload: 8 bytes
| | |Total: 8 bytes
| | 'Value: Pacman
| |
| |[390: String]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | 'Value: ate
| |
| |[395: String]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | 'Value: all
| |
| |[400: String]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | 'Value: the
| |
| |[405: String]:
| | |Payload: 6 bytes
| | |Total: 6 bytes
| | 'Value: dots
| |
| |[411: String]:
| | |Payload: 4 bytes
| | |Total: 4 bytes
| | 'Value: so
| |
| |[415: String]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | 'Value: now
| |
| |[420: String]:
| | |Payload: 8 bytes
| | |Total: 8 bytes
| | 'Value: hes
| |
| |[428: String]:
| | |Payload: 8 bytes
| | |Total: 8 bytes
| | 'Value: coming
| |
| |[436: String]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | 'Value: for
| |
| |[441: String]:
| | |Payload: 5 bytes
| | |Total: 5 bytes
| | 'Value: the
| |
| '[446: String]:
| |Payload: 8 bytes
| |Total: 8 bytes
| 'Value: words.
|
|
|[454: String] string:
| |Header: 9 bytes
| |Payload: 14 bytes
| |Total: 23 bytes
| 'Value: Hello World!
|
'[477: End]:
|Header: 1 byte
|Payload: 0 bytes
'Total: 1 byte

View File

@ -1,33 +1,67 @@
# Tests
# Resources
Data used for testing and understanding the internals of Minecraft/FOSS-VG,
also contains code to produce such data
## java/
Programs to produce data for figuring out how to interact
with Java-specific things
- `JavaStringGenerator.java`: A simple tool that reads from stdin and outputs Java-style UTF-8 to stdout
- `netty-tests/`: Figure out how Netty operates
## NBT_data/
Data used to test the NBT library
`bare_int64_tag`: What the name says
`bare_int64_tag_and_int32_tag`: What the name says
`simple_nbt`: A simple NBT file containing all tag types
`nested_compounds_and_lists`: A combination of nested compound and list tags (parser stress test)
`servers.dat`: Pulled from my Minecraft installation
`servers.dat_nbt_decoded.txt`: The same data manually decoded (This was done to get a better understanding how NBT works, might come in handy.)
`level.dat`: Pulled from one of my world saves (gzip-compressed)
`level.dat_decompressed`: The same data decompressed
## network_capture/
Network captures used to get an understanding of the protocol
`ping.pcapng`: WireShark capture of the multipayer screen server ping
`ping_decoded.txt`: Extracted TCP payloads from the network capture annotated with whats happening
## unicode_data/
This directory contains two files with unicode data. One is in Java format, the other is normal UTF-8.
Files with unicode data
- Bare ("normal") UTF-8
- Java format
## all_bytes
Every possible 8-bit byte in ascending order
## check_endianness.cpp
A simple tool to determine the endianness of the system and write the endianness header for FOSS-VG
A simple tool to determine the endianness of the system and write
the endianness header for FOSS-VG
Supports: Little Endian, Big Endian, PDP Endian, Honeywell Endian
Note that, while it can detect PDP and Honeywell endianness, the FOSS-VG project itself does not support these.
Usage: `check_endianness > header_file`
Usage example: `check_endianness > header_file`
Note that, while this tool should in theory be able to detect
PDP and Honeywell-316-style endianness, the FOSS-VG project itself
does not support these.
## region_files
## JavaStringGenerator.java
A simple tool written in Java that takes an input as UTF-8 and outputs it in Java-style UTF-8.
Usage example: `echo -ne "\x00" | java JavaStringGenerator > output_file`
## NBT_data
Data used to test the NBT library.
`servers.dat`: My current servers.dat as pulled from my Minecraft installation
`servers.dat_nbt_decoded.txt`: The same file manually decoded (I did this to get a better understanding how NBT works, might come in handy in the future.)
`simple_nbt`: A simple NBT file containing all tags
`nested_compounds_and_lists`: A combination of nested compound and list tags intended to be challenging to parse
Exactly what the name says. At this point just a random region file I grabbed
from Minecraft, will probably contain synthetic files for test cases in the
future as well.

BIN
resources/all_bytes Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
# Netty Testing
This sub-project is used to learn how Netty works
Build with Maven (`mvn compile`). Run with the build scripts.

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>foss_vg</groupId>
<artifactId>netty-tests</artifactId>
<version>1.0-SNAPSHOT</version>
<name>netty-tests</name>
<url>https://lostcave.ddnss.de/git/BodgeMaster/FOSS-VG</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.84.Final</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<!--
Removed all the bloat bc we don't need it.
Maven will probably choose a default version for the things I removed.
I don't care as targets other than compile and clean aren't needed here.
-->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -1,7 +1,8 @@
#!/usr/bin/env bash
# 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.
@ -15,9 +16,7 @@
# version 3 along with this program.
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
echo "################################################################################
Testing hexnet
################################################################################"
set -e
echo "Test not yet implemented."
#TODO: implement unit test after merging back with master
cd target/classes
java foss_vg.NettyClient

View File

@ -0,0 +1,22 @@
# 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
set -e
cd target/classes
java foss_vg.NettyServer

View File

@ -0,0 +1,25 @@
// 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
package foss_vg;
public class NettyClient {
public static void main(String[] args) {
}
}

View File

@ -0,0 +1,25 @@
// 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
package foss_vg;
public class NettyServer {
public static void main(String[] args) {
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,90 @@
if [ "$1" = "-v" ]; then
VERBOSE=true
shift
else
VERBOSE=false
fi
if [ "$1" = "-n" ]; then
DECOMPRESS=false
shift
else
DECOMPRESS=true
fi
if [ ! -f "$1" ]; then
echo "Usage: $0 [-v] [-n] FILE"
echo " -v display raw content and NBT dump"
echo " -n don't decompress"
exit 1
fi
# pointer data
OFFSET_HEX="0x$(dd bs=1 if="$1" count=3 2>/dev/null | hexdump -e '3/1 "%02x" "\n"')"
OFFSET="$(baseconvert -d $OFFSET_HEX)"
echo " offset: $OFFSET ($OFFSET_HEX)"
LENGTH_HEX="0x$(dd bs=1 if="$1" count=1 skip=3 2>/dev/null | hexdump -e '1/1 "%02x" "\n"')"
LENGTH="$(baseconvert -d $LENGTH_HEX)"
echo " length: $LENGTH ($LENGTH_HEX)"
#TODO: last modified
# chunk
DATA="$(dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | hexdump -v -e '16/1 "%02x" "\n"' | tr -d '
')"
# blob header
# bs=2 because each byte is two digits hex
COMPRESSED_LENGTH_HEX="0x$(dd bs=2 count=4 2> /dev/null <<< $DATA)"
COMPRESSED_LENGTH="$(baseconvert -d $COMPRESSED_LENGTH_HEX)"
echo " compressed length in bytes: $COMPRESSED_LENGTH ($COMPRESSED_LENGTH_HEX)"
FORMAT_HEX="0x$(dd bs=2 skip=4 count=1 2> /dev/null <<< $DATA)"
case $FORMAT_HEX in
"0x01")
FORMAT="gzip"
function UNCOMPRESS {
gzip -dc
}
;;
"0x02")
FORMAT="zlib"
function UNCOMPRESS {
cat > /tmp/chunk_zlib_decompress
python3 <<< "
import zlib,sys
a = open('/tmp/chunk_zlib_decompress', 'rb')
data = a.read()
a.close()
sys.stdout.buffer.write(zlib.decompress(data))
sys.stdout.buffer.flush()
"
rm /tmp/chunk_zlib_decompress
}
;;
*)
FORMAT="unknown"
function UNCOMPRESS {
false
}
;;
esac
echo " format: $FORMAT ($FORMAT_HEX)"
if $DECOMPRESS; then
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null | UNCOMPRESS > /tmp/chunk_uncompressed_nbt
else
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null > /tmp/chunk_compressed_nbt
fi
if $VERBOSE; then
echo "Raw chunk data:"
echo "$DATA"
echo "NBT dump:"
#TODO: use pipes instead of a file
#TODO: fix this up to work with both compressed and uncompressed NBT
dumpnbt /tmp/chunk_uncompressed_nbt
rm /tmp/chunk_uncompressed_nbt
fi

Binary file not shown.

View File

@ -35,10 +35,19 @@ fi
# dynamically linked libraries.
echo ">>> Building libs..."
create_directory bin/lib
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"
echo $COMPILE_COMMAND
$COMPILE_COMMAND &
COMPILE_COMMANDS=(
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/net/connection.so ./src/lib/net/connection.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/cli.so ./src/lib/cli.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/file.so ./src/lib/file.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/game/block.so ./src/lib/game/block.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/game/entity.so ./src/lib/game/entity.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/nbt.so ./src/lib/nbt.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/region.so ./src/lib/region.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -l:libz.so -o ./bin/lib/zlibutil.so ./src/lib/zlibutil.cpp"
)
for command in ${!COMPILE_COMMANDS[@]}; do
echo "${COMPILE_COMMANDS[command]}"
${COMPILE_COMMANDS[command]} &
$WAIT_ANYWAY
done
@ -55,12 +64,17 @@ wait
# How to run a tool: specify the library path to use for the dynamic linker
# when running a program
# Example: LD_LIBRARY_PATH=bin/lib bin/tools/dumpnbt
echo ">>> Building tools..."
echo ">>> Building programs..."
create_directory bin/tools
# add compile commands to this array
COMPILE_COMMANDS=(
"$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/tools/dumpnbt"
"$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/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.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/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
"$CXX_WITH_FLAGS src/tools/zlibutil.cpp -I./include -Lbin/lib -l:cli.so -l:file.so -l:zlibutil.so -l:libz.so -o bin/tools/zlibutil"
"$CXX_WITH_FLAGS -pthread src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
"$CXX_WITH_FLAGS -DFOSSVG_DEBUG src/fossvg.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -lglfw -lvulkan -o bin/fossvg"
"$CXX_WITH_FLAGS src/fossvgd.cpp -I./include -Lbin/lib -l:cli.so -o bin/fossvgd"
)
for command in ${!COMPILE_COMMANDS[@]}; do
echo "${COMPILE_COMMANDS[command]}"
@ -69,3 +83,21 @@ for command in ${!COMPILE_COMMANDS[@]}; do
done
wait
echo ">>> Compiling shaders..."
create_directory bin/shaders
for shader in $(find ./src/shaders -name "*.vsh"); do
COMPILE_COMMAND="dependencies/shaderc/bin/glslc -o $(sed -e 's/^.\/src/.\/bin/;s/vsh$/vsh.spv/' <<< $shader) -fshader-stage=vertex $shader"
echo $COMPILE_COMMAND
$COMPILE_COMMAND &
$WAIT_ANYWAY
done
for shader in $(find ./src/shaders -name "*.fsh"); do
COMPILE_COMMAND="dependencies/shaderc/bin/glslc -o $(sed -e 's/^.\/src/.\/bin/;s/fsh$/fsh.spv/' <<< $shader) -fshader-stage=fragment $shader"
echo $COMPILE_COMMAND
$COMPILE_COMMAND &
$WAIT_ANYWAY
done
wait

View File

@ -25,14 +25,21 @@ remove .endianness
remove resources/check_endianness
create_directory ./bin
create_directory ./bin/lib
create_directory ./bin/lib/net
create_directory ./include
ln -vs ../../dependencies/sockpp-0.7.1/build/libsockpp.so bin/lib/
ln -vs ../../dependencies/sockpp-0.7.1/build/libsockpp.so.0 bin/lib/
ln -vs ../../dependencies/sockpp-0.7.1/build/libsockpp.so.0.7.1 bin/lib/
if uname -s | tr [:upper:] [:lower:] | grep cygwin >/dev/null; then
ln -vs ../../dependencies/sockpp-0.8.1/build/cygsockpp-0.dll bin/lib/libsockpp.so
ln -vs ../../dependencies/sockpp-0.8.1/build/cygsockpp-0.dll bin/lib/
else
ln -vs ../../dependencies/sockpp-0.8.1/build/libsockpp.so bin/lib/
ln -vs ../../dependencies/sockpp-0.8.1/build/libsockpp.so.0 bin/lib/
ln -vs ../../dependencies/sockpp-0.8.1/build/libsockpp.so.0.8.1 bin/lib/
fi
ln -vs ../dependencies/sockpp-0.7.1/include/sockpp/ ./include/
ln -vs ../dependencies/sockpp-0.8.1/include/sockpp/ ./include/
ln -vs ../dependencies/tiny-utf8-4.4.3/include/tinyutf8/ ./include/
ln -vs ../dependencies/zlib-1.3.1/ ./include/zlib
create_file ./bin/.placeholder
create_file ./include/.placeholder

View File

@ -17,6 +17,7 @@
source scripts/lib.sh
#TODO: move this to download.sh
echo ">>> Checking download cache for unneeded or corrupted files..."
for file in $(ls .download_cache); do
#TODO: remove if unknown shasum
@ -35,6 +36,6 @@ done
echo "
>>> Cleaning dependencies..."
remove ./dependencies
remove -f ./dependencies
create_directory ./dependencies
create_file ./dependencies/.placeholder

61
scripts/download.sh Executable file
View File

@ -0,0 +1,61 @@
if [ "$#" -lt 3 -o "$#" -gt 3 ]; then
echo "Usage: $0 URL DESTINATION SHA256SUM"
exit 1
fi
source scripts/lib.sh
URL="$1"
DESTINATION="$2"
SHA256SUM="$3"
if command -v wget >/dev/null 2>&1; then
USE_WGET=yes
else
if command -v curl >/dev/null 2>&1; then
USE_WGET=no
else
echo "Found neither wget nor curl. Aborting."
exit 1
fi
fi
if [ ! -d .download_cache ]; then
echo "Cache directory missing."
create_directory .download_cache
fi
#TODO: keep track of which cached file is downloaded to which destination
#TODO: when downloading a file with a new hash to the same destination, mark the old one as no longer in use
#TODO: if there is an even older one for the same download path, delete it
#TODO: remove cache maintenance from clean_dependencies
if [ -f ".download_cache/$SHA256SUM" ]; then
if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then
echo "Using locally cached file for $DESTINATION"
cp ".download_cache/$SHA256SUM" "$DESTINATION"
exit 0
else
echo "Locally cached file for $DESTINATION is corrupted."
rm ".download_cache/$SHA256SUM"
$0 "$URL" "$DESTINATION" "$SHA256SUM"
exit $?
fi
else
echo -n "Downloading $URL to $DESTINATION... "
if [ $USE_WGET = yes ]; then
wget -O ".download_cache/$SHA256SUM" "$URL" >/dev/null 2>&1
else
curl -L "$URL" --output ".download_cache/$SHA256SUM" >/dev/null 2>&1
fi
if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then
cp ".download_cache/$SHA256SUM" "$DESTINATION"
echo "done."
exit 0
else
echo "error."
echo "Checksum verification failed. Your download is either corrupted or the file has been altered. Removing file."
rm ".download_cache/$SHA256SUM"
exit 1
fi
fi

15
scripts/lib.sh Normal file → Executable file
View File

@ -57,11 +57,18 @@ fi
# `rm -v` only prints the names of the removed things instead of a more
# comprehensible message like "removing NAME".
function remove {
echo "Removing $1..."
if [ -d "$1" ]; then
rm -rv "$1"
local USE_FORCE=""
if [ "$1" = "-f" ]; then
USE_FORCE="f"
shift
echo "Forcefully removing $1..."
else
rm -v "$1"
echo "Removing $1..."
fi;
if [ -d "$1" ]; then
rm -"$USE_FORCE"rv "$1"
else
rm -"$USE_FORCE"v "$1"
fi
}

View File

@ -17,68 +17,19 @@
source scripts/lib.sh
echo -n "Wget or curl? "
if command -v wget >/dev/null 2>&1; then
USE_WGET=yes
echo "wget"
else
if command -v curl >/dev/null 2>&1; then
USE_WGET=no
echo "curl"
else
echo "Found neither wget nor curl. Aborting."
exit 1
fi
fi
function download {
URL="$1"
DESTINATION="$2"
SHA256SUM="$3"
if [ ! -d .download_cache ]; then
echo "Cache directory missing."
create_directory .download_cache
fi
if [ -f ".download_cache/$SHA256SUM" ]; then
if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then
echo "Using locally cached file for $DESTINATION"
cp ".download_cache/$SHA256SUM" "$DESTINATION"
return 0
else
echo "Locally cached file for $DESTINATION is corrupted."
rm ".download_cache/$SHA256SUM"
download "$URL" "$DESTINATION" "$SHA256SUM"
return $?
fi
else
echo -n "Downloading $URL to $DESTINATION... "
if [ $USE_WGET = yes ]; then
wget -O ".download_cache/$SHA256SUM" "$URL" >/dev/null 2>&1
else
curl -L "$URL" --output ".download_cache/$SHA256SUM" >/dev/null 2>&1
fi
if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then
cp ".download_cache/$SHA256SUM" "$DESTINATION"
echo "done."
return 0
else
echo "error."
echo "Checksum verification failed. Your download is either corrupted or the file has been altered. Removing file."
rm ".download_cache/$SHA256SUM"
return 1
fi
fi
}
scripts/clean.sh
scripts/clean_dependencies.sh
set -e # failures are not acceptable here
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/fpagliughi/sockpp/archive/refs/tags/v0.7.1.tar.gz dependencies/tmp/sockpp.tar.gz 2e023528bebbd2ac083fc91fbe6d5c4158c3336bedbcff48f594f3b28f53b940
scripts/download.sh https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f
scripts/download.sh https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.8.1.tar.gz dependencies/tmp/sockpp.tar.gz a8aedff8bd8c1da530b91be650352008fddabc9f1df0d19701d76cbc359c8651
scripts/download.sh https://www.zlib.net/zlib-1.3.1.tar.xz dependencies/tmp/zlib.tar.xz 38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32
#TODO: figure out how to cache shaderc
#also TODO: target a specific commit
git clone --branch known-good https://github.com/google/shaderc.git dependencies/tmp/shaderc
#scripts/download.sh https://github.com/google/shaderc/archive/refs/tags/v2023.7.tar.gz dependencies/tmp/shaderc.tar.gz 681e1340726a0bf46bea7e31f10cbfe78e01e4446a35d90fedc2b78d400fcdeb
echo -n ">>> Extracting tiny-utf8... "
gzip -d dependencies/tmp/tiny-utf8.tar.gz
@ -90,11 +41,60 @@ gzip -d dependencies/tmp/sockpp.tar.gz
tar -xf dependencies/tmp/sockpp.tar -C dependencies
echo "done"
echo ">>> Building sockpp... "
pushd dependencies/sockpp-0.7.1/ >/dev/null 2>&1
cmake -Bbuild .
cmake --build build
echo -n ">>> Extracting zlib... "
xz -d dependencies/tmp/zlib.tar.xz
tar -xf dependencies/tmp/zlib.tar -C dependencies
echo "done"
echo ">>> Building sockpp..."
pushd dependencies/sockpp-0.8.1/ >/dev/null 2>&1
if uname -s | tr [:upper:] [:lower:] | grep cygwin >/dev/null; then
echo "Adding Cygwin workaound for building sockpp."
#for FILE in "$(find ./ -type f)"; do
# sed -i -e 's/_WIN32/PLEASE_DO_NOT_DEFINE_THIS_MACRO/g' $FILE
#done
#mv ./include/sockpp/socket.h ./include/sockpp/socket.h_original
#echo '#include <sys/time.h>
##include "socket.h_original"' > ./include/sockpp/socket.h
sed -i -e 's/SO_REUSEPORT/SO_REUSEADDR/g' ./src/acceptor.cpp
#CFLAGS="-D_XOPEN_SOURCE=700" CXXFLAGS="-D_XOPEN_SOURCE=700" cmake -Bbuild
#CFLAGS="-D_XOPEN_SOURCE=700" CXXFLAGS="-D_XOPEN_SOURCE=700" cmake --build build
cmake -Bbuild .
cmake --build build
else
cmake -Bbuild .
cmake --build build
fi
popd >/dev/null 2>&1
echo ">>> done"
echo ">>> Dealing with shaderc shenanigans..."
pushd dependencies/tmp/shaderc
echo "Getting sources using the provided script..."
./update_shaderc_sources.py
SHADERC_BUILD="build-$(dd if=/dev/urandom bs=1 count=5 2>/dev/null | base32)"
echo "Creating and entering directory $SHADERC_BUILD."
mkdir "$SHADERC_BUILD"
cd "$SHADERC_BUILD"
echo "Running CMake..."
CXXFLAGS="-Wno-error" cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../src/
echo "Running Ninja..."
ninja
popd >/dev/null 2>&1
#if needed copy more relevant files to dependencies/shaderc
echo "Copying binary to dependencies/shaderc/bin..."
mkdir -vp dependencies/shaderc/bin
cp -v "dependencies/tmp/shaderc/$SHADERC_BUILD/glslc/glslc" dependencies/shaderc/bin
echo ">>> done"
echo ">>> Building zlib..."
pushd dependencies/zlib-1.3.1/
./configure
make
popd
echo "done"
echo ">>> Cleaning up..."
remove dependencies/tmp
remove -f dependencies/tmp

View File

@ -33,12 +33,13 @@ echo ">>> Building tests..."
# add compile commands to this array
COMPILE_COMMANDS=(
"$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/nbt_read_write_helpers.cpp -I./include -Lbin/lib -l:nbt.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/javacompat.cpp -I./include -Lbin/lib -l:javacompat.so -o bin/test/javacompat"
"$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"
"$CXX_WITH_FLAGS src/test/javacompat.cpp -I./include -Lbin/lib -o bin/test/javacompat"
"$CXX_WITH_FLAGS src/test/nbt_tags.cpp -I./include -Lbin/lib -l:nbt.so -o bin/test/nbt_tags"
"$CXX_WITH_FLAGS src/test/nbt_size_helpers.cpp -I./include -Lbin/lib -l:nbt.so -o bin/test/nbt_size_helpers"
"$CXX_WITH_FLAGS src/test/file.cpp -I./include -Lbin/lib -l:file.so -o bin/test/file"
"$CXX_WITH_FLAGS src/test/varint.cpp -I./include -Lbin/lib -o bin/test/varint"
)
for command in ${!COMPILE_COMMANDS[@]}; do
echo "${COMPILE_COMMANDS[command]}"

11
scripts/test/arraydump.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
echo "================================================================================"
echo -n "Testing \`arraydump\`... "
[ -x bin/tools/arraydump ] \
&& [ "$(bin/tools/arraydump resources/all_bytes)" = "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255}" ] \
&& [ "$(bin/tools/arraydump --hexadecimal resources/all_bytes)" = "{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}" ] \
&& [ "$(bin/tools/arraydump --octal resources/all_bytes)" = "{0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377}" ] \
&& [ "$(bin/tools/arraydump --binary resources/all_bytes)" = "{0b00000000, 0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101, 0b00000110, 0b00000111, 0b00001000, 0b00001001, 0b00001010, 0b00001011, 0b00001100, 0b00001101, 0b00001110, 0b00001111, 0b00010000, 0b00010001, 0b00010010, 0b00010011, 0b00010100, 0b00010101, 0b00010110, 0b00010111, 0b00011000, 0b00011001, 0b00011010, 0b00011011, 0b00011100, 0b00011101, 0b00011110, 0b00011111, 0b00100000, 0b00100001, 0b00100010, 0b00100011, 0b00100100, 0b00100101, 0b00100110, 0b00100111, 0b00101000, 0b00101001, 0b00101010, 0b00101011, 0b00101100, 0b00101101, 0b00101110, 0b00101111, 0b00110000, 0b00110001, 0b00110010, 0b00110011, 0b00110100, 0b00110101, 0b00110110, 0b00110111, 0b00111000, 0b00111001, 0b00111010, 0b00111011, 0b00111100, 0b00111101, 0b00111110, 0b00111111, 0b01000000, 0b01000001, 0b01000010, 0b01000011, 0b01000100, 0b01000101, 0b01000110, 0b01000111, 0b01001000, 0b01001001, 0b01001010, 0b01001011, 0b01001100, 0b01001101, 0b01001110, 0b01001111, 0b01010000, 0b01010001, 0b01010010, 0b01010011, 0b01010100, 0b01010101, 0b01010110, 0b01010111, 0b01011000, 0b01011001, 0b01011010, 0b01011011, 0b01011100, 0b01011101, 0b01011110, 0b01011111, 0b01100000, 0b01100001, 0b01100010, 0b01100011, 0b01100100, 0b01100101, 0b01100110, 0b01100111, 0b01101000, 0b01101001, 0b01101010, 0b01101011, 0b01101100, 0b01101101, 0b01101110, 0b01101111, 0b01110000, 0b01110001, 0b01110010, 0b01110011, 0b01110100, 0b01110101, 0b01110110, 0b01110111, 0b01111000, 0b01111001, 0b01111010, 0b01111011, 0b01111100, 0b01111101, 0b01111110, 0b01111111, 0b10000000, 0b10000001, 0b10000010, 0b10000011, 0b10000100, 0b10000101, 0b10000110, 0b10000111, 0b10001000, 0b10001001, 0b10001010, 0b10001011, 0b10001100, 0b10001101, 0b10001110, 0b10001111, 0b10010000, 0b10010001, 0b10010010, 0b10010011, 0b10010100, 0b10010101, 0b10010110, 0b10010111, 0b10011000, 0b10011001, 0b10011010, 0b10011011, 0b10011100, 0b10011101, 0b10011110, 0b10011111, 0b10100000, 0b10100001, 0b10100010, 0b10100011, 0b10100100, 0b10100101, 0b10100110, 0b10100111, 0b10101000, 0b10101001, 0b10101010, 0b10101011, 0b10101100, 0b10101101, 0b10101110, 0b10101111, 0b10110000, 0b10110001, 0b10110010, 0b10110011, 0b10110100, 0b10110101, 0b10110110, 0b10110111, 0b10111000, 0b10111001, 0b10111010, 0b10111011, 0b10111100, 0b10111101, 0b10111110, 0b10111111, 0b11000000, 0b11000001, 0b11000010, 0b11000011, 0b11000100, 0b11000101, 0b11000110, 0b11000111, 0b11001000, 0b11001001, 0b11001010, 0b11001011, 0b11001100, 0b11001101, 0b11001110, 0b11001111, 0b11010000, 0b11010001, 0b11010010, 0b11010011, 0b11010100, 0b11010101, 0b11010110, 0b11010111, 0b11011000, 0b11011001, 0b11011010, 0b11011011, 0b11011100, 0b11011101, 0b11011110, 0b11011111, 0b11100000, 0b11100001, 0b11100010, 0b11100011, 0b11100100, 0b11100101, 0b11100110, 0b11100111, 0b11101000, 0b11101001, 0b11101010, 0b11101011, 0b11101100, 0b11101101, 0b11101110, 0b11101111, 0b11110000, 0b11110001, 0b11110010, 0b11110011, 0b11110100, 0b11110101, 0b11110110, 0b11110111, 0b11111000, 0b11111001, 0b11111010, 0b11111011, 0b11111100, 0b11111101, 0b11111110, 0b11111111}" ] \
&& echo "PASS" \
|| echo "FAIL"
echo "================================================================================"

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 "================================================================================"

16
scripts/test/dumpnbt.sh Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
echo "================================================================================"
echo -n "Testing \`dumpnbt\`... "
[ "$(dumpnbt resources/NBT_data/bare_int64_tag)" = "$(cat resources/NBT_data/bare_int64_tag.dumpnbt_out)" ] \
&& [ "$(dumpnbt resources/NBT_data/bare_int64_tag_and_int32_tag)" = "$(cat resources/NBT_data/bare_int64_tag_and_int32_tag.dumpnbt_out)" ] \
&& [ "$(dumpnbt resources/NBT_data/servers.dat)" = "$(cat resources/NBT_data/servers.dat.dumpnbt_out)" ] \
&& [ "$(dumpnbt resources/NBT_data/simple_nbt)" = "$(cat resources/NBT_data/simple_nbt.dumpnbt_out)" ] \
&& [ "$(dumpnbt resources/NBT_data/nested_compounds_and_lists)" = "$(cat resources/NBT_data/nested_compounds_and_lists.dumpnbt_out)" ] \
&& [ "$(dumpnbt resources/NBT_data/level.dat_decompressed)" = "$(cat resources/NBT_data/level.dat_decompressed.dumpnbt_out)" ] \
&& [ "$(dumpnbt resources/NBT_data/arrays_inside_lists)" = "$(cat resources/NBT_data/arrays_inside_lists.dumpnbt_out)" ] \
&& echo "PASS" \
|| echo "FAIL"
echo "================================================================================"
#TODO: test with compressed NBT files

46
scripts/test/zlibutil.sh Executable file
View File

@ -0,0 +1,46 @@
#!/usr/bin/env bash
echo "================================================================================"
echo "Testing \`zlibutil\`:"
echo "--------------------------------------------------------------------------------"
TMPDIR="$(mktemp -d -t fossvg-zlibutil-XXXXX)"
TMPDATA="$(dd if=/dev/urandom bs=33 count=1 2>/dev/null | base64)"
echo -n "Compression test... "
echo -n "$TMPDATA" >> "$TMPDIR/compress"
zlibutil "$TMPDIR/compress"
python3 <<< "
import zlib, sys
tmpfile = open('$TMPDIR/compress.zz', 'rb')
data = tmpfile.read()
tmpfile.close()
try:
if zlib.decompress(data)==b'$TMPDATA':
print('PASS')
else:
print('FAIL: Wrong data.')
except:
print('FAIL: Exception.')
"
echo -n "Decompression test... "
#TODO: create a compressed file using another implementation (Python)
python3 <<< "
import zlib
tmpfile = open('$TMPDIR/decompress.zz', 'wb')
tmpfile.write(zlib.compress(b'$TMPDATA'))
tmpfile.close()
"
zlibutil -d "$TMPDIR/decompress.zz"
if [ "$(cat "$TMPDIR/decompress")" = "$TMPDATA" ]; then
echo "PASS"
else
echo "FAIL"
fi
rm -r "$TMPDIR"
echo "================================================================================"

View File

View File

@ -13,9 +13,15 @@
# version 3 along with this program.
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
echo -n "Loading shell environment for FOSS-VG development... "
echo ">>> Loading shell environment for FOSS-VG development..."
PROJECT_BASE_DIR="$( cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 ; pwd -P )"
export PROJECT_BASE_DIR="$( cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 ; pwd -P )"
echo "Project base directory is $PROJECT_BASE_DIR"
if [ -f "$PROJECT_BASE_DIR/.localenv.bashrc" ]; then
source "$PROJECT_BASE_DIR/.localenv.bashrc"
echo "Applied local environment customizations."
fi
alias clean="pushd \"$PROJECT_BASE_DIR\" >/dev/null 2>&1; scripts/clean.sh; popd >/dev/null 2>&1"
alias clean_dependencies="pushd \"$PROJECT_BASE_DIR\" >/dev/null 2>&1; scripts/clean_dependencies.sh; popd >/dev/null 2>&1"
@ -33,15 +39,79 @@ function build {
popd >/dev/null 2>&1
}
echo "Added aliases and functions."
export PATH="$PROJECT_BASE_DIR/bin:$PROJECT_BASE_DIR/bin/tools:$PROJECT_BASE_DIR/scripts/tools:$PATH"
if uname -s | tr [:upper:] [:lower:] | grep cygwin >/dev/null; then
echo "Adding Cygwin workaound for library path."
export PATH="$PROJECT_BASE_DIR/bin/lib:$PATH"
fi
echo "PATH is $PATH"
if [ -z "$LD_LIBRARY_PATH" ]; then
export LD_LIBRARY_PATH="$PROJECT_BASE_DIR"/bin/lib
else
export LD_LIBRARY_PATH="$PROJECT_BASE_DIR"/bin/lib:"$LD_LIBRARY_PATH"
fi
echo "LD_LIBRARY_PATH is $LD_LIBRARY_PATH"
if [ -f "$PROJECT_BASE_DIR/.localenv.bashrc" ]; then
source "$PROJECT_BASE_DIR/.localenv.bashrc"
echo ">>> Checking for dependencies..."
MISSING_DEPS=0
if command -v wget > /dev/null 2>&1; then
true
else
if command -v curl > /dev/null 2>&1; then
true
else
echo "WARNING: \`wget\` or \`curl\` is needed to download some additional dependencies."
MISSING_DEPS=1
fi
fi
echo "done."
if command -v sha256sum > /dev/null 2>&1; then
true
else
if command -v sha256 > /dev/null 2>&1; then
true
else
echo "WARNING: Coreutils \`sha256sum\` or a \`sha256\` as found on NetBSD is needed to verify downloaded files."
MISSING_DEPS=1
fi
fi
if command -v gzip > /dev/null 2>&1; then
true
else
echo "WARNING: \`gzip\` is needed to decompress downloaded dependencies."
MISSING_DEPS=1
fi
if command -v tar > /dev/null 2>&1; then
true
else
echo "WARNING: \`tar\` is needed to unpack downloaded dependencies."
MISSING_DEPS=1
fi
if command -v cmake > /dev/null 2>&1; then
true
else
echo "WARNING: \`cmake\` is needed to build downloaded dependencies."
MISSING_DEPS=1
fi
if [ -z "$CXX" ]; then
if command -v c++ > /dev/null 2>&1; then
true
else
echo "WARNING: Your system does not appear to have a standard C++ compiler. If you have a C++ compiler installed, but not linked to \`c++\` on your PATH, set it manually using \`CXX=/path/to/your/compiler\`."
MISSING_DEPS=1
fi
fi
if [ "$MISSING_DEPS" -eq 0 ]; then
echo "All set."
fi
unset MISSING_DEPS

150
src/fossvg.cpp Normal file
View File

@ -0,0 +1,150 @@
// 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 <iostream>
#include <vector>
#include <cstdint>
#include <string>
#define GLFW_INCLUDE_VULKAN
extern "C" {
#include <GLFW/glfw3.h>
}
#include "./lib/cli.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
uint32_t windowWidth = 1366;
uint32_t windowHeight = 768;
//TODO: check the TODO above glfwInit() in void main()
// #### Callbacks ##############################################################
void cursorPositionCallback([[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double x, [[maybe_unused]] double y) {
}
void keyCallback([[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int32_t key, [[maybe_unused]] int32_t scancode, [[maybe_unused]] int32_t action, [[maybe_unused]] int32_t mods) {
}
void textInputCallback([[maybe_unused]] GLFWwindow* window, [[maybe_unused]] uint32_t codepoint) {
}
void cursorEnterLeaveCallback([[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int32_t entered) {
}
void mouseButtonCallback([[maybe_unused]] GLFWwindow* window, [[maybe_unused]] int32_t button, [[maybe_unused]] int32_t action, [[maybe_unused]] int32_t mods) {
}
void scrollCallback([[maybe_unused]] GLFWwindow* window, [[maybe_unused]] double x, [[maybe_unused]] double y) {
}
// #### End Callbacks ##########################################################
int main(int argc, char* argv[]) {
std::vector<CLI::Flag> flags;
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;
options.push_back(CLI::Option('x', "window-width", "PIXELS", "window width on startup"));
options.push_back(CLI::Option('y', "window-height", "PIXELS", "window height on startup"));
std::vector<CLI::Argument> arguments;
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "FOSS-VG Client");
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"
<< "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;
}
if (cliParser.getOption("window-width").errorCode != ErrorCodes::NOT_PRESENT) {
windowWidth = std::stoi(cliParser.getOption("window-width").value);
}
if (cliParser.getOption("window-height").errorCode != ErrorCodes::NOT_PRESENT) {
windowHeight = std::stoi(cliParser.getOption("window-height").value);
}
// TODO: Find a better place for this
// Ideally, the window management and rendering portion of FOSS-VG should
// live in a library so it can be easily reloaded/restarted for things like
// switching from/to fullscreen. For now, I am going to put it here because
// I want to get it going before making it pretty.
{
if (!glfwInit()) {
return EXIT_RUNTIME;
}
// do not create OpenGL context
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
//TODO: add a version macro
// (for example Git commit hash passed on the compiler command line)
std::string windowTitle = "FOSS-VG";
// Apparently, this also allows to set things like whether the window is full-screen
GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, windowTitle.c_str(), nullptr, nullptr);
if (window == nullptr) {
return EXIT_RUNTIME;
}
glfwSetCursorPosCallback(window, cursorPositionCallback);
glfwSetKeyCallback(window, keyCallback);
glfwSetCharCallback(window, textInputCallback);
glfwSetCursorEnterCallback(window, cursorEnterLeaveCallback);
glfwSetMouseButtonCallback(window, mouseButtonCallback);
glfwSetScrollCallback(window, scrollCallback);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
}
return EXIT_SUCCESS;
}

67
src/fossvgd.cpp Normal file
View File

@ -0,0 +1,67 @@
// 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 <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('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;
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "FOSS-VG Server");
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"
<< "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;
}
return EXIT_SUCCESS;
}

View File

@ -1,5 +1,8 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
@ -199,7 +202,6 @@ namespace CLI {
}
ArgumentsParser::~ArgumentsParser() {
//TODO: check that this actually runs
for (auto const& [shortName, flag]: this->flagsByShortName) {
delete flag;
}
@ -318,6 +320,10 @@ namespace CLI {
}
}
if (this->additionalInfo != "") {
usageString += "\nAdditional Info:\n\n\t" + this->additionalInfo + "\n";
}
return usageString;
}
}

View File

@ -17,43 +17,54 @@
#include <cstdint>
//TODO: needed macros:
// TRY: takes a variable, a function call, and the ErrorOr return type of the calling function - intended to automatically unwrap the ErrorOr data type or propagate the error upwards
// RAISE: takes an error code and optionally a message to produce something like `return ErrorOr<T>(true, errorCode, file, lineNumber, message)`
template <typename T>
struct ErrorOr {
bool isError;
uint8_t errorCode;
T value;
ErrorOr();
ErrorOr(T);
ErrorOr(bool, uint8_t);
ErrorOr(bool, uint8_t, T);
ErrorOr() {
this->isError = false;
this->errorCode = 0;
}
ErrorOr(T value) {
this->isError = false;
this->errorCode = 0;
this->value = value;
}
ErrorOr(bool isError, uint8_t errorCode) {
this->isError = isError;
this->errorCode = errorCode;
}
ErrorOr(bool isError, uint8_t errorCode, T value) {
this->isError = isError;
this->errorCode = errorCode;
this->value = value;
}
};
template <typename T>
ErrorOr<T>::ErrorOr() {
this->isError = false;
this->errorCode = 0;
}
struct ErrorOrVoid {
bool isError;
uint8_t errorCode;
template <typename T>
ErrorOr<T>::ErrorOr(T value) {
this->isError = false;
this->errorCode = 0;
this->value = value;
}
ErrorOrVoid() {
this->isError = false;
this->errorCode = 0;
}
template <typename T>
ErrorOr<T>::ErrorOr(bool isError, uint8_t errorCode) {
this->isError = isError;
this->errorCode = errorCode;
}
template <typename T>
ErrorOr<T>::ErrorOr(bool isError, uint8_t errorCode, T value) {
this->isError = isError;
this->errorCode = errorCode;
this->value = value;
}
ErrorOrVoid(bool isError, uint8_t errorCode) {
this->isError = isError;
this->errorCode = errorCode;
}
};
namespace ErrorCodes {
// These are all arbitrary values used to assign error codes to different
@ -64,13 +75,10 @@ namespace ErrorCodes {
// Ahh yes, very useful.
const uint8_t SUCCESS = 0;
// IndexOutOfRangeException equivalent
const uint8_t OUT_OF_RANGE = 1;
// when going out of bounds in a non-predetermined way
// like OUT_OF_RANGE but when going out of bounds in a non-predetermined way
const uint8_t OVERRUN = 2;
// when checking for presence of something, for example CLI arguments
const uint8_t NOT_PRESENT = 3;
const uint8_t WRONG_USAGE = 4;
@ -83,6 +91,23 @@ namespace ErrorCodes {
const uint8_t NOT_YET_KNOWN = 7;
const uint8_t INVALID_TYPE = 8;
const uint8_t FILE_NOT_OPEN = 9;
const uint8_t FILE_NOT_FOUND = 10;
// when performing an operation that would technically be valid but must
// never be performed (like deleting an end tag from an NBT compound)
const uint8_t NOT_ALLOWED = 11;
const uint8_t MIXED_TYPES = 12;
// when too much data is available
const uint8_t OVERFLOW = 13;
const uint8_t COMPRESSION = 14;
const uint8_t DECOMPRESSION = 15;
const uint8_t UNIMPLEMENTED = 254;
const uint8_t UNKNOWN = 255;

326
src/lib/file.cpp Normal file
View File

@ -0,0 +1,326 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// Bodgemaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <fstream>
#include <filesystem>
#include <exception>
#include <vector>
#include <string>
#include "tinyutf8/tinyutf8.h"
#include "file.hpp"
File::File(std::string path, char mode, uint64_t cursorPosition): mode(mode), path(path), cursorPosition(cursorPosition){
std::filesystem::path filePath = path;
if(this->mode == 'w' || (this->mode == 'a' && !std::filesystem::exists(filePath))){
this->size = ErrorOr<uint64_t>(0);
}else{
this->size = ErrorOr<uint64_t>(std::filesystem::file_size(filePath));
}
this->open();
}
File::~File() {
if (this->isOpen) {
this->fileStream.close();
}
}
void File::open(){
switch(this->mode){
case 'w':
this->fileStream.open(this->path, std::fstream::out | std::fstream::binary);
break;
case 'm':
this->fileStream.open(this->path, std::fstream::out | std::fstream::in | std::fstream::binary);
break;
case 'r':
this->fileStream.open(this->path, std::fstream::in | std::fstream::binary);
break;
case 'a':
this->fileStream.open(this->path, std::fstream::app | std::fstream::binary);
break;
default:
break;
}
std::filesystem::path filePath = this->path;
this->size = ErrorOr<uint64_t>(std::filesystem::file_size(filePath));
this->isOpen = this->fileStream.is_open();
}
void File::close(){
this->fileStream.close();
std::filesystem::path filePath = this->path;
this->size = ErrorOr<uint64_t>(std::filesystem::file_size(filePath));
this->isOpen = false;
}
bool File::eof() {
return !this->size.isError && this->cursorPosition >= this->size.value;
}
ErrorOr<uint8_t> File::readByte(){
if (!this->isOpen) {
return ErrorOr<uint8_t>(true, ErrorCodes::FILE_NOT_OPEN);
}
if (!this->size.isError && this->cursorPosition >= this->size.value) {
return ErrorOr<uint8_t>(true, ErrorCodes::OVERRUN);
}
uint8_t* nextPointer = new uint8_t;
uint8_t nextByte;
bool failure = false;
try {
this->fileStream.seekg(this->cursorPosition);
this->fileStream.read(reinterpret_cast<char*>(nextPointer), 1);
nextByte = *nextPointer;
this->cursorPosition++;
} catch (std::exception& e) {
failure = true;
}
delete nextPointer;
return failure? ErrorOr<uint8_t>(true, ErrorCodes::UNKNOWN) : ErrorOr<uint8_t>(nextByte);
}
ErrorOr<std::vector<uint8_t>> File::read(uint64_t bytes){
if (!this->isOpen) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::FILE_NOT_OPEN);
}
if (!this->size.isError && this->cursorPosition >= this->size.value+bytes) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::OVERRUN);
}
uint8_t* buffer = new uint8_t[bytes];
std::vector<uint8_t> data;
bool failure = false;
try {
this->fileStream.seekg(this->cursorPosition);
this->fileStream.read(reinterpret_cast<char*>(buffer), bytes);
data = std::vector<uint8_t>(buffer, buffer+bytes);
this->cursorPosition += bytes;
} catch (std::exception& e) {
failure = true;
}
delete[] buffer;
return failure? ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::UNKNOWN) : ErrorOr<std::vector<uint8_t>>(data);
}
ErrorOr<tiny_utf8::string> File::readString(uint64_t bytes){
ErrorOr<std::vector<uint8_t>> data = this->read(bytes);
if(data.isError){
return ErrorOr<tiny_utf8::string>(true, data.errorCode);
}
std::string s;
for(auto byte: data.value){
s.push_back(byte);
}
return ErrorOr<tiny_utf8::string>(tiny_utf8::string(s));
}
ErrorOrVoid File::writeByte(uint8_t byte){
bool failure = false;
try{
this->fileStream << byte;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid();
}
ErrorOrVoid File::write(std::vector<uint8_t> data){
bool failure = false;
try{
this->fileStream << std::string(data.begin(), data.end());
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid();
}
ErrorOrVoid File::writeString(tiny_utf8::string data){
bool failure = false;
try{
this->fileStream << data;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid();
}
// Naive implementation of insertByte
ErrorOrVoid File::insertByte(uint8_t byte){
bool failure = false;
try{
uint8_t* buffer = new uint8_t[this->size.value];
std::vector<uint8_t> readData;
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
readData = std::vector<uint8_t>(buffer, buffer+this->size.value);
readData.insert(readData.begin()+this->cursorPosition, byte);
this->fileStream.seekg(0);
this->write(readData);
this->cursorPosition++;
delete[] buffer;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid();
}
ErrorOrVoid File::insert(std::vector<uint8_t> data){
bool failure = false;
try{
uint8_t* buffer = new uint8_t[this->size.value];
std::vector<uint8_t> readData;
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
readData = std::vector<uint8_t>(buffer, buffer+this->size.value);
readData.insert(readData.begin()+this->cursorPosition, data.begin(), data.end());
this->fileStream.seekg(0);
this->write(readData);
this->cursorPosition += data.size();
delete[] buffer;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid();
}
ErrorOrVoid File::insertString(tiny_utf8::string string){
bool failure = false;
try{
uint8_t* buffer = new uint8_t[this->size.value];
tiny_utf8::string readData;
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
readData = tiny_utf8::string((char *) buffer, 0, this->size.value);
readData.insert(readData.begin()+this->cursorPosition, string);
this->fileStream.seekg(0);
this->writeString(readData);
this->cursorPosition += string.size();
delete[] buffer;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOrVoid(true, ErrorCodes::UNKNOWN) : ErrorOrVoid();
}
ErrorOr<uint8_t> File::cutByte(){
bool failure = false;
uint8_t byte;
try{
uint8_t* buffer = new uint8_t[this->size.value];
std::vector<uint8_t> readData;
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
readData = std::vector<uint8_t>(buffer, buffer+this->size.value);
byte = readData[this->cursorPosition];
readData.erase(readData.begin() + this->cursorPosition);
std::filesystem::resize_file(this->path, readData.size());
this->fileStream.seekg(0);
this->write(readData);
//this->cursorPosition++;
delete[] buffer;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOr<uint8_t>(true, ErrorCodes::UNKNOWN) : ErrorOr<uint8_t>(byte);
}
ErrorOr<std::vector<uint8_t>> File::cut(uint64_t length){
bool failure = false;
std::vector<uint8_t> bytes;
try{
uint8_t* buffer = new uint8_t[this->size.value];
std::vector<uint8_t> readData;
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
readData = std::vector<uint8_t>(buffer, buffer+this->size.value);
bytes = std::vector<uint8_t>(readData.begin() + this->cursorPosition, readData.begin() + (this->cursorPosition + length));
readData.erase(readData.begin() + this->cursorPosition, readData.begin() + (this->cursorPosition + length));
std::filesystem::resize_file(this->path, readData.size());
this->fileStream.seekg(0);
this->write(readData);
//this->cursorPosition += length;
delete[] buffer;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::UNKNOWN) :ErrorOr<std::vector<uint8_t>>(bytes);
}
ErrorOr<tiny_utf8::string> File::cutString(uint64_t length){
bool failure = false;
tiny_utf8::string cutString;
try{
uint8_t* buffer = new uint8_t[this->size.value];
tiny_utf8::string readData;
this->fileStream.read(reinterpret_cast<char*>(buffer), this->size.value);
readData = tiny_utf8::string((char *) buffer, 0, this->size.value);
cutString = readData.substr(this->cursorPosition, length);
std::filesystem::resize_file(this->path, readData.size()-cutString.size());
this->fileStream.seekg(0);
this->writeString(readData.substr(this->cursorPosition+length));
//this->cursorPosition += length;
delete[] buffer;
}catch(std::exception& e){
failure = true;
}
return failure ? ErrorOr<tiny_utf8::string>(true, ErrorCodes::UNKNOWN) : ErrorOr<tiny_utf8::string>(cutString);
}
ErrorOr<File*> File::open(std::string path, char mode, uint64_t startPosition){
if (!std::filesystem::exists(path) && (mode == 'r' || mode == 'm')) {
return ErrorOr<File*>(true, ErrorCodes::FILE_NOT_FOUND, nullptr);
}
//TODO: check access perms
return ErrorOr<File*>(new File(path, mode, startPosition));
}

94
src/lib/file.hpp Normal file
View File

@ -0,0 +1,94 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <cstdint>
#include <string>
#include <fstream>
#include <vector>
#include <tinyutf8/tinyutf8.h>
#include "error.hpp"
class File {
private:
//TODO: add other necessary internals to this section as needed
char mode;
std::fstream fileStream;
//TODO: add other necessary details to the constructor as needed
// For example, the fstream (or whatever mechanism is used) needs
// to be handed over from File::open() to the File object.
//
// Remember to add a destructor to the public section if pointers
// are to be used.
File(std::string path, char mode, uint64_t cursorPosition);
public:
bool isOpen;
std::string path;
uint64_t cursorPosition;
// may be error if not a regular file or size cannot be determined
ErrorOr<uint64_t> size;
File() {};
~File();
void open();
void close();
bool eof();
// only applicable to read and edit modes
// moves the cursor to the right of the read section
ErrorOr<uint8_t> readByte();
ErrorOr<std::vector<uint8_t>> read(uint64_t bytes);
ErrorOr<tiny_utf8::string> readString(uint64_t bytes);
// only applicable to write, modify, append, and edit modes
// in modify and edit modes, overwrite whatever is at the
// cursor position if there is anything there
// moves the cursor to the right of the written section
ErrorOrVoid writeByte(uint8_t byte);
ErrorOrVoid write(std::vector<uint8_t> data);
ErrorOrVoid writeString(tiny_utf8::string string);
// only applicable to modify and edit modes
// insert at cursor position and move other contents to the right
// moves the cursor to the right of the inserted section
ErrorOrVoid insertByte(uint8_t byte);
ErrorOrVoid insert(std::vector<uint8_t> data);
ErrorOrVoid insertString(tiny_utf8::string string);
// only applicable to edit mode
// return the cut section, remove cut section from file
// moves the cursor to the right of where it happened
ErrorOr<uint8_t> cutByte();
ErrorOr<std::vector<uint8_t>> cut(uint64_t length);
ErrorOr<tiny_utf8::string> cutString(uint64_t length);
// modes:
// r (read)
// w (write: overwrite file deleting its previous contents)
// a (append: write to end of file)
// m (modify: write to file modifying its previous contents)
//
// A startPosition of 0xFFFFFFFF is considered to be the end of
// the file whatever its size.
static ErrorOr<File*> open(std::string path, char mode, uint64_t startPosition=0);
};

0
src/lib/game/block.cpp Normal file
View File

103
src/lib/game/block.hpp Normal file
View File

@ -0,0 +1,103 @@
#pragma once
#include <cstdint>
namespace block {
// For internal use only. These are examples, we will probably need
// a different way of assigning IDs in the future but a list should
// be fine for now, I guess.
// I dont know how Minecraft assigns its IDs or if it even matters
// given that it has used string IDs for a while now. We just need an
// internal way to distinguish between classes.
namespace ids {
const uint16_t AIR = 0;
const uint16_t STONE = 1;
}
// These are intended to be combined using bitwise OR.
namespace collisionBehavior {
// Let the block handle it.
// A function on the relevant block class will deal with it.
const uint8_t UNKNOWN = 0b00000000;
// Collision box inhibits movement?
// (stone or stone slab)
const uint8_t SOLID = 0b00000001;
// Does collision box fill entire block?
// (stone or grass block)
//
// The shape of the collision box is part of the relevant block class
// when this bit is unset.
const uint8_t FULL_BLOCK = 0b00000010;
const uint8_t SOLID_FULL_BLOCK = SOLID | FULL_BLOCK;
// Slow down entities when inside the block?
// (vines or soulsand)
//
// Entities are considered to be inside a given block when rounding
// their coordinates results in the coordinates of the block.
//
// The amount of slowdown is controlled by a function on the relevant
// block class.
const uint8_t SLOWDOWN = 0b00000100;
// Slow down entities when touching the collision box of the block?
// (honey block)
//
// The amount of slowdown is controlled by a function on the relevant
// block class.
const uint8_t SURFACE_SLOWDOWN = 0b00001000;
// Deal damage when entities are inside it?
// (berry bush)
//
// Entities are considered to be inside a given block when rounding
// their coordinates results in the coordinates of the block.
//
// The amount of damage is controlled by a function on the relevant
// block class.
const uint8_t DAMAGE = 0b00010000;
// Deal damage when entities touch the collision box?
// (magma block)
//
// The amount of damage is controlled by a function on the relevant
// block class.
const uint8_t SURFACE_DAMAGE = 0b00010000;
// Is the block bouncy?
// (bed or slime block)
//
// The bounciness of the block is handled by the relevant block class.
const uint8_t BOUNCY = 0b00100000;
}
class Generic {
private:
public:
virtual uint16_t id() = 0;
virtual uint8_t collisionBehavior() = 0;
//TODO: (not pure) virtual functions for collision box, slowdown, damage, bounciness, etc.
//TODO: (not pure) virtual function for hitbox (defaults to full block)
}
class Air {
public:
uint16_t id() {
return ids::AIR;
}
uint8_t collisionBehavior() {
// is a full block but doesn't collide or anything else
return collisionBehavior::FULL_BLOCK;
}
}
BlockGeneric* getNewBlockFromID(uint16_t id) {
//TODO
}
}

0
src/lib/game/entity.cpp Normal file
View File

0
src/lib/game/entity.hpp Normal file
View File

View File

@ -1,93 +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
#include <tinyutf8/tinyutf8.h>
#include <string>
#include "error.hpp"
#include "javacompat.hpp"
#include "../../.endianness"
#ifdef FOSSVG_ENDIAN_BIG_WORD
#error "Honeywell-316-style endianness is not supported. If you feel like it should, feel free to participate in the project to maintain it."
#endif
#ifdef FOSSVG_ENDIAN_LITTLE_WORD
#error "PDP-11-style endianness is not supported. If you feel like it should, feel free to participate in the project to maintain it."
#endif
#ifdef FOSSVG_ENDIAN_UNKNOWN
#error "The endianness of your system could not be determined. Please set it manually. FOSS-VG is currently implemented using some endian-specific functions."
#endif
namespace JavaCompat {
ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size) {
std::string stdString;
uint16_t encodedSize = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]);
if(encodedSize != size){
return ErrorOr<tiny_utf8::string>(true, ErrorCodes::MISMATCHEDSIZE);
}
for(uint8_t i=2; i<size+2; i++){
if(i != 0){
if(data[i] == 0x80 && data[i-1] == 0xc0){
stdString[stdString.length() - 1] = '\0';
continue;
}
}
stdString.push_back((char) data[i]);
}
return ErrorOr<tiny_utf8::string>(tiny_utf8::string(stdString));
}
ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string data) {
uint16_t* size = new uint16_t;
uint8_t* sizeBytes = reinterpret_cast<uint8_t*>(size);
std::vector<uint8_t> output = std::vector<uint8_t>();
std::string stdString = data.cpp_str();
if(stdString.size() > 0xFFFF){
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::OVERRUN);
}
*size = (uint16_t) stdString.size();
//placeholder size bytes
output.push_back(0x00);
output.push_back(0x00);
for(uint16_t i=0; i<stdString.size(); i++){
if((uint8_t) stdString[i] == 0x00){
*size += 1;
output.push_back(0xc0);
output.push_back(0x80);
continue;
}
output.push_back(stdString[i]);
}
#ifdef FOSSVG_BIG_ENDIAN
output[0] = *sizeBytes;
output[1] = *(sizeBytes+1);
#else
#ifdef FOSSVG_LITTLE_ENDIAN
output[0] = *(sizeBytes+1);
output[1] = *sizeBytes;
#else
#error "NBT::helper::writeInt16: An implementation for your endianness is unavailable."
#endif
#endif
return ErrorOr(output);
}
}

View File

@ -13,11 +13,83 @@
//version 3 along with this program.
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <vector>
#pragma once
#include <tinyutf8/tinyutf8.h>
#include <string>
#include "error.hpp"
#include "../../.endianness"
#ifdef FOSSVG_ENDIAN_BIG_WORD
#error "Honeywell-316-style endianness is not supported. If you feel like it should, feel free to participate in the project to maintain it."
#endif
#ifdef FOSSVG_ENDIAN_LITTLE_WORD
#error "PDP-11-style endianness is not supported. If you feel like it should, feel free to participate in the project to maintain it."
#endif
#ifdef FOSSVG_ENDIAN_UNKNOWN
#error "The endianness of your system could not be determined. Please set it manually. FOSS-VG is currently implemented using some endian-specific functions."
#endif
namespace JavaCompat {
ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size);
ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string data);
ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size) {
std::string stdString;
uint16_t encodedSize = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]);
if(encodedSize != size){
return ErrorOr<tiny_utf8::string>(true, ErrorCodes::MISMATCHEDSIZE);
}
for(uint16_t i=2; i<size+2; i++){
if(i != 0){
if(data[i] == 0x80 && data[i-1] == 0xc0){
stdString[stdString.length() - 1] = '\0';
continue;
}
}
stdString.push_back((char) data[i]);
}
return ErrorOr<tiny_utf8::string>(tiny_utf8::string(stdString));
}
ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string data) {
uint16_t* size = new uint16_t;
uint8_t* sizeBytes = reinterpret_cast<uint8_t*>(size);
std::vector<uint8_t> output = std::vector<uint8_t>();
std::string stdString = data.cpp_str();
if(stdString.size() > 0xFFFF){
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::OVERRUN);
}
*size = (uint16_t) stdString.size();
//placeholder size bytes
output.push_back(0x00);
output.push_back(0x00);
for(uint16_t i=0; i<stdString.size(); i++){
if((uint8_t) stdString[i] == 0x00){
*size += 1;
output.push_back(0xc0);
output.push_back(0x80);
continue;
}
output.push_back(stdString[i]);
}
//FIXME: endian-dependent implementation
#ifdef FOSSVG_BIG_ENDIAN
output[0] = *sizeBytes;
output[1] = *(sizeBytes+1);
#else
#ifdef FOSSVG_LITTLE_ENDIAN
output[0] = *(sizeBytes+1);
output[1] = *sizeBytes;
#else
#error "JavaCompat::exportJavaString: An implementation for your endianness is unavailable."
#endif
#endif
return ErrorOr(output);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -19,29 +19,31 @@
// NBT tags have a type, optionally a name which consists of the name size and the name string, optionally content type, and optionally a payload which can consist of optionally content type, optionally a content size,
// and the stored content. The format in which they are stored is as follows: <type><name size><name><payload>. All numbers are stored in big endian representation.
// All tag types:
// generic representation: Tag(uint8:tag_type, String:name, uint16:name_size, byte[]:content, int32:size)
// None (compound end): Tag( 0, "", 0, None, 0) => used to determine the end of a compound tag, only the type gets stored
// int8: Tag( 1, String:name, uint16:name_size, int8:content, 1) => a single signed byte, size not stored
// int16: Tag( 2, String:name, uint16:name_size, int16:content, 2) => 16 bit signed integer, size not stored
// int32: Tag( 3, String:name, uint16:name_size, int32:content, 4) => 32 bit signed integer, size not stored
// int64: Tag( 4, String:name, uint16:name_size, int64:content, 8) => 64 bit signed integer, size not stored
// float: Tag( 5, String:name, uint16:name_size, float:content, 4) => 32 bit IEEE754 floating point number, size not stored
// double: Tag( 6, String:name, uint16:name_size, double:content, 8) => 64 bit IEEE754 floating point number, size not stored
// int8[]: Tag( 7, String:name, uint16:name_size, int8[]:content, int32:size) => content stored prefixed with size
// String: Tag( 8, String:name, uint16:name_size, String:content, uint16:size) => Java style modified UTF-8 string, content stored prefixed with size
// Tag[] (list): Tag<Tag:type>( 9, String:name, uint16:name_size, Tag[]:content, int32:size) => list of tags of the same type with tag type and name information omitted prefixed by (in order) content type and size
// Tag[] (compound): Tag(10, String:name, uint16:name_size, Tag[]:content, int32:size) => list of tags, last tag is always an end tag, size not stored
// int32[]: Tag(11, String:name, uint16:name_size, int32[]:content,int32:size) => list of 32 bit signed integers prefixed with its size, endianness not verified at this point
// int64[]: Tag(12, String:name, uint16:name_size, int64[]:content,int32:size) => list of 64 bit signed integers prefixed with its size, endianness not verified at this point
// Generic: Tag(uint8:tag_type, String:name, uint16:name_size, byte[]:content, int32:size)
// End: Tag( 0, "", 0, None, 0) => used to determine the end of a compound tag, only the type gets stored
// Int8: Tag( 1, String:name, uint16:name_size, int8:content, 1) => a single signed byte, size not stored
// Int16: Tag( 2, String:name, uint16:name_size, int16:content, 2) => 16 bit signed integer, size not stored
// Int32: Tag( 3, String:name, uint16:name_size, int32:content, 4) => 32 bit signed integer, size not stored
// Int64: Tag( 4, String:name, uint16:name_size, int64:content, 8) => 64 bit signed integer, size not stored
// Float: Tag( 5, String:name, uint16:name_size, float:content, 4) => 32 bit IEEE754 floating point number, size not stored
// Double: Tag( 6, String:name, uint16:name_size, double:content, 8) => 64 bit IEEE754 floating point number, size not stored
// Int8Array: Tag( 7, String:name, uint16:name_size, int8[]:content, int32:length) => content stored prefixed with size
// String: Tag( 8, String:name, uint16:name_size, String:content, uint16:size) => Java style modified UTF-8 string, content stored prefixed with size
// List: Tag<Tag:type>( 9, String:name, uint16:name_size, Tag[]:content, int32:length) => list of tags of the same type with tag type and name information omitted prefixed by (in order) content type and length
// Compound: Tag(10, String:name, uint16:name_size, Tag[]:content, int32:length) => list of tags, last tag is always an end tag, size not stored
// Int32Array: Tag(11, String:name, uint16:name_size, int32[]:content,int32:length) => list of 32 bit signed integers prefixed with its size
// Int64Array: Tag(12, String:name, uint16:name_size, int64[]:content,int32:length) => list of 64 bit signed integers prefixed with its size
#pragma once
#include <cstdint>
#include <vector>
#include <tinyutf8/tinyutf8.h>
#include <mutex>
#include "error.hpp"
namespace NBT {
namespace helper {
namespace Helper {
ErrorOr<int8_t> readInt8(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
ErrorOr<int16_t> readInt16(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
ErrorOr<int32_t> readInt32(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
@ -61,7 +63,7 @@ namespace NBT {
void writeDouble(std::vector<uint8_t>* destination, double data);
void writeInt8Array(std::vector<uint8_t>* destination, std::vector<int8_t> data);
void writeInt8Array(std::vector<uint8_t>* destination, int8_t data[], uint32_t dataSize);
void writeString(std::vector<uint8_t>* destination, tiny_utf8::string data);
ErrorOrVoid writeString(std::vector<uint8_t>* destination, tiny_utf8::string data);
void writeInt32Array(std::vector<uint8_t>* destination, std::vector<int32_t> data);
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);
@ -72,46 +74,236 @@ namespace NBT {
}
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;
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;
// This is a workaround that's not part of the spec.
const uint8_t INVALID = 255;
}
//Generic parent class to make declaration easier
template <typename T>
class Tag{
public:
uint8_t tagType;
tiny_utf8::string name;
uint16_t nameSize;
T content;
int32_t size;
namespace Tag {
Tag(){}
Tag(uint8_t tagType, tiny_utf8::string name, uint16_t nameSize, T content, uint32_t size);
};
class Generic {
protected:
std::mutex mutex;
uint8_t type;
public:
tiny_utf8::string name;
class End: public Tag<uint8_t>{
public:
End();
};
Generic();
virtual ~Generic();
class Byte: public Tag<int8_t>{
public:
Byte(tiny_utf8::string name, uint16_t nameSize, int8_t content);
Byte(uint8_t data[]);
bool validate(uint8_t data[]);
};
virtual ErrorOrVoid serialize(std::vector<uint8_t>* rawData);
virtual ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData);
uint8_t getTagType();
};
bool validateRawNBTData(uint8_t data[], int length, uint64_t initialPosition=0);
class End: public Generic {
public:
End();
// This needs a separate serializer because
// END tags have a special header.
ErrorOrVoid serialize(std::vector<uint8_t>* rawData) override;
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
};
class Int8: public Generic {
private:
int8_t value;
public:
Int8();
Int8(tiny_utf8::string name, int8_t value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
int8_t getValue();
void setValue(int8_t value);
};
class Int16: public Generic {
private:
int16_t value;
public:
Int16();
Int16(tiny_utf8::string name, int16_t value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
int16_t getValue();
void setValue(int16_t value);
};
class Int32: public Generic {
private:
int32_t value;
public:
Int32();
Int32(tiny_utf8::string name, int32_t value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
int32_t getValue();
void setValue(int32_t value);
};
class Int64: public Generic {
private:
int64_t value;
public:
Int64();
Int64(tiny_utf8::string name, int64_t value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
int64_t getValue();
void setValue(int64_t value);
};
class Float: public Generic {
private:
float value;
public:
Float();
Float(tiny_utf8::string name, float value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
float getValue();
void setValue(float value);
};
class Double: public Generic {
private:
double value;
public:
Double();
Double(tiny_utf8::string name, double value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
double getValue();
void setValue(double value);
};
class Int8Array: public Generic {
private:
std::vector<int8_t> data;
public:
Int8Array();
Int8Array(tiny_utf8::string name, std::vector<int8_t> data);
Int8Array(tiny_utf8::string name, uint64_t length, int8_t data[]);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
std::vector<int8_t> getData();
ErrorOr<int8_t> getValue(uint64_t position);
void setData(std::vector<int8_t> newData);
ErrorOrVoid setValue(uint64_t position, int8_t value);
uint64_t length();
void addElement(int8_t element);
ErrorOrVoid removeElement(uint64_t position);
};
class String: public Generic {
private:
tiny_utf8::string value;
public:
String();
String(tiny_utf8::string name, tiny_utf8::string value);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
tiny_utf8::string getValue();
void setValue(tiny_utf8::string value);
};
class List: public Generic {
private:
std::vector<Generic*> tags;
uint8_t containedType;
List(tiny_utf8::string name, std::vector<Generic*> data);
public:
List();
List(tiny_utf8::string name, uint8_t type);
~List() override;
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
uint8_t getContainedType();
ErrorOr<Generic*> getElementPointer(uint64_t position);
ErrorOrVoid setElementPointerAt(uint64_t position, Generic* pointer);
ErrorOrVoid appendPointer(Generic* pointer);
ErrorOrVoid deleteElement(uint64_t position);
uint64_t length();
static ErrorOr<List*> constructWithData(tiny_utf8::string name, std::vector<Generic*> data);
};
class Compound: public Generic {
private:
std::vector<Generic*> tags;
// built-in end tag
End* endPointer;
Compound(tiny_utf8::string name, std::vector<Generic*> data);
public:
Compound();
Compound(tiny_utf8::string name);
~Compound() override;
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
ErrorOr<Generic*> getElementPointer(uint64_t position);
ErrorOrVoid setElementPointerAt(uint64_t position, Generic* pointer);
ErrorOrVoid appendPointer(Generic* pointer);
ErrorOrVoid deleteElement(uint64_t position);
uint64_t length();
static ErrorOr<Compound*> constructWithData(tiny_utf8::string name, std::vector<Generic*> data);
};
class Int32Array: public Generic {
private:
std::vector<int32_t> data;
public:
Int32Array();
Int32Array(tiny_utf8::string name, std::vector<int32_t> data);
Int32Array(tiny_utf8::string name, uint64_t length, int32_t data[]);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
std::vector<int32_t> getData();
ErrorOr<int32_t> getValue(uint64_t position);
void setData(std::vector<int32_t> newData);
ErrorOrVoid setValue(uint64_t position, int32_t value);
uint64_t length();
void addElement(int32_t element);
ErrorOrVoid removeElement(uint64_t position);
};
class Int64Array: public Generic {
private:
std::vector<int64_t> data;
public:
Int64Array();
Int64Array(tiny_utf8::string name, std::vector<int64_t> data);
Int64Array(tiny_utf8::string name, uint64_t length, int64_t data[]);
ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData) override;
std::vector<int64_t> getData();
ErrorOr<int64_t> getValue(uint64_t position);
void setData(std::vector<int64_t> newData);
ErrorOrVoid setValue(uint64_t position, int64_t value);
uint64_t length();
void addElement(int64_t element);
ErrorOrVoid removeElement(uint64_t position);
};
}
ErrorOr<std::vector<Tag::Generic*>> deserialize(uint8_t data[], uint64_t dataSize, uint64_t initialPosition=0, uint64_t* processedDataSize=nullptr);
bool validateRawNBTData(uint8_t data[], uint64_t dataSize, uint64_t initialPosition=0, uint64_t* processedDataSize=nullptr);
}

View File

@ -0,0 +1,16 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

View File

@ -0,0 +1,42 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <string>
#include "../error.hpp"
namespace network {
struct Connection {
}
// host could be a hostname or address
ErrorOr<Connection> connect(std::string host);
void disconnect(Connection);
// start listening for incoming connections
ErrorOrVoid startListening();
// stop listening for new incoming connections but keep existing
// connections open
void stopListening();
// stop listening for incoming connections and disconnect all
void stopCommunication();
ErrorOr<Connection> acceptNextIncoming();
}

View File

@ -0,0 +1,70 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <cstdint>
#include <vector>
#include "../../error.hpp"
namespace Position {
struct Location {
// 26 bit integer
int32_t x;
// 12 bit integer
int16_t y;
// 26 bit integer
int32_t z;
}
Location fromPosition(uint64_t position) {
Location location;
location.x = (int32_t) ((0xFFFFFFC000000000 & position) >> 38);
if (location.x >= 0x02000000) {
location.x -= 0x04000000;
}
location.y = (int16_t) ((0x0000000000000FFF & position));
if (location.y >= 0x0800) {
location.y -= 0x1000;
}
location.z = (int32_t) ((0x0000003FFFFFF000 & position) >> 12);
if (location.z >= 0x02000000) {
location.z -= 0x04000000;
}
}
ErrorOr<Location> fromPosition(std::vector data, uint64_t initialPosition=0) {
if (inititalPosition >= data.size()) {
return ErrorOr<Location>(true, ErrorCodes::OUT_OF_BOUNDS);
}
if (initialPosition+7 >= data.size()) {
return ErrorOr<Location>(true, ErrorCodes::OVERRUN);
}
uint64_t deserialized = 0;
for (uint8_t i=0; i<8; i++) {
deserialized += (uint64_t) data[initialPosition+i] << i*8;
}
return ErrorOr<Location>(fromPosition(deserialized));
}
}

View File

@ -0,0 +1,141 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <cstdint>
#include <vector>
#include "../../error.hpp"
namespace VarInt {
// up to 5 bytes, least significant byte first, most significant bit
// indicates whether the next byte is still part of the number
ErrorOr<int32_t> fromVar32(std::vector<uint8_t> data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) {
if (initialPosition >= data.size()) {
return ErrorOr<int32_t>(true, ErrorCodes::OUT_OF_RANGE);
}
int32_t returnValue = 0;
uint64_t currentPosition = initialPosition;
uint8_t bits = 0;
while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+4) {
returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits);
(*processedBytes)++;
bits += 7;
currentPosition++;
// check after increasing so we don't need to check outside the loop
if (currentPosition >= data.size()) {
return ErrorOr<int32_t>(true, ErrorCodes::OVERRUN);
}
}
if (data[currentPosition] & 0b10000000) {
return ErrorOr<int32_t>(true, ErrorCodes::OVERFLOW);
}
returnValue = returnValue + (((int32_t) 0b01111111 & data[currentPosition]) << bits);
(*processedBytes)++;
return ErrorOr<int32_t>(returnValue);
}
// up to 10 bytes, least significant byte first, most significant bit
// indicates whether the next byte is still part of the number
ErrorOr<int64_t> fromVar64(std::vector<uint8_t> data, uint64_t initialPosition=0, uint8_t* processedBytes=nullptr) {
if (initialPosition >= data.size()) {
return ErrorOr<int64_t>(true, ErrorCodes::OUT_OF_RANGE);
}
int64_t returnValue = 0;
uint64_t currentPosition = initialPosition;
uint8_t bits = 0;
while (data[currentPosition] & 0b10000000 && currentPosition < initialPosition+9) {
returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits);
(*processedBytes)++;
bits += 7;
currentPosition++;
// check after increasing so we don't need to check outside the loop
if (currentPosition >= data.size()) {
return ErrorOr<int64_t>(true, ErrorCodes::OVERRUN);
}
}
if (data[currentPosition] & 0b10000000) {
return ErrorOr<int64_t>(true, ErrorCodes::OVERFLOW);
}
returnValue = returnValue + (((int64_t) 0b01111111 & data[currentPosition]) << bits);
(*processedBytes)++;
return ErrorOr<int64_t>(returnValue);
}
// appends to the vector
void toVar32(int32_t value, std::vector<uint8_t> &data) {
uint8_t nextByte;
uint8_t shift = 0;
// do something else after the 4th shift
while (shift < 4) {
if (shift>0 && value==0) {
return;
}
nextByte = value & 0b01111111;
value = (value >> 7) & 0x01FFFFFF;
shift++;
if (value>0) {
nextByte = nextByte + 0b10000000;
}
data.push_back(nextByte);
}
if (value>0) {
data.push_back(value & 0b00001111);
}
}
// appends to the vector
void toVar64(int64_t value, std::vector<uint8_t> &data) {
uint8_t nextByte;
uint8_t shift = 0;
// do something else after the 4th shift
while (shift < 9) {
if (shift>0 && value==0) {
return;
}
nextByte = value & 0b01111111;
value = (value >> 7) & 0x01FFFFFFFFFFFFFF;
shift++;
if (value>0) {
nextByte = nextByte + 0b10000000;
}
data.push_back(nextByte);
}
if (value>0) {
data.push_back(value & 0b00000001);
}
}
}

43
src/lib/net/packet.hpp Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <vector>
#include <cstdint>
namespace Packet {
struct DataContainer {
uint32_t typeID;
std::vector<uint8_t> payload;
}
namespace TypeID {
// These are guessed names for what the package IDs could mean.
// Some package IDs are used multiple times. I assume the different
// connection states (handshaking, status, login, and play) play a role
// in identifying what kind of package has been received.
// State: handshaking
const uint32_t HANDSHAKE = 0;
// State: status
const uint32_t STATUS = 0;
const uint32_t PING = 1;
}
}

16
src/lib/net/tcp_client.c Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

16
src/lib/net/tcp_client.h Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

16
src/lib/net/tcp_server.c Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

16
src/lib/net/tcp_server.h Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

17
src/lib/region.cpp Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2023, 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

57
src/lib/region.hpp Normal file
View File

@ -0,0 +1,57 @@
// Copyright 2023, 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
// File structure:
// 4K table of uint32_t: pointing to chunks
// -> 24bit offset, 8 bit length
// -> both offset and length are multiplied by 4096 to get the real value
// -> lowest valid offset = 2
// -> chunk is not present if pointer=0
// -> chunk calculation: ((x % 32) + (z % 32) * 32) * 4
// -> what about negative chunks?
// 4k table of uint32_t: last modified timestamps
// individual chunks
// -> 5 byte header
// -> 4 byte length
// -> 1 byte compression type: 0?? 1->gzip 2->zlib
// -> extension idea: support for other compression algorithms
// - lzma
// - xz
// - lz4
// - zstd
// -> compressed NBT data
#pragma once
#include <cstdint>
class Region {
uint32_t storagePointers[1024];
uint32_t lastModifiedTimestamps[1024];
// Chunk coordinates are uint8_t here bc they are 0<=x<32.
uint32_t* coordsToStoragePointer(uint8_t x, uint8_t z) {
return &storagePointers[z*32 + x];
}
// Chunk coordinates are uint8_t here bc they are 0<=x<32.
uint32_t* coordsToLastModified(uint8_t x, uint8_t z) {
return &lastModifiedTimestamps[z*32 + x];
}
}

116
src/lib/zlibutil.cpp Normal file
View File

@ -0,0 +1,116 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// Jocadbz
//
// 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
// includes vector and error.hpp
#include "zlibutil.hpp"
#include <zlib/zlib.h>
#include <cstring>
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#define CHUNK_SIZE 16384 // Chunk size
namespace zlib {
ErrorOr<std::vector<uint8_t>> compressData(std::vector<uint8_t> data) {
// I, too, love the fact that raw bytes are signed and therefore can have negative values. -_-
std::vector<int8_t> signedData = std::vector<int8_t>(data.begin(), data.end());
z_stream zs;
memset(&zs, 0, sizeof(zs));
if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::COMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("deflateInit failed while compressing."));
}
zs.next_in = reinterpret_cast<Bytef*>(reinterpret_cast<char*>(signedData.data()));
zs.avail_in = signedData.size();
int ret;
char outbuffer[CHUNK_SIZE];
std::vector<char> compressedData;
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = CHUNK_SIZE;
ret = deflate(&zs, Z_FINISH);
if (compressedData.size() < zs.total_out)
compressedData.insert(compressedData.end(), outbuffer, outbuffer + CHUNK_SIZE - zs.avail_out);
} while (ret == Z_OK);
deflateEnd(&zs);
if (ret != Z_STREAM_END) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::COMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("Error while compressing: " + std::to_string(ret)));
}
return ErrorOr<std::vector<uint8_t>>(std::vector<uint8_t>(compressedData.begin(), compressedData.end()));
}
ErrorOr<std::vector<uint8_t>> decompressData(std::vector<uint8_t> data) {
// I, too, love the fact that raw bytes are signed and therefore can have negative values. -_-
std::vector<int8_t> signedData = std::vector<int8_t>(data.begin(), data.end());
z_stream zs;
memset(&zs, 0, sizeof(zs));
if (inflateInit(&zs) != Z_OK) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::DECOMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("inflateInit failed while decompressing."));
}
zs.next_in = reinterpret_cast<Bytef*>(reinterpret_cast<char*>(signedData.data()));
zs.avail_in = signedData.size();
int ret;
char outbuffer[CHUNK_SIZE];
std::vector<char> decompressedData;
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = CHUNK_SIZE;
ret = inflate(&zs, 0);
if (decompressedData.size() < zs.total_out)
decompressedData.insert(decompressedData.end(), outbuffer, outbuffer + CHUNK_SIZE - zs.avail_out);
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::DECOMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("Error while decompressing: " + std::to_string(ret)));
}
return ErrorOr<std::vector<uint8_t>>(std::vector<uint8_t>(decompressedData.begin(), decompressedData.end()));
}
}

27
src/lib/zlibutil.hpp Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2024, FOSS-VG Developers and Contributers
//
// Author(s):
// Jocadbz
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <vector>
#include "error.hpp"
namespace zlib {
ErrorOr<std::vector<uint8_t>> compressData(std::vector<uint8_t> data);
ErrorOr<std::vector<uint8_t>> decompressData(std::vector<uint8_t> data);
}

0
src/shaders/.gitkeep Normal file
View File

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");
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;
}

215
src/test/file.cpp Normal file
View File

@ -0,0 +1,215 @@
// 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 <vector>
#include "assert.hpp"
#include "tinyutf8/tinyutf8.h"
#include "../lib/file.hpp"
int main(){
std::cout << "################################################################################" << std::endl;
std::cout << "File tests" << std::endl;
std::cout << "################################################################################" << std::endl;
File* file;
//readByte test
file = File::open("resources/unicode_data/normal_utf-8", 'r').value;
uint8_t byte = file->readByte().value;
ASSERT(byte == 'T');
std::cout << "Passed read byte test." << std::endl;
//read test
std::vector<uint8_t> bytes = file->read(5).value;
//cursorPosition has already moved forward by one
ASSERT(bytes == std::vector<uint8_t>({'e', 's', 't', ' ', 's'}));
std::cout << "Passed read test." << std::endl;
//readString test
tiny_utf8::string data = file->readString(5).value;
ASSERT(data == "tring");
std::cout << "Passed read string test." << std::endl;
file->close();
delete file;
//Write Tests
File *writeFile;
File *readFile;
//writeByte test
writeFile = File::open("resources/writeTest", 'w').value;
writeFile->writeByte('a');
writeFile->close();
readFile = File::open("resources/writeTest", 'r').value;
uint8_t testByte = readFile->readByte().value;
readFile->close();
ASSERT(testByte == 'a');
std::cout << "Passed write byte test." << std::endl;
//write test
writeFile->open();
writeFile->write(std::vector<uint8_t>({'a', 'b', 'c'}));
writeFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string testBytes = readFile->readString(3).value;
readFile->close();
ASSERT(testBytes == "abc");
std::cout << "Passed write test." << std::endl;
writeFile->open();
writeFile->writeString(tiny_utf8::string("Hallo"));
writeFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string testString = readFile->readString(5).value;
readFile->close();
ASSERT(testString == "Hallo");
std::cout << "Passed write string test." << std::endl;
delete writeFile;
File *appendFile;
appendFile = File::open("resources/writeTest", 'a').value;
appendFile->writeByte(',');
appendFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string appendByteString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(appendByteString == "Hallo,");
std::cout << "Passed append byte test." << std::endl;
appendFile->open();
appendFile->write(std::vector<uint8_t>({' ', 'I', 'c', 'h'}));
appendFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string appendBytesString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(appendBytesString == "Hallo, Ich");
std::cout << "Passed append test" << std::endl;
appendFile->open();
appendFile->writeString(" bin Shwoomple.");
appendFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string appendString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(appendString == "Hallo, Ich bin Shwoomple.");
std::cout << "Passed append string test" << std::endl;
delete appendFile;
//test insert functions
File *modifyFile;
modifyFile = File::open("resources/writeTest", 'm').value;
modifyFile->cursorPosition = 5;
modifyFile->insertByte(',');
modifyFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string modifyByteString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(modifyByteString == "Hallo,, Ich bin Shwoomple.");
std::cout << "Passed modify byte test" << std::endl;
modifyFile->open();
modifyFile->cursorPosition = 6;
modifyFile->insert(std::vector<uint8_t>({' ', 'H', 'i'}));
modifyFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string modifyBytesString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(modifyBytesString == "Hallo, Hi, Ich bin Shwoomple.");
std::cout << "Passed modify test" << std::endl;
modifyFile->open();
modifyFile->cursorPosition = 9;
modifyFile->insertString(" THE CAKE IS A LIE");
modifyFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string modifyString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(modifyString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple.");
std::cout << "Passed modify string test" << std::endl;
//test cut functions
modifyFile->open();
modifyFile->cursorPosition = modifyFile->size.value-1;
ErrorOr<uint8_t> cutByte = modifyFile->cutByte();
modifyFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string cutByteString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(modifyFile->cursorPosition == modifyFile->size.value);
ASSERT(cutByte.value == '.');
ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple");
std::cout << "Passed cut byte test." << std::endl;
modifyFile->open();
modifyFile->cursorPosition = 9;
ErrorOr<std::vector<uint8_t>> cutBytes = modifyFile->cut(18);
modifyFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string cutBytesString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(modifyFile->cursorPosition == 9);
ASSERT(cutBytes.value == std::vector<uint8_t>({' ', 'T', 'H', 'E', ' ', 'C', 'A', 'K', 'E', ' ', 'I', 'S', ' ','A', ' ', 'L', 'I', 'E'}))
ASSERT(cutBytesString == "Hallo, Hi, Ich bin Shwoomple");
std::cout << "Passed cut test." << std::endl;
modifyFile->open();
modifyFile->cursorPosition = 0;
ErrorOr<tiny_utf8::string> cutString = modifyFile->cutString(7);
modifyFile->close();
readFile->open();
readFile->cursorPosition = 0;
tiny_utf8::string cutReadString = readFile->readString(readFile->size.value).value;
readFile->close();
ASSERT(modifyFile->cursorPosition == 0);
ASSERT(cutString.value == "Hallo, ");
ASSERT(cutReadString == "Hi, Ich bin Shwoomple");
std::cout << "Passed cutString test." << std::endl;
}

View File

@ -75,7 +75,16 @@ int main(){
tiny_utf8::string normalString = tiny_utf8::string(normalStdString);
// check for normal operation
ASSERT(normalString == importedString);
// check for mismatched size error
std::string javaStdStringCopy = javaStdString;
javaStdStringCopy[0]='b';
ErrorOr<tiny_utf8::string> errorString = JavaCompat::importJavaString(reinterpret_cast<uint8_t*>(javaStdStringCopy.data()), 0x75);
ASSERT(errorString.isError);
ASSERT(errorString.errorCode == ErrorCodes::MISMATCHEDSIZE);
std::cout << "Passed Import Java string test." << std::endl;
//using normalString from when we read the file earlier
@ -91,5 +100,5 @@ int main(){
std::cout << "Passed Export Java string test." << std::endl;
delete nextChar;
return 0;
return 0;
}

View File

@ -29,32 +29,41 @@ int main(){
std::cout << "NBT read/write helper tests" << std::endl;
std::cout << "################################################################################" << std::endl;
uint8_t validNBTDataBlob[] = {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 validNBTDataBlobSize = 478;
uint64_t currentPositionInBlob;
// used for all integer tests
uint8_t dataForIntTest[] = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
uint64_t dataSize = 10;
uint64_t currentPosition;
// int8 ############################################################
// read successfully
uint64_t currentPosition = 5;
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).value == 35);
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == false);
currentPosition = 5;
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).value == 35);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == false);
// begin of data
currentPosition = 0;
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).value == 30);
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).value == 30);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == false);
// end of data
currentPosition = 9;
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).value == 39);
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).value == 39);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == false);
// out of bounds
currentPosition = 10;
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt8(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt8(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0x13A;
ASSERT(NBT::Helper::readInt8(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt8(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == 100);
std::cout << "Passed readInt8 NBT helper test" << std::endl;
std::vector<uint8_t>* writeInt8TestResult = new std::vector<uint8_t>();
NBT::helper::writeInt8(writeInt8TestResult, (int8_t) 8);
NBT::Helper::writeInt8(writeInt8TestResult, (int8_t) 8);
std::vector<uint8_t> dereferencedWriteInt8TestResult = *writeInt8TestResult;
delete writeInt8TestResult;
ASSERT(dereferencedWriteInt8TestResult.back() == (uint8_t) 8);
@ -64,29 +73,33 @@ int main(){
// int16 ###########################################################
// read successfully
currentPosition = 5;
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).value == 8996);
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).value == 8996);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == false);
// begin of data
currentPosition = 0;
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).value == 7711);
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).value == 7711);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == false);
// end of data
currentPosition = 8;
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).value == 9767);
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).value == 9767);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == false);
// partially out of bounds
currentPosition = 9;
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// fully out of bounds
currentPosition = 10;
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt16(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt16(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0xb9;
ASSERT(NBT::Helper::readInt16(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt16(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == 2000);
std::cout << "Passed readInt16 NBT helper test" << std::endl;
std::vector<uint8_t>* writeInt16TestResult = new std::vector<uint8_t>();
NBT::helper::writeInt16(writeInt16TestResult, (int16_t) 0xABCD);
NBT::Helper::writeInt16(writeInt16TestResult, (int16_t) 0xABCD);
std::vector<uint8_t> dereferencedWriteInt16TestResult = *writeInt16TestResult;
delete writeInt16TestResult;
ASSERT(dereferencedWriteInt16TestResult[0] == (uint8_t) 0xAB && dereferencedWriteInt16TestResult[1] == (uint8_t) 0xCD);
@ -96,29 +109,34 @@ int main(){
// int32 ###########################################################
// read successfully
currentPosition = 5;
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).value == 589571366);
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).value == 589571366);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == false);
// begin of data
currentPosition = 0;
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).value == 505356321);
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).value == 505356321);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == false);
// end of data
currentPosition = 6;
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).value == 606414375);
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).value == 606414375);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == false);
// partially out of bounds
currentPosition = 7;
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// fully out of bounds
currentPosition = 10;
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt32(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt32(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0xc3;
ASSERT(NBT::Helper::readInt32(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt32(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == 10101010);
std::cout << "Passed readInt32 NBT helper test" << std::endl;
std::vector<uint8_t>* writeInt32TestResult = new std::vector<uint8_t>();
NBT::helper::writeInt32(writeInt32TestResult, (int32_t) 0x12345678);
NBT::Helper::writeInt32(writeInt32TestResult, (int32_t) 0x12345678);
// delete before checking assertions so we don't leak
std::vector<uint8_t> dereferencedWriteInt32TestResult = *writeInt32TestResult;
delete writeInt32TestResult;
ASSERT(
@ -133,29 +151,34 @@ int main(){
// int64 ###########################################################
// read successfully
currentPosition = 1;
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).value == 2242829044932683046);
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).value == 2242829044932683046);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == false);
// begin of data
currentPosition = 0;
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).value == 2170488872094606373);
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).value == 2170488872094606373);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == false);
// end of data
currentPosition = 2;
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).value == 2315169217770759719);
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).value == 2315169217770759719);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == false);
// partially out of bounds
currentPosition = 3;
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// fully out of bounds
currentPosition = 10;
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt64(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt64(dataForIntTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0xf1;
ASSERT(NBT::Helper::readInt64(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt64(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == 810001800766);
std::cout << "Passed readInt64 NBT helper test" << std::endl;
std::vector<uint8_t>* writeInt64TestResult = new std::vector<uint8_t>();
NBT::helper::writeInt64(writeInt64TestResult, (int64_t) 0x0123456789ABCDEF);
NBT::Helper::writeInt64(writeInt64TestResult, (int64_t) 0x0123456789ABCDEF);
// delete before checking assertions so we don't leak
std::vector<uint8_t> dereferencedWriteInt64TestResult = *writeInt64TestResult;
delete writeInt64TestResult;
ASSERT(
@ -190,30 +213,34 @@ int main(){
// int8 "array" ####################################################
// read successfully
currentPosition = 0;
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int8_t>({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}));
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int8_t>({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}));
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
// read empty
currentPosition = 112;
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int8_t>());
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int8_t>());
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
// read overrun
currentPosition = 20;
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read with size partially out of bounds
currentPosition = 114;
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read out of bounds
currentPosition = 200;
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt8Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0x148;
ASSERT(NBT::Helper::readInt8Array(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt8Array(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == std::vector<int8_t>({(int8_t) 0x71, (int8_t) 0x35, (int8_t) 0x77, (int8_t) 0x62, (int8_t) 0x54, (int8_t) 0x64, (int8_t) 0xf5, (int8_t) 0x32}));
std::cout << "Passed readInt8Array NBT helper test" << std::endl;
std::vector<uint8_t>* int8ArrayTestOutput = new std::vector<uint8_t>();
int8_t writeDataTest[] = {1,2,3,4};
NBT::helper::writeInt8Array(int8ArrayTestOutput, writeDataTest, (uint32_t)4);
NBT::Helper::writeInt8Array(int8ArrayTestOutput, writeDataTest, (uint32_t)4);
ASSERT(
int8ArrayTestOutput->at(0) == 0 &&
int8ArrayTestOutput->at(1) == 0 &&
@ -225,7 +252,7 @@ int main(){
int8ArrayTestOutput->at(7) == 4
);
int8ArrayTestOutput->clear();
NBT::helper::writeInt8Array(int8ArrayTestOutput, std::vector<int8_t>({1,2,3,4}));
NBT::Helper::writeInt8Array(int8ArrayTestOutput, std::vector<int8_t>({1,2,3,4}));
ASSERT(
int8ArrayTestOutput->at(0) == 0 &&
int8ArrayTestOutput->at(1) == 0 &&
@ -242,30 +269,34 @@ int main(){
// int32 "array" ###################################################
// read successfully
currentPosition = 68;
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int32_t>({1027489600, 1094861636, 1162233672, 1229605708, 1296977744, 1364349780, 1431721816, 1499093852, 1566465888, 1633837924}));
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int32_t>({1027489600, 1094861636, 1162233672, 1229605708, 1296977744, 1364349780, 1431721816, 1499093852, 1566465888, 1633837924}));
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
// read empty
currentPosition = 112;
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int32_t>());
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int32_t>());
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
// read overrun
currentPosition = 20;
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read with size partially out of bounds
currentPosition = 114;
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read out of bounds
currentPosition = 200;
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt32Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0xd5;
ASSERT(NBT::Helper::readInt32Array(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt32Array(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == std::vector<int32_t>({(int32_t) 0x17bfe83c, (int32_t) 0xa8fb, (int32_t) 0x7fffffff, (int32_t) 0x61727261}));
std::cout << "Passed readInt32Array NBT helper test" << std::endl;
std::vector<uint8_t>* int32ArrayTestOutput = new std::vector<uint8_t>();
int32_t input32[] = {0x01234567, 0x01234567};
NBT::helper::writeInt32Array(int32ArrayTestOutput, input32, 2);
NBT::Helper::writeInt32Array(int32ArrayTestOutput, input32, 2);
ASSERT(
int32ArrayTestOutput->at(0) == 0x00 &&
int32ArrayTestOutput->at(1) == 0x00 &&
@ -281,7 +312,7 @@ int main(){
int32ArrayTestOutput->at(11) == 0x67
);
int32ArrayTestOutput->clear();
NBT::helper::writeInt32Array(int32ArrayTestOutput, std::vector<int32_t>({0x01234567, 0x01234567}));
NBT::Helper::writeInt32Array(int32ArrayTestOutput, std::vector<int32_t>({0x01234567, 0x01234567}));
ASSERT(
int32ArrayTestOutput->at(0) == 0x00 &&
int32ArrayTestOutput->at(1) == 0x00 &&
@ -303,30 +334,34 @@ int main(){
// int64 "array" ###################################################
// read successfully
currentPosition = 44;
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int64_t>({2966230773313449776, 3544952156018063160, 4123673537695186954, 4413034230074983236, 4991755612779596620}));
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int64_t>({2966230773313449776, 3544952156018063160, 4123673537695186954, 4413034230074983236, 4991755612779596620}));
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
// read empty
currentPosition = 112;
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int64_t>());
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).value == std::vector<int64_t>());
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == false);
// read overrun
currentPosition = 20;
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read with size partially out of bounds
currentPosition = 114;
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read out of bounds
currentPosition = 200;
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readInt64Array(dataForIntArrayTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0x107;
ASSERT(NBT::Helper::readInt64Array(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readInt64Array(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == std::vector<int64_t>({(int64_t) 239865, (int64_t) 23586749, (int64_t) 9223372036854775807, (int64_t) 188944201329624, (int64_t) 3116157694992754}));
std::cout << "Passed readInt64Array NBT helper test" << std::endl;
std::vector<uint8_t>* int64ArrayTestOutput = new std::vector<uint8_t>();
int64_t input64[] = {0x0123456789ABCDEF, 0x0123456789ABCDEF};
NBT::helper::writeInt64Array(int64ArrayTestOutput, input64, 2);
NBT::Helper::writeInt64Array(int64ArrayTestOutput, input64, 2);
ASSERT(
int64ArrayTestOutput->at(0) == 0x00 &&
int64ArrayTestOutput->at(1) == 0x00 &&
@ -350,7 +385,7 @@ int main(){
int64ArrayTestOutput->at(19) == 0xEF
);
int64ArrayTestOutput->clear();
NBT::helper::writeInt64Array(int64ArrayTestOutput, std::vector<int64_t>({0x0123456789ABCDEF, 0x0123456789ABCDEF}));
NBT::Helper::writeInt64Array(int64ArrayTestOutput, std::vector<int64_t>({0x0123456789ABCDEF, 0x0123456789ABCDEF}));
ASSERT(
int64ArrayTestOutput->at(0) == 0x00 &&
int64ArrayTestOutput->at(1) == 0x00 &&
@ -383,21 +418,25 @@ int main(){
dataSize = 4;
currentPosition = 0;
// read successfully
ASSERT(NBT::helper::readFloat(dataForFloatTest, dataSize, currentPosition).value == -63351.46484375f);
ASSERT(NBT::helper::readFloat(dataForFloatTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readFloat(dataForFloatTest, dataSize, currentPosition).value == -63351.46484375f);
ASSERT(NBT::Helper::readFloat(dataForFloatTest, dataSize, currentPosition).isError == false);
// read overrun
currentPosition = 1;
ASSERT(NBT::helper::readFloat(dataForFloatTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readFloat(dataForFloatTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::Helper::readFloat(dataForFloatTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readFloat(dataForFloatTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read out of bounds
currentPosition = 4;
ASSERT(NBT::helper::readFloat(dataForFloatTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readFloat(dataForFloatTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readFloat(dataForFloatTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readFloat(dataForFloatTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0xad;
ASSERT(NBT::Helper::readFloat(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readFloat(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == 35.2678337097168);
std::cout << "Passed readFloat NBT helper test" << std::endl;
std::vector<uint8_t>* writeFloatTestResult = new std::vector<uint8_t>();
NBT::helper::writeFloat(writeFloatTestResult, (float) -63351.46484375f);
NBT::Helper::writeFloat(writeFloatTestResult, (float) -63351.46484375f);
std::vector<uint8_t> dereferencedWriteFloatTestResult = *writeFloatTestResult;
delete writeFloatTestResult;
ASSERT(
@ -414,21 +453,25 @@ int main(){
dataSize = 8;
currentPosition = 0;
// read successfully
ASSERT(NBT::helper::readDouble(dataForDoubleTest, dataSize, currentPosition).value == -20.015625476837158203125);
ASSERT(NBT::helper::readDouble(dataForDoubleTest, dataSize, currentPosition).isError == false);
ASSERT(NBT::Helper::readDouble(dataForDoubleTest, dataSize, currentPosition).value == -20.015625476837158203125);
ASSERT(NBT::Helper::readDouble(dataForDoubleTest, dataSize, currentPosition).isError == false);
// read overrun
currentPosition = 1;
ASSERT(NBT::helper::readDouble(dataForDoubleTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readDouble(dataForDoubleTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::Helper::readDouble(dataForDoubleTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readDouble(dataForDoubleTest, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
// read out of bounds
currentPosition = 8;
ASSERT(NBT::helper::readDouble(dataForDoubleTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::helper::readDouble(dataForDoubleTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
ASSERT(NBT::Helper::readDouble(dataForDoubleTest, dataSize, currentPosition).isError == true);
ASSERT(NBT::Helper::readDouble(dataForDoubleTest, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
// read from a bigger blob
currentPositionInBlob = 0x9d;
ASSERT(NBT::Helper::readDouble(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readDouble(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == 623593.6542742235);
std::cout << "Passed readDouble NBT helper test" << std::endl;
std::vector<uint8_t>* writeDoubleTestResult = new std::vector<uint8_t>();
NBT::helper::writeDouble(writeDoubleTestResult, (double) -20.015625476837158203125);
NBT::Helper::writeDouble(writeDoubleTestResult, (double) -20.015625476837158203125);
std::vector<uint8_t> dereferencedWriteDoubleTestResult = *writeDoubleTestResult;
delete writeDoubleTestResult;
ASSERT(
@ -487,15 +530,22 @@ int main(){
std::cerr << "Failed to open file: " << normalFilePath << std::endl;
return 2;
}
tiny_utf8::string normalString = tiny_utf8::string(normalStdString);
ASSERT(normalString == NBT::helper::readString(reinterpret_cast<uint8_t*>(javaStdString.data()), 0x75, 0).value)
ASSERT(NBT::helper::readString(reinterpret_cast<uint8_t*>(javaStdString.data()), 0xFFFFF, 0).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::helper::readString(reinterpret_cast<uint8_t*>(javaStdString.data()), 0xF, 0).errorCode == ErrorCodes::MISMATCHEDSIZE);
std::cout << "Passed readString NBT helper test." << std::endl;
delete nextChar;
ASSERT(normalString == NBT::Helper::readString(reinterpret_cast<uint8_t*>(javaStdString.data()), javaStdString.size(), 0).value)
javaStdString[0] = '1';
ASSERT(NBT::Helper::readString(reinterpret_cast<uint8_t*>(javaStdString.data()), javaStdString.size(), 0).errorCode == ErrorCodes::OVERRUN);
ASSERT(NBT::Helper::readString(reinterpret_cast<uint8_t*>(javaStdString.data()), javaStdString.size(), javaStdString.size()).errorCode == ErrorCodes::OUT_OF_RANGE);
//reading data from the blob at the top of this file
currentPositionInBlob = 0x1cf;
ASSERT(NBT::Helper::readString(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).isError == false);
ASSERT(NBT::Helper::readString(validNBTDataBlob, validNBTDataBlobSize, currentPositionInBlob).value == "Hello World!");
std::cout << "Passed readString NBT helper test." << std::endl;
char* nextChar1 = new char;
//reading data from the java modified utf8 file
@ -517,11 +567,17 @@ int main(){
std::cerr << "Failed to open file: " << javaFilePath1 << std::endl;
return 2;
}
delete nextChar1;
std::vector<uint8_t>* exportedString = new std::vector<uint8_t>();
NBT::helper::writeString(exportedString, normalString);
NBT::Helper::writeString(exportedString, normalString);
ASSERT(javaStdString1 == *exportedString);
//check that we get an error when trying to write a string that is too long
std::string overrunString = std::string(0x10000, '.');
ASSERT(NBT::Helper::writeString(exportedString, tiny_utf8::string(overrunString)).isError);
ASSERT(NBT::Helper::writeString(exportedString, tiny_utf8::string(overrunString)).errorCode == ErrorCodes::OVERRUN);
std::cout << "Passed writeString NBT helper test." << std::endl;
return 0;

View File

@ -101,16 +101,16 @@ int main() {
// 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);
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);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 477);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 477);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 1);
@ -118,8 +118,8 @@ int main() {
ASSERT(dataLength.value == 0);
//const uint8_t INT8 = 1;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x133);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x133);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x133);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x133);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 8);
@ -127,8 +127,8 @@ int main() {
ASSERT(dataLength.value == 1);
//const uint8_t INT16 = 2;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xb1);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xb1);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xb1);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xb1);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 10);
@ -136,16 +136,16 @@ int main() {
ASSERT(dataLength.value == 1);
//const uint8_t INT32 = 3;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xbb);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xbb);
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);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x67);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x67);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 18);
@ -153,8 +153,8 @@ int main() {
ASSERT(dataLength.value == 1);
//const uint8_t INT64 = 4;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xe9);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xe9);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xe9);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xe9);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 16);
@ -162,8 +162,8 @@ int main() {
ASSERT(dataLength.value == 1);
//const uint8_t FLOAT = 5;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xa5);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xa5);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xa5);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xa5);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 12);
@ -171,8 +171,8 @@ int main() {
ASSERT(dataLength.value == 1);
//const uint8_t DOUBLE = 6;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x94);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x94);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x94);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x94);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 17);
@ -180,8 +180,8 @@ int main() {
ASSERT(dataLength.value == 1);
//const uint8_t INT8_ARRAY = 7;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x13b);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x13b);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x13b);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x13b);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 25);
@ -189,16 +189,16 @@ int main() {
ASSERT(dataLength.value == 8);
//const uint8_t STRING = 8;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x1c6);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x1c6);
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);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x79);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x79);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 26);
@ -206,16 +206,16 @@ int main() {
ASSERT(dataLength.value == 12);
//const uint8_t LIST = 9;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x154);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x154);
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);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x16a);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x16a);
ASSERT(totalSize.isError);
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
@ -223,8 +223,8 @@ int main() {
ASSERT(dataLength.value == 12);
//const uint8_t COMPOUND = 10;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x5c);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x5c);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x5c);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x5c);
ASSERT(totalSize.isError);
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
@ -232,8 +232,8 @@ int main() {
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);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xc7);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xc7);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 34);
@ -241,8 +241,8 @@ int main() {
ASSERT(dataLength.value == 4);
//const uint8_t INT64_ARRAY= 12;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xf9);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xf9);
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xf9);
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xf9);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 58);

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +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
#include <string>
#include <vector>
#include <iostream>
#include "../lib/nbt.hpp"
#include "../lib/error.hpp"
#include "../lib/javacompat.hpp"
int main() {
std::cout << "================================================================================" << std::endl;
std::cout << "NBT write string helper failure mode test" << std::endl;
std::cout << "================================================================================" << std::endl;
std::cout << "This is supposed to abort." << std::endl;
std::vector<uint8_t>* exportedString = new std::vector<uint8_t>();
std::string overrunString = std::string(0xFFFFF, '.');
NBT::helper::writeString(exportedString, tiny_utf8::string(overrunString));
}

287
src/test/varint.cpp Normal file
View File

@ -0,0 +1,287 @@
// Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster, Shwoomple
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <iostream>
#include <cstdint>
#include <vector>
#include "assert.hpp"
#include "../lib/error.hpp"
#include "../lib/net/conversion/varint.hpp"
int main() {
std::cout << "################################################################################" << std::endl;
std::cout << "VarInt tests" << std::endl;
std::cout << "################################################################################" << std::endl;
// examples for numbers
//
// 32 Bit
// 0000 0000 0000 0000 0000 0000 0000 0000 = 0 -> 0000 0000
// 1111 1111 1111 1111 1111 1111 1111 1111 = -1 (unsigned int32 max) -> 1111 1111 1111 1111 1111 1111 1111 1111 0000 1111
// 0000 0000 0010 0100 0011 1101 1011 1101 = 2375101 -> 1011 1101 1111 1011 1001 0000 0000 0001
// 0000 0000 0000 0000 0001 0001 0001 0001 = 4369 -> 1001 0001 0010 0010
//
// 64 Bit
// 0010 0000 0001 0000 0000 0000 1010 0010 1010 1000 0010 0000 1101 0000 1001 0011 = 2310347307446489235 -> 1101 0011 1010 0001 1000 0011 1100 0001 1010 1010 1001 0100 1000 0000 1000 1000 0010 0000
// 1000 0000 0100 0000 0010 0000 0001 0000 0000 1000 0000 0100 0000 0010 0000 0001 = -9205322385119247871 -> 1000 0001 1000 0100 1001 0000 1100 0000 1000 0000 1000 0010 1000 1000 1010 0000 1000 0000 0000 0001
// 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 = -1 (unsigned int64 max) -> 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0000 0001
{
std::vector<uint8_t> data = std::vector<uint8_t>();
uint8_t processedBytes;
ErrorOr<int32_t> result = VarInt::fromVar32(data, 0, &processedBytes);
ASSERT(result.isError);
ASSERT(result.errorCode == ErrorCodes::OUT_OF_RANGE);
}
{
std::vector<uint8_t> data = { 0x84 };
uint8_t processedBytes;
ErrorOr<int32_t> result = VarInt::fromVar32(data, 0, &processedBytes);
ASSERT(result.isError);
ASSERT(result.errorCode == ErrorCodes::OVERRUN);
}
{
std::vector<uint8_t> data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 };
uint8_t processedBytes;
ErrorOr<int32_t> result = VarInt::fromVar32(data, 0, &processedBytes);
ASSERT(result.isError);
ASSERT(result.errorCode == ErrorCodes::OVERFLOW);
}
uint8_t zeroProcessedBytes = 0;
std::vector<uint8_t> zeroData;
zeroData.push_back(0);
ErrorOr<int32_t> zero = VarInt::fromVar32(zeroData, 0, &zeroProcessedBytes);
ASSERT(!zero.isError);
ASSERT(zero.value == 0);
ASSERT(zeroProcessedBytes == 1);
uint8_t minusOneProcessedBytes = 0;
std::vector<uint8_t> minusOneData;
minusOneData.push_back(255);
minusOneData.push_back(255);
minusOneData.push_back(255);
minusOneData.push_back(255);
minusOneData.push_back(15);
ErrorOr<int32_t> minusOne = VarInt::fromVar32(minusOneData, 0, &minusOneProcessedBytes);
ASSERT(!minusOne.isError);
ASSERT(minusOne.value == -1);
ASSERT(minusOneProcessedBytes == 5);
uint8_t smallProcessedBytes = 0;
std::vector<uint8_t> smallData;
// offset data by 3 to test initialPosition feature
smallData.push_back(0b10010001);
smallData.push_back(0b10010001);
smallData.push_back(0b10010001);
smallData.push_back(0b10010001);
smallData.push_back(0b00100010);
ErrorOr<int32_t> small = VarInt::fromVar32(smallData, 3, &smallProcessedBytes);
ASSERT(!small.isError);
ASSERT(small.value == 4369);
ASSERT(smallProcessedBytes == 2);
uint8_t bigProcessedBytes = 0;
std::vector<uint8_t> bigData;
bigData.push_back(0b10111101);
bigData.push_back(0b11111011);
bigData.push_back(0b10010000);
bigData.push_back(0b00000001);
ErrorOr<int32_t> big = VarInt::fromVar32(bigData, 0, &bigProcessedBytes);
ASSERT(!big.isError);
ASSERT(big.value == 2375101);
ASSERT(bigProcessedBytes == 4);
//TODO: test error conditions
std::cout << "Passed fromVar32 test." << std::endl;
{
std::vector<uint8_t> data = std::vector<uint8_t>();
uint8_t processedBytes;
ErrorOr<int64_t> result = VarInt::fromVar64(data, 0, &processedBytes);
ASSERT(result.isError);
ASSERT(result.errorCode == ErrorCodes::OUT_OF_RANGE);
}
{
std::vector<uint8_t> data = { 0x84 };
uint8_t processedBytes;
ErrorOr<int64_t> result = VarInt::fromVar64(data, 0, &processedBytes);
ASSERT(result.isError);
ASSERT(result.errorCode == ErrorCodes::OVERRUN);
}
{
std::vector<uint8_t> data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 };
uint8_t processedBytes;
ErrorOr<int64_t> result = VarInt::fromVar64(data, 0, &processedBytes);
ASSERT(result.isError);
ASSERT(result.errorCode == ErrorCodes::OVERFLOW);
}
uint8_t zero64ProcessedBytes = 0;
std::vector<uint8_t> zero64Data;
zero64Data.push_back(0);
ErrorOr<int64_t> zero64 = VarInt::fromVar64(zero64Data, 0, &zero64ProcessedBytes);
ASSERT(!zero64.isError);
ASSERT(zero64.value == 0);
ASSERT(zero64ProcessedBytes == 1);
uint8_t minusOne64ProcessedBytes = 0;
std::vector<uint8_t> minusOne64Data;
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(255);
minusOne64Data.push_back(1);
ErrorOr<int64_t> minusOne64 = VarInt::fromVar64(minusOne64Data, 0, &minusOne64ProcessedBytes);
ASSERT(!minusOne64.isError);
ASSERT(minusOne64.value == -1);
ASSERT(minusOne64ProcessedBytes == 10);
// 0010 0000 0001 0000 0000 0000 1010 0010 1010 1000 0010 0000 1101 0000 1001 0011 = 2310347307446489235 -> 1101 0011 1010 0001 1000 0011 1100 0001 1010 1010 1001 0100 1000 0000 1000 1000 0010 0000
uint8_t small64ProcessedBytes = 0;
std::vector<uint8_t> small64Data;
// offset data by 3 to test initialPosition feature
small64Data.push_back(0b11010011);
small64Data.push_back(0b11010011);
small64Data.push_back(0b11010011);
small64Data.push_back(0b10010011);
small64Data.push_back(0b10100001);
small64Data.push_back(0b10000011);
small64Data.push_back(0b11000001);
small64Data.push_back(0b10101010);
small64Data.push_back(0b10010100);
small64Data.push_back(0b10000000);
small64Data.push_back(0b10001000);
small64Data.push_back(0b00100000);
ErrorOr<int64_t> small64 = VarInt::fromVar64(small64Data, 3, &small64ProcessedBytes);
ASSERT(!small64.isError);
ASSERT(small64.value == 2310347307446489235);
ASSERT(small64ProcessedBytes == 9);
// 1000 0000 0100 0000 0010 0000 0001 0000 0000 1000 0000 0100 0000 0010 0000 0001 = -9205322385119247871 -> 1000 0001 1000 0100 1001 0000 1100 0000 1000 0000 1000 0010 1000 1000 1010 0000 1000 0000 0000 0001
uint8_t big64ProcessedBytes = 0;
std::vector<uint8_t> big64Data;
big64Data.push_back(0b10000001);
big64Data.push_back(0b10000100);
big64Data.push_back(0b10010000);
big64Data.push_back(0b11000000);
big64Data.push_back(0b10000000);
big64Data.push_back(0b10000010);
big64Data.push_back(0b10001000);
big64Data.push_back(0b10100000);
big64Data.push_back(0b10000000);
big64Data.push_back(0b00000001);
ErrorOr<int64_t> big64 = VarInt::fromVar64(big64Data, 0, &big64ProcessedBytes);
ASSERT(!big64.isError);
ASSERT(big64.value == -9205322385119247871);
ASSERT(big64ProcessedBytes == 10);
//TODO: Test error conditions
std::cout << "Passed fromVar64 test." << std::endl;
// reversing all the previous tests
std::vector<uint8_t> dataDump;
VarInt::toVar32(0, dataDump);
ASSERT(dataDump[0] == 0);
VarInt::toVar32(-1, dataDump);
ASSERT(
dataDump[1]==255 &&
dataDump[2]==255 &&
dataDump[3]==255 &&
dataDump[4]==255 &&
dataDump[5]==15
);
VarInt::toVar32(4369, dataDump);
ASSERT(
dataDump[6]==0b10010001 &&
dataDump[7]==0b00100010
);
VarInt::toVar32(2375101, dataDump);
ASSERT(
dataDump[8]==0b10111101 &&
dataDump[9]==0b11111011 &&
dataDump[10]==0b10010000 &&
dataDump[11]==0b00000001
);
std::cout << "Passed toVar32 test." << std::endl;
VarInt::toVar64(0, dataDump);
ASSERT(dataDump[12]==0);
VarInt::toVar64(-1, dataDump);
ASSERT(
dataDump[13]==255 &&
dataDump[14]==255 &&
dataDump[15]==255 &&
dataDump[16]==255 &&
dataDump[17]==255 &&
dataDump[18]==255 &&
dataDump[19]==255 &&
dataDump[20]==255 &&
dataDump[21]==255 &&
dataDump[22]==1
);
VarInt::toVar64(2310347307446489235, dataDump);
ASSERT(
dataDump[23]==0b10010011 &&
dataDump[24]==0b10100001 &&
dataDump[25]==0b10000011 &&
dataDump[26]==0b11000001 &&
dataDump[27]==0b10101010 &&
dataDump[28]==0b10010100 &&
dataDump[29]==0b10000000 &&
dataDump[30]==0b10001000 &&
dataDump[31]==0b00100000
);
VarInt::toVar64(-9205322385119247871, dataDump);
ASSERT(
dataDump[32]==0b10000001 &&
dataDump[33]==0b10000100 &&
dataDump[34]==0b10010000 &&
dataDump[35]==0b11000000 &&
dataDump[36]==0b10000000 &&
dataDump[37]==0b10000010 &&
dataDump[38]==0b10001000 &&
dataDump[39]==0b10100000 &&
dataDump[40]==0b10000000 &&
dataDump[41]==0b00000001
)
std::cout << "Passed toVar64 test." << std::endl;
return 0;
}

116
src/tools/arraydump.cpp Normal file
View File

@ -0,0 +1,116 @@
// 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 <iomanip>
#include <iostream>
#include <vector>
#include "../lib/cli.hpp"
#include "../lib/file.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", "write output as hexadecimal numbers"));
flags.push_back(CLI::Flag('o', "octal", "write output as octal numbers"));
flags.push_back(CLI::Flag('b', "binary", "write output as binary numbers"));
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("FILE", "path of the file to dump"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Dump files as C++ array literals");
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"
<< "ArrayDump 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;
}
ErrorOr<File*> filePointer = File::open(cliParser.getArgument(0).value, 'r');
if (filePointer.isError) {
std::cout << "Failed to open file: " << cliParser.getArgument(0).value << std::endl;
return EXIT_RUNTIME;
}
File* file = filePointer.value;
std::cout << "{";
if (cliParser.getFlag("hexadecimal").value) {
if (!file->eof()) {
std::cout << "0x" << std::setw(2) << std::setfill('0') << std::hex << (int) file->readByte().value;
}
while (!file->eof()) {
std::cout << ", 0x" << std::setw(2) << std::setfill('0') << std::hex << (int) file->readByte().value;
}
} else if (cliParser.getFlag("octal").value) {
if (!file->eof()) {
std::cout << "0" << std::setw(3) << std::setfill('0') << std::oct << (int) file->readByte().value;
}
while (!file->eof()) {
std::cout << ", 0" << std::setw(3) << std::setfill('0') << std::oct << (int) file->readByte().value;
}
} else if (cliParser.getFlag("binary").value) {
if (!file->eof()) {
std::cout << "0b" << std::bitset<8>((int) file->readByte().value);
}
while (!file->eof()) {
std::cout << ", 0b" << std::bitset<8>((int) file->readByte().value);
}
} else {
if (!file->eof()) {
std::cout << (int) file->readByte().value;
}
while (!file->eof()) {
std::cout << ", " << (int) file->readByte().value;
}
}
std::cout << "}" << std::endl;
delete file;
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;
}

View File

@ -13,8 +13,359 @@
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <iostream>
#include <fstream>
#include <vector>
#include <tinyutf8/tinyutf8.h>
#include "../lib/nbt.hpp"
#include "../lib/cli.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#define EXIT_UNIMPLEMENTED 3
void printTagTypeName(NBT::Tag::Generic* tag, uint64_t offsetBytes) {
std::cout << "[" << offsetBytes << ": ";
switch (tag->getTagType()) {
case NBT::TagType::END:
std::cout << "End";
break;
case NBT::TagType::INT8:
std::cout << "8 Bit Integer";
break;
case NBT::TagType::INT16:
std::cout << "16 Bit Integer";
break;
case NBT::TagType::INT32:
std::cout << "32 Bit Integer";
break;
case NBT::TagType::INT64:
std::cout << "64 Bit Integer";
break;
case NBT::TagType::FLOAT:
std::cout << "Float";
break;
case NBT::TagType::DOUBLE:
std::cout << "Double";
break;
case NBT::TagType::INT8_ARRAY:
std::cout << "Array of 8 Bit Integers";
break;
case NBT::TagType::STRING:
std::cout << "String";
break;
case NBT::TagType::LIST:
std::cout << "List";
break;
case NBT::TagType::COMPOUND:
std::cout << "Compound";
break;
case NBT::TagType::INT32_ARRAY:
std::cout << "Array of 32 Bit Integers";
break;
case NBT::TagType::INT64_ARRAY:
std::cout << "Array of 64 Bit Integers";
break;
default:
// WTF? How'd you even get here?
std::cout << "Unknown Type";
}
std::cout << "]";
if (tag->name == "") {
std::cout << ":";
} else {
std::cout << " " << tag->name << ":";
}
}
void printNBytes(uint64_t bytes) {
std::cout << bytes << (bytes==1? " byte":" bytes");
}
void drawTree(NBT::Tag::Generic* tag, tiny_utf8::string prefix, uint64_t offsetBytes, bool listMode=false) {
std::vector<uint8_t> serialized;
uint64_t headerSize = 0;
if (listMode) {
tag->serializeWithoutHeader(&serialized);
std::cout << prefix << "|Payload: ";
printNBytes(serialized.size());
std::cout << std::endl;
} else {
tag->serialize(&serialized);
if (tag->getTagType() == NBT::TagType::END) {
headerSize = 1;
} else {
headerSize = (uint64_t) NBT::Helper::readInt16(serialized.data(), serialized.size(), 1).value+3;
}
std::cout << prefix << "|Header: ";
printNBytes(headerSize);
std::cout << std::endl;
std::cout << prefix << "|Payload: ";
printNBytes(serialized.size() - headerSize);
std::cout << std::endl;
}
if (tag->getTagType() == NBT::TagType::END) {
std::cout << prefix << "'Total: ";
} else {
std::cout << prefix << "|Total: ";
}
printNBytes(serialized.size());
std::cout << std::endl;
switch (tag->getTagType()) {
case NBT::TagType::END:
break;
case NBT::TagType::INT8:
std::cout << prefix << "'Value: " << (int32_t) reinterpret_cast<NBT::Tag::Int8*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::INT16:
std::cout << prefix << "'Value: " << (int32_t) reinterpret_cast<NBT::Tag::Int16*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::INT32:
std::cout << prefix << "'Value: " << reinterpret_cast<NBT::Tag::Int32*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::INT64:
std::cout << prefix << "'Value: " << reinterpret_cast<NBT::Tag::Int64*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::FLOAT:
std::cout << prefix << "'Value: " << reinterpret_cast<NBT::Tag::Float*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::DOUBLE:
std::cout << prefix << "'Value: " << reinterpret_cast<NBT::Tag::Double*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::INT8_ARRAY: {
NBT::Tag::Int8Array* array = reinterpret_cast<NBT::Tag::Int8Array*>(tag);
std::cout << prefix << "|Length: " << array->length() << std::endl;
std::cout << prefix << "'Values: " << std::endl;
for (uint64_t i=0; i<array->length(); i++) {
if (i == array->length()-1) {
std::cout << prefix << " '" << (int64_t) array->getValue(i).value << std::endl;
} else {
std::cout << prefix << " |" << (int64_t) array->getValue(i).value << std::endl;
}
}
break;
}
case NBT::TagType::STRING:
std::cout << prefix << "'Value: " << reinterpret_cast<NBT::Tag::String*>(tag)->getValue() << std::endl;
break;
case NBT::TagType::LIST: {
NBT::Tag::List* list = reinterpret_cast<NBT::Tag::List*>(tag);
std::cout << prefix << "|Contained Type: ";
switch (list->getContainedType()) {
case NBT::TagType::END:
std::cout << "End";
break;
case NBT::TagType::INT8:
std::cout << "8 Bit Integer";
break;
case NBT::TagType::INT16:
std::cout << "16 Bit Integer";
break;
case NBT::TagType::INT32:
std::cout << "32 Bit Integer";
break;
case NBT::TagType::INT64:
std::cout << "64 Bit Integer";
break;
case NBT::TagType::FLOAT:
std::cout << "Float";
break;
case NBT::TagType::DOUBLE:
std::cout << "Double";
break;
case NBT::TagType::INT8_ARRAY:
std::cout << "Array of 8 Bit Integers";
break;
case NBT::TagType::STRING:
std::cout << "String";
break;
case NBT::TagType::LIST:
std::cout << "List";
break;
case NBT::TagType::COMPOUND:
std::cout << "Compound";
break;
case NBT::TagType::INT32_ARRAY:
std::cout << "Array of 32 Bit Integers";
break;
case NBT::TagType::INT64_ARRAY:
std::cout << "Array of 64 Bit Integers";
break;
default:
// WTF? How'd you even get here?
std::cout << "Unknown Type";
}
std::cout << std::endl;
if (list->length() > 0) {
std::cout << prefix << "|Length: " << list->length() << std::endl;
std::cout << prefix << "|" << std::endl;
} else {
std::cout << prefix << "'Length: " << list->length() << std::endl;
}
offsetBytes = offsetBytes + headerSize + 5;
for (uint64_t i=0; i<list->length(); i++) {
if (i == list->length()-1) {
std::cout << prefix << "'";
printTagTypeName(list->getElementPointer(i).value, offsetBytes);
std::cout << std::endl;
drawTree(list->getElementPointer(i).value, prefix+" ", offsetBytes, true);
} else {
std::cout << prefix << "|";
printTagTypeName(list->getElementPointer(i).value, offsetBytes);
std::cout << std::endl;
drawTree(list->getElementPointer(i).value, prefix+"| ", offsetBytes, true);
}
std::vector<uint8_t> serializedElement;
list->getElementPointer(i).value->serializeWithoutHeader(&serializedElement);
offsetBytes += serializedElement.size();
}
break;
}
case NBT::TagType::COMPOUND: {
NBT::Tag::Compound* compound = reinterpret_cast<NBT::Tag::Compound*>(tag);
std::cout << prefix << "|Length: " << compound->length() << std::endl;
std::cout << prefix << "|" << std::endl;
offsetBytes = offsetBytes + headerSize;
for (uint64_t i=0; i<compound->length(); i++) {
if (i == compound->length()-1) {
std::cout << prefix << "'";
printTagTypeName(compound->getElementPointer(i).value, offsetBytes);
std::cout << std::endl;
drawTree(compound->getElementPointer(i).value, prefix+" ", offsetBytes);
} else {
std::cout << prefix << "|";
printTagTypeName(compound->getElementPointer(i).value, offsetBytes);
std::cout << std::endl;
drawTree(compound->getElementPointer(i).value, prefix+"| ", offsetBytes);
}
std::vector<uint8_t> serializedElement;
compound->getElementPointer(i).value->serialize(&serializedElement);
offsetBytes += serializedElement.size();
}
break;
}
case NBT::TagType::INT32_ARRAY: {
NBT::Tag::Int32Array* array = reinterpret_cast<NBT::Tag::Int32Array*>(tag);
std::cout << prefix << "|Length: " << array->length() << std::endl;
std::cout << prefix << "'Values: " << std::endl;
for (uint64_t i=0; i<array->length(); i++) {
if (i == array->length()-1) {
std::cout << prefix << " '" << array->getValue(i).value << std::endl;
} else {
std::cout << prefix << " |" << array->getValue(i).value << std::endl;
}
}
break;
}
case NBT::TagType::INT64_ARRAY: {
NBT::Tag::Int64Array* array = reinterpret_cast<NBT::Tag::Int64Array*>(tag);
std::cout << prefix << "|Length: " << array->length() << std::endl;
std::cout << prefix << "'Values: " << std::endl;
for (uint64_t i=0; i<array->length(); i++) {
if (i == array->length()-1) {
std::cout << prefix << " '" << array->getValue(i).value << std::endl;
} else {
std::cout << prefix << " |" << array->getValue(i).value << std::endl;
}
}
break;
}
default:
// WTF? How'd you even get here?
std::cout << prefix << "'???" << std::endl;
}
std::cout << prefix << std::endl;
}
int main(int argc, char* argv[]) {
return 0;
std::vector<CLI::Flag> flags;
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("FILE", "path of the file to dump"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Present NBT in human or machine readable formats");
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"
<< "DumpNBT 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::cerr << cliParser.getUsage() << std::endl;
return EXIT_USAGE;
}
std::ifstream fileStream;
fileStream.open(cliParser.getArgument(0).value, std::ios::in | std::ios::binary | std::ios::ate);
if (!fileStream.is_open()) {
std::cerr << argv[0] << ": Could not open file: " << cliParser.getArgument(0).value << std::endl;
return EXIT_RUNTIME;
}
uint64_t fileSize = fileStream.tellg();
fileStream.seekg(0, std::ios::beg);
uint8_t data[fileSize];
uint8_t* nextByte = new uint8_t;
for (uint64_t i=0; i<fileSize; i++) {
fileStream.read(reinterpret_cast<char*>(nextByte), 1);
data[i] = *nextByte;
}
fileStream.close();
ErrorOr<std::vector<NBT::Tag::Generic*>> tags = NBT::deserialize(data, fileSize);
if (tags.isError) {
std::cerr << "Invalid data." << std::endl;
return EXIT_RUNTIME;
}
uint64_t offsetBytes = 0;
for (uint64_t i=0; i<tags.value.size(); i++) {
printTagTypeName(tags.value[i], offsetBytes);
std::cout << std::endl;
drawTree(tags.value[i], "", offsetBytes);
std::vector<uint8_t> serialized;
tags.value[i]->serialize(&serialized);
offsetBytes += serialized.size();
}
return EXIT_SUCCESS;
}

View File

@ -1,5 +1,8 @@
//Copyright 2022, FOSS-VG Developers and Contributers
//
// Author(s):
// BodgeMaster, Shwoomple
//
//This program is free software: you can redistribute it and/or modify it
//under the terms of the GNU Affero General Public License as published
//by the Free Software Foundation, version 3.
@ -13,167 +16,260 @@
//version 3 along with this program.
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdint>
#include <cctype>
#include <sockpp/tcp_acceptor.h>
#include <sockpp/tcp6_acceptor.h>
#include <thread>
#include <mutex>
#include <chrono>
#include <csignal>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <string>
#include <sockpp/tcp_acceptor.h>
#include <sockpp/tcp_connector.h>
#include <sockpp/tcp6_acceptor.h>
#include <sockpp/tcp6_connector.h>
#include <sockpp/udp_socket.h>
#include <sockpp/udp6_socket.h>
#include <thread>
#include <vector>
#include "../lib/error.hpp"
#include "../lib/cli.hpp"
#include "../lib/error.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#define EXIT_UNIMPLEMENTED 3
#define EXIT_SIGNAL 4
bool ipv4 = true;
bool ipv6 = true;
bool tcp = true;
bool udp = true;
bool listenMode = false;
int64_t mtu = 1500;
std::string host;
in_port_t port;
sockpp::tcp_socket* tcpSocket;
sockpp::tcp6_socket* tcp6Socket;
// TCP v4 server
sockpp::tcp_socket tcpSocket;
sockpp::tcp_acceptor tcpAcceptor;
// TCP v4 client
sockpp::tcp_connector tcpConnector;
// TCP v6 server
sockpp::tcp6_socket tcp6Socket;
sockpp::tcp6_acceptor tcp6Acceptor;
std::mutex tcpSocketMutex;
std::mutex tcp6SocketMutex;
std::mutex consoleMutex;
// used for coordinated graceful exit across threads
// TCP v6 client
sockpp::tcp6_connector tcp6Connector;
// UDP v4 server and client
sockpp::udp_socket udpSocket;
// UDP v6 server and client
sockpp::udp6_socket udp6Socket;
bool exitProgram = false;
bool ipv4 = false;
bool ipv6 = false;
bool tcp = false;
bool udp = false;
bool outgoing = false;
std::string host;
in_port_t port;
// This is probably bigger than the MTU on any given network.
// This should allow us to read entire packets at once when they arrive
// slowly enough to be read individually.
const uint32_t bufferSize = 2048;
uint8_t networkBuffer[bufferSize];
std::string readByteFromStdin() {
std::string input = "";
// read 2 characters from stdin
char characterInput;
bool readByte = false;
uint16_t iterationsSinceLastInput = 0;
while (input.length() < 2 && !exitProgram) {
if (std::cin.good()) {
std::cin.get(characterInput);
readByte = true;
} else {
readByte = false;
}
// ignore space, tabs, and newlines
if (readByte && characterInput!=' ' && characterInput!='\n' && characterInput!='\r' && characterInput!='\t') {
input.push_back(characterInput);
}
iterationsSinceLastInput++;
if (readByte) {
iterationsSinceLastInput = 0;
}
if (iterationsSinceLastInput>1024) {
// prevent integer overflow
iterationsSinceLastInput = 1024;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
return exitProgram? "" : std::string(1, (char) std::stoi(input, nullptr, 16));
}
void signalHandler(int signal) {
// shut down gracefully
exitProgram = true;
// if still waiting for incoming connection, stop waiting
tcpAcceptor.shutdown();
tcp6Acceptor.shutdown();
// tell sockpp to close TCP socket if open because it blocks when trying
// to read and there is no data
if (tcpSocket != nullptr && *tcpSocket) {
// Intentionally not using the mutex here
std::cout << "test\n";
tcpSocket->shutdown(SHUT_RD);
tcpAcceptor.shutdown();
if (tcpSocket) {
tcpSocket.shutdown(SHUT_RD);
}
if (tcp6Socket != nullptr && *tcp6Socket) {
// Intentionally not using the mutex here
tcp6Socket->shutdown(SHUT_RD);
if (tcpConnector) {
tcpConnector.shutdown(SHUT_RD);
}
//TODO: figure out if - and how - this applies to UDP
// Priority is to finish up all unfinished business that can be finished up.
// If something has the console mutex locked, that should not prevent
// other threads from winding down. This is why logging happens last.
consoleMutex.lock();
std::cerr << "Received signal " << signal << ", shutting down." << std::endl;
consoleMutex.unlock();
std::exit(signal);
if (tcp6Socket) {
tcp6Socket.shutdown(SHUT_RD);
}
if (tcp6Connector) {
tcp6Connector.shutdown(SHUT_RD);
}
if (udpSocket) {
udpSocket.shutdown(SHUT_RD);
}
if (udp6Socket) {
udp6Socket.shutdown(SHUT_RD);
}
std::cerr << "Received signal " << signal << ", bye!" << std::endl;
std::exit(EXIT_SIGNAL);
}
void readFromTCPSocket(sockpp::tcp_socket* socket, int64_t mtu) {
ssize_t numBytes;
uint8_t buffer[mtu];
tcpSocketMutex.lock();
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];
void readFromTCP() {
ssize_t byteCount;
while (!exitProgram && (outgoing? (byteCount = tcpConnector.read(networkBuffer, bufferSize)) > 0 : (byteCount = tcpSocket.read(networkBuffer, bufferSize)) > 0)) {
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout.flush();
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];
void writeToTCP() {
while (!exitProgram) {
if (outgoing) {
if (tcpConnector.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcpConnector.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcpConnector.last_error_str() << std::endl;
return;
}
} else {
if (tcpSocket.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcpSocket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcpSocket.last_error_str() << std::endl;
return;
}
}
}
}
void readFromTCP6() {
ssize_t byteCount;
while (!exitProgram && (outgoing? (byteCount = tcp6Connector.read(networkBuffer, bufferSize)) > 0 : (byteCount = tcp6Socket.read(networkBuffer, bufferSize)) > 0)) {
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[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){
void writeToTCP6() {
while (!exitProgram) {
//TODO: Implement locking/unlocking/threading shenanigans
if (outgoing) {
if (tcp6Connector.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcp6Connector.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcp6Connector.last_error_str() << std::endl;
return;
}
} else {
if (tcp6Socket.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcp6Socket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcp6Socket.last_error_str() << std::endl;
return;
}
}
}
consoleMutex.lock();
std::cerr << std::endl << "Connection closed." << std::endl;
consoleMutex.unlock();
}
void writeToTCP6Socket(sockpp::tcp6_socket* socket){
void readFromUDP() {
ssize_t byteCount;
sockpp::udp_socket::addr_t peer;
while ((byteCount = udpSocket.recv_from(networkBuffer, bufferSize, &peer)) > 0) {
std::cout << peer << ": ";
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout << std::dec << std::endl;
}
}
void writeToUDP(sockpp::udp_socket::addr_t peer) {
while (!exitProgram) {
//TODO: Implement locking/unlocking/threading shenanigans
if (udpSocket.send_to(readByteFromStdin(), peer) == -1 && !exitProgram) {
exitProgram = true;
udpSocket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << udpSocket.last_error_str() << std::endl;
return;
}
}
consoleMutex.lock();
std::cerr << std::endl << "Connection closed." << std::endl;
consoleMutex.unlock();
}
int main(int argc, char* argv[]){
void readFromUDP6() {
ssize_t byteCount;
sockpp::udp6_socket::addr_t peer;
while ((byteCount = udp6Socket.recv_from(networkBuffer, bufferSize, &peer)) > 0) {
std::cout << peer << ": ";
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout << std::dec << std::endl;
}
}
void writeToUDP6(sockpp::udp6_socket::addr_t peer) {
while (!exitProgram) {
if (udp6Socket.send_to(readByteFromStdin(), peer) == -1 && !exitProgram) {
exitProgram = true;
udp6Socket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << udp6Socket.last_error_str() << std::endl;
return;
}
}
}
int main(int argc, char* argv[]) {
std::signal(SIGINT, signalHandler);
std::signal(SIGTERM, signalHandler);
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('6', "ipv6", "use IPv6, defaults to both when -4 and -6 are omitted, otherwise uses what is specified"));
flags.push_back(CLI::Flag('t', "tcp", "use TCP, 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('e', "echo-back", "echo input back to stdout"));
flags.push_back(CLI::Flag('4', "ipv4", "use IPv4, either this or IPv6 has to be specified"));
flags.push_back(CLI::Flag('6', "ipv6", "use IPv6, either this or IPv4 has to be specified"));
flags.push_back(CLI::Flag('t', "tcp", "use TCP, either this or UDP has to be specified"));
flags.push_back(CLI::Flag('u', "udp", "use UDP, either this or TCP has to be specified"));
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;
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(
'p', "print-prefixes", "TCPin:UDPin:TCPout:UDPout",
"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(
'i', "input-prefixes", "TCP:UDP",
"override default prefixes for input (defaults to \"t:u\")"
));
options.push_back(CLI::Option('c', "connect", "HOST", "make an outgoing connection to HOST instead of listening for an incoming connection"));
options.push_back(CLI::Option('b', "bind", "ADDRESS", "(UDP only) bind to ADDRESS instead of localhost"));
std::vector<CLI::Argument> arguments;
arguments.push_back(CLI::Argument("PORT", "the port to use"));
arguments.push_back(CLI::Argument("PORT", "the port to lsiten on (or connect to)"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary tcp/udp connections in hex format.");
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary TCP/UDP connections in hex format", "Spaces, tabs, newlines, and carriage returns in the input are ignored.\n\tYou may want to disable input echoing using `stty -echo` (reenable using `stty echo`).\n\tNote that many terminals do line buffering on the input by default.");
if (cliParser.getFlag("help").value){
if (cliParser.getFlag("help").value) {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_SUCCESS;
}
if (cliParser.getFlag("license").value){
if (cliParser.getFlag("license").value) {
std::cout
<< "Copyright 2022, FOSS-VG Developers and Contributers\n"
<< "\n"
@ -194,99 +290,205 @@ int main(int argc, char* argv[]){
<< std::endl;
return EXIT_SUCCESS;
}
if (cliParser.wrongUsage) {
std::cout << cliParser.getUsage() << std::endl;
return EXIT_USAGE;
}
if (cliParser.getFlag("ipv4").value || cliParser.getFlag("ipv6").value) {
ipv4 = cliParser.getFlag("ipv4").value;
ipv6 = cliParser.getFlag("ipv4").value;
ipv4 = cliParser.getFlag("ipv4").value;
ipv6 = cliParser.getFlag("ipv6").value;
tcp = cliParser.getFlag("tcp").value;
udp = cliParser.getFlag("udp").value;
if (cliParser.getOption("connect").errorCode != ErrorCodes::NOT_PRESENT) {
outgoing = true;
host = cliParser.getOption("connect").value;
}
if (cliParser.getFlag("tcp").value || cliParser.getFlag("udp").value) {
tcp = cliParser.getFlag("tcp").value;
udp = cliParser.getFlag("udp").value;
if (!(ipv4 || ipv6) || (ipv4 && ipv6) || !(tcp || udp) || (tcp && udp)) {
std::cout << "Please specify which protocols to use (one of IPv4/IPv6, one of TCP/UDP)." << std::endl;
return EXIT_USAGE;
}
if (cliParser.getOption('c').errorCode == ErrorCodes::NOT_PRESENT) {
listenMode = true;
}
if (cliParser.getOption("mtu-optimize").errorCode == ErrorCodes::SUCCESS) {
mtu = std::stol(cliParser.getOption("mtu-optimize").value);
}
host = cliParser.getOption("connect").value;
//FIXME: use a function that returns a fixed-width data type instead,
// ensure that the given value is a valid port
port = (in_port_t) std::stoi(cliParser.getArgument(0).value);
if (listenMode) {
if (udp) {
std::cerr << "UDP support is not implemented yet." << std::endl;
return EXIT_UNIMPLEMENTED;
if (outgoing) {
if (tcp) {
std::cerr << "Connecting to " << host << " on port " << (int) port << " (TCP)..." << std::endl;
if (ipv4) {
// TCP v4 out
tcpConnector = sockpp::tcp_connector({host, port});
if (!tcpConnector) {
std::cerr << "Error connecting to " << host << " on port " << port << std::endl;
std::cerr << tcpConnector.last_error_str() << std::endl;
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP = std::thread(readFromTCP);
std::thread threadWriteToTCP = std::thread(writeToTCP);
threadReadFromTCP.join();
threadWriteToTCP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// TCP v6 out
tcp6Connector = sockpp::tcp6_connector({host, port});
if (!tcp6Connector) {
std::cerr << "Error connecting to " << host << " on port " << port << std::endl;
std::cerr << tcp6Connector.last_error_str() << std::endl;
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP6 = std::thread(readFromTCP6);
std::thread threadWriteToTCP6 = std::thread(writeToTCP6);
threadReadFromTCP6.join();
threadWriteToTCP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
} else {
std::cerr << "Talking to " << host << " on port " << (int) port << " (UDP)..." << std::endl;
if (ipv4) {
// UDP v4 out
if (!udpSocket) {
std::cerr << "Error creating UDP socket: " << udpSocket.last_error_str() << std::endl;
}
// Btw: Did you know that UDP has no concept of a connection?
sockpp::udp_socket::addr_t peer = sockpp::inet_address(host, port);
if (!udpSocket.connect(peer)) {
std::cerr << "Error associating socket with " << host << " port " << port << std::endl;
std::cerr << udpSocket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP = std::thread(readFromUDP);
std::thread threadWriteToUDP = std::thread(writeToUDP, peer);
threadReadFromUDP.join();
threadWriteToUDP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// UDP v6 out
if (!udp6Socket) {
std::cerr << "Error creating UDP socket: " << udp6Socket.last_error_str() << std::endl;
}
// Btw: Did you know that UDP has no concept of a connection?
sockpp::udp6_socket::addr_t peer = sockpp::inet6_address(host, port);
if (!udp6Socket.connect(peer)) {
std::cerr << "Error associating socket with " << host << " port " << port << std::endl;
std::cerr << udp6Socket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP6 = std::thread(readFromUDP6);
std::thread threadWriteToUDP6 = std::thread(writeToUDP6, peer);
threadReadFromUDP6.join();
threadWriteToUDP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
}
if (ipv6) {
//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(!tcp6Acceptor){
std::cerr << "Error while creating TCP6 acceptor: " << tcp6Acceptor.last_error_str() << std::endl;
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;
}
if(ipv4){
std::cerr << "Listening on port " << port << "." << 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();
delete tcpSocket;
return EXIT_SUCCESS;
}
} else {
std::cerr << "Client mode is not implemented yet." << std::endl;
return EXIT_UNIMPLEMENTED;
if (tcp) {
std::cerr << "Listening on port " << (int) port << " (TCP)..." << std::endl;
if (ipv4) {
// TCP v4 in
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 = 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;
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP = std::thread(readFromTCP);
std::thread threadWriteToTCP = std::thread(writeToTCP);
threadReadFromTCP.join();
threadWriteToTCP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// TCP v6 in
tcp6Acceptor = sockpp::tcp6_acceptor(port);
if (!tcp6Acceptor) {
std::cerr << "Error while creating TCP acceptor: " << tcp6Acceptor.last_error_str() << std::endl;
return EXIT_RUNTIME;
}
sockpp::inet6_address peer;
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;
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP6 = std::thread(readFromTCP6);
std::thread threadWriteToTCP6 = std::thread(writeToTCP6);
threadReadFromTCP6.join();
threadWriteToTCP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
} else {
std::string address = "localhost";
if (cliParser.getOption("bind").errorCode != ErrorCodes::NOT_PRESENT) {
address = cliParser.getOption("bind").value;
}
std::cerr << "Listening on " << address << " port " << (int) port << " (UDP)..." << std::endl;
if (ipv4) {
// UDP v4 in
if (!udpSocket) {
std::cerr << "Error creating UDP socket: " << udpSocket.last_error_str() << std::endl;
}
if (!udpSocket.bind(sockpp::inet_address(address, port))) {
std::cerr << "Error binding UDP socket to " << address << " port " << port << ": " << udpSocket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP = std::thread(readFromUDP);
// Can't send bc we have no idea where to send to.
//std::thread threadWriteToUDP = std::thread(writeToUDP);
threadReadFromUDP.join();
//threadWriteToUDP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// UDP v6 in
if (!udp6Socket) {
std::cerr << "Error creating UDP socket: " << udp6Socket.last_error_str() << std::endl;
}
if (!udp6Socket.bind(sockpp::inet6_address(address, port))) {
std::cerr << "Error binding UDP socket to " << address << " port " << port << ": " << udp6Socket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP6 = std::thread(readFromUDP6);
// Can't send bc we have no idea where to send to.
//std::thread threadWriteToUDP6 = std::thread(writeToUDP6);
threadReadFromUDP6.join();
//threadWriteToUDP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
}
}
}

155
src/tools/zlibutil.cpp Normal file
View File

@ -0,0 +1,155 @@
// Copyright 2024, FOSS-VG Developers and Contributers
//
// Author(s):
// Jocadbz
//
// 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 <iomanip>
#include <iostream>
#include <vector>
#include <tinyutf8/tinyutf8.h>
#include <zlib/zlib.h>
#include <cstring>
#include <fstream>
#include "../lib/cli.hpp"
#include "../lib/file.hpp"
#include "../lib/zlibutil.hpp"
#include "../lib/error.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#define CHUNK_SIZE 16384 // Chunk size
/*
Finally, the main file
*/
int main(int argc, char* argv[]) {
std::vector<CLI::Flag> flags;
flags.push_back(CLI::Flag('d', "decompress", "descompress a file"));
std::vector<CLI::Option> options;
std::vector<CLI::Argument> arguments;
arguments.push_back(CLI::Argument("FILE", "path of the file to compress/decompress"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Compress or decompress files using zlib");
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"
<< "ZlibUtil 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 filename = cliParser.getArgument(0).value;
ErrorOr<File*> filePointer = File::open(filename, 'r');
if (filePointer.isError) {
std::cout << "Failed to open file: " << filename << std::endl;
return EXIT_RUNTIME;
}
File* file = filePointer.value;
File* writeFile;
if (cliParser.getFlag("decompress").value) {
std::vector<uint8_t> bytes = file->read(file->size.value).value;
ErrorOr<std::vector<uint8_t>> decompressed = zlib::decompressData(bytes);
if (decompressed.isError) {
std::cout << "Error: Failed to decompress: " << filename << std::endl;
delete file;
// not cleaning up writeFile here bc it hasn't been created
return EXIT_RUNTIME;
}
std::string outFilename;
if (filename.length() > 3 && filename.rfind(".zz") == filename.length()-3) {
outFilename = filename.substr(0, filename.length()-3);
} else {
outFilename = filename + ".uncompressed";
}
writeFile = File::open(outFilename, 'w').value;
writeFile->write(decompressed.value);
writeFile->close();
} else {
std::vector<uint8_t> bytes = file->read(file->size.value).value;
ErrorOr<std::vector<uint8_t>> compressed = zlib::compressData(bytes);
if (compressed.isError) {
std::cout << "Error: Failed to compress: " << filename << std::endl;
delete file;
// not cleaning up writeFile here bc it hasn't been created
return EXIT_RUNTIME;
}
writeFile = File::open(filename + ".zz", 'w').value;
writeFile->write(compressed.value);
writeFile->close();
}
delete file;
delete writeFile;
}