Compare commits
183 Commits
0462756451
...
38fad56965
Author | SHA1 | Date |
---|---|---|
Shwoomple | 38fad56965 | |
BodgeMaster | f6b965040d | |
BodgeMaster | b5c18cd0de | |
BodgeMaster | a1ba08b7db | |
BodgeMaster | 1d7e98d0b3 | |
BodgeMaster | a7e07d2c3c | |
BodgeMaster | 7ae843039c | |
BodgeMaster | 5574cdb4bf | |
BodgeMaster | 89cfb9d850 | |
BodgeMaster | f681c54c82 | |
BodgeMaster | ee0ebb273c | |
Shwoomple | 8dea1f2d31 | |
Shwoomple | c825c73afd | |
Shwoomple | e7711a3d59 | |
Shwoomple | e7ce6f5cd4 | |
BodgeMaster | ee9b5d4f67 | |
BodgeMaster | b84130344d | |
BodgeMaster | 25d7806f6d | |
Shwoomple | 6e57a86338 | |
Shwoomple | c54eb48887 | |
BodgeMaster | c14504ce0b | |
BodgeMaster | 92cf81c1b4 | |
BodgeMaster | df35243ee9 | |
BodgeMaster | 36dcf0a0f5 | |
BodgeMaster | 93fdcb7b65 | |
BodgeMaster | 8d2f3f2fa5 | |
BodgeMaster | cdc23e7468 | |
BodgeMaster | e9bfb6eeee | |
BodgeMaster | 8b62ec9c88 | |
BodgeMaster | ca0af3306f | |
BodgeMaster | 9b21dfaee5 | |
BodgeMaster | 996154fbbc | |
BodgeMaster | 77dd79398f | |
BodgeMaster | fd5fe3967f | |
BodgeMaster | 374466f26c | |
BodgeMaster | 3b56a52085 | |
BodgeMaster | 7be73f86d4 | |
BodgeMaster | 71834e1018 | |
BodgeMaster | ccce564219 | |
BodgeMaster | 53279c6905 | |
BodgeMaster | f8dd10d301 | |
BodgeMaster | 6672a4f149 | |
BodgeMaster | d5ce50a4a9 | |
BodgeMaster | f0092b78d3 | |
BodgeMaster | b1ba33b39f | |
BodgeMaster | 833c09e2da | |
BodgeMaster | b53999a548 | |
BodgeMaster | 379903d751 | |
BodgeMaster | 17792ec5bf | |
BodgeMaster | 9ce35b5c6b | |
BodgeMaster | be08a97275 | |
BodgeMaster | 6bdf99c897 | |
BodgeMaster | 936def1a65 | |
BodgeMaster | 3cc1222de9 | |
BodgeMaster | ecf3b14b5a | |
BodgeMaster | 8da758becd | |
BodgeMaster | 1e5051b503 | |
BodgeMaster | 3b4c125ca2 | |
BodgeMaster | 4cb1206839 | |
BodgeMaster | 39c5940200 | |
BodgeMaster | f3e03710f6 | |
BodgeMaster | 72fc923839 | |
BodgeMaster | 5059bd0193 | |
BodgeMaster | 8bb633f118 | |
BodgeMaster | ec44ac9531 | |
BodgeMaster | 341b4c187e | |
BodgeMaster | 79650e390e | |
BodgeMaster | 2d2b67373c | |
BodgeMaster | 4c4366f7e6 | |
BodgeMaster | 4ef1d2c44f | |
Shwoomple | 5920d1d004 | |
Shwoomple | 056c1e6b11 | |
BodgeMaster | 8b1491c311 | |
BodgeMaster | fc2caf3bc0 | |
BodgeMaster | 89baeebc65 | |
Shwoomple | c204aa7d76 | |
BodgeMaster | 09503d3dc7 | |
BodgeMaster | 9fb06c998e | |
BodgeMaster | aa97154474 | |
BodgeMaster | 9abfd9e5a9 | |
Shwoomple | 150ce826ba | |
Shwoomple | 3449e3b9c4 | |
Charlie Root | 213d28a9b8 | |
Shwoomple | c1d7801436 | |
Shwoomple | 9610f4a4a2 | |
BodgeMaster | 434c976cc5 | |
BodgeMaster | 47fd1f8970 | |
BodgeMaster | 10b1d9fa0c | |
Shwoomple | e8d41efeef | |
Shwoomple | 508b5e67e7 | |
BodgeMaster | 398321e415 | |
BodgeMaster | 53878c3e2b | |
BodgeMaster | ad291ee77d | |
BodgeMaster | 6149418f52 | |
BodgeMaster | ac12bcf865 | |
BodgeMaster | 8b92d24ab9 | |
BodgeMaster | aab91a2523 | |
BodgeMaster | 58b1199e38 | |
Shwoomple | 48f8a7dcf2 | |
BodgeMaster | 209d0828b4 | |
BodgeMaster | b4d4ce77b2 | |
BodgeMaster | ee5048331c | |
BodgeMaster | 629c999336 | |
BodgeMaster | cdd17045d1 | |
BodgeMaster | bb40f6553e | |
BodgeMaster | a9759e3bc2 | |
BodgeMaster | ab1164557d | |
BodgeMaster | 1b8819ffe5 | |
BodgeMaster | 4934a78aaa | |
BodgeMaster | 327ad9a9b5 | |
BodgeMaster | bddab2e9f8 | |
BodgeMaster | 017c8a61f8 | |
BodgeMaster | 5272636cb8 | |
BodgeMaster | 91d16ea451 | |
BodgeMaster | a1fc0ce4b4 | |
Shwoomple | ca7b121c4d | |
BodgeMaster | 25bec4c587 | |
BodgeMaster | 589cf1ddaf | |
BodgeMaster | 884a5239c6 | |
BodgeMaster | 9190cad80d | |
BodgeMaster | a862590370 | |
BodgeMaster | 3995e97f03 | |
BodgeMaster | c9ec524db1 | |
BodgeMaster | 73ae58e522 | |
BodgeMaster | acc19ae100 | |
BodgeMaster | 149285c357 | |
BodgeMaster | 0c92bdf8fd | |
BodgeMaster | 86f1ef596f | |
BodgeMaster | 027f324f03 | |
BodgeMaster | 7a2c1d7d57 | |
BodgeMaster | 6fecb2cdb7 | |
BodgeMaster | e882a09099 | |
BodgeMaster | 748c91c375 | |
BodgeMaster | f5d85da98c | |
BodgeMaster | 396b9673fd | |
BodgeMaster | 68fbf3ae20 | |
BodgeMaster | 4363432025 | |
BodgeMaster | 5400790e78 | |
BodgeMaster | c7dd5471dd | |
BodgeMaster | 8048dc8891 | |
BodgeMaster | a1f16e6f6b | |
Shwoomple | cb7b5ddba7 | |
Shwoomple | e0648720bb | |
Shwoomple | ebcf436a18 | |
BodgeMaster | c59a1ac723 | |
BodgeMaster | aef91fe7cd | |
BodgeMaster | 4af9003761 | |
Milan Suman | 704b440d5a | |
BodgeMaster | 608767f5c2 | |
BodgeMaster | e31bff0802 | |
BodgeMaster | 5c73308934 | |
BodgeMaster | b59fe1857e | |
BodgeMaster | 69f15e928a | |
BodgeMaster | d0d02fc8d2 | |
BodgeMaster | 1308327fae | |
BodgeMaster | 4582c3e595 | |
BodgeMaster | 28719072bb | |
BodgeMaster | 800fd66044 | |
BodgeMaster | d90e7f16bd | |
BodgeMaster | 845b3fb922 | |
Milan Suman | 4f1ad714bd | |
BodgeMaster | adc9a7f36b | |
BodgeMaster | b044503951 | |
BodgeMaster | d97e1a8336 | |
BodgeMaster | 6baff11ebd | |
BodgeMaster | c9d6cf0b5e | |
BodgeMaster | 7d7ce2ba6b | |
BodgeMaster | a51c65c9f2 | |
BodgeMaster | 8bb0732cc6 | |
BodgeMaster | 0dcc579bb5 | |
BodgeMaster | db3b133f88 | |
BodgeMaster | 44a20c875a | |
BodgeMaster | 1804433a9f | |
BodgeMaster | 2cc2543b2a | |
BodgeMaster | a0d2974f0a | |
Milan Suman | 4659946a2f | |
Milan Suman | b5312aeb58 | |
BodgeMaster | 9562ae7be9 | |
BodgeMaster | b1733bc007 | |
Milan Suman | d315c6fcfc | |
Milan Suman | 2f38636a27 | |
BodgeMaster | 21310fecc7 | |
BodgeMaster | 09e2030a55 |
|
@ -4,6 +4,13 @@
|
|||
/dependencies/*
|
||||
!/dependencies/.placeholder
|
||||
|
||||
/include/*
|
||||
!/include/.placeholder
|
||||
|
||||
.download_cache
|
||||
|
||||
.localenv.bashrc
|
||||
|
||||
# ignore endianness check
|
||||
/.endianness
|
||||
/resources/check_endianness
|
||||
|
@ -16,3 +23,5 @@
|
|||
|
||||
#vscode
|
||||
.vscode
|
||||
|
||||
writeTest
|
12
Makefile
12
Makefile
|
@ -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
|
18
README.md
18
README.md
|
@ -22,13 +22,19 @@ Immediate goals:
|
|||
|
||||
### Prerequisites:
|
||||
|
||||
This project requires bash and a C++20 compiler.
|
||||
Build dependencies:
|
||||
|
||||
The project setup requires wget or curl, gzip, and tar.
|
||||
- bash
|
||||
- a C++ 20 compiler
|
||||
|
||||
Additional requirements for building dependencies:
|
||||
Setup dependencies:
|
||||
|
||||
- sockpp: a C compiler, CMake
|
||||
- wget or curl
|
||||
- gzip
|
||||
- sha256sum (or NetBSD's sha256, hashalot's sha256 will not work)
|
||||
- tar
|
||||
- a C compiler (for sockpp)
|
||||
- CMake (for sockpp)
|
||||
|
||||
**For people using other shells than bash:** You need to at least have bash
|
||||
installed to use the scripts, but using it as your shell while working on
|
||||
|
@ -45,7 +51,9 @@ point to `bin/lib`.
|
|||
- `git clone` this repository
|
||||
- if using bash:
|
||||
- `source` the file `setupenv.bashrc` from the project's base directory
|
||||
to load the provided shell environment
|
||||
to load the provided shell environment (local customizations to the
|
||||
environment can be placed in a fiile `.localenv.bashrc` in the project's
|
||||
root directory if necessary)
|
||||
- `setup_project`
|
||||
- if not using bash or not using the provided environment:
|
||||
- `cd` to the project's base directory
|
||||
|
|
|
@ -48,11 +48,6 @@ universally used.
|
|||
Use explicitly sized data types where possible.
|
||||
For example, use `int32_t` instead of `int`.
|
||||
|
||||
When coming up with names, refer to data types by category and size.
|
||||
For example, refer to double precision floating point numbers as `float64`
|
||||
instead of `double`.
|
||||
|
||||
|
||||
## Shell Script
|
||||
|
||||
Use the hash bang `#!/usr/bin/env bash`.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -24,11 +24,15 @@ Provided aliases:
|
|||
|
||||
## setup_project
|
||||
|
||||
Cleans the project and its dependencies first, ensuring the project is in
|
||||
a known state, then downloads and extracts dependencies.
|
||||
Cleans the project and its dependencies first (see below), ensuring
|
||||
the project is in a known state, then sets up dependencies.
|
||||
|
||||
This will probably do more in the future (for example compile dependencies
|
||||
that need to be compiled).
|
||||
This includes downloading (and caching) of files that are not yet
|
||||
locally cached and compiling dependencies that need to be compiled.
|
||||
|
||||
This script’s intended purpose is setting up a development environment but
|
||||
it can also be used to update the locally set-up dependencies to the ones
|
||||
that the project is using.
|
||||
|
||||
|
||||
# build
|
||||
|
@ -55,14 +59,37 @@ Accepted environment variables:
|
|||
- `CXX`: override the default compiler
|
||||
- `CXXFLAGS`: override the default compiler flags, must at least specify
|
||||
the C++ version
|
||||
- `SINGLE`: if set to `yes`, causes the test script to compile the tests in
|
||||
single-threaded mode¹
|
||||
|
||||
¹Unit tests are always run one after the other.
|
||||
|
||||
|
||||
# clean
|
||||
|
||||
Removes and re-creates `bin/`. Also removes the endianness header and
|
||||
the endianness check binary.
|
||||
Removes and re-creates `bin/` and `include/`, then re-creates symlinks to
|
||||
shared object and header files as needed for the build process.
|
||||
Also removes the endianness header and the endianness check binary.
|
||||
|
||||
|
||||
# clean_dependencies
|
||||
|
||||
Removes and re-creates `dependencies/`.
|
||||
Removes and re-creates `dependencies/` and prunes the download cache of files
|
||||
that either have been corrupted or are no longer used.
|
||||
|
||||
# lib
|
||||
|
||||
This is not a script you are supposed to run. It's a library that contains
|
||||
some functions for the other scripts to work properly on all platforms.
|
||||
|
||||
Features it provides:
|
||||
|
||||
- `$WAIT_ANYWAY`: a variable containing the `wait` command if `SINGLE=yes`
|
||||
is set.
|
||||
- `$CXX_WITH_FLAGS`: deals with `CXX` and `CXXFLAGS` environment variables
|
||||
so it can be used as a generic compiler command
|
||||
- function `check_sha256`: deals with `sha256sum` and NetBSD's `sha256`
|
||||
- function `remove`: better verbosity
|
||||
- function `create_directory`: alternative to `mkdir -v` because that's not
|
||||
available on some systems
|
||||
- function `create_file`: the same but for files
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -23,11 +23,11 @@ A simple tool written in Java that takes an input as UTF-8 and outputs it in Jav
|
|||
Usage example: `echo -ne "\x00" | java JavaStringGenerator > output_file`
|
||||
|
||||
|
||||
## servers.dat
|
||||
## NBT_data
|
||||
|
||||
My current servers.dat as pulled from my Minecraft installation. Used for testing the NBT library until we have something better.
|
||||
Data used to test the NBT library.
|
||||
|
||||
|
||||
## 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.
|
||||
`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
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,354 @@
|
|||
#############################################################################
|
||||
# Examples for all types of tags: #
|
||||
#############################################################################
|
||||
|
||||
[0: End]:
|
||||
|–Header: 1 byte
|
||||
|–Payload: 0 bytes
|
||||
'–Total: 1 byte
|
||||
|
||||
[0: 8 Bit Integer] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 1 byte
|
||||
|–Total: 8 bytes
|
||||
'–Value: 0
|
||||
|
||||
[0: 16 Bit Integer] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 2 bytes
|
||||
|–Total: 9 bytes
|
||||
'–Value: 0
|
||||
|
||||
[0: 32 Bit Integer] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 4 bytes
|
||||
|–Total: 11 bytes
|
||||
'–Value: 0
|
||||
|
||||
[0: 64 Bit Integer] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 8 bytes
|
||||
|–Total: 15 bytes
|
||||
'–Value: 0
|
||||
|
||||
[0: Float] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 4 bytes
|
||||
|–Total: 11 bytes
|
||||
'–Value: 0
|
||||
|
||||
[0: Double] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 8 bytes
|
||||
|–Total: 15 bytes
|
||||
'–Value: 0
|
||||
|
||||
[0: Array of 8 Bit Integers] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 7 bytes
|
||||
|–Total: 14 bytes
|
||||
|–Length: 3
|
||||
'–Values:
|
||||
|–0
|
||||
|–0
|
||||
'–0
|
||||
|
||||
[0: String] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 14 bytes
|
||||
|–Total: 21 bytes
|
||||
'–Value: Hello World!
|
||||
|
||||
[0: List] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 8 bytes
|
||||
|–Total: 15 bytes
|
||||
|–Contained Type: 8 Bit Integer
|
||||
|–Length: 3
|
||||
|
|
||||
|–[12: 8 Bit Integer]:
|
||||
| |–Payload: 1 byte
|
||||
| |–Total: 1 byte
|
||||
| '–Value: 0
|
||||
|
|
||||
|–[13: 8 Bit Integer]:
|
||||
| |–Payload: 1 byte
|
||||
| |–Total: 1 byte
|
||||
| '–Value: 0
|
||||
|
|
||||
'–[14: 8 Bit Integer]:
|
||||
|–Payload: 1 byte
|
||||
|–Total: 1 byte
|
||||
'–Value: 0
|
||||
|
||||
[0: Compound] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 25 bytes
|
||||
|–Total: 32 bytes
|
||||
|–Length: 4
|
||||
|
|
||||
|–[7: 8 Bit Integer] name:
|
||||
| |–Header: 7 bytes
|
||||
| |–Payload: 1 byte
|
||||
| |–Total: 8 bytes
|
||||
| '–Value: 0
|
||||
|
|
||||
|–[15: 8 Bit Integer] name:
|
||||
| |–Header: 7 bytes
|
||||
| |–Payload: 1 byte
|
||||
| |–Total: 8 bytes
|
||||
| '–Value: 0
|
||||
|
|
||||
|–[23: 8 Bit Integer] name:
|
||||
| |–Header: 7 bytes
|
||||
| |–Payload: 1 byte
|
||||
| |–Total: 8 bytes
|
||||
| '–Value: 0
|
||||
|
|
||||
'–[31: End]:
|
||||
|–Header: 1 byte
|
||||
|–Payload: 0 bytes
|
||||
'–Total: 1 byte
|
||||
|
||||
[0: Array of 32 Bit Integers] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 16 bytes
|
||||
|–Total: 23 bytes
|
||||
|–Length: 3
|
||||
'–Values:
|
||||
|–0
|
||||
|–0
|
||||
'–0
|
||||
|
||||
[0: Array of 64 Bit Integers] name:
|
||||
|–Header: 7 bytes
|
||||
|–Payload: 28 bytes
|
||||
|–Total: 35 bytes
|
||||
|–Length: 3
|
||||
'–Values:
|
||||
|–0
|
||||
|–0
|
||||
'–0
|
||||
|
||||
#############################################################################
|
||||
# Output for simple_nbt (what it's supposed to look like) #
|
||||
#############################################################################
|
||||
|
||||
[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. Let’s 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: 623593.6542742235
|
||||
|
|
||||
|–[165: Float] float:
|
||||
| |–Header: 8 bytes
|
||||
| |–Payload: 4 bytes
|
||||
| |–Total: 12 bytes
|
||||
| '–Value: 35.2678337097168
|
||||
|
|
||||
|–[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
|
||||
| |–245
|
||||
| '–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: he’s
|
||||
| |
|
||||
| |–[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
|
|
@ -15,20 +15,7 @@
|
|||
# version 3 along with this program.
|
||||
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
if [ "$(tr '[:upper:]' '[:lower:]' <<< $SINGLE)" = "yes" ]; then
|
||||
echo "Running build script in single-threaded mode."
|
||||
WAIT_ANYWAY="wait"
|
||||
else
|
||||
WAIT_ANYWAY=""
|
||||
fi
|
||||
|
||||
if [ -z "$CXX" ]; then
|
||||
CXX="c++"
|
||||
fi
|
||||
if [ -z "$CXXFLAGS" ]; then
|
||||
CXXFLAGS="-std=c++20 -Wall"
|
||||
fi
|
||||
CXX_WITH_FLAGS="$CXX $CXXFLAGS"
|
||||
source scripts/lib.sh
|
||||
|
||||
# if unknown, figure out endianness
|
||||
if [ -f .endianness ]; then
|
||||
|
@ -46,10 +33,10 @@ fi
|
|||
|
||||
# `.cpp` files in src/lib will be automatically picked up and compiled into
|
||||
# dynamically linked libraries.
|
||||
echo "Building libs..."
|
||||
mkdir -pv bin/lib
|
||||
echo ">>> Building libs..."
|
||||
create_directory bin/lib
|
||||
for lib in $(find ./src/lib -name "*.cpp"); do
|
||||
COMPILE_COMMAND="$CXX_WITH_FLAGS -I dependencies/tiny-utf8-4.4.3/include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib"
|
||||
COMPILE_COMMAND="$CXX_WITH_FLAGS -I ./include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib"
|
||||
echo $COMPILE_COMMAND
|
||||
$COMPILE_COMMAND &
|
||||
$WAIT_ANYWAY
|
||||
|
@ -68,12 +55,14 @@ 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..."
|
||||
mkdir -pv bin/tools
|
||||
echo ">>> Building tools..."
|
||||
create_directory bin/tools
|
||||
# add compile commands to this array
|
||||
COMPILE_COMMANDS=(
|
||||
"$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -Lbin/lib -l:nbt.so -o bin/tools/dumpnbt"
|
||||
"$CXX_WITH_FLAGS src/tools/hexnet.cpp -Lbin/lib -l:cli.so -l:libsockpp.so -Idependencies/sockpp-0.7.1/include -o bin/tools/hexnet"
|
||||
"$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -l:cli.so -o bin/tools/dumpnbt"
|
||||
"$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump"
|
||||
"$CXX_WITH_FLAGS src/tools/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
|
||||
"$CXX_WITH_FLAGS -pthread src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
|
||||
)
|
||||
for command in ${!COMPILE_COMMANDS[@]}; do
|
||||
echo "${COMPILE_COMMANDS[command]}"
|
||||
|
|
|
@ -15,15 +15,24 @@
|
|||
# version 3 along with this program.
|
||||
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
rm -rv ./bin
|
||||
rm -vf .endianness
|
||||
rm -vf resources/check_endianness
|
||||
mkdir -v ./bin
|
||||
mkdir -v ./bin/lib
|
||||
echo ">>> Cleaning build files..."
|
||||
|
||||
source scripts/lib.sh
|
||||
|
||||
remove ./bin
|
||||
remove ./include
|
||||
remove .endianness
|
||||
remove resources/check_endianness
|
||||
create_directory ./bin
|
||||
create_directory ./bin/lib
|
||||
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/
|
||||
|
||||
set -v
|
||||
echo -n "" > ./bin/.placeholder
|
||||
ln -vs ../dependencies/sockpp-0.7.1/include/sockpp/ ./include/
|
||||
ln -vs ../dependencies/tiny-utf8-4.4.3/include/tinyutf8/ ./include/
|
||||
|
||||
create_file ./bin/.placeholder
|
||||
create_file ./include/.placeholder
|
||||
|
|
|
@ -15,7 +15,26 @@
|
|||
# version 3 along with this program.
|
||||
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
rm -rv ./dependencies
|
||||
mkdir -v ./dependencies
|
||||
set -v
|
||||
echo -n "" > ./dependencies/.placeholder
|
||||
source scripts/lib.sh
|
||||
|
||||
echo ">>> Checking download cache for unneeded or corrupted files..."
|
||||
for file in $(ls .download_cache); do
|
||||
#TODO: remove if unknown shasum
|
||||
if grep $file scripts/setup_project.sh >/dev/null 2>&1; then
|
||||
if check_sha256 ".download_cache/$file" "$file"; then
|
||||
echo -n "."
|
||||
else
|
||||
echo -n "!"
|
||||
rm ".download_cache/$file"
|
||||
fi
|
||||
else
|
||||
echo -n "x"
|
||||
rm ".download_cache/$file"
|
||||
fi
|
||||
done
|
||||
echo "
|
||||
>>> Cleaning dependencies..."
|
||||
|
||||
remove ./dependencies
|
||||
create_directory ./dependencies
|
||||
create_file ./dependencies/.placeholder
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
#!/bin/echo You are not supposed to run this file.
|
||||
|
||||
# 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
|
||||
|
||||
if [ "$(tr '[:upper:]' '[:lower:]' <<< $SINGLE)" = "yes" ]; then
|
||||
echo "Single-threaded mode enabled."
|
||||
WAIT_ANYWAY="wait"
|
||||
else
|
||||
WAIT_ANYWAY=""
|
||||
fi
|
||||
|
||||
if [ -z "$CXX" ]; then
|
||||
CXX="c++"
|
||||
fi
|
||||
if [ -z "$CXXFLAGS" ]; then
|
||||
CXXFLAGS="-std=c++20 -Wall -Wextra"
|
||||
fi
|
||||
CXX_WITH_FLAGS="$CXX $CXXFLAGS"
|
||||
|
||||
# automatically find and use an appropriate sha256 sum command
|
||||
# currently supports sha256sum and NetBSD's sha256
|
||||
if command -v sha256sum > /dev/null; then
|
||||
function check_sha256 {
|
||||
FILE="$1"
|
||||
CHECKSUM="$2"
|
||||
sha256sum --check <<< "$CHECKSUM *$FILE" >/dev/null 2>&1
|
||||
return $?
|
||||
}
|
||||
else
|
||||
if command -v sha256 > /dev/null; then
|
||||
function check_sha256 {
|
||||
FILE="$1"
|
||||
CHECKSUM="$2"
|
||||
sha256 -c <<< "SHA256 ($FILE) = $CHECKSUM" >/dev/null 2>&1
|
||||
return $?
|
||||
}
|
||||
else
|
||||
echo "Could not find sha256sum or sha256."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# This function exists to make the output more sensible on platforms where
|
||||
# `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"
|
||||
else
|
||||
rm -v "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# some platforms don’t support `mkdir -v`
|
||||
function create_directory {
|
||||
echo "Creating directory: $1"
|
||||
mkdir -p "$1"
|
||||
}
|
||||
|
||||
# `mkfile -v` if you will
|
||||
function create_file {
|
||||
echo "Creating file: $1"
|
||||
touch "$1"
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
# version 3 along with this program.
|
||||
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
source scripts/lib.sh
|
||||
|
||||
echo -n "Wget or curl? "
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
USE_WGET=yes
|
||||
|
@ -32,53 +34,67 @@ fi
|
|||
function download {
|
||||
URL="$1"
|
||||
DESTINATION="$2"
|
||||
SHA256SUM="$3 *$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 "$DESTINATION" "$URL" >/dev/null 2>&1
|
||||
wget -O ".download_cache/$SHA256SUM" "$URL" >/dev/null 2>&1
|
||||
else
|
||||
curl -L "$URL" --output "$DESTINATION" >/dev/null 2>&1
|
||||
curl -L "$URL" --output ".download_cache/$SHA256SUM" >/dev/null 2>&1
|
||||
fi
|
||||
if sha256sum --check <<< $SHA256SUM >/dev/null 2>&1; then
|
||||
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."
|
||||
rm -v "$DESTINATION"
|
||||
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
|
||||
}
|
||||
|
||||
echo "Cleaning build files..."
|
||||
scripts/clean.sh
|
||||
echo "Cleaning dependencies..."
|
||||
scripts/clean_dependencies.sh
|
||||
|
||||
set -e # failures are not acceptable here
|
||||
mkdir -v dependencies/tmp
|
||||
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
|
||||
#TODO: keep the files somewhere else as a cache and only download the ones
|
||||
# we don't have or that got corrupted
|
||||
#TODO: once we cache files properly, have clean_dependencies.sh prune
|
||||
# unknown files from the cache (for example old versions
|
||||
# of dependencies)
|
||||
|
||||
echo -n "Extracting tiny-utf8... "
|
||||
echo -n ">>> Extracting tiny-utf8... "
|
||||
gzip -d dependencies/tmp/tiny-utf8.tar.gz
|
||||
tar -xf dependencies/tmp/tiny-utf8.tar -C dependencies
|
||||
echo "done."
|
||||
echo "done"
|
||||
|
||||
echo -n "Extracting sockpp... "
|
||||
echo -n ">>> Extracting sockpp... "
|
||||
gzip -d dependencies/tmp/sockpp.tar.gz
|
||||
tar -xf dependencies/tmp/sockpp.tar -C dependencies
|
||||
echo "done."
|
||||
echo -n "Building sockpp... "
|
||||
echo "done"
|
||||
|
||||
echo ">>> Building sockpp... "
|
||||
pushd dependencies/sockpp-0.7.1/ >/dev/null 2>&1
|
||||
cmake -Bbuild .
|
||||
cmake --build build
|
||||
popd >/dev/null 2>&1
|
||||
echo "done."
|
||||
|
||||
rm -rv dependencies/tmp
|
||||
echo ">>> Cleaning up..."
|
||||
remove dependencies/tmp
|
||||
|
|
|
@ -15,13 +15,7 @@
|
|||
# version 3 along with this program.
|
||||
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
if [ -z "$CXX" ]; then
|
||||
CXX="c++"
|
||||
fi
|
||||
if [ -z "$CXXFLAGS" ]; then
|
||||
CXXFLAGS="-std=c++20 -Wall"
|
||||
fi
|
||||
CXX_WITH_FLAGS="$CXX $CXXFLAGS"
|
||||
source scripts/lib.sh
|
||||
|
||||
echo -n "Using LD_LIBRARY_PATH "
|
||||
if [ -z "$LD_LIBRARY_PATH" ]; then
|
||||
|
@ -31,25 +25,38 @@ else
|
|||
fi
|
||||
echo "$LD_LIBRARY_PATH"
|
||||
|
||||
mkdir -pv bin/test
|
||||
echo ">>> Cleaning tests..."
|
||||
remove bin/test
|
||||
create_directory bin/test
|
||||
|
||||
echo "Building tests..."
|
||||
echo ">>> Building tests..."
|
||||
|
||||
# add compile commands to this array
|
||||
COMPILE_COMMANDS=(
|
||||
"$CXX_WITH_FLAGS src/test/nbt_helpers.cpp -Lbin/lib -l:nbt.so -o bin/test/nbt_helpers"
|
||||
"$CXX_WITH_FLAGS src/test/nbt_read_write_helpers.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_read_write_helpers"
|
||||
"$CXX_WITH_FLAGS src/test/cli_argument_parser.cpp -Lbin/lib -l:cli.so -o bin/test/cli_argument_parser"
|
||||
"$CXX_WITH_FLAGS src/test/javacompat.cpp -Idependencies/tiny-utf8-4.4.3/include -Lbin/lib -l:javacompat.so -o bin/test/javacompat"
|
||||
"$CXX_WITH_FLAGS src/test/javacompat.cpp -I./include -Lbin/lib -l:javacompat.so -o bin/test/javacompat"
|
||||
"$CXX_WITH_FLAGS src/test/nbt_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/file.cpp -I./include -Lbin/lib -l:file.so -o bin/test/file"
|
||||
)
|
||||
for command in ${!COMPILE_COMMANDS[@]}; do
|
||||
echo "${COMPILE_COMMANDS[command]}"
|
||||
${COMPILE_COMMANDS[command]} &
|
||||
$WAIT_ANYWAY
|
||||
done
|
||||
|
||||
wait
|
||||
|
||||
echo "Running tests..."
|
||||
echo ">>> Running tests..."
|
||||
|
||||
# explicitly allow commands to fail at this stage
|
||||
set +e
|
||||
|
||||
for test in $(ls bin/test); do
|
||||
bin/test/$test
|
||||
done
|
||||
|
||||
for test in $(ls scripts/test); do
|
||||
scripts/test/$test
|
||||
done
|
||||
|
|
|
@ -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 "================================================================================"
|
|
@ -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 "================================================================================"
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2022, FOSS-VG Developers and Contributers
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# version 3 along with this program.
|
||||
# If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
echo "################################################################################
|
||||
Testing hexnet
|
||||
################################################################################"
|
||||
|
||||
echo "Test not yet implemented."
|
||||
#TODO: implement unit test after merging back with master
|
|
@ -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 )"
|
||||
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,13 +39,75 @@ function build {
|
|||
popd >/dev/null 2>&1
|
||||
}
|
||||
|
||||
echo "Added aliases and functions."
|
||||
|
||||
export PATH="$PROJECT_BASE_DIR/bin/tools:$PROJECT_BASE_DIR/scripts/tools:$PATH"
|
||||
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"
|
||||
|
||||
unset PROJECT_BASE_DIR
|
||||
echo ">>> Checking for dependencies..."
|
||||
MISSING_DEPS=0
|
||||
|
||||
echo "done."
|
||||
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
|
||||
|
||||
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
|
||||
|
|
225
src/lib/cli.cpp
225
src/lib/cli.cpp
|
@ -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,13 +16,12 @@
|
|||
// version 3 along with this program.
|
||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include "cli.h++"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "error.h++"
|
||||
#include "cli.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
namespace CLI {
|
||||
Flag::Flag() {
|
||||
|
@ -32,10 +34,10 @@ namespace CLI {
|
|||
this->present = false;
|
||||
}
|
||||
|
||||
UnpositionalArgument::UnpositionalArgument() {
|
||||
Option::Option() {
|
||||
this->present = false;
|
||||
}
|
||||
UnpositionalArgument::UnpositionalArgument(char shortName, std::string longName, std::string placeholder, std::string description) {
|
||||
Option::Option(char shortName, std::string longName, std::string placeholder, std::string description) {
|
||||
this->shortName = shortName;
|
||||
this->longName = longName;
|
||||
this->description = description;
|
||||
|
@ -43,23 +45,22 @@ namespace CLI {
|
|||
this->present = false;
|
||||
}
|
||||
|
||||
PositionalArgument::PositionalArgument() {
|
||||
Argument::Argument() {
|
||||
this->present = false;
|
||||
}
|
||||
PositionalArgument::PositionalArgument(std::string placeholder, std::string description) {
|
||||
Argument::Argument(std::string placeholder, std::string description) {
|
||||
this->description = description;
|
||||
this->placeholder = placeholder;
|
||||
this->present = false;
|
||||
}
|
||||
|
||||
// using int here bc that's how main() is defined
|
||||
ArgumentsParser::ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<UnpositionalArgument> unpositionalArguments, std::vector<PositionalArgument> positionalArguments) {
|
||||
ArgumentsParser::ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments) {
|
||||
this->wrongUsage = false;
|
||||
this->wrongUsageMessages = std::vector<std::string>();
|
||||
this->programName = std::string(argv[0]);
|
||||
this->positionalArguments = positionalArguments;
|
||||
// create lookup tables for all flags and unpositional arguments
|
||||
// by their names
|
||||
this->arguments = arguments;
|
||||
// create lookup tables for all flags and options by their names
|
||||
this->flagsByShortName = std::map<char, Flag*>();
|
||||
this->flagsByLongName = std::map<std::string, Flag*>();
|
||||
for (Flag flag: flags) {
|
||||
|
@ -68,25 +69,25 @@ namespace CLI {
|
|||
this->flagsByShortName[flag.shortName] = flagPointer;
|
||||
this->flagsByLongName[flag.longName] = flagPointer;
|
||||
}
|
||||
this->argumentsByShortName = std::map<char, UnpositionalArgument*>();
|
||||
this->argumentsByLongName = std::map<std::string, UnpositionalArgument*>();
|
||||
for (UnpositionalArgument unpositionalArgument: unpositionalArguments) {
|
||||
UnpositionalArgument* argumentPointer = new UnpositionalArgument();
|
||||
*argumentPointer = unpositionalArgument;
|
||||
this->argumentsByShortName[unpositionalArgument.shortName] = argumentPointer;
|
||||
this->argumentsByLongName[unpositionalArgument.longName] = argumentPointer;
|
||||
this->optionsByShortName = std::map<char, Option*>();
|
||||
this->optionsByLongName = std::map<std::string, Option*>();
|
||||
for (Option option: options) {
|
||||
Option* optionPointer = new Option();
|
||||
*optionPointer = option;
|
||||
this->optionsByShortName[option.shortName] = optionPointer;
|
||||
this->optionsByLongName[option.longName] = optionPointer;
|
||||
}
|
||||
|
||||
UnpositionalArgument* argumentWaitingForValue = nullptr;
|
||||
std::vector<CLI::PositionalArgument>::size_type positionalArgumentCounter = 0;
|
||||
Option* optionWaitingForValue = nullptr;
|
||||
std::vector<CLI::Argument>::size_type argumentCounter = 0;
|
||||
for (int i=1; i<argc; i++) {
|
||||
std::string argument(argv[i]);
|
||||
if (argument[0]=='-') {
|
||||
// do we have unfinished business?
|
||||
if (argumentWaitingForValue!=nullptr) {
|
||||
if (optionWaitingForValue!=nullptr) {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+argumentWaitingForValue->longName);
|
||||
argumentWaitingForValue = nullptr;
|
||||
this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+optionWaitingForValue->longName);
|
||||
optionWaitingForValue = nullptr;
|
||||
}
|
||||
// long name or short name?
|
||||
if (argument[1]=='-') {
|
||||
|
@ -98,15 +99,19 @@ namespace CLI {
|
|||
auto position = argument.find("=");
|
||||
if (position==std::string::npos) {
|
||||
// no =value
|
||||
//is argument or flag?
|
||||
//is option or flag?
|
||||
std::string argumentName = argument.substr(2,argument.length()-2);
|
||||
if (flagsByLongName.contains(argumentName)) {
|
||||
// flag
|
||||
flagsByLongName[argumentName]->present = true;
|
||||
} else if (argumentsByLongName.contains(argumentName)) {
|
||||
// unpositional argument
|
||||
argumentsByLongName[argumentName]->present = true;
|
||||
argumentWaitingForValue = argumentsByLongName[argumentName];
|
||||
} else if (optionsByLongName.contains(argumentName)) {
|
||||
// option
|
||||
optionsByLongName[argumentName]->present = true;
|
||||
optionWaitingForValue = optionsByLongName[argumentName];
|
||||
if (i+1 == argc) {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+argumentName);
|
||||
}
|
||||
} else {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Unknown argument or flag: ")+argument);
|
||||
|
@ -115,9 +120,9 @@ namespace CLI {
|
|||
// has =value
|
||||
std::string value = argument.substr(position+1, argument.length()-position-1);
|
||||
std::string argumentName = argument.substr(2, position-2);
|
||||
if (argumentsByLongName.contains(argumentName)) {
|
||||
argumentsByLongName[argumentName]->present = true;
|
||||
argumentsByLongName[argumentName]->value = value;
|
||||
if (optionsByLongName.contains(argumentName)) {
|
||||
optionsByLongName[argumentName]->present = true;
|
||||
optionsByLongName[argumentName]->value = value;
|
||||
} else {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Unknown argument (or it's a flag that doesn't take a value): ")+argument);
|
||||
|
@ -129,23 +134,29 @@ namespace CLI {
|
|||
// length is defined as
|
||||
// (std::__cxx11::basic_string<char>::size_type ?)
|
||||
// starting at 1 because 0 is '-'
|
||||
for (int i=1; i<(int) argument.length(); i++) {
|
||||
//is argument or flag?
|
||||
if (flagsByShortName.contains(argument[i])) {
|
||||
flagsByShortName[argument[i]]->present = true;
|
||||
} else if (argumentsByShortName.contains(argument[i])) {
|
||||
argumentsByShortName[argument[i]]->present = true;
|
||||
for (int j=1; j<(int) argument.length(); j++) {
|
||||
// is option or flag?
|
||||
if (flagsByShortName.contains(argument[j])) {
|
||||
// flag
|
||||
flagsByShortName[argument[j]]->present = true;
|
||||
} else if (optionsByShortName.contains(argument[j])) {
|
||||
// option
|
||||
optionsByShortName[argument[j]]->present = true;
|
||||
//FIXME: see above
|
||||
if (i+1==(int) argument.length()) {
|
||||
argumentWaitingForValue = argumentsByShortName[argument[i]];
|
||||
if (j+1==(int) argument.length()) {
|
||||
optionWaitingForValue = optionsByShortName[argument[j]];
|
||||
if (i+1 == argc) {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+this->optionsByShortName[argument[j]]->longName);
|
||||
}
|
||||
} else {
|
||||
//assume the rest of the argv is a concatenated argument value
|
||||
argumentsByShortName[argument[i]]->value = argument.substr(i+1, argument.length()-i-1);
|
||||
optionsByShortName[argument[j]]->value = argument.substr(j+1, argument.length()-j-1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Unknown argument or flag(s): ")+argument.substr(i, argument.length()-i));
|
||||
this->wrongUsageMessages.push_back(std::string("Unknown argument or flag(s): ")+argument.substr(j, argument.length()-j));
|
||||
// err on the side of caution to ensure that
|
||||
// no unwanted options get activated on programs
|
||||
// that deal gracefully with unrecognized command
|
||||
|
@ -155,39 +166,48 @@ namespace CLI {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// positional argument or value for unpositional arg?
|
||||
if (argumentWaitingForValue==nullptr) {
|
||||
// positional argument
|
||||
if (positionalArgumentCounter < this->positionalArguments.size()) {
|
||||
this->positionalArguments.at(positionalArgumentCounter).present = true;
|
||||
this->positionalArguments.at(positionalArgumentCounter).value = argument;
|
||||
// argument or value for option?
|
||||
if (optionWaitingForValue==nullptr) {
|
||||
// argument
|
||||
if (argumentCounter < this->arguments.size()) {
|
||||
this->arguments.at(argumentCounter).present = true;
|
||||
this->arguments.at(argumentCounter).value = argument;
|
||||
} else {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Too many positional arguments. Unexpected encounter of: ")+argument);
|
||||
this->wrongUsageMessages.push_back(std::string("Too many arguments! Unexpected encounter of: ")+argument);
|
||||
}
|
||||
positionalArgumentCounter++;
|
||||
argumentCounter++;
|
||||
} else {
|
||||
// value for unpositional argument
|
||||
argumentWaitingForValue->value = argument;
|
||||
argumentWaitingForValue = nullptr;
|
||||
// value for option
|
||||
optionWaitingForValue->value = argument;
|
||||
optionWaitingForValue = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (PositionalArgument const& positionalArgument: this->positionalArguments) {
|
||||
if (!positionalArgument.present) {
|
||||
for (Argument const& argument: this->arguments) {
|
||||
if (!argument.present) {
|
||||
this->wrongUsage = true;
|
||||
this->wrongUsageMessages.push_back(std::string("Too few positional arguments! Missing: ")+positionalArgument.placeholder);
|
||||
this->wrongUsageMessages.push_back(std::string("Too few arguments! Missing: ")+argument.placeholder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentsParser::ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description): ArgumentsParser::ArgumentsParser(argc, argv, flags, options, arguments) {
|
||||
this->description = description;
|
||||
}
|
||||
|
||||
ArgumentsParser::ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description, std::string additionalInfo): ArgumentsParser::ArgumentsParser(argc, argv, flags, options, arguments) {
|
||||
this->description = description;
|
||||
this->additionalInfo = additionalInfo;
|
||||
}
|
||||
|
||||
ArgumentsParser::~ArgumentsParser() {
|
||||
//TODO: check that this actually runs
|
||||
for (auto const& [shortName, flag]: this->flagsByShortName) {
|
||||
delete flag;
|
||||
}
|
||||
for (auto const& [shortName, unpositionalArgument]: this->argumentsByShortName) {
|
||||
delete unpositionalArgument;
|
||||
for (auto const& [shortName, option]: this->optionsByShortName) {
|
||||
delete option;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,35 +231,100 @@ namespace CLI {
|
|||
else return ErrorOr<bool> (false, ErrorCodes::NOT_PRESENT, false);
|
||||
}
|
||||
|
||||
ErrorOr<std::string> ArgumentsParser::getPositionalArgument(std::vector<CLI::PositionalArgument>::size_type position){
|
||||
if (position >= this->positionalArguments.size()) return ErrorOr<std::string>(true, ErrorCodes::OUT_OF_RANGE, std::string(""));
|
||||
ErrorOr<std::string> ArgumentsParser::getArgument(std::vector<CLI::Argument>::size_type position){
|
||||
if (position >= this->arguments.size()) return ErrorOr<std::string>(true, ErrorCodes::OUT_OF_RANGE, std::string(""));
|
||||
if (this->wrongUsage) {
|
||||
if (this->positionalArguments.at(position).present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->positionalArguments.at(position).value);
|
||||
if (this->arguments.at(position).present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->arguments.at(position).value);
|
||||
else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||
}
|
||||
return ErrorOr<std::string>(this->positionalArguments.at(position).value);
|
||||
return ErrorOr<std::string>(this->arguments.at(position).value);
|
||||
}
|
||||
|
||||
ErrorOr<std::string> ArgumentsParser::getUnpositionalArgument(char shortName) {
|
||||
if (!this->argumentsByShortName.contains(shortName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string(""));
|
||||
ErrorOr<std::string> ArgumentsParser::getOption(char shortName) {
|
||||
if (!this->optionsByShortName.contains(shortName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string(""));
|
||||
if (this->wrongUsage) {
|
||||
if (this->argumentsByShortName[shortName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->argumentsByShortName[shortName]->value);
|
||||
if (this->optionsByShortName[shortName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->optionsByShortName[shortName]->value);
|
||||
else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||
}
|
||||
if (this->argumentsByShortName[shortName]->present) return ErrorOr<std::string>(this->argumentsByShortName[shortName]->value);
|
||||
if (this->optionsByShortName[shortName]->present) return ErrorOr<std::string>(this->optionsByShortName[shortName]->value);
|
||||
// argument is not present, but this is not an error -> false, NOT_PRESENT, ""
|
||||
else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||
}
|
||||
|
||||
ErrorOr<std::string> ArgumentsParser::getUnpositionalArgument(std::string longName) {
|
||||
if (!this->argumentsByLongName.contains(longName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string(""));
|
||||
ErrorOr<std::string> ArgumentsParser::getOption(std::string longName) {
|
||||
if (!this->optionsByLongName.contains(longName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string(""));
|
||||
if (this->wrongUsage) {
|
||||
if (this->argumentsByLongName[longName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->argumentsByLongName[longName]->value);
|
||||
if (this->optionsByLongName[longName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->optionsByLongName[longName]->value);
|
||||
else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||
}
|
||||
if (this->argumentsByLongName[longName]->present) return ErrorOr<std::string>(this->argumentsByLongName[longName]->value);
|
||||
if (this->optionsByLongName[longName]->present) return ErrorOr<std::string>(this->optionsByLongName[longName]->value);
|
||||
// argument is not present, but this is not an error -> false, NOT_PRESENT, ""
|
||||
else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||
}
|
||||
//std::string ArgumentsParser::getUsage();
|
||||
|
||||
std::string ArgumentsParser::getUsage(){
|
||||
std::string usageString = "";
|
||||
if (this->description != "") {
|
||||
usageString += "Help: " + this->programName + "\n\n\t" + this->description + "\n\n";
|
||||
}
|
||||
usageString += "Usage: " + this->programName + " ";
|
||||
|
||||
if(!this->flagsByShortName.empty()){
|
||||
usageString += "[-";
|
||||
}
|
||||
|
||||
for(const auto& [key, value]: this->flagsByShortName){
|
||||
usageString.push_back(key);
|
||||
}
|
||||
|
||||
if(!this->flagsByShortName.empty()){
|
||||
usageString += "] ";
|
||||
}
|
||||
|
||||
for(const auto& [key, value]: this->optionsByShortName){
|
||||
usageString += "[-";
|
||||
usageString.push_back(key);
|
||||
usageString += " " + value->placeholder + "] ";
|
||||
}
|
||||
|
||||
for(const auto& argument: this->arguments){
|
||||
usageString += argument.placeholder + " ";
|
||||
}
|
||||
|
||||
usageString.push_back('\n');
|
||||
|
||||
if(!this->flagsByShortName.empty()){
|
||||
usageString += "\nFlags:\n";
|
||||
|
||||
for(const auto& [key, value]: this->flagsByShortName){
|
||||
usageString += "\t-";
|
||||
usageString.push_back(key);
|
||||
usageString += ", --" + value->longName + "\n\t\t" + value->description + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!this->optionsByShortName.empty()){
|
||||
usageString += "\nOptions:\n";
|
||||
|
||||
for(const auto& [key, value]: this->optionsByShortName){
|
||||
usageString += "\t-";
|
||||
usageString.push_back(key);
|
||||
usageString += " " + value->placeholder + ", --" + value->longName + "=" + value->placeholder + "\n\t\t" + value->description + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!this->arguments.empty()){
|
||||
usageString += "\nArguments:\n";
|
||||
|
||||
for(const auto& argument: this->arguments){
|
||||
usageString += "\t" + argument.placeholder + "\n\t\t" + argument.description + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (this->additionalInfo != "") {
|
||||
usageString += "\nAdditional Info:\n\n\t" + this->additionalInfo + "\n";
|
||||
}
|
||||
|
||||
return usageString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "error.h++"
|
||||
#include "error.hpp"
|
||||
|
||||
namespace CLI {
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace CLI {
|
|||
Flag(char shortName, std::string longName, std::string description);
|
||||
};
|
||||
|
||||
struct UnpositionalArgument {
|
||||
struct Option {
|
||||
char shortName;
|
||||
std::string longName;
|
||||
// used for automatic usage generation
|
||||
|
@ -45,11 +45,11 @@ namespace CLI {
|
|||
bool present;
|
||||
std::string value;
|
||||
|
||||
UnpositionalArgument();
|
||||
UnpositionalArgument(char shortName, std::string longName, std::string placeholder, std::string description);
|
||||
Option();
|
||||
Option(char shortName, std::string longName, std::string placeholder, std::string description);
|
||||
};
|
||||
|
||||
struct PositionalArgument {
|
||||
struct Argument {
|
||||
// used for automatic usage generation
|
||||
std::string description;
|
||||
std::string placeholder; // the "HOST" in "ping [-c <COUNT>] <HOST>"
|
||||
|
@ -57,17 +57,19 @@ namespace CLI {
|
|||
bool present;
|
||||
std::string value;
|
||||
|
||||
PositionalArgument();
|
||||
PositionalArgument(std::string placeholder, std::string description);
|
||||
Argument();
|
||||
Argument(std::string placeholder, std::string description);
|
||||
};
|
||||
|
||||
class ArgumentsParser {
|
||||
private:
|
||||
std::map<char, Flag*> flagsByShortName;
|
||||
std::map<std::string, Flag*> flagsByLongName;
|
||||
std::map<char, UnpositionalArgument*> argumentsByShortName;
|
||||
std::map<std::string, UnpositionalArgument*> argumentsByLongName;
|
||||
std::vector<PositionalArgument> positionalArguments;
|
||||
std::map<char, Option*> optionsByShortName;
|
||||
std::map<std::string, Option*> optionsByLongName;
|
||||
std::vector<Argument> arguments;
|
||||
std::string description;
|
||||
std::string additionalInfo;
|
||||
|
||||
public:
|
||||
std::string programName;
|
||||
|
@ -75,14 +77,16 @@ namespace CLI {
|
|||
std::vector<std::string> wrongUsageMessages;
|
||||
|
||||
// using int here bc that's how main() is defined
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<UnpositionalArgument> unpositionalArguments, std::vector<PositionalArgument> positionalArguments);
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments);
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description);
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description, std::string additionalInfo);
|
||||
~ArgumentsParser();
|
||||
|
||||
ErrorOr<bool> getFlag(char shortName);
|
||||
ErrorOr<bool> getFlag(std::string longName);
|
||||
ErrorOr<std::string> getPositionalArgument(std::vector<CLI::PositionalArgument>::size_type position);
|
||||
ErrorOr<std::string> getUnpositionalArgument(char shortName);
|
||||
ErrorOr<std::string> getUnpositionalArgument(std::string longName);
|
||||
ErrorOr<std::string> getArgument(std::vector<CLI::Argument>::size_type position);
|
||||
ErrorOr<std::string> getOption(char shortName);
|
||||
ErrorOr<std::string> getOption(std::string longName);
|
||||
|
||||
std::string getUsage();
|
||||
};
|
|
@ -23,37 +23,43 @@ struct ErrorOr {
|
|||
uint8_t errorCode;
|
||||
T value;
|
||||
|
||||
ErrorOr<T>();
|
||||
ErrorOr<T>(T);
|
||||
ErrorOr<T>(bool, uint8_t);
|
||||
ErrorOr<T>(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() {
|
||||
struct ErrorOrVoid {
|
||||
bool isError;
|
||||
uint8_t errorCode;
|
||||
|
||||
ErrorOrVoid() {
|
||||
this->isError = false;
|
||||
this->errorCode = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ErrorOr<T>::ErrorOr(T value) {
|
||||
this->isError = false;
|
||||
this->errorCode = 0;
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ErrorOr<T>::ErrorOr(bool isError, uint8_t errorCode) {
|
||||
ErrorOrVoid(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;
|
||||
}
|
||||
};
|
||||
|
||||
namespace ErrorCodes {
|
||||
// These are all arbitrary values used to assign error codes to different
|
||||
|
@ -64,13 +70,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;
|
||||
|
@ -78,6 +81,20 @@ namespace ErrorCodes {
|
|||
// when dealing with maps
|
||||
const uint8_t UNKNOWN_KEY = 5;
|
||||
|
||||
//mismatched size in java strings
|
||||
const uint8_t MISMATCHEDSIZE = 6;
|
||||
|
||||
const uint8_t NOT_YET_KNOWN = 7;
|
||||
|
||||
const uint8_t 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 UNIMPLEMENTED = 254;
|
||||
|
||||
const uint8_t UNKNOWN = 255;
|
|
@ -0,0 +1,274 @@
|
|||
// 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();
|
||||
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);
|
||||
readData.insert(readData.begin()+this->cursorPosition, string);
|
||||
|
||||
this->fileStream.seekg(0);
|
||||
|
||||
//TODO: fix hack. tinyutf8 appends "_utf-8" when readData is assigned: tiny_utf8::string((char *) buffer);
|
||||
this->writeString(readData.substr(0, readData.find("_utf-8")));
|
||||
this->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);
|
||||
|
||||
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<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));
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// 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 <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);
|
||||
};
|
|
@ -15,18 +15,30 @@
|
|||
|
||||
#include <tinyutf8/tinyutf8.h>
|
||||
#include <string>
|
||||
#include "error.h++"
|
||||
#include "error.hpp"
|
||||
#include "javacompat.hpp"
|
||||
#include "../../.endianness"
|
||||
|
||||
#include "javacompat.h++"
|
||||
#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 {
|
||||
//FIXME: contrary to what I said, we need to explicitly pass the data
|
||||
// size because files could have been tampered with or corrupted
|
||||
tiny_utf8::string importJavaString(uint8_t data[]) {
|
||||
ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size) {
|
||||
std::string stdString;
|
||||
uint16_t size = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]);
|
||||
uint16_t encodedSize = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]);
|
||||
|
||||
for(uint8_t i=2; i<size+2; i++){
|
||||
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';
|
||||
|
@ -35,11 +47,48 @@ namespace JavaCompat {
|
|||
}
|
||||
stdString.push_back((char) data[i]);
|
||||
}
|
||||
return tiny_utf8::string(stdString);
|
||||
return ErrorOr<tiny_utf8::string>(tiny_utf8::string(stdString));
|
||||
}
|
||||
/*
|
||||
ErrorOr<uint8_t*> exportJavaString(tiny_utf8::string data) {
|
||||
return ErrorOr(nullptr);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,12 +13,11 @@
|
|||
//version 3 along with this program.
|
||||
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include <vector>
|
||||
#include <tinyutf8/tinyutf8.h>
|
||||
#include "error.h++"
|
||||
#include "error.hpp"
|
||||
|
||||
namespace JavaCompat {
|
||||
//FIXME: contrary to what I said, we need to explicitly pass the data
|
||||
// size because files could have been tampered with or corrupted
|
||||
tiny_utf8::string importJavaString(uint8_t data[]);
|
||||
ErrorOr<uint8_t*> exportJavaString(tiny_utf8::string data);
|
||||
ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size);
|
||||
ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string data);
|
||||
}
|
1546
src/lib/nbt.cpp
1546
src/lib/nbt.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,79 +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
|
||||
|
||||
// information taken from https://wiki.vg/NBT
|
||||
// This is an attempt at creating a uniform model for all NBT tags to allow for a uniform interface based on subclassing a single NBT tag super class.
|
||||
|
||||
// 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
|
||||
// float32: Tag( 5, String:name, uint16:name_size, float32:content,4) => 32 bit IEEE754 floating point number, size not stored
|
||||
// float64: Tag( 6, String:name, uint16:name_size, float64: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
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "error.h++"
|
||||
|
||||
namespace NBT {
|
||||
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);
|
||||
ErrorOr<int64_t> readInt64(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
//FIXME: we just assume that float is a single-precision IEEE754
|
||||
// floating point number
|
||||
ErrorOr<float> readFloat32(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
//FIXME: we just assume that double is a double-precision IEEE754
|
||||
// floating point number
|
||||
ErrorOr<double> readFloat64(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<std::vector<int8_t>> readInt8Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
//ErrorOr<> readString(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<std::vector<int32_t>> readInt32Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<std::vector<int64_t>> readInt64Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
|
||||
void writeInt8(std::vector<uint8_t>* destination, int8_t data);
|
||||
void writeInt16(std::vector<uint8_t>* destination, int16_t data);
|
||||
void writeInt32(std::vector<uint8_t>* destination, int32_t data);
|
||||
void writeInt64(std::vector<uint8_t>* destination, int64_t data);
|
||||
//FIXME: we just assume that float is a single-precision IEEE754
|
||||
// floating point number
|
||||
void writeFloat32(std::vector<uint8_t>* destination, float data);
|
||||
//FIXME: we just assume that double is a single-precision IEEE754
|
||||
// floating point number
|
||||
void writeFloat64(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, <string type> 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);
|
||||
void writeInt64Array(std::vector<uint8_t>* destination, int64_t data[], uint32_t dataSize);
|
||||
}
|
||||
|
||||
bool validateRawNBTData(uint8_t data[], int length);
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
// 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
|
||||
|
||||
// information taken from https://wiki.vg/NBT
|
||||
// This is an attempt at creating a uniform model for all NBT tags to allow for a uniform interface based on subclassing a single NBT tag super class.
|
||||
|
||||
// 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: 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 {
|
||||
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);
|
||||
ErrorOr<int64_t> readInt64(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<float> readFloat(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<double> readDouble(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<std::vector<int8_t>> readInt8Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<tiny_utf8::string> readString(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<std::vector<int32_t>> readInt32Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<std::vector<int64_t>> readInt64Array(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
|
||||
void writeInt8(std::vector<uint8_t>* destination, int8_t data);
|
||||
void writeInt16(std::vector<uint8_t>* destination, int16_t data);
|
||||
void writeInt32(std::vector<uint8_t>* destination, int32_t data);
|
||||
void writeInt64(std::vector<uint8_t>* destination, int64_t data);
|
||||
void writeFloat(std::vector<uint8_t>* destination, float data);
|
||||
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);
|
||||
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);
|
||||
void writeInt64Array(std::vector<uint8_t>* destination, int64_t data[], uint32_t dataSize);
|
||||
|
||||
ErrorOr<uint64_t> totalTagSize(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
ErrorOr<int32_t> containedDataLength(uint8_t data[], uint64_t dataSize, uint64_t currentPosition);
|
||||
}
|
||||
|
||||
namespace TagType {
|
||||
const uint8_t END = 0;
|
||||
const uint8_t INT8 = 1;
|
||||
const uint8_t INT16 = 2;
|
||||
const uint8_t INT32 = 3;
|
||||
const uint8_t INT64 = 4;
|
||||
const uint8_t FLOAT = 5;
|
||||
const uint8_t DOUBLE = 6;
|
||||
const uint8_t INT8_ARRAY = 7;
|
||||
const uint8_t STRING = 8;
|
||||
const uint8_t LIST = 9;
|
||||
const uint8_t COMPOUND = 10;
|
||||
const uint8_t INT32_ARRAY= 11;
|
||||
const uint8_t INT64_ARRAY= 12;
|
||||
// This is a workaround that's not part of the spec.
|
||||
const uint8_t INVALID = 255;
|
||||
}
|
||||
|
||||
namespace Tag {
|
||||
|
||||
class Generic {
|
||||
protected:
|
||||
std::mutex mutex;
|
||||
uint8_t type;
|
||||
public:
|
||||
tiny_utf8::string name;
|
||||
|
||||
Generic();
|
||||
virtual ~Generic();
|
||||
|
||||
virtual ErrorOrVoid serialize(std::vector<uint8_t>* rawData);
|
||||
virtual ErrorOrVoid serializeWithoutHeader(std::vector<uint8_t>* rawData);
|
||||
uint8_t getTagType();
|
||||
};
|
||||
|
||||
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;
|
||||
public:
|
||||
List();
|
||||
List(tiny_utf8::string name, uint8_t type);
|
||||
List(tiny_utf8::string name, std::vector<Generic*> data);
|
||||
|
||||
~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();
|
||||
};
|
||||
|
||||
class Compound: public Generic {
|
||||
private:
|
||||
std::vector<Generic*> tags;
|
||||
// built-in end tag
|
||||
End* endPointer;
|
||||
public:
|
||||
Compound();
|
||||
Compound(tiny_utf8::string name);
|
||||
Compound(tiny_utf8::string name, std::vector<Generic*> data);
|
||||
|
||||
~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();
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
|
@ -15,4 +15,4 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#define ASSERT(truth) if ((truth)); else { std::cout << "Assertion failed: " << #truth << std::endl; return 1; }
|
||||
#define ASSERT(truth) if ((truth)); else { std::cout << "On line " << __LINE__ << ": Assertion failed: " << #truth << std::endl; return 1; }
|
|
@ -16,14 +16,14 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "assert.h++"
|
||||
#include "../lib/error.h++"
|
||||
#include "assert.hpp"
|
||||
#include "../lib/error.hpp"
|
||||
|
||||
#include "../lib/cli.h++"
|
||||
#include "../lib/cli.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int main() {
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "CLI argument parser tests" << std::endl;
|
||||
std::cout << "CLI argument parsing tests" << std::endl;
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
|
||||
// Valid parameter test ############################################
|
||||
|
@ -31,7 +31,7 @@ int main(int argc, char* argv[]) {
|
|||
// with many variations of valid input on a single command line.
|
||||
//
|
||||
// simulated command line:
|
||||
// test -0 -ab -12345 --long-flag -cconcatenated -d separate-value -efdouble-concatenated "positional argument 0" -gh concatenated-separate-value --long-argument-with-value-included="included value" --long-argument-with-value-separated "separate value" "positional argument 1" "positional argument 2"
|
||||
// test -0 -ab -12345 --long-flag -cconcatenated -d separate-value -efdouble-concatenated "argument 0" -gh concatenated-separate-value --long-argument-with-value-included="included value" --long-argument-with-value-separated "separate value" "argument 1" "argument 2"
|
||||
|
||||
std::vector<CLI::Flag> validTestFlags;
|
||||
validTestFlags.push_back(CLI::Flag('0', "00000", "a short flag on its own"));
|
||||
|
@ -47,19 +47,19 @@ int main(int argc, char* argv[]) {
|
|||
validTestFlags.push_back(CLI::Flag('g', "ggggg", "short flags concatenated with an argument that has a separate value"));
|
||||
validTestFlags.push_back(CLI::Flag('6', "66666", "unused flag"));
|
||||
|
||||
std::vector<CLI::UnpositionalArgument> validTestUnpositionalArguments;
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('c', "ccccc", "VALUE", "short argument concatenated with its value"));
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('d', "ddddd", " VALUE", "short argument with separate value"));
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('f', "fffff", "VALUE", "short argument concatenated with a flag and its value"));
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('h', "hhhhh", " VALUE", "short argument concatenated with a flag with separate value"));
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('x', "long-argument-with-value-included", "VALUE", "long argument with its value included using ="));
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('y', "long-argument-with-value-separated", " VALUE", "long argument with separate value"));
|
||||
validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('z', "zzzzz", "NOPE", "unused argument"));
|
||||
std::vector<CLI::Option> validTestOptions;
|
||||
validTestOptions.push_back(CLI::Option('c', "ccccc", "VALUE", "short argument concatenated with its value"));
|
||||
validTestOptions.push_back(CLI::Option('d', "ddddd", " VALUE", "short argument with separate value"));
|
||||
validTestOptions.push_back(CLI::Option('f', "fffff", "VALUE", "short argument concatenated with a flag and its value"));
|
||||
validTestOptions.push_back(CLI::Option('h', "hhhhh", " VALUE", "short argument concatenated with a flag with separate value"));
|
||||
validTestOptions.push_back(CLI::Option('x', "long-argument-with-value-included", "VALUE", "long argument with its value included using ="));
|
||||
validTestOptions.push_back(CLI::Option('y', "long-argument-with-value-separated", " VALUE", "long argument with separate value"));
|
||||
validTestOptions.push_back(CLI::Option('z', "zzzzz", "NOPE", "unused argument"));
|
||||
|
||||
std::vector<CLI::PositionalArgument> validTestPositionalArguments;
|
||||
validTestPositionalArguments.push_back(CLI::PositionalArgument("argument0", "positional argument between optional parameters"));
|
||||
validTestPositionalArguments.push_back(CLI::PositionalArgument("argument1", "positional argument"));
|
||||
validTestPositionalArguments.push_back(CLI::PositionalArgument("argument2", "positional argument"));
|
||||
std::vector<CLI::Argument> validTestArguments;
|
||||
validTestArguments.push_back(CLI::Argument("argument0", "argument between optional parameters"));
|
||||
validTestArguments.push_back(CLI::Argument("argument1", "argument"));
|
||||
validTestArguments.push_back(CLI::Argument("argument2", "argument"));
|
||||
|
||||
const char** validTestParameterList = new const char*[17];
|
||||
validTestParameterList[ 0] = "test";
|
||||
|
@ -71,17 +71,17 @@ int main(int argc, char* argv[]) {
|
|||
validTestParameterList[ 6] = "-d";
|
||||
validTestParameterList[ 7] = "separate-value";
|
||||
validTestParameterList[ 8] = "-efdouble-concatenated";
|
||||
validTestParameterList[ 9] = "positional argument 0";
|
||||
validTestParameterList[ 9] = "argument 0";
|
||||
validTestParameterList[10] = "-gh";
|
||||
validTestParameterList[11] = "concatenated-separate-value";
|
||||
validTestParameterList[12] = "--long-argument-with-value-included=included value";
|
||||
validTestParameterList[13] = "--long-argument-with-value-separated";
|
||||
validTestParameterList[14] = "separate value";
|
||||
validTestParameterList[15] = "positional argument 1";
|
||||
validTestParameterList[16] = "positional argument 2";
|
||||
validTestParameterList[15] = "argument 1";
|
||||
validTestParameterList[16] = "argument 2";
|
||||
int validTestParameterCount = 17;
|
||||
|
||||
CLI::ArgumentsParser validTestParameterParser = CLI::ArgumentsParser(validTestParameterCount, validTestParameterList, validTestFlags, validTestUnpositionalArguments, validTestPositionalArguments);
|
||||
CLI::ArgumentsParser validTestParameterParser = CLI::ArgumentsParser(validTestParameterCount, validTestParameterList, validTestFlags, validTestOptions, validTestArguments);
|
||||
|
||||
ASSERT(!validTestParameterParser.wrongUsage);
|
||||
ASSERT(validTestParameterParser.programName == std::string("test"));
|
||||
|
@ -115,49 +115,50 @@ int main(int argc, char* argv[]) {
|
|||
ASSERT(!validTestParameterParser.getFlag('6').isError);
|
||||
ASSERT(!validTestParameterParser.getFlag('6').value);
|
||||
ASSERT(!validTestParameterParser.getFlag(std::string("66666")).value);
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('c').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('c').value==std::string("concatenated"));
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("ccccc")).value==std::string("concatenated"));
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('d').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('d').value==std::string("separate-value"));
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("ddddd")).value==std::string("separate-value"));
|
||||
ASSERT(!validTestParameterParser.getOption('c').isError);
|
||||
ASSERT(validTestParameterParser.getOption('c').value==std::string("concatenated"));
|
||||
ASSERT(validTestParameterParser.getOption(std::string("ccccc")).value==std::string("concatenated"));
|
||||
ASSERT(!validTestParameterParser.getOption('d').isError);
|
||||
ASSERT(validTestParameterParser.getOption('d').value==std::string("separate-value"));
|
||||
ASSERT(validTestParameterParser.getOption(std::string("ddddd")).value==std::string("separate-value"));
|
||||
ASSERT(!validTestParameterParser.getFlag('e').isError);
|
||||
ASSERT(validTestParameterParser.getFlag('e').value);
|
||||
ASSERT(validTestParameterParser.getFlag(std::string("eeeee")).value);
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('f').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('f').value==std::string("double-concatenated"));
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("fffff")).value==std::string("double-concatenated"));
|
||||
ASSERT(!validTestParameterParser.getPositionalArgument(0).isError);
|
||||
ASSERT(validTestParameterParser.getPositionalArgument(0).value=="positional argument 0");
|
||||
ASSERT(!validTestParameterParser.getOption('f').isError);
|
||||
ASSERT(validTestParameterParser.getOption('f').value==std::string("double-concatenated"));
|
||||
ASSERT(validTestParameterParser.getOption(std::string("fffff")).value==std::string("double-concatenated"));
|
||||
ASSERT(!validTestParameterParser.getArgument(0).isError);
|
||||
ASSERT(validTestParameterParser.getArgument(0).value=="argument 0");
|
||||
ASSERT(!validTestParameterParser.getFlag('g').isError);
|
||||
ASSERT(validTestParameterParser.getFlag('g').value);
|
||||
ASSERT(validTestParameterParser.getFlag(std::string("ggggg")).value);
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('h').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('h').value==std::string("concatenated-separate-value"));
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("hhhhh")).value==std::string("concatenated-separate-value"));
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('x').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('x').value==std::string("included value"));
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("long-argument-with-value-included")).value==std::string("included value"));
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('y').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('y').value==std::string("separate value"));
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("long-argument-with-value-separated")).value==std::string("separate value"));
|
||||
ASSERT(!validTestParameterParser.getPositionalArgument(1).isError);
|
||||
ASSERT(validTestParameterParser.getPositionalArgument(1).value=="positional argument 1");
|
||||
ASSERT(!validTestParameterParser.getPositionalArgument(2).isError);
|
||||
ASSERT(validTestParameterParser.getPositionalArgument(2).value=="positional argument 2");
|
||||
ASSERT(!validTestParameterParser.getUnpositionalArgument('z').isError);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('z').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(validTestParameterParser.getUnpositionalArgument('z').value == std::string(""));
|
||||
ASSERT(!validTestParameterParser.getOption('h').isError);
|
||||
ASSERT(validTestParameterParser.getOption('h').value==std::string("concatenated-separate-value"));
|
||||
ASSERT(validTestParameterParser.getOption(std::string("hhhhh")).value==std::string("concatenated-separate-value"));
|
||||
ASSERT(!validTestParameterParser.getOption('x').isError);
|
||||
ASSERT(validTestParameterParser.getOption('x').value==std::string("included value"));
|
||||
ASSERT(validTestParameterParser.getOption(std::string("long-argument-with-value-included")).value==std::string("included value"));
|
||||
ASSERT(!validTestParameterParser.getOption('y').isError);
|
||||
ASSERT(validTestParameterParser.getOption('y').value==std::string("separate value"));
|
||||
ASSERT(validTestParameterParser.getOption(std::string("long-argument-with-value-separated")).value==std::string("separate value"));
|
||||
ASSERT(!validTestParameterParser.getArgument(1).isError);
|
||||
ASSERT(validTestParameterParser.getArgument(1).value=="argument 1");
|
||||
ASSERT(!validTestParameterParser.getArgument(2).isError);
|
||||
ASSERT(validTestParameterParser.getArgument(2).value=="argument 2");
|
||||
ASSERT(!validTestParameterParser.getOption('z').isError);
|
||||
ASSERT(validTestParameterParser.getOption('z').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(validTestParameterParser.getOption('z').value == std::string(""));
|
||||
ASSERT(validTestParameterParser.wrongUsageMessages.size() == 0);
|
||||
|
||||
delete[] validTestParameterList;
|
||||
std::cout << "Passed valid input test." << std::endl;
|
||||
std::cout << "Passed valid command line test." << std::endl;
|
||||
|
||||
// empty input (valid and invalid) #################################
|
||||
std::vector<CLI::Flag> emptyTestFlags;
|
||||
|
||||
std::vector<CLI::UnpositionalArgument> emptyTestUnpositionalArguments;
|
||||
std::vector<CLI::Option> emptyTestOptions;
|
||||
|
||||
std::vector<CLI::PositionalArgument> emptyTestPositionalArguments;
|
||||
std::vector<CLI::Argument> emptyTestArguments;
|
||||
|
||||
const char** emptyTestParameterList = new const char*[1];
|
||||
// The command is always a part of a command line, even if it is empty
|
||||
|
@ -167,27 +168,26 @@ int main(int argc, char* argv[]) {
|
|||
int emptyTestParameterCount = 1;
|
||||
|
||||
// valid
|
||||
CLI::ArgumentsParser validEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestUnpositionalArguments, emptyTestPositionalArguments);
|
||||
CLI::ArgumentsParser validEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestOptions, emptyTestArguments);
|
||||
ASSERT(!validEmptyTestParameterParser.wrongUsage);
|
||||
ASSERT(validEmptyTestParameterParser.programName == std::string("test"));
|
||||
ASSERT(validEmptyTestParameterParser.wrongUsageMessages.size() == 0);
|
||||
|
||||
//invalid
|
||||
emptyTestPositionalArguments.push_back(CLI::PositionalArgument("argument", "positional argument"));
|
||||
emptyTestArguments.push_back(CLI::Argument("argument", "argument"));
|
||||
|
||||
CLI::ArgumentsParser invalidEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestUnpositionalArguments, emptyTestPositionalArguments);
|
||||
CLI::ArgumentsParser invalidEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestOptions, emptyTestArguments);
|
||||
ASSERT(invalidEmptyTestParameterParser.wrongUsage);
|
||||
ASSERT(invalidEmptyTestParameterParser.programName == std::string("test"));
|
||||
ASSERT(invalidEmptyTestParameterParser.getPositionalArgument(0).isError);
|
||||
ASSERT(invalidEmptyTestParameterParser.getPositionalArgument(0).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(invalidEmptyTestParameterParser.getArgument(0).isError);
|
||||
ASSERT(invalidEmptyTestParameterParser.getArgument(0).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(invalidEmptyTestParameterParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(invalidEmptyTestParameterParser.wrongUsageMessages.at(0) == "Too few arguments! Missing: argument");
|
||||
|
||||
delete[] emptyTestParameterList;
|
||||
std::cout << "Passed empty input test." << std::endl;
|
||||
std::cout << "Passed empty command line test." << std::endl;
|
||||
|
||||
//TODO add tests for invalid input
|
||||
// test cases for invalid input:
|
||||
// - unknown flags, arguments (mixed with other input and standalone)
|
||||
// - too few, too many positional arguments (mixed with other input and standalone)
|
||||
// - check the produced error messages
|
||||
// unknown flag ####################################################
|
||||
|
||||
std::vector<CLI::Flag> unknownFlagTestFlags;
|
||||
unknownFlagTestFlags.push_back(CLI::Flag('0', "zero", "test flag"));
|
||||
|
@ -197,11 +197,11 @@ int main(int argc, char* argv[]) {
|
|||
unknownFlagTestFlags.push_back(CLI::Flag('4', "four", "test flag"));
|
||||
unknownFlagTestFlags.push_back(CLI::Flag('5', "five", "test flag"));
|
||||
|
||||
std::vector<CLI::UnpositionalArgument> unknownFlagTestUnpositionalArguments;
|
||||
std::vector<CLI::Option> unknownFlagTestOptions;
|
||||
|
||||
std::vector<CLI::PositionalArgument> unknownFlagTestPositionalArguments;
|
||||
std::vector<CLI::Argument> unknownFlagTestArguments;
|
||||
|
||||
const char** unknownFlagTestParameterList = new const char*[3];
|
||||
const char** unknownFlagTestParameterList = new const char*[7];
|
||||
unknownFlagTestParameterList[0] = "test";
|
||||
unknownFlagTestParameterList[1] = "-a";
|
||||
unknownFlagTestParameterList[2] = "-1";
|
||||
|
@ -211,20 +211,554 @@ int main(int argc, char* argv[]) {
|
|||
unknownFlagTestParameterList[6] = "-5";
|
||||
int unknownFlagStandaloneTestParameterCount = 2;
|
||||
|
||||
CLI::ArgumentsParser unknownFlagStandaloneTestParser = CLI::ArgumentsParser(unknownFlagStandaloneTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestUnpositionalArguments, unknownFlagTestPositionalArguments);
|
||||
CLI::ArgumentsParser unknownFlagStandaloneTestParser = CLI::ArgumentsParser(unknownFlagStandaloneTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestOptions, unknownFlagTestArguments);
|
||||
ASSERT(unknownFlagStandaloneTestParser.getFlag('1').isError);
|
||||
ASSERT(unknownFlagStandaloneTestParser.getFlag('1').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(!unknownFlagStandaloneTestParser.getFlag('1').value);
|
||||
ASSERT(unknownFlagStandaloneTestParser.getFlag(std::string("four")).isError);
|
||||
ASSERT(unknownFlagStandaloneTestParser.getFlag(std::string("four")).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(!unknownFlagStandaloneTestParser.getFlag(std::string("four")).value);
|
||||
ASSERT(unknownFlagStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownFlagStandaloneTestParser.wrongUsageMessages.at(0) == "Unknown argument or flag(s): a");
|
||||
|
||||
int unknownFlagMixedTestParameterCount = 7;
|
||||
|
||||
CLI::ArgumentsParser unknownFlagMixedTestParser = CLI::ArgumentsParser(unknownFlagMixedTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestUnpositionalArguments, unknownFlagTestPositionalArguments);
|
||||
CLI::ArgumentsParser unknownFlagMixedTestParser = CLI::ArgumentsParser(unknownFlagMixedTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestOptions, unknownFlagTestArguments);
|
||||
ASSERT(unknownFlagMixedTestParser.getFlag('1').isError);
|
||||
ASSERT(unknownFlagMixedTestParser.getFlag('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownFlagMixedTestParser.getFlag('1').value);
|
||||
ASSERT(unknownFlagMixedTestParser.getFlag(std::string("four")).isError);
|
||||
ASSERT(unknownFlagMixedTestParser.getFlag(std::string("four")).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownFlagMixedTestParser.getFlag(std::string("four")).value);
|
||||
ASSERT(unknownFlagMixedTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownFlagMixedTestParser.wrongUsageMessages.at(0) == "Unknown argument or flag(s): a");
|
||||
|
||||
delete[] unknownFlagTestParameterList;
|
||||
|
||||
std::vector<CLI::Flag> unknownLongFlagTestFlags;
|
||||
unknownLongFlagTestFlags.push_back(CLI::Flag('0', "zero", "test flag"));
|
||||
unknownLongFlagTestFlags.push_back(CLI::Flag('1', "one", "test flag"));
|
||||
unknownLongFlagTestFlags.push_back(CLI::Flag('2', "two", "test flag"));
|
||||
unknownLongFlagTestFlags.push_back(CLI::Flag('3', "three","test flag"));
|
||||
unknownLongFlagTestFlags.push_back(CLI::Flag('4', "four", "test flag"));
|
||||
unknownLongFlagTestFlags.push_back(CLI::Flag('5', "five", "test flag"));
|
||||
|
||||
std::vector<CLI::Option> unknownLongFlagTestOptions;
|
||||
|
||||
std::vector<CLI::Argument> unknownLongFlagTestArguments;
|
||||
|
||||
const char** unknownLongFlagTestParameterList = new const char*[7];
|
||||
unknownLongFlagTestParameterList[0] = "test";
|
||||
unknownLongFlagTestParameterList[1] = "--a";
|
||||
unknownLongFlagTestParameterList[2] = "-1";
|
||||
unknownLongFlagTestParameterList[3] = "-2";
|
||||
unknownLongFlagTestParameterList[4] = "-3";
|
||||
unknownLongFlagTestParameterList[5] = "-4";
|
||||
unknownLongFlagTestParameterList[6] = "-5";
|
||||
int unknownLongFlagStandaloneTestParameterCount = 2;
|
||||
|
||||
CLI::ArgumentsParser unknownLongFlagStandaloneTestParser = CLI::ArgumentsParser(unknownLongFlagStandaloneTestParameterCount, unknownLongFlagTestParameterList, unknownLongFlagTestFlags, unknownLongFlagTestOptions, unknownLongFlagTestArguments);
|
||||
ASSERT(unknownLongFlagStandaloneTestParser.getFlag('1').isError);
|
||||
ASSERT(unknownLongFlagStandaloneTestParser.getFlag('1').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(!unknownLongFlagStandaloneTestParser.getFlag('1').value);
|
||||
ASSERT(unknownLongFlagStandaloneTestParser.getFlag(std::string("four")).isError);
|
||||
ASSERT(unknownLongFlagStandaloneTestParser.getFlag(std::string("four")).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(!unknownLongFlagStandaloneTestParser.getFlag(std::string("four")).value);
|
||||
ASSERT(unknownLongFlagStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownLongFlagStandaloneTestParser.wrongUsageMessages.at(0) == "Unknown argument or flag: --a");
|
||||
|
||||
int unknownLongFlagMixedTestParameterCount = 7;
|
||||
|
||||
CLI::ArgumentsParser unknownLongFlagMixedTestParser = CLI::ArgumentsParser(unknownLongFlagMixedTestParameterCount, unknownLongFlagTestParameterList, unknownLongFlagTestFlags, unknownLongFlagTestOptions, unknownLongFlagTestArguments);
|
||||
ASSERT(unknownLongFlagMixedTestParser.getFlag('1').isError);
|
||||
ASSERT(unknownLongFlagMixedTestParser.getFlag('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownLongFlagMixedTestParser.getFlag('1').value);
|
||||
ASSERT(unknownLongFlagMixedTestParser.getFlag(std::string("four")).isError);
|
||||
ASSERT(unknownLongFlagMixedTestParser.getFlag(std::string("four")).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownLongFlagMixedTestParser.getFlag(std::string("four")).value);
|
||||
ASSERT(unknownLongFlagMixedTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownLongFlagMixedTestParser.wrongUsageMessages.at(0) == "Unknown argument or flag: --a");
|
||||
|
||||
delete[] unknownLongFlagTestParameterList;
|
||||
std::cout << "Passed unknown flag test." << std::endl;
|
||||
|
||||
// unknown argument ################################################
|
||||
|
||||
std::vector<CLI::Flag> unknownOptionTestFlags;
|
||||
|
||||
std::vector<CLI::Option> unknownOptionTestOptions;
|
||||
unknownOptionTestOptions.push_back(CLI::Option('0', "zero", "zero", "test argument"));
|
||||
unknownOptionTestOptions.push_back(CLI::Option('1', "one", "one", "test argument"));
|
||||
unknownOptionTestOptions.push_back(CLI::Option('2', "two", "two", "test argument"));
|
||||
unknownOptionTestOptions.push_back(CLI::Option('3', "three","three","test argument"));
|
||||
unknownOptionTestOptions.push_back(CLI::Option('4', "four", "four", "test argument"));
|
||||
unknownOptionTestOptions.push_back(CLI::Option('5', "five", "five", "test argument"));
|
||||
|
||||
std::vector<CLI::Argument> unknownOptionTestArguments;
|
||||
|
||||
const char** unknownOptionTestParameterList = new const char*[7];
|
||||
unknownOptionTestParameterList[0] = "test";
|
||||
unknownOptionTestParameterList[1] = "-a123";
|
||||
unknownOptionTestParameterList[2] = "-1a";
|
||||
unknownOptionTestParameterList[3] = "-2b";
|
||||
unknownOptionTestParameterList[4] = "-3c";
|
||||
unknownOptionTestParameterList[5] = "-4d";
|
||||
unknownOptionTestParameterList[6] = "-5e";
|
||||
int unknownOptionStandaloneTestParameterCount = 2;
|
||||
|
||||
CLI::ArgumentsParser unknownOptionStandaloneTestParser = CLI::ArgumentsParser(unknownOptionStandaloneTestParameterCount, unknownOptionTestParameterList, unknownOptionTestFlags, unknownOptionTestOptions, unknownOptionTestArguments);
|
||||
ASSERT(unknownOptionStandaloneTestParser.getOption('1').isError);
|
||||
ASSERT(unknownOptionStandaloneTestParser.getOption('1').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(unknownOptionStandaloneTestParser.getOption('1').value == "");
|
||||
ASSERT(unknownOptionStandaloneTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(unknownOptionStandaloneTestParser.getOption(std::string("four")).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(unknownOptionStandaloneTestParser.getOption(std::string("four")).value == "");
|
||||
ASSERT(unknownOptionStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownOptionStandaloneTestParser.wrongUsageMessages.at(0) == "Unknown argument or flag(s): a123");
|
||||
|
||||
int unknownOptionMixedTestParameterCount = 7;
|
||||
|
||||
CLI::ArgumentsParser unknownOptionMixedTestParser = CLI::ArgumentsParser(unknownOptionMixedTestParameterCount, unknownOptionTestParameterList, unknownOptionTestFlags, unknownOptionTestOptions, unknownOptionTestArguments);
|
||||
ASSERT(unknownOptionMixedTestParser.getOption('1').isError);
|
||||
ASSERT(unknownOptionMixedTestParser.getOption('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownOptionMixedTestParser.getOption('1').value == "a");
|
||||
ASSERT(unknownOptionMixedTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(unknownOptionMixedTestParser.getOption(std::string("four")).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownOptionMixedTestParser.getOption(std::string("four")).value == "d");
|
||||
ASSERT(unknownOptionMixedTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownOptionMixedTestParser.wrongUsageMessages.at(0) == "Unknown argument or flag(s): a123");
|
||||
|
||||
delete[] unknownOptionTestParameterList;
|
||||
|
||||
std::vector<CLI::Flag> unknownLongOptionTestFlags;
|
||||
|
||||
std::vector<CLI::Option> unknownLongOptionTestOptions;
|
||||
unknownLongOptionTestOptions.push_back(CLI::Option('0', "zero", "zero", "test argument"));
|
||||
unknownLongOptionTestOptions.push_back(CLI::Option('1', "one", "one", "test argument"));
|
||||
unknownLongOptionTestOptions.push_back(CLI::Option('2', "two", "two", "test argument"));
|
||||
unknownLongOptionTestOptions.push_back(CLI::Option('3', "three","three","test argument"));
|
||||
unknownLongOptionTestOptions.push_back(CLI::Option('4', "four", "four", "test argument"));
|
||||
unknownLongOptionTestOptions.push_back(CLI::Option('5', "five", "five", "test argument"));
|
||||
|
||||
std::vector<CLI::Argument> unknownLongOptionTestArguments;
|
||||
|
||||
const char** unknownLongOptionTestParameterList = new const char*[7];
|
||||
unknownLongOptionTestParameterList[0] = "test";
|
||||
unknownLongOptionTestParameterList[1] = "--a=123";
|
||||
unknownLongOptionTestParameterList[2] = "-1a";
|
||||
unknownLongOptionTestParameterList[3] = "-2b";
|
||||
unknownLongOptionTestParameterList[4] = "-3c";
|
||||
unknownLongOptionTestParameterList[5] = "-4d";
|
||||
unknownLongOptionTestParameterList[6] = "-5e";
|
||||
int unknownLongOptionStandaloneTestParameterCount = 2;
|
||||
|
||||
CLI::ArgumentsParser unknownLongOptionStandaloneTestParser = CLI::ArgumentsParser(unknownLongOptionStandaloneTestParameterCount, unknownLongOptionTestParameterList, unknownLongOptionTestFlags, unknownLongOptionTestOptions, unknownLongOptionTestArguments);
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.getOption('1').isError);
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.getOption('1').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.getOption('1').value == "");
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.getOption(std::string("four")).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.getOption(std::string("four")).value == "");
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownLongOptionStandaloneTestParser.wrongUsageMessages.at(0) == "Unknown argument (or it's a flag that doesn't take a value): --a=123");
|
||||
|
||||
int unknownLongOptionMixedTestParameterCount = 7;
|
||||
|
||||
CLI::ArgumentsParser unknownLongOptionMixedTestParser = CLI::ArgumentsParser(unknownLongOptionMixedTestParameterCount, unknownLongOptionTestParameterList, unknownLongOptionTestFlags, unknownLongOptionTestOptions, unknownLongOptionTestArguments);
|
||||
ASSERT(unknownLongOptionMixedTestParser.getOption('1').isError);
|
||||
ASSERT(unknownLongOptionMixedTestParser.getOption('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownLongOptionMixedTestParser.getOption('1').value == "a");
|
||||
ASSERT(unknownLongOptionMixedTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(unknownLongOptionMixedTestParser.getOption(std::string("four")).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(unknownLongOptionMixedTestParser.getOption(std::string("four")).value == "d");
|
||||
ASSERT(unknownLongOptionMixedTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(unknownLongOptionMixedTestParser.wrongUsageMessages.at(0) == "Unknown argument (or it's a flag that doesn't take a value): --a=123");
|
||||
|
||||
delete[] unknownLongOptionTestParameterList;
|
||||
std::cout << "Passed unknown option test." << std::endl;
|
||||
|
||||
// incomplete option ###############################################
|
||||
|
||||
std::vector<CLI::Flag> incompleteOptionTestFlags;
|
||||
|
||||
std::vector<CLI::Option> incompleteOptionTestOptions;
|
||||
incompleteOptionTestOptions.push_back(CLI::Option('0', "zero", "zero", "test option"));
|
||||
incompleteOptionTestOptions.push_back(CLI::Option('1', "one", "one", "test option"));
|
||||
incompleteOptionTestOptions.push_back(CLI::Option('2', "two", "two", "test option"));
|
||||
incompleteOptionTestOptions.push_back(CLI::Option('3', "three","three","test option"));
|
||||
incompleteOptionTestOptions.push_back(CLI::Option('4', "four", "four", "test option"));
|
||||
incompleteOptionTestOptions.push_back(CLI::Option('5', "five", "five", "test option"));
|
||||
|
||||
std::vector<CLI::Argument> incompleteOptionTestArguments;
|
||||
|
||||
const char** incompleteOptionTestParameterList = new const char*[6];
|
||||
incompleteOptionTestParameterList[0] = "test";
|
||||
incompleteOptionTestParameterList[1] = "-1";
|
||||
incompleteOptionTestParameterList[2] = "--two="; // value ""
|
||||
incompleteOptionTestParameterList[3] = "-3c";
|
||||
incompleteOptionTestParameterList[4] = "-4";
|
||||
incompleteOptionTestParameterList[5] = "-5e";
|
||||
int incompleteOptionStandaloneTestParameterCount = 2;
|
||||
|
||||
CLI::ArgumentsParser incompleteOptionStandaloneTestParser = CLI::ArgumentsParser(incompleteOptionStandaloneTestParameterCount, incompleteOptionTestParameterList, incompleteOptionTestFlags, incompleteOptionTestOptions, incompleteOptionTestArguments);
|
||||
ASSERT(incompleteOptionStandaloneTestParser.getOption('1').isError);
|
||||
ASSERT(incompleteOptionStandaloneTestParser.getOption('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteOptionStandaloneTestParser.getOption('1').value == "");
|
||||
ASSERT(incompleteOptionStandaloneTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(incompleteOptionStandaloneTestParser.getOption(std::string("four")).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(incompleteOptionStandaloneTestParser.getOption(std::string("four")).value == "");
|
||||
ASSERT(incompleteOptionStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(incompleteOptionStandaloneTestParser.wrongUsageMessages.at(0) == "Argument expects value but has none: one");
|
||||
|
||||
int incompleteOptionMixedTestParameterCount = 6;
|
||||
|
||||
CLI::ArgumentsParser incompleteOptionMixedTestParser = CLI::ArgumentsParser(incompleteOptionMixedTestParameterCount, incompleteOptionTestParameterList, incompleteOptionTestFlags, incompleteOptionTestOptions, incompleteOptionTestArguments);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption('1').isError);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption('1').value == "");
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption(std::string("four")).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption(std::string("four")).value == "");
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption('5').isError);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption('5').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteOptionMixedTestParser.getOption('5').value == "e");
|
||||
ASSERT(incompleteOptionMixedTestParser.wrongUsageMessages.size() == 2);
|
||||
ASSERT(incompleteOptionMixedTestParser.wrongUsageMessages.at(0) == "Argument expects value but has none: one");
|
||||
ASSERT(incompleteOptionMixedTestParser.wrongUsageMessages.at(1) == "Argument expects value but has none: four");
|
||||
|
||||
delete[] incompleteOptionTestParameterList;
|
||||
|
||||
std::vector<CLI::Flag> incompleteLongOptionTestFlags;
|
||||
|
||||
std::vector<CLI::Option> incompleteLongOptionTestOptions;
|
||||
incompleteLongOptionTestOptions.push_back(CLI::Option('0', "zero", "zero", "test argument"));
|
||||
incompleteLongOptionTestOptions.push_back(CLI::Option('1', "one", "one", "test argument"));
|
||||
incompleteLongOptionTestOptions.push_back(CLI::Option('2', "two", "two", "test argument"));
|
||||
incompleteLongOptionTestOptions.push_back(CLI::Option('3', "three","three","test argument"));
|
||||
incompleteLongOptionTestOptions.push_back(CLI::Option('4', "four", "four", "test argument"));
|
||||
incompleteLongOptionTestOptions.push_back(CLI::Option('5', "five", "five", "test argument"));
|
||||
|
||||
std::vector<CLI::Argument> incompleteLongOptionTestArguments;
|
||||
|
||||
const char** incompleteLongOptionTestParameterList = new const char*[8];
|
||||
incompleteLongOptionTestParameterList[0] = "test";
|
||||
incompleteLongOptionTestParameterList[1] = "--one";
|
||||
incompleteLongOptionTestParameterList[2] = "--two";
|
||||
incompleteLongOptionTestParameterList[3] = "b";
|
||||
incompleteLongOptionTestParameterList[4] = "-3c";
|
||||
incompleteLongOptionTestParameterList[5] = "arg";
|
||||
incompleteLongOptionTestParameterList[6] = "--four";
|
||||
incompleteLongOptionTestParameterList[7] = "--five=e";
|
||||
int incompleteLongOptionStandaloneTestParameterCount = 2;
|
||||
|
||||
CLI::ArgumentsParser incompleteLongOptionStandaloneTestParser = CLI::ArgumentsParser(incompleteLongOptionStandaloneTestParameterCount, incompleteLongOptionTestParameterList, incompleteLongOptionTestFlags, incompleteLongOptionTestOptions, incompleteLongOptionTestArguments);
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.getOption('1').isError);
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.getOption('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.getOption('1').value == "");
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.getOption(std::string("four")).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.getOption(std::string("four")).value == "");
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(incompleteLongOptionStandaloneTestParser.wrongUsageMessages.at(0) == "Argument expects value but has none: one");
|
||||
|
||||
int incompleteLongOptionMixedTestParameterCount = 8;
|
||||
incompleteLongOptionTestArguments.push_back(CLI::Argument("arg", "argument"));
|
||||
|
||||
CLI::ArgumentsParser incompleteLongOptionMixedTestParser = CLI::ArgumentsParser(incompleteLongOptionMixedTestParameterCount, incompleteLongOptionTestParameterList, incompleteLongOptionTestFlags, incompleteLongOptionTestOptions, incompleteLongOptionTestArguments);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('1').isError);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('1').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('1').value == "");
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('2').isError);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('2').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('2').value == "b");
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption(std::string("four")).isError);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption(std::string("four")).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption(std::string("four")).value == "");
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('5').isError);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('5').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.getOption('5').value == "e");
|
||||
ASSERT(incompleteLongOptionMixedTestParser.wrongUsageMessages.size() == 2);
|
||||
ASSERT(incompleteLongOptionMixedTestParser.wrongUsageMessages.at(0) == "Argument expects value but has none: one");
|
||||
ASSERT(incompleteLongOptionMixedTestParser.wrongUsageMessages.at(1) == "Argument expects value but has none: four");
|
||||
|
||||
delete[] incompleteLongOptionTestParameterList;
|
||||
std::cout << "Passed incomplete option test." << std::endl;
|
||||
|
||||
// too few arguments ###############################################
|
||||
|
||||
std::vector<CLI::Flag> tooFewArgumentsTestFlags;
|
||||
tooFewArgumentsTestFlags.push_back(CLI::Flag('a', "aaaaa", "test flag"));
|
||||
|
||||
std::vector<CLI::Option> tooFewArgumentsTestOptions;
|
||||
tooFewArgumentsTestOptions.push_back(CLI::Option('b', "bbbbb", "b", "test argument"));
|
||||
tooFewArgumentsTestOptions.push_back(CLI::Option('c', "ccccc", "c", "test argument"));
|
||||
tooFewArgumentsTestOptions.push_back(CLI::Option('d', "ddddd", "d", "test argument"));
|
||||
|
||||
std::vector<CLI::Argument> tooFewArgumentsTestArguments;
|
||||
tooFewArgumentsTestArguments.push_back(CLI::Argument("argument0", "test argument"));
|
||||
tooFewArgumentsTestArguments.push_back(CLI::Argument("argument1", "test argument"));
|
||||
tooFewArgumentsTestArguments.push_back(CLI::Argument("argument2", "test argument"));
|
||||
tooFewArgumentsTestArguments.push_back(CLI::Argument("argument3", "test argument"));
|
||||
tooFewArgumentsTestArguments.push_back(CLI::Argument("argument4", "test argument"));
|
||||
|
||||
const char** tooFewArgumentsTestParameterList = new const char*[10];
|
||||
tooFewArgumentsTestParameterList[0] = "test";
|
||||
tooFewArgumentsTestParameterList[1] = "arg_0";
|
||||
tooFewArgumentsTestParameterList[2] = "-a";//
|
||||
tooFewArgumentsTestParameterList[3] = "-b";
|
||||
tooFewArgumentsTestParameterList[4] = "1";
|
||||
tooFewArgumentsTestParameterList[5] = "-c5";
|
||||
tooFewArgumentsTestParameterList[6] = "arg_1";
|
||||
tooFewArgumentsTestParameterList[7] = "--ddddd";
|
||||
tooFewArgumentsTestParameterList[8] = "ddd";
|
||||
tooFewArgumentsTestParameterList[9] = "arg_2";
|
||||
|
||||
int tooFewArgumentsStandaloneTestParameterCount = 2;
|
||||
CLI::ArgumentsParser tooFewArgumentsStandaloneTestParser = CLI::ArgumentsParser(tooFewArgumentsStandaloneTestParameterCount, tooFewArgumentsTestParameterList, tooFewArgumentsTestFlags, tooFewArgumentsTestOptions, tooFewArgumentsTestArguments);
|
||||
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getArgument(0).isError);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getArgument(0).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getArgument(0).value == "arg_0");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getArgument(1).isError);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getArgument(1).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getArgument(1).value == "");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('b').isError);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('b').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('b').value == "");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('c').isError);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('c').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('c').value == "");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('d').isError);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('d').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.getOption('d').value == "");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.wrongUsageMessages.size() == 4);
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.wrongUsageMessages.at(0) == "Too few arguments! Missing: argument1");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.wrongUsageMessages.at(1) == "Too few arguments! Missing: argument2");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.wrongUsageMessages.at(2) == "Too few arguments! Missing: argument3");
|
||||
ASSERT(tooFewArgumentsStandaloneTestParser.wrongUsageMessages.at(3) == "Too few arguments! Missing: argument4");
|
||||
|
||||
int tooFewArgumentsMixedTestParameterCount = 10;
|
||||
CLI::ArgumentsParser tooFewArgumentsMixedTestParser = CLI::ArgumentsParser(tooFewArgumentsMixedTestParameterCount, tooFewArgumentsTestParameterList, tooFewArgumentsTestFlags, tooFewArgumentsTestOptions, tooFewArgumentsTestArguments);
|
||||
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(0).isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(0).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(0).value == "arg_0");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(1).isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(1).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(1).value == "arg_1");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(2).isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(2).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(2).value == "arg_2");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(3).isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(3).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(3).value == "");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(4).isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(4).errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getArgument(4).value == "");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('b').isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('b').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('b').value == "1");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('c').isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('c').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('c').value == "5");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('d').isError);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('d').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.getOption('d').value == "ddd");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.wrongUsageMessages.size() == 2);
|
||||
ASSERT(tooFewArgumentsMixedTestParser.wrongUsageMessages.at(0) == "Too few arguments! Missing: argument3");
|
||||
ASSERT(tooFewArgumentsMixedTestParser.wrongUsageMessages.at(1) == "Too few arguments! Missing: argument4");
|
||||
|
||||
delete[] tooFewArgumentsTestParameterList;
|
||||
std::cout << "Passed too few arguments test." << std::endl;
|
||||
|
||||
// too many arguments ##############################################
|
||||
|
||||
std::vector<CLI::Flag> tooManyArgumentsTestFlags;
|
||||
tooManyArgumentsTestFlags.push_back(CLI::Flag('a', "aaaaa", "test flag"));
|
||||
|
||||
std::vector<CLI::Option> tooManyArgumentsTestOptions;
|
||||
tooManyArgumentsTestOptions.push_back(CLI::Option('b', "bbbbb", "b", "test argument"));
|
||||
tooManyArgumentsTestOptions.push_back(CLI::Option('c', "ccccc", "c", "test argument"));
|
||||
tooManyArgumentsTestOptions.push_back(CLI::Option('d', "ddddd", "d", "test argument"));
|
||||
|
||||
std::vector<CLI::Argument> tooManyArgumentsTestArguments;
|
||||
tooManyArgumentsTestArguments.push_back(CLI::Argument("argument0", "test argument"));
|
||||
|
||||
const char** tooManyArgumentsTestParameterList = new const char*[10];
|
||||
tooManyArgumentsTestParameterList[0] = "test";
|
||||
tooManyArgumentsTestParameterList[1] = "arg_0";
|
||||
tooManyArgumentsTestParameterList[2] = "arg_1";
|
||||
tooManyArgumentsTestParameterList[3] = "-a";//
|
||||
tooManyArgumentsTestParameterList[4] = "-b";
|
||||
tooManyArgumentsTestParameterList[5] = "1";
|
||||
tooManyArgumentsTestParameterList[6] = "-c5";
|
||||
tooManyArgumentsTestParameterList[7] = "--ddddd";
|
||||
tooManyArgumentsTestParameterList[8] = "ddd";
|
||||
tooManyArgumentsTestParameterList[9] = "arg_2";
|
||||
|
||||
int tooManyArgumentsStandaloneTestParameterCount = 3;
|
||||
CLI::ArgumentsParser tooManyArgumentsStandaloneTestParser = CLI::ArgumentsParser(tooManyArgumentsStandaloneTestParameterCount, tooManyArgumentsTestParameterList, tooManyArgumentsTestFlags, tooManyArgumentsTestOptions, tooManyArgumentsTestArguments);
|
||||
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getArgument(0).isError);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getArgument(0).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getArgument(0).value == "arg_0");
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('b').isError);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('b').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('b').value == "");
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('c').isError);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('c').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('c').value == "");
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('d').isError);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('d').errorCode == ErrorCodes::NOT_PRESENT);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.getOption('d').value == "");
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.wrongUsageMessages.size() == 1);
|
||||
ASSERT(tooManyArgumentsStandaloneTestParser.wrongUsageMessages.at(0) == "Too many arguments! Unexpected encounter of: arg_1");
|
||||
|
||||
int tooManyArgumentsMixedTestParameterCount = 10;
|
||||
CLI::ArgumentsParser tooManyArgumentsMixedTestParser = CLI::ArgumentsParser(tooManyArgumentsMixedTestParameterCount, tooManyArgumentsTestParameterList, tooManyArgumentsTestFlags, tooManyArgumentsTestOptions, tooManyArgumentsTestArguments);
|
||||
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getArgument(0).isError);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getArgument(0).errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getArgument(0).value == "arg_0");
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('b').isError);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('b').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('b').value == "1");
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('c').isError);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('c').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('c').value == "5");
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('d').isError);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('d').errorCode == ErrorCodes::WRONG_USAGE);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.getOption('d').value == "ddd");
|
||||
ASSERT(tooManyArgumentsMixedTestParser.wrongUsageMessages.size() == 2);
|
||||
ASSERT(tooManyArgumentsMixedTestParser.wrongUsageMessages.at(0) == "Too many arguments! Unexpected encounter of: arg_1");
|
||||
ASSERT(tooManyArgumentsMixedTestParser.wrongUsageMessages.at(1) == "Too many arguments! Unexpected encounter of: arg_2");
|
||||
|
||||
delete[] tooManyArgumentsTestParameterList;
|
||||
std::cout << "Passed too many arguments test." << std::endl;
|
||||
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "CLI argument parser help tests" << std::endl;
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
|
||||
// normal usage with all types of CLI input ########################
|
||||
std::vector<CLI::Flag> helpTestFlags;
|
||||
helpTestFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
helpTestFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> helpTestOptions;
|
||||
helpTestOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
helpTestOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> helpTestArguments;
|
||||
helpTestArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
helpTestArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** helpTestCommand = new const char*[1];
|
||||
helpTestCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser helpTestParser = CLI::ArgumentsParser(1, helpTestCommand, helpTestFlags, helpTestOptions, helpTestArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(helpTestParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
std::cout << "Passed normal usage test." << std::endl;
|
||||
|
||||
// no description ##################################################
|
||||
std::vector<CLI::Flag> usageOnlyTestFlags;
|
||||
usageOnlyTestFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
usageOnlyTestFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> usageOnlyTestOptions;
|
||||
usageOnlyTestOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
usageOnlyTestOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> usageOnlyTestArguments;
|
||||
usageOnlyTestArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
usageOnlyTestArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** usageOnlyTestCommand = new const char*[1];
|
||||
usageOnlyTestCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser usageOnlyTestParser = CLI::ArgumentsParser(1, usageOnlyTestCommand, usageOnlyTestFlags, usageOnlyTestOptions, usageOnlyTestArguments);
|
||||
|
||||
ASSERT(usageOnlyTestParser.getUsage() == "Usage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
std::cout << "Passed normal usage without description test." << std::endl;
|
||||
|
||||
// no flags ########################################################
|
||||
std::vector<CLI::Flag> noFlagsFlags;
|
||||
|
||||
std::vector<CLI::Option> noFlagsOptions;
|
||||
noFlagsOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
noFlagsOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> noFlagsArguments;
|
||||
noFlagsArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
noFlagsArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** noFlagsCommand = new const char*[1];
|
||||
noFlagsCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noFlagsParser = CLI::ArgumentsParser(1, noFlagsCommand, noFlagsFlags, noFlagsOptions, noFlagsArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noFlagsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
|
||||
// no options ######################################################
|
||||
std::vector<CLI::Flag> noOptionsFlags;
|
||||
noOptionsFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
noOptionsFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> noOptionsOptions;
|
||||
|
||||
std::vector<CLI::Argument> noOptionsArguments;
|
||||
noOptionsArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
noOptionsArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** noOptionsCommand = new const char*[1];
|
||||
noOptionsCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noOptionsParser = CLI::ArgumentsParser(1, noOptionsCommand, noOptionsFlags, noOptionsOptions, noOptionsArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noOptionsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
|
||||
// no arguments ####################################################
|
||||
std::vector<CLI::Flag> noArgumentsFlags;
|
||||
noArgumentsFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
noArgumentsFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> noArgumentsOptions;
|
||||
noArgumentsOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
noArgumentsOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> noArgumentsArguments;
|
||||
|
||||
const char** noArgumentsCommand = new const char*[1];
|
||||
noArgumentsCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noArgumentsParser = CLI::ArgumentsParser(1, noArgumentsCommand, noArgumentsFlags, noArgumentsOptions, noArgumentsArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noArgumentsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n");
|
||||
std::cout << "Passed absent section usage test." << std::endl;
|
||||
|
||||
// no CLI input ####################################################
|
||||
std::vector<CLI::Flag> noCLIFlags;
|
||||
|
||||
std::vector<CLI::Option> noCLIOptions;
|
||||
|
||||
std::vector<CLI::Argument> noCLIArguments;
|
||||
|
||||
const char** noCLICommand = new const char*[1];
|
||||
noCLICommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noCLIParser = CLI::ArgumentsParser(1, noCLICommand, noCLIFlags, noCLIOptions, noCLIArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noCLIParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator \n");
|
||||
std::cout << "Passed no CLI input usage test." << std::endl;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
// 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(cutByte.value == '.');
|
||||
ASSERT(cutByteString == "Hallo, Hi THE CAKE IS A LIE, Ich bin Shwoomple");
|
||||
std::cout << "Passed cut byte test." << std::endl;
|
||||
}
|
|
@ -13,12 +13,12 @@
|
|||
// version 3 along with this program.
|
||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include "assert.h++"
|
||||
#include "../lib/javacompat.h++"
|
||||
#include <iostream>
|
||||
#include <tinyutf8/tinyutf8.h>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include "assert.hpp"
|
||||
#include "../lib/javacompat.hpp"
|
||||
|
||||
|
||||
int main(){
|
||||
|
@ -28,7 +28,7 @@ int main(){
|
|||
// java-style_unicode: 119 bytes, 85 characters ??
|
||||
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "Java String Tests" << std::endl;
|
||||
std::cout << "Javacompat tests" << std::endl;
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
|
||||
char* nextChar = new char;
|
||||
|
@ -52,7 +52,7 @@ int main(){
|
|||
return 2;
|
||||
}
|
||||
|
||||
tiny_utf8::string importedString = JavaCompat::importJavaString(reinterpret_cast<uint8_t*>(javaStdString.data()));
|
||||
tiny_utf8::string importedString = JavaCompat::importJavaString(reinterpret_cast<uint8_t*>(javaStdString.data()), 0x75).value;
|
||||
|
||||
std::streampos normalSize;
|
||||
std::string normalStdString;
|
||||
|
@ -75,9 +75,30 @@ 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
|
||||
//there's no need to read the same file twice
|
||||
|
||||
std::vector<uint8_t> data = JavaCompat::exportJavaString(normalString).value;
|
||||
std::string exportedString = std::string();
|
||||
for(int i=0; i<(int) data.size(); i++){
|
||||
exportedString.push_back(data[i]);
|
||||
}
|
||||
|
||||
ASSERT(exportedString == javaStdString);
|
||||
std::cout << "Passed Export Java string test." << std::endl;
|
||||
delete nextChar;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,446 +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 <iostream>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "assert.h++"
|
||||
|
||||
#include "../lib/nbt.h++"
|
||||
#include "../lib/error.h++"
|
||||
|
||||
int main(){
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "NBT helper tests" << std::endl;
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
|
||||
// used for all integer tests
|
||||
uint8_t dataForIntTest[] = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
|
||||
uint64_t dataSize = 10;
|
||||
|
||||
// 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);
|
||||
// begin of data
|
||||
currentPosition = 0;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
std::vector<uint8_t> dereferencedWriteInt8TestResult = *writeInt8TestResult;
|
||||
delete writeInt8TestResult;
|
||||
ASSERT(dereferencedWriteInt8TestResult.back() == (uint8_t) 8);
|
||||
|
||||
std::cout << "Passed writeInt8 NBT helper test" << std::endl;
|
||||
|
||||
// int16 ###########################################################
|
||||
// read successfully
|
||||
currentPosition = 5;
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 8;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
std::vector<uint8_t> dereferencedWriteInt16TestResult = *writeInt16TestResult;
|
||||
delete writeInt16TestResult;
|
||||
ASSERT(dereferencedWriteInt16TestResult[0] == (uint8_t) 0xAB && dereferencedWriteInt16TestResult[1] == (uint8_t) 0xCD);
|
||||
|
||||
std::cout << "Passed writeInt16 NBT helper test" << std::endl;
|
||||
|
||||
// int32 ###########################################################
|
||||
// read successfully
|
||||
currentPosition = 5;
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 6;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
std::vector<uint8_t> dereferencedWriteInt32TestResult = *writeInt32TestResult;
|
||||
delete writeInt32TestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteInt32TestResult[0] == (uint8_t) 0x12 &&
|
||||
dereferencedWriteInt32TestResult[1] == (uint8_t) 0x34 &&
|
||||
dereferencedWriteInt32TestResult[2] == (uint8_t) 0x56 &&
|
||||
dereferencedWriteInt32TestResult[3] == (uint8_t) 0x78
|
||||
);
|
||||
|
||||
std::cout << "Passed writeInt32 NBT helper test" << std::endl;
|
||||
|
||||
// int64 ###########################################################
|
||||
// read successfully
|
||||
currentPosition = 1;
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 2;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
std::vector<uint8_t> dereferencedWriteInt64TestResult = *writeInt64TestResult;
|
||||
delete writeInt64TestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteInt64TestResult[0] == (uint8_t) 0x01 &&
|
||||
dereferencedWriteInt64TestResult[1] == (uint8_t) 0x23 &&
|
||||
dereferencedWriteInt64TestResult[2] == (uint8_t) 0x45 &&
|
||||
dereferencedWriteInt64TestResult[3] == (uint8_t) 0x67 &&
|
||||
dereferencedWriteInt64TestResult[4] == (uint8_t) 0x89 &&
|
||||
dereferencedWriteInt64TestResult[5] == (uint8_t) 0xAB &&
|
||||
dereferencedWriteInt64TestResult[6] == (uint8_t) 0xCD &&
|
||||
dereferencedWriteInt64TestResult[7] == (uint8_t) 0xEF
|
||||
);
|
||||
|
||||
std::cout << "Passed writeInt64 NBT helper test" << std::endl;
|
||||
|
||||
//##################################################################
|
||||
|
||||
// used for integer "array" tests
|
||||
uint8_t dataForIntArrayTest[] = {
|
||||
0, 0, 0, 20,
|
||||
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,
|
||||
0, 0, 0, 5,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||
0, 0, 0, 10,
|
||||
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,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
dataSize = 116;
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
// read overrun
|
||||
currentPosition = 20;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
ASSERT(
|
||||
int8ArrayTestOutput->at(0) == 0 &&
|
||||
int8ArrayTestOutput->at(1) == 0 &&
|
||||
int8ArrayTestOutput->at(2) == 0 &&
|
||||
int8ArrayTestOutput->at(3) == 4 &&
|
||||
int8ArrayTestOutput->at(4) == 1 &&
|
||||
int8ArrayTestOutput->at(5) == 2 &&
|
||||
int8ArrayTestOutput->at(6) == 3 &&
|
||||
int8ArrayTestOutput->at(7) == 4
|
||||
);
|
||||
int8ArrayTestOutput->clear();
|
||||
NBT::helper::writeInt8Array(int8ArrayTestOutput, std::vector<int8_t>({1,2,3,4}));
|
||||
ASSERT(
|
||||
int8ArrayTestOutput->at(0) == 0 &&
|
||||
int8ArrayTestOutput->at(1) == 0 &&
|
||||
int8ArrayTestOutput->at(2) == 0 &&
|
||||
int8ArrayTestOutput->at(3) == 4 &&
|
||||
int8ArrayTestOutput->at(4) == 1 &&
|
||||
int8ArrayTestOutput->at(5) == 2 &&
|
||||
int8ArrayTestOutput->at(6) == 3 &&
|
||||
int8ArrayTestOutput->at(7) == 4
|
||||
);
|
||||
delete int8ArrayTestOutput;
|
||||
std::cout << "Passed writeInt8Array NBT helper test" << std::endl;
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
// read overrun
|
||||
currentPosition = 20;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
ASSERT(
|
||||
int32ArrayTestOutput->at(0) == 0x00 &&
|
||||
int32ArrayTestOutput->at(1) == 0x00 &&
|
||||
int32ArrayTestOutput->at(2) == 0x00 &&
|
||||
int32ArrayTestOutput->at(3) == 0x02 &&
|
||||
int32ArrayTestOutput->at(4) == 0x01 &&
|
||||
int32ArrayTestOutput->at(5) == 0x23 &&
|
||||
int32ArrayTestOutput->at(6) == 0x45 &&
|
||||
int32ArrayTestOutput->at(7) == 0x67 &&
|
||||
int32ArrayTestOutput->at(8) == 0x01 &&
|
||||
int32ArrayTestOutput->at(9) == 0x23 &&
|
||||
int32ArrayTestOutput->at(10) == 0x45 &&
|
||||
int32ArrayTestOutput->at(11) == 0x67
|
||||
);
|
||||
int32ArrayTestOutput->clear();
|
||||
NBT::helper::writeInt32Array(int32ArrayTestOutput, std::vector<int32_t>({0x01234567, 0x01234567}));
|
||||
ASSERT(
|
||||
int32ArrayTestOutput->at(0) == 0x00 &&
|
||||
int32ArrayTestOutput->at(1) == 0x00 &&
|
||||
int32ArrayTestOutput->at(2) == 0x00 &&
|
||||
int32ArrayTestOutput->at(3) == 0x02 &&
|
||||
int32ArrayTestOutput->at(4) == 0x01 &&
|
||||
int32ArrayTestOutput->at(5) == 0x23 &&
|
||||
int32ArrayTestOutput->at(6) == 0x45 &&
|
||||
int32ArrayTestOutput->at(7) == 0x67 &&
|
||||
int32ArrayTestOutput->at(8) == 0x01 &&
|
||||
int32ArrayTestOutput->at(9) == 0x23 &&
|
||||
int32ArrayTestOutput->at(10) == 0x45 &&
|
||||
int32ArrayTestOutput->at(11) == 0x67
|
||||
);
|
||||
delete int32ArrayTestOutput;
|
||||
|
||||
std::cout << "Passed writeInt32Array NBT helper test" << std::endl;
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
// read overrun
|
||||
currentPosition = 20;
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
ASSERT(
|
||||
int64ArrayTestOutput->at(0) == 0x00 &&
|
||||
int64ArrayTestOutput->at(1) == 0x00 &&
|
||||
int64ArrayTestOutput->at(2) == 0x00 &&
|
||||
int64ArrayTestOutput->at(3) == 0x02 &&
|
||||
int64ArrayTestOutput->at(4) == 0x01 &&
|
||||
int64ArrayTestOutput->at(5) == 0x23 &&
|
||||
int64ArrayTestOutput->at(6) == 0x45 &&
|
||||
int64ArrayTestOutput->at(7) == 0x67 &&
|
||||
int64ArrayTestOutput->at(8) == 0x89 &&
|
||||
int64ArrayTestOutput->at(9) == 0xAB &&
|
||||
int64ArrayTestOutput->at(10) == 0xCD &&
|
||||
int64ArrayTestOutput->at(11) == 0xEF &&
|
||||
int64ArrayTestOutput->at(12) == 0x01 &&
|
||||
int64ArrayTestOutput->at(13) == 0x23 &&
|
||||
int64ArrayTestOutput->at(14) == 0x45 &&
|
||||
int64ArrayTestOutput->at(15) == 0x67 &&
|
||||
int64ArrayTestOutput->at(16) == 0x89 &&
|
||||
int64ArrayTestOutput->at(17) == 0xAB &&
|
||||
int64ArrayTestOutput->at(18) == 0xCD &&
|
||||
int64ArrayTestOutput->at(19) == 0xEF
|
||||
);
|
||||
int64ArrayTestOutput->clear();
|
||||
NBT::helper::writeInt64Array(int64ArrayTestOutput, std::vector<int64_t>({0x0123456789ABCDEF, 0x0123456789ABCDEF}));
|
||||
ASSERT(
|
||||
int64ArrayTestOutput->at(0) == 0x00 &&
|
||||
int64ArrayTestOutput->at(1) == 0x00 &&
|
||||
int64ArrayTestOutput->at(2) == 0x00 &&
|
||||
int64ArrayTestOutput->at(3) == 0x02 &&
|
||||
int64ArrayTestOutput->at(4) == 0x01 &&
|
||||
int64ArrayTestOutput->at(5) == 0x23 &&
|
||||
int64ArrayTestOutput->at(6) == 0x45 &&
|
||||
int64ArrayTestOutput->at(7) == 0x67 &&
|
||||
int64ArrayTestOutput->at(8) == 0x89 &&
|
||||
int64ArrayTestOutput->at(9) == 0xAB &&
|
||||
int64ArrayTestOutput->at(10) == 0xCD &&
|
||||
int64ArrayTestOutput->at(11) == 0xEF &&
|
||||
int64ArrayTestOutput->at(12) == 0x01 &&
|
||||
int64ArrayTestOutput->at(13) == 0x23 &&
|
||||
int64ArrayTestOutput->at(14) == 0x45 &&
|
||||
int64ArrayTestOutput->at(15) == 0x67 &&
|
||||
int64ArrayTestOutput->at(16) == 0x89 &&
|
||||
int64ArrayTestOutput->at(17) == 0xAB &&
|
||||
int64ArrayTestOutput->at(18) == 0xCD &&
|
||||
int64ArrayTestOutput->at(19) == 0xEF &&
|
||||
true
|
||||
);
|
||||
delete int64ArrayTestOutput;
|
||||
|
||||
std::cout << "Passed writeInt32Array NBT helper test" << std::endl;
|
||||
|
||||
// float32 ["float" in the current implementation :( ] #############
|
||||
uint8_t dataForFloat32Test[] = {0xC7, 0x77, 0x77, 0x77};
|
||||
dataSize = 4;
|
||||
currentPosition = 0;
|
||||
// read successfully
|
||||
ASSERT(NBT::helper::readFloat32(dataForFloat32Test, dataSize, currentPosition).value == -63351.46484375f);
|
||||
ASSERT(NBT::helper::readFloat32(dataForFloat32Test, dataSize, currentPosition).isError == false);
|
||||
// read overrun
|
||||
currentPosition = 1;
|
||||
ASSERT(NBT::helper::readFloat32(dataForFloat32Test, dataSize, currentPosition).isError == true);
|
||||
ASSERT(NBT::helper::readFloat32(dataForFloat32Test, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
|
||||
// read out of bounds
|
||||
currentPosition = 4;
|
||||
ASSERT(NBT::helper::readFloat32(dataForFloat32Test, dataSize, currentPosition).isError == true);
|
||||
ASSERT(NBT::helper::readFloat32(dataForFloat32Test, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
|
||||
|
||||
std::cout << "Passed readFloat32 NBT helper test" << std::endl;
|
||||
|
||||
std::vector<uint8_t>* writeFloat32TestResult = new std::vector<uint8_t>();
|
||||
NBT::helper::writeFloat32(writeFloat32TestResult, (float) -63351.46484375f);
|
||||
std::vector<uint8_t> dereferencedWriteFloat32TestResult = *writeFloat32TestResult;
|
||||
delete writeFloat32TestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteFloat32TestResult[0] == (uint8_t) 0xC7 &&
|
||||
dereferencedWriteFloat32TestResult[1] == (uint8_t) 0x77 &&
|
||||
dereferencedWriteFloat32TestResult[2] == (uint8_t) 0x77 &&
|
||||
dereferencedWriteFloat32TestResult[3] == (uint8_t) 0x77
|
||||
);
|
||||
|
||||
std::cout << "Passed writeFloat32 NBT helper test" << std::endl;
|
||||
|
||||
// float64 ["double" in the current implementation :( ] ############
|
||||
uint8_t dataForFloat64Test[] = {0xC0, 0x34, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00};
|
||||
dataSize = 8;
|
||||
currentPosition = 0;
|
||||
// read successfully
|
||||
ASSERT(NBT::helper::readFloat64(dataForFloat64Test, dataSize, currentPosition).value == -20.015625476837158203125);
|
||||
ASSERT(NBT::helper::readFloat64(dataForFloat64Test, dataSize, currentPosition).isError == false);
|
||||
// read overrun
|
||||
currentPosition = 1;
|
||||
ASSERT(NBT::helper::readFloat64(dataForFloat64Test, dataSize, currentPosition).isError == true);
|
||||
ASSERT(NBT::helper::readFloat64(dataForFloat64Test, dataSize, currentPosition).errorCode == ErrorCodes::OVERRUN);
|
||||
// read out of bounds
|
||||
currentPosition = 8;
|
||||
ASSERT(NBT::helper::readFloat64(dataForFloat64Test, dataSize, currentPosition).isError == true);
|
||||
ASSERT(NBT::helper::readFloat64(dataForFloat64Test, dataSize, currentPosition).errorCode == ErrorCodes::OUT_OF_RANGE);
|
||||
|
||||
std::cout << "Passed readFloat64 NBT helper test" << std::endl;
|
||||
|
||||
std::vector<uint8_t>* writeFloat64TestResult = new std::vector<uint8_t>();
|
||||
NBT::helper::writeFloat64(writeFloat64TestResult, (double) -20.015625476837158203125);
|
||||
std::vector<uint8_t> dereferencedWriteFloat64TestResult = *writeFloat64TestResult;
|
||||
delete writeFloat64TestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteFloat64TestResult[0] == (uint8_t) 0xC0 &&
|
||||
dereferencedWriteFloat64TestResult[1] == (uint8_t) 0x34 &&
|
||||
dereferencedWriteFloat64TestResult[2] == (uint8_t) 0x04 &&
|
||||
dereferencedWriteFloat64TestResult[3] == (uint8_t) 0x00 &&
|
||||
dereferencedWriteFloat64TestResult[4] == (uint8_t) 0x08 &&
|
||||
dereferencedWriteFloat64TestResult[5] == (uint8_t) 0x00 &&
|
||||
dereferencedWriteFloat64TestResult[6] == (uint8_t) 0x00 &&
|
||||
dereferencedWriteFloat64TestResult[7] == (uint8_t) 0x00
|
||||
);
|
||||
|
||||
std::cout << "Passed writeInt64 NBT helper test" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,584 @@
|
|||
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, version 3.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied
|
||||
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// version 3 along with this program.
|
||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include "../lib/nbt.hpp"
|
||||
#include "../lib/error.hpp"
|
||||
#include "../lib/javacompat.hpp"
|
||||
|
||||
int main(){
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "NBT 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
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 9;
|
||||
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);
|
||||
// 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);
|
||||
std::vector<uint8_t> dereferencedWriteInt8TestResult = *writeInt8TestResult;
|
||||
delete writeInt8TestResult;
|
||||
ASSERT(dereferencedWriteInt8TestResult.back() == (uint8_t) 8);
|
||||
|
||||
std::cout << "Passed writeInt8 NBT helper test" << std::endl;
|
||||
|
||||
// int16 ###########################################################
|
||||
// read successfully
|
||||
currentPosition = 5;
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 8;
|
||||
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::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);
|
||||
// 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);
|
||||
std::vector<uint8_t> dereferencedWriteInt16TestResult = *writeInt16TestResult;
|
||||
delete writeInt16TestResult;
|
||||
ASSERT(dereferencedWriteInt16TestResult[0] == (uint8_t) 0xAB && dereferencedWriteInt16TestResult[1] == (uint8_t) 0xCD);
|
||||
|
||||
std::cout << "Passed writeInt16 NBT helper test" << std::endl;
|
||||
|
||||
// int32 ###########################################################
|
||||
// read successfully
|
||||
currentPosition = 5;
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 6;
|
||||
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::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);
|
||||
// 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);
|
||||
// delete before checking assertions so we don't leak
|
||||
std::vector<uint8_t> dereferencedWriteInt32TestResult = *writeInt32TestResult;
|
||||
delete writeInt32TestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteInt32TestResult[0] == (uint8_t) 0x12 &&
|
||||
dereferencedWriteInt32TestResult[1] == (uint8_t) 0x34 &&
|
||||
dereferencedWriteInt32TestResult[2] == (uint8_t) 0x56 &&
|
||||
dereferencedWriteInt32TestResult[3] == (uint8_t) 0x78
|
||||
);
|
||||
|
||||
std::cout << "Passed writeInt32 NBT helper test" << std::endl;
|
||||
|
||||
// int64 ###########################################################
|
||||
// read successfully
|
||||
currentPosition = 1;
|
||||
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);
|
||||
// end of data
|
||||
currentPosition = 2;
|
||||
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::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);
|
||||
// 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);
|
||||
// delete before checking assertions so we don't leak
|
||||
std::vector<uint8_t> dereferencedWriteInt64TestResult = *writeInt64TestResult;
|
||||
delete writeInt64TestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteInt64TestResult[0] == (uint8_t) 0x01 &&
|
||||
dereferencedWriteInt64TestResult[1] == (uint8_t) 0x23 &&
|
||||
dereferencedWriteInt64TestResult[2] == (uint8_t) 0x45 &&
|
||||
dereferencedWriteInt64TestResult[3] == (uint8_t) 0x67 &&
|
||||
dereferencedWriteInt64TestResult[4] == (uint8_t) 0x89 &&
|
||||
dereferencedWriteInt64TestResult[5] == (uint8_t) 0xAB &&
|
||||
dereferencedWriteInt64TestResult[6] == (uint8_t) 0xCD &&
|
||||
dereferencedWriteInt64TestResult[7] == (uint8_t) 0xEF
|
||||
);
|
||||
|
||||
std::cout << "Passed writeInt64 NBT helper test" << std::endl;
|
||||
|
||||
//##################################################################
|
||||
|
||||
// used for integer "array" tests
|
||||
uint8_t dataForIntArrayTest[] = {
|
||||
0, 0, 0, 20,
|
||||
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,
|
||||
0, 0, 0, 5,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||
0, 0, 0, 10,
|
||||
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,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
dataSize = 116;
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
// read overrun
|
||||
currentPosition = 20;
|
||||
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::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);
|
||||
// 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);
|
||||
ASSERT(
|
||||
int8ArrayTestOutput->at(0) == 0 &&
|
||||
int8ArrayTestOutput->at(1) == 0 &&
|
||||
int8ArrayTestOutput->at(2) == 0 &&
|
||||
int8ArrayTestOutput->at(3) == 4 &&
|
||||
int8ArrayTestOutput->at(4) == 1 &&
|
||||
int8ArrayTestOutput->at(5) == 2 &&
|
||||
int8ArrayTestOutput->at(6) == 3 &&
|
||||
int8ArrayTestOutput->at(7) == 4
|
||||
);
|
||||
int8ArrayTestOutput->clear();
|
||||
NBT::Helper::writeInt8Array(int8ArrayTestOutput, std::vector<int8_t>({1,2,3,4}));
|
||||
ASSERT(
|
||||
int8ArrayTestOutput->at(0) == 0 &&
|
||||
int8ArrayTestOutput->at(1) == 0 &&
|
||||
int8ArrayTestOutput->at(2) == 0 &&
|
||||
int8ArrayTestOutput->at(3) == 4 &&
|
||||
int8ArrayTestOutput->at(4) == 1 &&
|
||||
int8ArrayTestOutput->at(5) == 2 &&
|
||||
int8ArrayTestOutput->at(6) == 3 &&
|
||||
int8ArrayTestOutput->at(7) == 4
|
||||
);
|
||||
delete int8ArrayTestOutput;
|
||||
std::cout << "Passed writeInt8Array NBT helper test" << std::endl;
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
// read overrun
|
||||
currentPosition = 20;
|
||||
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::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);
|
||||
// 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);
|
||||
ASSERT(
|
||||
int32ArrayTestOutput->at(0) == 0x00 &&
|
||||
int32ArrayTestOutput->at(1) == 0x00 &&
|
||||
int32ArrayTestOutput->at(2) == 0x00 &&
|
||||
int32ArrayTestOutput->at(3) == 0x02 &&
|
||||
int32ArrayTestOutput->at(4) == 0x01 &&
|
||||
int32ArrayTestOutput->at(5) == 0x23 &&
|
||||
int32ArrayTestOutput->at(6) == 0x45 &&
|
||||
int32ArrayTestOutput->at(7) == 0x67 &&
|
||||
int32ArrayTestOutput->at(8) == 0x01 &&
|
||||
int32ArrayTestOutput->at(9) == 0x23 &&
|
||||
int32ArrayTestOutput->at(10) == 0x45 &&
|
||||
int32ArrayTestOutput->at(11) == 0x67
|
||||
);
|
||||
int32ArrayTestOutput->clear();
|
||||
NBT::Helper::writeInt32Array(int32ArrayTestOutput, std::vector<int32_t>({0x01234567, 0x01234567}));
|
||||
ASSERT(
|
||||
int32ArrayTestOutput->at(0) == 0x00 &&
|
||||
int32ArrayTestOutput->at(1) == 0x00 &&
|
||||
int32ArrayTestOutput->at(2) == 0x00 &&
|
||||
int32ArrayTestOutput->at(3) == 0x02 &&
|
||||
int32ArrayTestOutput->at(4) == 0x01 &&
|
||||
int32ArrayTestOutput->at(5) == 0x23 &&
|
||||
int32ArrayTestOutput->at(6) == 0x45 &&
|
||||
int32ArrayTestOutput->at(7) == 0x67 &&
|
||||
int32ArrayTestOutput->at(8) == 0x01 &&
|
||||
int32ArrayTestOutput->at(9) == 0x23 &&
|
||||
int32ArrayTestOutput->at(10) == 0x45 &&
|
||||
int32ArrayTestOutput->at(11) == 0x67
|
||||
);
|
||||
delete int32ArrayTestOutput;
|
||||
|
||||
std::cout << "Passed writeInt32Array NBT helper test" << std::endl;
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
// read overrun
|
||||
currentPosition = 20;
|
||||
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::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);
|
||||
// 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);
|
||||
ASSERT(
|
||||
int64ArrayTestOutput->at(0) == 0x00 &&
|
||||
int64ArrayTestOutput->at(1) == 0x00 &&
|
||||
int64ArrayTestOutput->at(2) == 0x00 &&
|
||||
int64ArrayTestOutput->at(3) == 0x02 &&
|
||||
int64ArrayTestOutput->at(4) == 0x01 &&
|
||||
int64ArrayTestOutput->at(5) == 0x23 &&
|
||||
int64ArrayTestOutput->at(6) == 0x45 &&
|
||||
int64ArrayTestOutput->at(7) == 0x67 &&
|
||||
int64ArrayTestOutput->at(8) == 0x89 &&
|
||||
int64ArrayTestOutput->at(9) == 0xAB &&
|
||||
int64ArrayTestOutput->at(10) == 0xCD &&
|
||||
int64ArrayTestOutput->at(11) == 0xEF &&
|
||||
int64ArrayTestOutput->at(12) == 0x01 &&
|
||||
int64ArrayTestOutput->at(13) == 0x23 &&
|
||||
int64ArrayTestOutput->at(14) == 0x45 &&
|
||||
int64ArrayTestOutput->at(15) == 0x67 &&
|
||||
int64ArrayTestOutput->at(16) == 0x89 &&
|
||||
int64ArrayTestOutput->at(17) == 0xAB &&
|
||||
int64ArrayTestOutput->at(18) == 0xCD &&
|
||||
int64ArrayTestOutput->at(19) == 0xEF
|
||||
);
|
||||
int64ArrayTestOutput->clear();
|
||||
NBT::Helper::writeInt64Array(int64ArrayTestOutput, std::vector<int64_t>({0x0123456789ABCDEF, 0x0123456789ABCDEF}));
|
||||
ASSERT(
|
||||
int64ArrayTestOutput->at(0) == 0x00 &&
|
||||
int64ArrayTestOutput->at(1) == 0x00 &&
|
||||
int64ArrayTestOutput->at(2) == 0x00 &&
|
||||
int64ArrayTestOutput->at(3) == 0x02 &&
|
||||
int64ArrayTestOutput->at(4) == 0x01 &&
|
||||
int64ArrayTestOutput->at(5) == 0x23 &&
|
||||
int64ArrayTestOutput->at(6) == 0x45 &&
|
||||
int64ArrayTestOutput->at(7) == 0x67 &&
|
||||
int64ArrayTestOutput->at(8) == 0x89 &&
|
||||
int64ArrayTestOutput->at(9) == 0xAB &&
|
||||
int64ArrayTestOutput->at(10) == 0xCD &&
|
||||
int64ArrayTestOutput->at(11) == 0xEF &&
|
||||
int64ArrayTestOutput->at(12) == 0x01 &&
|
||||
int64ArrayTestOutput->at(13) == 0x23 &&
|
||||
int64ArrayTestOutput->at(14) == 0x45 &&
|
||||
int64ArrayTestOutput->at(15) == 0x67 &&
|
||||
int64ArrayTestOutput->at(16) == 0x89 &&
|
||||
int64ArrayTestOutput->at(17) == 0xAB &&
|
||||
int64ArrayTestOutput->at(18) == 0xCD &&
|
||||
int64ArrayTestOutput->at(19) == 0xEF &&
|
||||
true
|
||||
);
|
||||
delete int64ArrayTestOutput;
|
||||
|
||||
std::cout << "Passed writeInt64Array NBT helper test" << std::endl;
|
||||
|
||||
// float ###########################################################
|
||||
uint8_t dataForFloatTest[] = {0xC7, 0x77, 0x77, 0x77};
|
||||
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);
|
||||
// read overrun
|
||||
currentPosition = 1;
|
||||
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);
|
||||
// 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);
|
||||
std::vector<uint8_t> dereferencedWriteFloatTestResult = *writeFloatTestResult;
|
||||
delete writeFloatTestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteFloatTestResult[0] == (uint8_t) 0xC7 &&
|
||||
dereferencedWriteFloatTestResult[1] == (uint8_t) 0x77 &&
|
||||
dereferencedWriteFloatTestResult[2] == (uint8_t) 0x77 &&
|
||||
dereferencedWriteFloatTestResult[3] == (uint8_t) 0x77
|
||||
);
|
||||
|
||||
std::cout << "Passed writeFloat NBT helper test" << std::endl;
|
||||
|
||||
// double ##########################################################
|
||||
uint8_t dataForDoubleTest[] = {0xC0, 0x34, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00};
|
||||
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);
|
||||
// read overrun
|
||||
currentPosition = 1;
|
||||
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);
|
||||
// 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);
|
||||
std::vector<uint8_t> dereferencedWriteDoubleTestResult = *writeDoubleTestResult;
|
||||
delete writeDoubleTestResult;
|
||||
ASSERT(
|
||||
dereferencedWriteDoubleTestResult[0] == (uint8_t) 0xC0 &&
|
||||
dereferencedWriteDoubleTestResult[1] == (uint8_t) 0x34 &&
|
||||
dereferencedWriteDoubleTestResult[2] == (uint8_t) 0x04 &&
|
||||
dereferencedWriteDoubleTestResult[3] == (uint8_t) 0x00 &&
|
||||
dereferencedWriteDoubleTestResult[4] == (uint8_t) 0x08 &&
|
||||
dereferencedWriteDoubleTestResult[5] == (uint8_t) 0x00 &&
|
||||
dereferencedWriteDoubleTestResult[6] == (uint8_t) 0x00 &&
|
||||
dereferencedWriteDoubleTestResult[7] == (uint8_t) 0x00
|
||||
);
|
||||
|
||||
std::cout << "Passed writeDouble NBT helper test" << std::endl;
|
||||
|
||||
//readString test
|
||||
char* nextChar = new char;
|
||||
|
||||
//reading data from the java modified utf8 file
|
||||
std::streampos javaSize;
|
||||
std::string javaStdString;
|
||||
const char* javaFilePath = "./resources/unicode_data/java-style_unicode";
|
||||
std::ifstream javaFile(javaFilePath, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if(javaFile.is_open()){
|
||||
javaSize = javaFile.tellg();
|
||||
javaFile.seekg(0, std::ios::beg);
|
||||
|
||||
for (int i=0; i<javaSize; i++) {
|
||||
javaFile.read(nextChar, 1);
|
||||
javaStdString.push_back(*nextChar);
|
||||
}
|
||||
|
||||
javaFile.close();
|
||||
} else {
|
||||
std::cerr << "Failed to open file: " << javaFilePath << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
//reading data from the normal utf8 file
|
||||
std::streampos normalSize;
|
||||
std::string normalStdString;
|
||||
const char* normalFilePath = "./resources/unicode_data/normal_utf-8";
|
||||
std::ifstream normalFile(normalFilePath, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if(normalFile.is_open()){
|
||||
normalSize = normalFile.tellg();
|
||||
normalFile.seekg(0, std::ios::beg);
|
||||
|
||||
for (int i=0; i<normalSize; i++) {
|
||||
normalFile.read(nextChar, 1);
|
||||
normalStdString.push_back(*nextChar);
|
||||
}
|
||||
|
||||
normalFile.close();
|
||||
} else {
|
||||
std::cerr << "Failed to open file: " << normalFilePath << std::endl;
|
||||
return 2;
|
||||
}
|
||||
tiny_utf8::string normalString = tiny_utf8::string(normalStdString);
|
||||
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
|
||||
std::streampos javaSize1;
|
||||
std::vector<uint8_t> javaStdString1;
|
||||
const char* javaFilePath1 = "./resources/unicode_data/java-style_unicode";
|
||||
std::ifstream javaFile1(javaFilePath1, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if(javaFile1.is_open()){
|
||||
javaSize1 = javaFile1.tellg();
|
||||
javaFile1.seekg(0, std::ios::beg);
|
||||
|
||||
for (int i=0; i<javaSize1; i++) {
|
||||
javaFile1.read(nextChar1, 1);
|
||||
javaStdString1.push_back(*nextChar1);
|
||||
}
|
||||
|
||||
javaFile1.close();
|
||||
} else {
|
||||
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);
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, version 3.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied
|
||||
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// version 3 along with this program.
|
||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include "../lib/nbt.hpp"
|
||||
#include "../lib/error.hpp"
|
||||
|
||||
int main() {
|
||||
std::cout
|
||||
<< "################################################################################\n"
|
||||
<< "NBT size helper tests\n"
|
||||
<< "################################################################################"
|
||||
<< std::endl;
|
||||
|
||||
// a full copy of /resources/NBT_data/simple_nbt
|
||||
//
|
||||
// This contains all tag types. It is most likely not suitable for
|
||||
// tests chasing edge cases as it is - as the name says - really
|
||||
// basic NBT data.
|
||||
uint8_t simpleNBTData[] = {
|
||||
0x0a, 0x00, 0x00, 0x08, 0x00, 0x3e, 0x53, 0x70,
|
||||
0x61, 0x63, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64,
|
||||
0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c,
|
||||
0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74,
|
||||
0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20,
|
||||
0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20,
|
||||
0x69, 0x6e, 0x20, 0x74, 0x61, 0x67, 0x20, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x73, 0x2c, 0x20, 0x72, 0x69,
|
||||
0x67, 0x68, 0x74, 0x3f, 0x00, 0x16, 0x49, 0x64,
|
||||
0x6b, 0x2e, 0x20, 0x4c, 0x65, 0x74, 0xe2, 0x80,
|
||||
0x99, 0x73, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20,
|
||||
0x6f, 0x75, 0x74, 0x2e, 0x0a, 0x00, 0x08, 0x63,
|
||||
0x6f, 0x6d, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x03,
|
||||
0x00, 0x0b, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x6e,
|
||||
0x75, 0x6d, 0x62, 0x65, 0x72, 0xd3, 0x07, 0x23,
|
||||
0x41, 0x08, 0x00, 0x09, 0x73, 0x6f, 0x6d, 0x65,
|
||||
0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x0c, 0x65,
|
||||
0x61, 0x74, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6f,
|
||||
0x6b, 0x69, 0x65, 0x00, 0x06, 0x00, 0x06, 0x64,
|
||||
0x6f, 0x75, 0x62, 0x6c, 0x65, 0x41, 0x23, 0x07,
|
||||
0xd3, 0x4e, 0xfd, 0x07, 0xf1, 0x05, 0x00, 0x05,
|
||||
0x66, 0x6c, 0x6f, 0x61, 0x74, 0x42, 0x0d, 0x12,
|
||||
0x43, 0x02, 0x00, 0x05, 0x69, 0x6e, 0x74, 0x31,
|
||||
0x36, 0x07, 0xd0, 0x03, 0x00, 0x05, 0x69, 0x6e,
|
||||
0x74, 0x33, 0x32, 0x00, 0x9a, 0x21, 0x12, 0x0b,
|
||||
0x00, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f,
|
||||
0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x00,
|
||||
0x04, 0x17, 0xbf, 0xe8, 0x3c, 0x00, 0x00, 0xa8,
|
||||
0xfb, 0x7f, 0xff, 0xff, 0xff, 0x61, 0x72, 0x72,
|
||||
0x61, 0x04, 0x00, 0x05, 0x69, 0x6e, 0x74, 0x36,
|
||||
0x34, 0x00, 0x00, 0x00, 0xbc, 0x97, 0xde, 0x9e,
|
||||
0x3e, 0x0c, 0x00, 0x0b, 0x69, 0x6e, 0x74, 0x36,
|
||||
0x34, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00,
|
||||
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xa8, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x67, 0xe7, 0xbd, 0x7f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x00, 0x00, 0xab, 0xd8, 0x00,
|
||||
0x00, 0xab, 0xd8, 0x00, 0x0b, 0x12, 0x21, 0x00,
|
||||
0x79, 0x61, 0x72, 0x01, 0x00, 0x04, 0x69, 0x6e,
|
||||
0x74, 0x38, 0x64, 0x07, 0x00, 0x0a, 0x69, 0x6e,
|
||||
0x74, 0x38, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79,
|
||||
0x00, 0x00, 0x00, 0x08, 0x71, 0x35, 0x77, 0x62,
|
||||
0x54, 0x64, 0xf5, 0x32, 0x09, 0x00, 0x09, 0x6c,
|
||||
0x69, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x38,
|
||||
0x01, 0x00, 0x00, 0x00, 0x05, 0x41, 0x60, 0x4e,
|
||||
0x7f, 0xfa, 0x09, 0x00, 0x0c, 0x6c, 0x69, 0x73,
|
||||
0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
|
||||
0x73, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06,
|
||||
0x50, 0x61, 0x63, 0x6d, 0x61, 0x6e, 0x00, 0x03,
|
||||
0x61, 0x74, 0x65, 0x00, 0x03, 0x61, 0x6c, 0x6c,
|
||||
0x00, 0x03, 0x74, 0x68, 0x65, 0x00, 0x04, 0x64,
|
||||
0x6f, 0x74, 0x73, 0x00, 0x02, 0x73, 0x6f, 0x00,
|
||||
0x03, 0x6e, 0x6f, 0x77, 0x00, 0x06, 0x68, 0x65,
|
||||
0xe2, 0x80, 0x99, 0x73, 0x00, 0x06, 0x63, 0x6f,
|
||||
0x6d, 0x69, 0x6e, 0x67, 0x00, 0x03, 0x66, 0x6f,
|
||||
0x72, 0x00, 0x03, 0x74, 0x68, 0x65, 0x00, 0x06,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x73, 0x2e, 0x08, 0x00,
|
||||
0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
|
||||
0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
|
||||
0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00
|
||||
};
|
||||
uint64_t simpleNBTDataSize = 478;
|
||||
|
||||
//##################################################################
|
||||
// Basic valid data tests
|
||||
//##################################################################
|
||||
// const uint8_t END = 0;
|
||||
ErrorOr<uint64_t> totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x93);
|
||||
ErrorOr<int32_t> dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x93);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 1);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 0);
|
||||
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 477);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 477);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 1);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 0);
|
||||
|
||||
//const uint8_t INT8 = 1;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x133);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x133);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 8);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
//const uint8_t INT16 = 2;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xb1);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xb1);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 10);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
//const uint8_t INT32 = 3;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xbb);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xbb);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 12);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x67);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x67);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 18);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
//const uint8_t INT64 = 4;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xe9);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xe9);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 16);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
//const uint8_t FLOAT = 5;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xa5);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xa5);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 12);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
//const uint8_t DOUBLE = 6;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x94);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x94);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 17);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 1);
|
||||
|
||||
//const uint8_t INT8_ARRAY = 7;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x13b);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x13b);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 25);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 8);
|
||||
|
||||
//const uint8_t STRING = 8;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x1c6);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x1c6);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 23);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 12);
|
||||
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x79);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x79);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 26);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 12);
|
||||
|
||||
//const uint8_t LIST = 9;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x154);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x154);
|
||||
|
||||
ASSERT(totalSize.isError);
|
||||
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 5);
|
||||
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x16a);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x16a);
|
||||
|
||||
ASSERT(totalSize.isError);
|
||||
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 12);
|
||||
|
||||
//const uint8_t COMPOUND = 10;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x5c);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x5c);
|
||||
|
||||
ASSERT(totalSize.isError);
|
||||
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||
ASSERT(dataLength.isError);
|
||||
ASSERT(dataLength.errorCode == ErrorCodes::NOT_YET_KNOWN);
|
||||
|
||||
//const uint8_t INT32_ARRAY= 11;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xc7);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xc7);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 34);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 4);
|
||||
|
||||
//const uint8_t INT64_ARRAY= 12;
|
||||
totalSize = NBT::Helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xf9);
|
||||
dataLength = NBT::Helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xf9);
|
||||
|
||||
ASSERT(!totalSize.isError);
|
||||
ASSERT(totalSize.value == 58);
|
||||
ASSERT(!dataLength.isError);
|
||||
ASSERT(dataLength.value == 5);
|
||||
|
||||
std::cout << "Passed simple valid data test." << std::endl;
|
||||
|
||||
//TODO: add tests for errors and edge cases
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -13,8 +13,360 @@
|
|||
// version 3 along with this program.
|
||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include "../lib/nbt.h++"
|
||||
#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"));
|
||||
flags.push_back(CLI::Flag('x', "hexadecimal", "print numbers in hex format"));
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,68 +16,479 @@
|
|||
//version 3 along with this program.
|
||||
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <cctype>
|
||||
#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.h++"
|
||||
#include "../lib/cli.h++"
|
||||
#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
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
// tell sockpp to close TCP socket if open because it blocks when trying
|
||||
// to read and there is no data
|
||||
tcpAcceptor.shutdown();
|
||||
if (tcpSocket) {
|
||||
tcpSocket.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (tcpConnector) {
|
||||
tcpConnector.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void writeToTCP6() {
|
||||
while (!exitProgram) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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[]) {
|
||||
|
||||
// Argument parsing ################################################
|
||||
bool ipv4 = true;
|
||||
bool ipv6 = true;
|
||||
bool tcp = true;
|
||||
bool udp = true;
|
||||
bool listen = false;
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
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('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::UnpositionalArgument> unpositionalArguments;
|
||||
unpositionalArguments.push_back(CLI::UnpositionalArgument('c', "connect", "HOST", "connect to HOST, listen for incoming connections if omitted"));
|
||||
std::vector<CLI::Option> options;
|
||||
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::PositionalArgument> positionalArguments;
|
||||
positionalArguments.push_back(CLI::PositionalArgument("PORT", "the port to use"));
|
||||
std::vector<CLI::Argument> arguments;
|
||||
arguments.push_back(CLI::Argument("PORT", "the port to lsiten on (or connect to)"));
|
||||
|
||||
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, unpositionalArguments, positionalArguments);
|
||||
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) {
|
||||
std::cout << cliParser.getUsage() << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (cliParser.getFlag("license").value) {
|
||||
std::cout
|
||||
<< "Copyright 2022, FOSS-VG Developers and Contributers\n"
|
||||
<< "\n"
|
||||
<< "Hexnet is part of the FOSS-VG development tool suite.\n"
|
||||
<< "\n"
|
||||
<< "This program is free software: you can redistribute it and/or modify it\n"
|
||||
<< "under the terms of the GNU Affero General Public License as published\n"
|
||||
<< "by the Free Software Foundation, version 3.\n"
|
||||
<< "\n"
|
||||
<< "This program is distributed in the hope that it will be useful,\n"
|
||||
<< "but WITHOUT ANY WARRANTY; without even the implied\n"
|
||||
<< "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
<< "See the GNU Affero General Public License for more details.\n"
|
||||
<< "\n"
|
||||
<< "You should have received a copy of the GNU Affero General Public License\n"
|
||||
<< "version 3 along with this program.\n"
|
||||
<< "If not, see https://www.gnu.org/licenses/agpl-3.0.en.html"
|
||||
<< std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (cliParser.wrongUsage) {
|
||||
//TODO: spit out usage information generated by the parser
|
||||
std::cout << cliParser.getUsage() << std::endl;
|
||||
return EXIT_USAGE;
|
||||
}
|
||||
if (cliParser.getFlag('4').value || cliParser.getFlag('6').value) {
|
||||
ipv4 = cliParser.getFlag('4').value;
|
||||
ipv6 = cliParser.getFlag('6').value;
|
||||
}
|
||||
if (cliParser.getFlag('t').value || cliParser.getFlag('u').value) {
|
||||
tcp = cliParser.getFlag('t').value;
|
||||
udp = cliParser.getFlag('u').value;
|
||||
}
|
||||
if (cliParser.getUnpositionalArgument('c').errorCode == ErrorCodes::NOT_PRESENT) {
|
||||
listen = true;
|
||||
}
|
||||
host = cliParser.getUnpositionalArgument('c').value;
|
||||
//FIXME: use a function that returns a fixed-width data type instead
|
||||
port = (uint16_t) std::stoi(cliParser.getPositionalArgument(0).value);
|
||||
|
||||
std::cerr << "Port: " << (int) port << std::endl;
|
||||
std::cerr << (listen? "Listening" : "Host: ") << host << std::endl;
|
||||
std::cerr << "IPv4: " << (ipv4? "yes" : "no") << std::endl;
|
||||
std::cerr << "IPv6: " << (ipv6? "yes" : "no") << std::endl;
|
||||
std::cerr << "TCP: " << ( tcp? "yes" : "no") << std::endl;
|
||||
std::cerr << "UDP: " << ( udp? "yes" : "no") << std::endl;
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
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 (!(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;
|
||||
}
|
||||
|
||||
port = (in_port_t) std::stoi(cliParser.getArgument(0).value);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue