Compare commits
	
		
			No commits in common. "38fad56965af02ec13fb430abeecf23c0f5a8af2" and "046275645139c237c35deb5193d798849254fad1" have entirely different histories. 
		
	
	
		
			38fad56965
			...
			0462756451
		
	
		|  | @ -4,13 +4,6 @@ | ||||||
| /dependencies/* | /dependencies/* | ||||||
| !/dependencies/.placeholder | !/dependencies/.placeholder | ||||||
| 
 | 
 | ||||||
| /include/* |  | ||||||
| !/include/.placeholder |  | ||||||
| 
 |  | ||||||
| .download_cache |  | ||||||
| 
 |  | ||||||
| .localenv.bashrc |  | ||||||
| 
 |  | ||||||
| # ignore endianness check | # ignore endianness check | ||||||
| /.endianness | /.endianness | ||||||
| /resources/check_endianness | /resources/check_endianness | ||||||
|  | @ -23,5 +16,3 @@ | ||||||
| 
 | 
 | ||||||
| #vscode | #vscode | ||||||
| .vscode | .vscode | ||||||
| 
 |  | ||||||
| writeTest |  | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | 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,19 +22,13 @@ Immediate goals: | ||||||
| 
 | 
 | ||||||
| ### Prerequisites: | ### Prerequisites: | ||||||
| 
 | 
 | ||||||
| Build dependencies: | This project requires bash and a C++20 compiler. | ||||||
| 
 | 
 | ||||||
| - bash | The project setup requires wget or curl, gzip, and tar. | ||||||
| - a C++ 20 compiler |  | ||||||
| 
 | 
 | ||||||
| Setup dependencies: | Additional requirements for building dependencies: | ||||||
| 
 | 
 | ||||||
| - wget or curl | - sockpp: a C compiler, CMake | ||||||
| - 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 | **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 | installed to use the scripts, but using it as your shell while working on | ||||||
|  | @ -51,9 +45,7 @@ point to `bin/lib`. | ||||||
| - `git clone` this repository | - `git clone` this repository | ||||||
| - if using bash: | - if using bash: | ||||||
|   - `source` the file `setupenv.bashrc` from the project's base directory |   - `source` the file `setupenv.bashrc` from the project's base directory | ||||||
|     to load the provided shell environment (local customizations to the |     to load the provided shell environment | ||||||
|     environment can be placed in a fiile `.localenv.bashrc` in the project's |  | ||||||
|     root directory if necessary) |  | ||||||
|   - `setup_project` |   - `setup_project` | ||||||
| - if not using bash or not using the provided environment: | - if not using bash or not using the provided environment: | ||||||
|   - `cd` to the project's base directory |   - `cd` to the project's base directory | ||||||
|  |  | ||||||
|  | @ -48,6 +48,11 @@ universally used. | ||||||
| Use explicitly sized data types where possible. | Use explicitly sized data types where possible. | ||||||
| For example, use `int32_t` instead of `int`. | 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 | ## Shell Script | ||||||
| 
 | 
 | ||||||
| Use the hash bang `#!/usr/bin/env bash`. | Use the hash bang `#!/usr/bin/env bash`. | ||||||
|  |  | ||||||
|  | @ -1,8 +1,5 @@ | ||||||
| Copyright <year>, FOSS-VG Developers and Contributers | 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 | This program is free software: you can redistribute it and/or modify it | ||||||
| under the terms of the GNU Affero General Public License as published | under the terms of the GNU Affero General Public License as published | ||||||
| by the Free Software Foundation, version 3. | by the Free Software Foundation, version 3. | ||||||
|  |  | ||||||
|  | @ -24,15 +24,11 @@ Provided aliases: | ||||||
| 
 | 
 | ||||||
| ## setup_project | ## setup_project | ||||||
| 
 | 
 | ||||||
| Cleans the project and its dependencies first (see below), ensuring | Cleans the project and its dependencies first, ensuring the project is in | ||||||
| the project is in a known state, then sets up dependencies. | a known state, then downloads and extracts dependencies. | ||||||
| 
 | 
 | ||||||
| This includes downloading (and caching) of files that are not yet | This will probably do more in the future (for example compile dependencies | ||||||
| locally cached and compiling dependencies that need to be compiled. | 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 | # build | ||||||
|  | @ -59,37 +55,14 @@ Accepted environment variables: | ||||||
| - `CXX`: override the default compiler | - `CXX`: override the default compiler | ||||||
| - `CXXFLAGS`: override the default compiler flags, must at least specify | - `CXXFLAGS`: override the default compiler flags, must at least specify | ||||||
|    the C++ version |    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 | # clean | ||||||
| 
 | 
 | ||||||
| Removes and re-creates `bin/` and `include/`, then re-creates symlinks to | Removes and re-creates `bin/`. Also removes the endianness header and | ||||||
| shared object and header files as needed for the build process. | the endianness check binary. | ||||||
| Also removes the endianness header and the endianness check binary. |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # clean_dependencies | # clean_dependencies | ||||||
| 
 | 
 | ||||||
| Removes and re-creates `dependencies/` and prunes the download cache of files | Removes and re-creates `dependencies/`. | ||||||
| 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` | Usage example: `echo -ne "\x00" | java JavaStringGenerator > output_file` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## NBT_data | ## servers.dat | ||||||
| 
 | 
 | ||||||
| Data used to test the NBT library. | My current servers.dat as pulled from my Minecraft installation. Used for testing the NBT library until we have something better. | ||||||
| 
 | 
 | ||||||
| `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.) | ## servers.dat_nbt_decoded.txt | ||||||
| `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 | The same file manually decoded. I did this to get a better understanding how NBT works, might come in handy in the future. | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -1,354 +0,0 @@ | ||||||
| ############################################################################# |  | ||||||
| # 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,7 +15,20 @@ | ||||||
| # version 3 along with this program. | # version 3 along with this program. | ||||||
| # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | ||||||
| 
 | 
 | ||||||
| source scripts/lib.sh | 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" | ||||||
| 
 | 
 | ||||||
| # if unknown, figure out endianness | # if unknown, figure out endianness | ||||||
| if [ -f .endianness ]; then | if [ -f .endianness ]; then | ||||||
|  | @ -33,10 +46,10 @@ fi | ||||||
| 
 | 
 | ||||||
| # `.cpp` files in src/lib will be automatically picked up and compiled into | # `.cpp` files in src/lib will be automatically picked up and compiled into | ||||||
| # dynamically linked libraries. | # dynamically linked libraries. | ||||||
| echo ">>> Building libs..." | echo "Building libs..." | ||||||
| create_directory bin/lib | mkdir -pv bin/lib | ||||||
| for lib in $(find ./src/lib -name "*.cpp"); do | for lib in $(find ./src/lib -name "*.cpp"); do | ||||||
|     COMPILE_COMMAND="$CXX_WITH_FLAGS -I ./include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib" |     COMPILE_COMMAND="$CXX_WITH_FLAGS -I dependencies/tiny-utf8-4.4.3/include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib" | ||||||
|     echo $COMPILE_COMMAND |     echo $COMPILE_COMMAND | ||||||
|     $COMPILE_COMMAND & |     $COMPILE_COMMAND & | ||||||
|     $WAIT_ANYWAY |     $WAIT_ANYWAY | ||||||
|  | @ -55,14 +68,12 @@ wait | ||||||
| # How to run a tool: specify the library path to use for the dynamic linker | # How to run a tool: specify the library path to use for the dynamic linker | ||||||
| #   when running a program | #   when running a program | ||||||
| # Example: LD_LIBRARY_PATH=bin/lib bin/tools/dumpnbt | # Example: LD_LIBRARY_PATH=bin/lib bin/tools/dumpnbt | ||||||
| echo ">>> Building tools..." | echo "Building tools..." | ||||||
| create_directory bin/tools | mkdir -pv bin/tools | ||||||
| # add compile commands to this array | # add compile commands to this array | ||||||
| COMPILE_COMMANDS=( | COMPILE_COMMANDS=( | ||||||
|     "$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -l:cli.so -o bin/tools/dumpnbt" |     "$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -Lbin/lib -l:nbt.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/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/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 | for command in ${!COMPILE_COMMANDS[@]}; do | ||||||
|     echo "${COMPILE_COMMANDS[command]}" |     echo "${COMPILE_COMMANDS[command]}" | ||||||
|  |  | ||||||
|  | @ -15,24 +15,15 @@ | ||||||
| # version 3 along with this program. | # version 3 along with this program. | ||||||
| # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | ||||||
| 
 | 
 | ||||||
| echo ">>> Cleaning build files..." | rm -rv ./bin | ||||||
| 
 | rm -vf .endianness | ||||||
| source scripts/lib.sh | rm -vf resources/check_endianness | ||||||
| 
 | mkdir -v ./bin | ||||||
| remove ./bin | mkdir -v ./bin/lib | ||||||
| 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 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 bin/lib/ | ||||||
| ln -vs ../../dependencies/sockpp-0.7.1/build/libsockpp.so.0.7.1 bin/lib/ | ln -vs ../../dependencies/sockpp-0.7.1/build/libsockpp.so.0.7.1 bin/lib/ | ||||||
| 
 | 
 | ||||||
| ln -vs ../dependencies/sockpp-0.7.1/include/sockpp/ ./include/ | set -v | ||||||
| ln -vs ../dependencies/tiny-utf8-4.4.3/include/tinyutf8/ ./include/ | echo -n "" > ./bin/.placeholder | ||||||
| 
 |  | ||||||
| create_file ./bin/.placeholder |  | ||||||
| create_file ./include/.placeholder |  | ||||||
|  |  | ||||||
|  | @ -15,26 +15,7 @@ | ||||||
| # version 3 along with this program. | # version 3 along with this program. | ||||||
| # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | ||||||
| 
 | 
 | ||||||
| source scripts/lib.sh | rm -rv ./dependencies | ||||||
| 
 | mkdir -v ./dependencies | ||||||
| echo ">>> Checking download cache for unneeded or corrupted files..." | set -v | ||||||
| for file in $(ls .download_cache); do | echo -n "" > ./dependencies/.placeholder | ||||||
|     #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 |  | ||||||
|  |  | ||||||
|  | @ -1,78 +0,0 @@ | ||||||
| #!/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,8 +15,6 @@ | ||||||
| # version 3 along with this program. | # version 3 along with this program. | ||||||
| # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | ||||||
| 
 | 
 | ||||||
| source scripts/lib.sh |  | ||||||
| 
 |  | ||||||
| echo -n "Wget or curl? " | echo -n "Wget or curl? " | ||||||
| if command -v wget >/dev/null 2>&1; then | if command -v wget >/dev/null 2>&1; then | ||||||
|     USE_WGET=yes |     USE_WGET=yes | ||||||
|  | @ -34,67 +32,53 @@ fi | ||||||
| function download { | function download { | ||||||
|     URL="$1" |     URL="$1" | ||||||
|     DESTINATION="$2" |     DESTINATION="$2" | ||||||
|     SHA256SUM="$3" |     SHA256SUM="$3 *$2" | ||||||
| 
 |  | ||||||
|     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... " |     echo -n "Downloading $URL to $DESTINATION... " | ||||||
|     if [ $USE_WGET = yes ]; then |     if [ $USE_WGET = yes ]; then | ||||||
|             wget -O ".download_cache/$SHA256SUM" "$URL" >/dev/null 2>&1 |         wget -O "$DESTINATION" "$URL" >/dev/null 2>&1 | ||||||
|     else |     else | ||||||
|             curl -L "$URL" --output ".download_cache/$SHA256SUM" >/dev/null 2>&1 |         curl -L "$URL" --output "$DESTINATION" >/dev/null 2>&1 | ||||||
|     fi |     fi | ||||||
|         if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then |     if sha256sum --check <<< $SHA256SUM >/dev/null 2>&1; then | ||||||
|             cp ".download_cache/$SHA256SUM" "$DESTINATION" |  | ||||||
|         echo "done." |         echo "done." | ||||||
|         return 0 |         return 0 | ||||||
|     else |     else | ||||||
|         echo "error." |         echo "error." | ||||||
|             echo "Checksum verification failed. Your download is either corrupted or the file has been altered. Removing file." |         echo "Checksum verification failed. Your download is either corrupted or the file has been altered." | ||||||
|             rm ".download_cache/$SHA256SUM" |         rm -v "$DESTINATION" | ||||||
|         return 1 |         return 1 | ||||||
|     fi |     fi | ||||||
|     fi |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | echo "Cleaning build files..." | ||||||
| scripts/clean.sh | scripts/clean.sh | ||||||
|  | echo "Cleaning dependencies..." | ||||||
| scripts/clean_dependencies.sh | scripts/clean_dependencies.sh | ||||||
| 
 | 
 | ||||||
| set -e # failures are not acceptable here | set -e # failures are not acceptable here | ||||||
| create_directory dependencies/tmp | mkdir -v dependencies/tmp | ||||||
| download https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f | download https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f | ||||||
| download https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.7.1.tar.gz dependencies/tmp/sockpp.tar.gz 2e023528bebbd2ac083fc91fbe6d5c4158c3336bedbcff48f594f3b28f53b940 | download https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.7.1.tar.gz dependencies/tmp/sockpp.tar.gz 2e023528bebbd2ac083fc91fbe6d5c4158c3336bedbcff48f594f3b28f53b940 | ||||||
|  | #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 | gzip -d dependencies/tmp/tiny-utf8.tar.gz | ||||||
| tar -xf dependencies/tmp/tiny-utf8.tar -C dependencies | tar -xf dependencies/tmp/tiny-utf8.tar -C dependencies | ||||||
| echo "done" | echo "done." | ||||||
| 
 | 
 | ||||||
| echo -n ">>> Extracting sockpp... " | echo -n "Extracting sockpp... " | ||||||
| gzip -d dependencies/tmp/sockpp.tar.gz | gzip -d dependencies/tmp/sockpp.tar.gz | ||||||
| tar -xf dependencies/tmp/sockpp.tar -C dependencies | tar -xf dependencies/tmp/sockpp.tar -C dependencies | ||||||
| echo "done" | echo "done." | ||||||
| 
 | echo -n "Building sockpp... " | ||||||
| echo ">>> Building sockpp... " |  | ||||||
| pushd dependencies/sockpp-0.7.1/ >/dev/null 2>&1 | pushd dependencies/sockpp-0.7.1/ >/dev/null 2>&1 | ||||||
| cmake -Bbuild . | cmake -Bbuild . | ||||||
| cmake --build build | cmake --build build | ||||||
| popd >/dev/null 2>&1 | popd >/dev/null 2>&1 | ||||||
|  | echo "done." | ||||||
| 
 | 
 | ||||||
| echo ">>> Cleaning up..." | rm -rv dependencies/tmp | ||||||
| remove dependencies/tmp |  | ||||||
|  |  | ||||||
|  | @ -15,7 +15,13 @@ | ||||||
| # version 3 along with this program. | # version 3 along with this program. | ||||||
| # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | ||||||
| 
 | 
 | ||||||
| source scripts/lib.sh | if [ -z "$CXX" ]; then | ||||||
|  |     CXX="c++" | ||||||
|  | fi | ||||||
|  | if [ -z "$CXXFLAGS" ]; then | ||||||
|  |     CXXFLAGS="-std=c++20 -Wall" | ||||||
|  | fi | ||||||
|  | CXX_WITH_FLAGS="$CXX $CXXFLAGS" | ||||||
| 
 | 
 | ||||||
| echo -n "Using LD_LIBRARY_PATH " | echo -n "Using LD_LIBRARY_PATH " | ||||||
| if [ -z "$LD_LIBRARY_PATH" ]; then | if [ -z "$LD_LIBRARY_PATH" ]; then | ||||||
|  | @ -25,38 +31,25 @@ else | ||||||
| fi | fi | ||||||
| echo "$LD_LIBRARY_PATH" | echo "$LD_LIBRARY_PATH" | ||||||
| 
 | 
 | ||||||
| echo ">>> Cleaning tests..." | mkdir -pv bin/test | ||||||
| remove bin/test |  | ||||||
| create_directory bin/test |  | ||||||
| 
 | 
 | ||||||
| echo ">>> Building tests..." | echo "Building tests..." | ||||||
| 
 | 
 | ||||||
| # add compile commands to this array | # add compile commands to this array | ||||||
| COMPILE_COMMANDS=( | COMPILE_COMMANDS=( | ||||||
|     "$CXX_WITH_FLAGS src/test/nbt_read_write_helpers.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_read_write_helpers" |     "$CXX_WITH_FLAGS src/test/nbt_helpers.cpp -Lbin/lib -l:nbt.so -o bin/test/nbt_helpers" | ||||||
|     "$CXX_WITH_FLAGS src/test/cli_argument_parser.cpp -Lbin/lib -l:cli.so -o bin/test/cli_argument_parser" |     "$CXX_WITH_FLAGS src/test/cli_argument_parser.cpp -Lbin/lib -l:cli.so -o bin/test/cli_argument_parser" | ||||||
|     "$CXX_WITH_FLAGS src/test/javacompat.cpp -I./include -Lbin/lib -l:javacompat.so -o bin/test/javacompat" |     "$CXX_WITH_FLAGS src/test/javacompat.cpp -Idependencies/tiny-utf8-4.4.3/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 | for command in ${!COMPILE_COMMANDS[@]}; do | ||||||
|     echo "${COMPILE_COMMANDS[command]}" |     echo "${COMPILE_COMMANDS[command]}" | ||||||
|     ${COMPILE_COMMANDS[command]} & |     ${COMPILE_COMMANDS[command]} & | ||||||
|     $WAIT_ANYWAY |  | ||||||
| done | done | ||||||
| 
 | 
 | ||||||
| wait | wait | ||||||
| 
 | 
 | ||||||
| echo ">>> Running tests..." | echo "Running tests..." | ||||||
| 
 |  | ||||||
| # explicitly allow commands to fail at this stage |  | ||||||
| set +e |  | ||||||
| 
 | 
 | ||||||
| for test in $(ls bin/test); do | for test in $(ls bin/test); do | ||||||
|     bin/test/$test |     bin/test/$test | ||||||
| done | done | ||||||
| 
 |  | ||||||
| for test in $(ls scripts/test); do |  | ||||||
|     scripts/test/$test |  | ||||||
| done |  | ||||||
|  |  | ||||||
|  | @ -1,11 +0,0 @@ | ||||||
| #!/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 "================================================================================" |  | ||||||
|  | @ -1,22 +0,0 @@ | ||||||
| #!/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 "================================================================================" |  | ||||||
|  | @ -1,23 +0,0 @@ | ||||||
| #!/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,15 +13,9 @@ | ||||||
| # version 3 along with this program. | # version 3 along with this program. | ||||||
| # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | # If not, see https://www.gnu.org/licenses/agpl-3.0.en.html | ||||||
| 
 | 
 | ||||||
| echo ">>> Loading shell environment for FOSS-VG development..." | echo -n "Loading shell environment for FOSS-VG development... " | ||||||
| 
 | 
 | ||||||
| PROJECT_BASE_DIR="$( cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 ; pwd -P )" | 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="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" | alias clean_dependencies="pushd \"$PROJECT_BASE_DIR\" >/dev/null 2>&1; scripts/clean_dependencies.sh; popd >/dev/null 2>&1" | ||||||
|  | @ -39,75 +33,13 @@ function build { | ||||||
|     popd >/dev/null 2>&1 |     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 | if [ -z "$LD_LIBRARY_PATH" ]; then | ||||||
|     export LD_LIBRARY_PATH="$PROJECT_BASE_DIR"/bin/lib |     export LD_LIBRARY_PATH="$PROJECT_BASE_DIR"/bin/lib | ||||||
| else | else | ||||||
|     export LD_LIBRARY_PATH="$PROJECT_BASE_DIR"/bin/lib:"$LD_LIBRARY_PATH" |     export LD_LIBRARY_PATH="$PROJECT_BASE_DIR"/bin/lib:"$LD_LIBRARY_PATH" | ||||||
| fi | fi | ||||||
| echo "LD_LIBRARY_PATH is $LD_LIBRARY_PATH" |  | ||||||
| 
 | 
 | ||||||
| echo ">>> Checking for dependencies..." | unset PROJECT_BASE_DIR | ||||||
| MISSING_DEPS=0 |  | ||||||
| 
 | 
 | ||||||
| if command -v wget > /dev/null 2>&1; then | echo "done." | ||||||
|     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,8 +1,5 @@ | ||||||
| // Copyright 2022, FOSS-VG Developers and Contributers
 | // Copyright 2022, FOSS-VG Developers and Contributers
 | ||||||
| //
 | //
 | ||||||
| // Author(s):
 |  | ||||||
| //  BodgeMaster, Shwoomple
 |  | ||||||
| //
 |  | ||||||
| // This program is free software: you can redistribute it and/or modify it
 | // This program is free software: you can redistribute it and/or modify it
 | ||||||
| // under the terms of the GNU Affero General Public License as published
 | // under the terms of the GNU Affero General Public License as published
 | ||||||
| // by the Free Software Foundation, version 3.
 | // by the Free Software Foundation, version 3.
 | ||||||
|  | @ -16,12 +13,13 @@ | ||||||
| // version 3 along with this program.
 | // version 3 along with this program.
 | ||||||
| // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | ||||||
| 
 | 
 | ||||||
|  | #include "cli.h++" | ||||||
|  | 
 | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| #include "cli.hpp" | #include "error.h++" | ||||||
| #include "error.hpp" |  | ||||||
| 
 | 
 | ||||||
| namespace CLI { | namespace CLI { | ||||||
|     Flag::Flag() { |     Flag::Flag() { | ||||||
|  | @ -34,10 +32,10 @@ namespace CLI { | ||||||
|         this->present = false; |         this->present = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Option::Option() { |     UnpositionalArgument::UnpositionalArgument() { | ||||||
|         this->present = false; |         this->present = false; | ||||||
|     } |     } | ||||||
|     Option::Option(char shortName, std::string longName, std::string placeholder, std::string description) { |     UnpositionalArgument::UnpositionalArgument(char shortName, std::string longName, std::string placeholder, std::string description) { | ||||||
|         this->shortName = shortName; |         this->shortName = shortName; | ||||||
|         this->longName = longName; |         this->longName = longName; | ||||||
|         this->description = description; |         this->description = description; | ||||||
|  | @ -45,22 +43,23 @@ namespace CLI { | ||||||
|         this->present = false; |         this->present = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Argument::Argument() { |     PositionalArgument::PositionalArgument() { | ||||||
|         this->present = false; |         this->present = false; | ||||||
|     } |     } | ||||||
|     Argument::Argument(std::string placeholder, std::string description) { |     PositionalArgument::PositionalArgument(std::string placeholder, std::string description) { | ||||||
|         this->description = description; |         this->description = description; | ||||||
|         this->placeholder = placeholder; |         this->placeholder = placeholder; | ||||||
|         this->present = false; |         this->present = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // using int here bc that's how main() is defined
 |     // using int here bc that's how main() is defined
 | ||||||
|     ArgumentsParser::ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments) { |     ArgumentsParser::ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<UnpositionalArgument> unpositionalArguments, std::vector<PositionalArgument> positionalArguments) { | ||||||
|         this->wrongUsage = false; |         this->wrongUsage = false; | ||||||
|         this->wrongUsageMessages = std::vector<std::string>(); |         this->wrongUsageMessages = std::vector<std::string>(); | ||||||
|         this->programName = std::string(argv[0]); |         this->programName = std::string(argv[0]); | ||||||
|         this->arguments = arguments; |         this->positionalArguments = positionalArguments; | ||||||
|         // create lookup tables for all flags and options by their names
 |         // create lookup tables for all flags and unpositional arguments
 | ||||||
|  |         // by their names
 | ||||||
|         this->flagsByShortName = std::map<char, Flag*>(); |         this->flagsByShortName = std::map<char, Flag*>(); | ||||||
|         this->flagsByLongName  = std::map<std::string, Flag*>(); |         this->flagsByLongName  = std::map<std::string, Flag*>(); | ||||||
|         for (Flag flag: flags) { |         for (Flag flag: flags) { | ||||||
|  | @ -69,25 +68,25 @@ namespace CLI { | ||||||
|             this->flagsByShortName[flag.shortName] = flagPointer; |             this->flagsByShortName[flag.shortName] = flagPointer; | ||||||
|             this->flagsByLongName[flag.longName]   = flagPointer; |             this->flagsByLongName[flag.longName]   = flagPointer; | ||||||
|         } |         } | ||||||
|         this->optionsByShortName = std::map<char, Option*>(); |         this->argumentsByShortName = std::map<char, UnpositionalArgument*>(); | ||||||
|         this->optionsByLongName = std::map<std::string, Option*>(); |         this->argumentsByLongName = std::map<std::string, UnpositionalArgument*>(); | ||||||
|         for (Option option: options) { |         for (UnpositionalArgument unpositionalArgument: unpositionalArguments) { | ||||||
|             Option* optionPointer = new Option(); |             UnpositionalArgument* argumentPointer = new UnpositionalArgument(); | ||||||
|             *optionPointer = option; |             *argumentPointer = unpositionalArgument; | ||||||
|             this->optionsByShortName[option.shortName] = optionPointer; |             this->argumentsByShortName[unpositionalArgument.shortName] = argumentPointer; | ||||||
|             this->optionsByLongName[option.longName]   = optionPointer; |             this->argumentsByLongName[unpositionalArgument.longName]   = argumentPointer; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Option* optionWaitingForValue = nullptr; |         UnpositionalArgument* argumentWaitingForValue = nullptr; | ||||||
|         std::vector<CLI::Argument>::size_type argumentCounter = 0; |         std::vector<CLI::PositionalArgument>::size_type positionalArgumentCounter = 0; | ||||||
|         for (int i=1; i<argc; i++) { |         for (int i=1; i<argc; i++) { | ||||||
|             std::string argument(argv[i]); |             std::string argument(argv[i]); | ||||||
|             if (argument[0]=='-') { |             if (argument[0]=='-') { | ||||||
|                 // do we have unfinished business?
 |                 // do we have unfinished business?
 | ||||||
|                 if (optionWaitingForValue!=nullptr) { |                 if (argumentWaitingForValue!=nullptr) { | ||||||
|                     this->wrongUsage = true; |                     this->wrongUsage = true; | ||||||
|                     this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+optionWaitingForValue->longName); |                     this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+argumentWaitingForValue->longName); | ||||||
|                     optionWaitingForValue = nullptr; |                     argumentWaitingForValue = nullptr; | ||||||
|                 } |                 } | ||||||
|                 // long name or short name?
 |                 // long name or short name?
 | ||||||
|                 if (argument[1]=='-') { |                 if (argument[1]=='-') { | ||||||
|  | @ -99,19 +98,15 @@ namespace CLI { | ||||||
|                     auto position = argument.find("="); |                     auto position = argument.find("="); | ||||||
|                     if (position==std::string::npos) { |                     if (position==std::string::npos) { | ||||||
|                         // no =value
 |                         // no =value
 | ||||||
|                         //is option or flag?
 |                         //is argument or flag?
 | ||||||
|                         std::string argumentName = argument.substr(2,argument.length()-2); |                         std::string argumentName = argument.substr(2,argument.length()-2); | ||||||
|                         if (flagsByLongName.contains(argumentName)) { |                         if (flagsByLongName.contains(argumentName)) { | ||||||
|                             // flag
 |                             // flag
 | ||||||
|                             flagsByLongName[argumentName]->present = true; |                             flagsByLongName[argumentName]->present = true; | ||||||
|                         } else if (optionsByLongName.contains(argumentName)) { |                         } else if (argumentsByLongName.contains(argumentName)) { | ||||||
|                             // option
 |                             // unpositional argument
 | ||||||
|                             optionsByLongName[argumentName]->present = true; |                             argumentsByLongName[argumentName]->present = true; | ||||||
|                             optionWaitingForValue = optionsByLongName[argumentName]; |                             argumentWaitingForValue = argumentsByLongName[argumentName]; | ||||||
|                             if (i+1 == argc) { |  | ||||||
|                                 this->wrongUsage = true; |  | ||||||
|                                 this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+argumentName); |  | ||||||
|                             } |  | ||||||
|                         } else { |                         } else { | ||||||
|                             this->wrongUsage = true; |                             this->wrongUsage = true; | ||||||
|                             this->wrongUsageMessages.push_back(std::string("Unknown argument or flag: ")+argument); |                             this->wrongUsageMessages.push_back(std::string("Unknown argument or flag: ")+argument); | ||||||
|  | @ -120,9 +115,9 @@ namespace CLI { | ||||||
|                         // has =value
 |                         // has =value
 | ||||||
|                         std::string value = argument.substr(position+1, argument.length()-position-1); |                         std::string value = argument.substr(position+1, argument.length()-position-1); | ||||||
|                         std::string argumentName = argument.substr(2, position-2); |                         std::string argumentName = argument.substr(2, position-2); | ||||||
|                         if (optionsByLongName.contains(argumentName)) { |                         if (argumentsByLongName.contains(argumentName)) { | ||||||
|                             optionsByLongName[argumentName]->present = true; |                             argumentsByLongName[argumentName]->present = true; | ||||||
|                             optionsByLongName[argumentName]->value = value; |                             argumentsByLongName[argumentName]->value = value; | ||||||
|                         } else { |                         } else { | ||||||
|                             this->wrongUsage = true; |                             this->wrongUsage = true; | ||||||
|                             this->wrongUsageMessages.push_back(std::string("Unknown argument (or it's a flag that doesn't take a value): ")+argument); |                             this->wrongUsageMessages.push_back(std::string("Unknown argument (or it's a flag that doesn't take a value): ")+argument); | ||||||
|  | @ -134,29 +129,23 @@ namespace CLI { | ||||||
|                     // length is defined as
 |                     // length is defined as
 | ||||||
|                     // (std::__cxx11::basic_string<char>::size_type ?)
 |                     // (std::__cxx11::basic_string<char>::size_type ?)
 | ||||||
|                     // starting at 1 because 0 is '-'
 |                     // starting at 1 because 0 is '-'
 | ||||||
|                     for (int j=1; j<(int) argument.length(); j++) { |                     for (int i=1; i<(int) argument.length(); i++) { | ||||||
|                         // is option or flag?
 |                         //is argument or flag?
 | ||||||
|                         if (flagsByShortName.contains(argument[j])) { |                         if (flagsByShortName.contains(argument[i])) { | ||||||
|                             // flag
 |                             flagsByShortName[argument[i]]->present = true; | ||||||
|                             flagsByShortName[argument[j]]->present = true; |                         } else if (argumentsByShortName.contains(argument[i])) { | ||||||
|                         } else if (optionsByShortName.contains(argument[j])) { |                             argumentsByShortName[argument[i]]->present = true; | ||||||
|                             // option
 |  | ||||||
|                             optionsByShortName[argument[j]]->present = true; |  | ||||||
|                             //FIXME: see above
 |                             //FIXME: see above
 | ||||||
|                             if (j+1==(int) argument.length()) { |                             if (i+1==(int) argument.length()) { | ||||||
|                                 optionWaitingForValue = optionsByShortName[argument[j]]; |                                 argumentWaitingForValue = argumentsByShortName[argument[i]]; | ||||||
|                                 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 { |                             } else { | ||||||
|                                 //assume the rest of the argv is a concatenated argument value
 |                                 //assume the rest of the argv is a concatenated argument value
 | ||||||
|                                 optionsByShortName[argument[j]]->value = argument.substr(j+1, argument.length()-j-1); |                                 argumentsByShortName[argument[i]]->value = argument.substr(i+1, argument.length()-i-1); | ||||||
|                                 break; |                                 break; | ||||||
|                             } |                             } | ||||||
|                         } else { |                         } else { | ||||||
|                             this->wrongUsage = true; |                             this->wrongUsage = true; | ||||||
|                             this->wrongUsageMessages.push_back(std::string("Unknown argument or flag(s): ")+argument.substr(j, argument.length()-j)); |                             this->wrongUsageMessages.push_back(std::string("Unknown argument or flag(s): ")+argument.substr(i, argument.length()-i)); | ||||||
|                             // err on the side of caution to ensure that
 |                             // err on the side of caution to ensure that
 | ||||||
|                             // no unwanted options get activated on programs
 |                             // no unwanted options get activated on programs
 | ||||||
|                             // that deal gracefully with unrecognized command
 |                             // that deal gracefully with unrecognized command
 | ||||||
|  | @ -166,48 +155,39 @@ namespace CLI { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // argument or value for option?
 |                 // positional argument or value for unpositional arg?
 | ||||||
|                 if (optionWaitingForValue==nullptr) { |                 if (argumentWaitingForValue==nullptr) { | ||||||
|                     // argument
 |                     // positional argument
 | ||||||
|                     if (argumentCounter < this->arguments.size()) { |                     if (positionalArgumentCounter < this->positionalArguments.size()) { | ||||||
|                         this->arguments.at(argumentCounter).present = true; |                         this->positionalArguments.at(positionalArgumentCounter).present = true; | ||||||
|                         this->arguments.at(argumentCounter).value = argument; |                         this->positionalArguments.at(positionalArgumentCounter).value = argument; | ||||||
|                     } else { |                     } else { | ||||||
|                         this->wrongUsage = true; |                         this->wrongUsage = true; | ||||||
|                         this->wrongUsageMessages.push_back(std::string("Too many arguments! Unexpected encounter of: ")+argument); |                         this->wrongUsageMessages.push_back(std::string("Too many positional arguments. Unexpected encounter of: ")+argument); | ||||||
|                     } |                     } | ||||||
|                     argumentCounter++; |                     positionalArgumentCounter++; | ||||||
|                 } else { |                 } else { | ||||||
|                     // value for option
 |                     // value for unpositional argument
 | ||||||
|                     optionWaitingForValue->value = argument; |                     argumentWaitingForValue->value = argument; | ||||||
|                     optionWaitingForValue = nullptr; |                     argumentWaitingForValue = nullptr; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         for (Argument const& argument: this->arguments) { |         for (PositionalArgument const& positionalArgument: this->positionalArguments) { | ||||||
|             if (!argument.present) { |             if (!positionalArgument.present) { | ||||||
|                 this->wrongUsage = true; |                 this->wrongUsage = true; | ||||||
|                 this->wrongUsageMessages.push_back(std::string("Too few arguments! Missing: ")+argument.placeholder); |                 this->wrongUsageMessages.push_back(std::string("Too few positional arguments! Missing: ")+positionalArgument.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() { |     ArgumentsParser::~ArgumentsParser() { | ||||||
|         //TODO: check that this actually runs
 |         //TODO: check that this actually runs
 | ||||||
|         for (auto const& [shortName, flag]: this->flagsByShortName) { |         for (auto const& [shortName, flag]: this->flagsByShortName) { | ||||||
|             delete flag; |             delete flag; | ||||||
|         } |         } | ||||||
|         for (auto const& [shortName, option]: this->optionsByShortName) { |         for (auto const& [shortName, unpositionalArgument]: this->argumentsByShortName) { | ||||||
|             delete option; |             delete unpositionalArgument; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -231,100 +211,35 @@ namespace CLI { | ||||||
|         else return ErrorOr<bool> (false, ErrorCodes::NOT_PRESENT, false); |         else return ErrorOr<bool> (false, ErrorCodes::NOT_PRESENT, false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ErrorOr<std::string> ArgumentsParser::getArgument(std::vector<CLI::Argument>::size_type position){ |     ErrorOr<std::string> ArgumentsParser::getPositionalArgument(std::vector<CLI::PositionalArgument>::size_type position){ | ||||||
|         if (position >= this->arguments.size()) return ErrorOr<std::string>(true, ErrorCodes::OUT_OF_RANGE, std::string("")); |         if (position >= this->positionalArguments.size()) return ErrorOr<std::string>(true, ErrorCodes::OUT_OF_RANGE, std::string("")); | ||||||
|         if (this->wrongUsage) { |         if (this->wrongUsage) { | ||||||
|             if (this->arguments.at(position).present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->arguments.at(position).value); |             if (this->positionalArguments.at(position).present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->positionalArguments.at(position).value); | ||||||
|             else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string("")); |             else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string("")); | ||||||
|         } |         } | ||||||
|         return ErrorOr<std::string>(this->arguments.at(position).value); |         return ErrorOr<std::string>(this->positionalArguments.at(position).value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ErrorOr<std::string> ArgumentsParser::getOption(char shortName) { |     ErrorOr<std::string> ArgumentsParser::getUnpositionalArgument(char shortName) { | ||||||
|         if (!this->optionsByShortName.contains(shortName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string("")); |         if (!this->argumentsByShortName.contains(shortName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string("")); | ||||||
|         if (this->wrongUsage) { |         if (this->wrongUsage) { | ||||||
|             if (this->optionsByShortName[shortName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->optionsByShortName[shortName]->value); |             if (this->argumentsByShortName[shortName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->argumentsByShortName[shortName]->value); | ||||||
|             else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string("")); |             else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string("")); | ||||||
|         } |         } | ||||||
|         if (this->optionsByShortName[shortName]->present) return ErrorOr<std::string>(this->optionsByShortName[shortName]->value); |         if (this->argumentsByShortName[shortName]->present) return ErrorOr<std::string>(this->argumentsByShortName[shortName]->value); | ||||||
|         // argument is not present, but this is not an error -> false, NOT_PRESENT, ""
 |         // argument is not present, but this is not an error -> false, NOT_PRESENT, ""
 | ||||||
|         else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string("")); |         else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string("")); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ErrorOr<std::string> ArgumentsParser::getOption(std::string longName) { |     ErrorOr<std::string> ArgumentsParser::getUnpositionalArgument(std::string longName) { | ||||||
|         if (!this->optionsByLongName.contains(longName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string("")); |         if (!this->argumentsByLongName.contains(longName)) return ErrorOr<std::string>(true, ErrorCodes::UNKNOWN_KEY, std::string("")); | ||||||
|         if (this->wrongUsage) { |         if (this->wrongUsage) { | ||||||
|             if (this->optionsByLongName[longName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->optionsByLongName[longName]->value); |             if (this->argumentsByLongName[longName]->present) return ErrorOr<std::string>(true, ErrorCodes::WRONG_USAGE, this->argumentsByLongName[longName]->value); | ||||||
|             else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string("")); |             else return ErrorOr<std::string>(true, ErrorCodes::NOT_PRESENT, std::string("")); | ||||||
|         } |         } | ||||||
|         if (this->optionsByLongName[longName]->present) return ErrorOr<std::string>(this->optionsByLongName[longName]->value); |         if (this->argumentsByLongName[longName]->present) return ErrorOr<std::string>(this->argumentsByLongName[longName]->value); | ||||||
|         // argument is not present, but this is not an error -> false, NOT_PRESENT, ""
 |         // argument is not present, but this is not an error -> false, NOT_PRESENT, ""
 | ||||||
|         else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string("")); |         else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string("")); | ||||||
|     } |     } | ||||||
| 
 |     //std::string ArgumentsParser::getUsage();
 | ||||||
|     std::string ArgumentsParser::getUsage(){ |  | ||||||
|         std::string usageString = ""; |  | ||||||
|         if (this->description != "") { |  | ||||||
|             usageString += "Help: " + this->programName + "\n\n\t" + this->description + "\n\n"; |  | ||||||
|         } |  | ||||||
|         usageString += "Usage: " + this->programName + " "; |  | ||||||
| 
 |  | ||||||
|         if(!this->flagsByShortName.empty()){ |  | ||||||
|             usageString += "[-"; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for(const auto& [key, value]: this->flagsByShortName){ |  | ||||||
|             usageString.push_back(key); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!this->flagsByShortName.empty()){ |  | ||||||
|             usageString += "] "; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for(const auto& [key, value]: this->optionsByShortName){ |  | ||||||
|             usageString += "[-"; |  | ||||||
|             usageString.push_back(key); |  | ||||||
|             usageString += " " + value->placeholder + "] "; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for(const auto& argument: this->arguments){ |  | ||||||
|             usageString += argument.placeholder + " "; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         usageString.push_back('\n'); |  | ||||||
| 
 |  | ||||||
|         if(!this->flagsByShortName.empty()){ |  | ||||||
|             usageString += "\nFlags:\n"; |  | ||||||
| 
 |  | ||||||
|             for(const auto& [key, value]: this->flagsByShortName){ |  | ||||||
|                 usageString += "\t-"; |  | ||||||
|                 usageString.push_back(key); |  | ||||||
|                 usageString += ", --" + value->longName + "\n\t\t" + value->description + "\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!this->optionsByShortName.empty()){ |  | ||||||
|             usageString += "\nOptions:\n"; |  | ||||||
| 
 |  | ||||||
|             for(const auto& [key, value]: this->optionsByShortName){ |  | ||||||
|                 usageString += "\t-"; |  | ||||||
|                 usageString.push_back(key); |  | ||||||
|                 usageString += " " + value->placeholder + ", --" + value->longName + "=" + value->placeholder + "\n\t\t" + value->description + "\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!this->arguments.empty()){ |  | ||||||
|             usageString += "\nArguments:\n"; |  | ||||||
| 
 |  | ||||||
|             for(const auto& argument: this->arguments){ |  | ||||||
|                 usageString += "\t" + argument.placeholder + "\n\t\t" + argument.description + "\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (this->additionalInfo != "") { |  | ||||||
|             usageString += "\nAdditional Info:\n\n\t" + this->additionalInfo + "\n"; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return usageString; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
| #include "error.hpp" | #include "error.h++" | ||||||
| 
 | 
 | ||||||
| namespace CLI { | namespace CLI { | ||||||
| 
 | 
 | ||||||
|  | @ -35,7 +35,7 @@ namespace CLI { | ||||||
|         Flag(char shortName, std::string longName, std::string description); |         Flag(char shortName, std::string longName, std::string description); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct Option { |     struct UnpositionalArgument { | ||||||
|         char shortName; |         char shortName; | ||||||
|         std::string longName; |         std::string longName; | ||||||
|         // used for automatic usage generation
 |         // used for automatic usage generation
 | ||||||
|  | @ -45,11 +45,11 @@ namespace CLI { | ||||||
|         bool present; |         bool present; | ||||||
|         std::string value; |         std::string value; | ||||||
| 
 | 
 | ||||||
|         Option(); |         UnpositionalArgument(); | ||||||
|         Option(char shortName, std::string longName, std::string placeholder, std::string description); |         UnpositionalArgument(char shortName, std::string longName, std::string placeholder, std::string description); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct Argument { |     struct PositionalArgument { | ||||||
|         // used for automatic usage generation
 |         // used for automatic usage generation
 | ||||||
|         std::string description; |         std::string description; | ||||||
|         std::string placeholder; // the "HOST" in "ping [-c <COUNT>] <HOST>"
 |         std::string placeholder; // the "HOST" in "ping [-c <COUNT>] <HOST>"
 | ||||||
|  | @ -57,19 +57,17 @@ namespace CLI { | ||||||
|         bool present; |         bool present; | ||||||
|         std::string value; |         std::string value; | ||||||
| 
 | 
 | ||||||
|         Argument(); |         PositionalArgument(); | ||||||
|         Argument(std::string placeholder, std::string description); |         PositionalArgument(std::string placeholder, std::string description); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     class ArgumentsParser { |     class ArgumentsParser { | ||||||
|         private: |         private: | ||||||
|             std::map<char, Flag*> flagsByShortName; |             std::map<char, Flag*> flagsByShortName; | ||||||
|             std::map<std::string, Flag*> flagsByLongName; |             std::map<std::string, Flag*> flagsByLongName; | ||||||
|             std::map<char, Option*> optionsByShortName; |             std::map<char, UnpositionalArgument*> argumentsByShortName; | ||||||
|             std::map<std::string, Option*> optionsByLongName; |             std::map<std::string, UnpositionalArgument*> argumentsByLongName; | ||||||
|             std::vector<Argument> arguments; |             std::vector<PositionalArgument> positionalArguments; | ||||||
|             std::string description; |  | ||||||
|             std::string additionalInfo; |  | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
|             std::string programName; |             std::string programName; | ||||||
|  | @ -77,16 +75,14 @@ namespace CLI { | ||||||
|             std::vector<std::string> wrongUsageMessages; |             std::vector<std::string> wrongUsageMessages; | ||||||
| 
 | 
 | ||||||
|             // using int here bc that's how main() is defined
 |             // using int here bc that's how main() is defined
 | ||||||
|             ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments); |             ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<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, 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(); |             ~ArgumentsParser(); | ||||||
| 
 | 
 | ||||||
|             ErrorOr<bool> getFlag(char shortName); |             ErrorOr<bool> getFlag(char shortName); | ||||||
|             ErrorOr<bool> getFlag(std::string longName); |             ErrorOr<bool> getFlag(std::string longName); | ||||||
|             ErrorOr<std::string> getArgument(std::vector<CLI::Argument>::size_type position); |             ErrorOr<std::string> getPositionalArgument(std::vector<CLI::PositionalArgument>::size_type position); | ||||||
|             ErrorOr<std::string> getOption(char shortName); |             ErrorOr<std::string> getUnpositionalArgument(char shortName); | ||||||
|             ErrorOr<std::string> getOption(std::string longName); |             ErrorOr<std::string> getUnpositionalArgument(std::string longName); | ||||||
| 
 | 
 | ||||||
|             std::string getUsage(); |             std::string getUsage(); | ||||||
|     }; |     }; | ||||||
|  | @ -23,43 +23,37 @@ struct ErrorOr { | ||||||
|     uint8_t errorCode; |     uint8_t errorCode; | ||||||
|     T value; |     T value; | ||||||
| 
 | 
 | ||||||
|     ErrorOr() { |     ErrorOr<T>(); | ||||||
|  |     ErrorOr<T>(T); | ||||||
|  |     ErrorOr<T>(bool, uint8_t); | ||||||
|  |     ErrorOr<T>(bool, uint8_t, T); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | ErrorOr<T>::ErrorOr() { | ||||||
|     this->isError = false; |     this->isError = false; | ||||||
|     this->errorCode = 0; |     this->errorCode = 0; | ||||||
|     } | } | ||||||
| 
 | 
 | ||||||
|     ErrorOr(T value) { | template <typename T> | ||||||
|  | ErrorOr<T>::ErrorOr(T value) { | ||||||
|     this->isError = false; |     this->isError = false; | ||||||
|     this->errorCode = 0; |     this->errorCode = 0; | ||||||
|     this->value = value; |     this->value = value; | ||||||
|     } | } | ||||||
| 
 | 
 | ||||||
|     ErrorOr(bool isError, uint8_t errorCode) { | template <typename T> | ||||||
|  | ErrorOr<T>::ErrorOr(bool isError, uint8_t errorCode) { | ||||||
|     this->isError = isError; |     this->isError = isError; | ||||||
|     this->errorCode = errorCode; |     this->errorCode = errorCode; | ||||||
|     } | } | ||||||
| 
 | 
 | ||||||
|     ErrorOr(bool isError, uint8_t errorCode, T value) { | template <typename T> | ||||||
|  | ErrorOr<T>::ErrorOr(bool isError, uint8_t errorCode, T value) { | ||||||
|     this->isError = isError; |     this->isError = isError; | ||||||
|     this->errorCode = errorCode; |     this->errorCode = errorCode; | ||||||
|     this->value = value; |     this->value = value; | ||||||
|     } | } | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct ErrorOrVoid { |  | ||||||
|     bool isError; |  | ||||||
|     uint8_t errorCode; |  | ||||||
| 
 |  | ||||||
|     ErrorOrVoid() { |  | ||||||
|         this->isError = false; |  | ||||||
|         this->errorCode = 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ErrorOrVoid(bool isError, uint8_t errorCode) { |  | ||||||
|         this->isError = isError; |  | ||||||
|         this->errorCode = errorCode; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| namespace ErrorCodes { | namespace ErrorCodes { | ||||||
|     // These are all arbitrary values used to assign error codes to different
 |     // These are all arbitrary values used to assign error codes to different
 | ||||||
|  | @ -70,10 +64,13 @@ namespace ErrorCodes { | ||||||
|     // Ahh yes, very useful.
 |     // Ahh yes, very useful.
 | ||||||
|     const uint8_t SUCCESS = 0; |     const uint8_t SUCCESS = 0; | ||||||
| 
 | 
 | ||||||
|  |     // IndexOutOfRangeException equivalent
 | ||||||
|     const uint8_t OUT_OF_RANGE = 1; |     const uint8_t OUT_OF_RANGE = 1; | ||||||
|     // like OUT_OF_RANGE but when going out of bounds in a non-predetermined way
 | 
 | ||||||
|  |     // when going out of bounds in a non-predetermined way
 | ||||||
|     const uint8_t OVERRUN = 2; |     const uint8_t OVERRUN = 2; | ||||||
| 
 | 
 | ||||||
|  |     // when checking for presence of something, for example CLI arguments
 | ||||||
|     const uint8_t NOT_PRESENT = 3; |     const uint8_t NOT_PRESENT = 3; | ||||||
| 
 | 
 | ||||||
|     const uint8_t WRONG_USAGE = 4; |     const uint8_t WRONG_USAGE = 4; | ||||||
|  | @ -81,20 +78,6 @@ namespace ErrorCodes { | ||||||
|     // when dealing with maps
 |     // when dealing with maps
 | ||||||
|     const uint8_t UNKNOWN_KEY = 5; |     const uint8_t UNKNOWN_KEY = 5; | ||||||
| 
 | 
 | ||||||
|     //mismatched size in java strings
 |  | ||||||
|     const uint8_t MISMATCHEDSIZE = 6; |  | ||||||
| 
 |  | ||||||
|     const uint8_t NOT_YET_KNOWN = 7; |  | ||||||
| 
 |  | ||||||
|     const uint8_t 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 UNIMPLEMENTED = 254; | ||||||
| 
 | 
 | ||||||
|     const uint8_t UNKNOWN = 255; |     const uint8_t UNKNOWN = 255; | ||||||
							
								
								
									
										274
									
								
								src/lib/file.cpp
								
								
								
								
							
							
						
						
									
										274
									
								
								src/lib/file.cpp
								
								
								
								
							|  | @ -1,274 +0,0 @@ | ||||||
| // 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)); |  | ||||||
| } |  | ||||||
|  | @ -1,92 +0,0 @@ | ||||||
| // 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,30 +15,18 @@ | ||||||
| 
 | 
 | ||||||
| #include <tinyutf8/tinyutf8.h> | #include <tinyutf8/tinyutf8.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include "error.hpp" | #include "error.h++" | ||||||
| #include "javacompat.hpp" |  | ||||||
| #include "../../.endianness" |  | ||||||
| 
 | 
 | ||||||
| #ifdef FOSSVG_ENDIAN_BIG_WORD | #include "javacompat.h++" | ||||||
|     #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 { | namespace JavaCompat { | ||||||
|     ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size) { |     //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[]) { | ||||||
|         std::string stdString; |         std::string stdString; | ||||||
|         uint16_t encodedSize = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]); |         uint16_t size = static_cast<uint16_t>(data[0])<<8 | static_cast<uint16_t>(data[1]); | ||||||
| 
 | 
 | ||||||
|         if(encodedSize != size){ |         for(uint8_t i=2; i<size+2; i++){ | ||||||
|             return ErrorOr<tiny_utf8::string>(true, ErrorCodes::MISMATCHEDSIZE); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for(uint16_t i=2; i<size+2; i++){ |  | ||||||
|             if(i != 0){ |             if(i != 0){ | ||||||
|                 if(data[i] == 0x80 && data[i-1] == 0xc0){ |                 if(data[i] == 0x80 && data[i-1] == 0xc0){ | ||||||
|                     stdString[stdString.length() - 1] = '\0'; |                     stdString[stdString.length() - 1] = '\0'; | ||||||
|  | @ -47,48 +35,11 @@ namespace JavaCompat { | ||||||
|             } |             } | ||||||
|             stdString.push_back((char) data[i]); |             stdString.push_back((char) data[i]); | ||||||
|         } |         } | ||||||
|         return ErrorOr<tiny_utf8::string>(tiny_utf8::string(stdString)); |         return tiny_utf8::string(stdString); | ||||||
|     } |     } | ||||||
| 
 |     /*
 | ||||||
|     ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string data) { |     ErrorOr<uint8_t*> exportJavaString(tiny_utf8::string data) { | ||||||
|         uint16_t* size = new uint16_t; |         return ErrorOr(nullptr); | ||||||
|         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,11 +13,12 @@ | ||||||
| //version 3 along with this program.
 | //version 3 along with this program.
 | ||||||
| //If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | //If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | ||||||
| 
 | 
 | ||||||
| #include <vector> |  | ||||||
| #include <tinyutf8/tinyutf8.h> | #include <tinyutf8/tinyutf8.h> | ||||||
| #include "error.hpp" | #include "error.h++" | ||||||
| 
 | 
 | ||||||
| namespace JavaCompat { | namespace JavaCompat { | ||||||
|     ErrorOr<tiny_utf8::string> importJavaString(uint8_t data[], uint16_t size); |     //FIXME: contrary to what I said, we need to explicitly pass the data
 | ||||||
|     ErrorOr<std::vector<uint8_t>> exportJavaString(tiny_utf8::string 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); | ||||||
| } | } | ||||||
							
								
								
									
										1546
									
								
								src/lib/nbt.cpp
								
								
								
								
							
							
						
						
									
										1546
									
								
								src/lib/nbt.cpp
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,79 @@ | ||||||
|  | // 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); | ||||||
|  | } | ||||||
							
								
								
									
										307
									
								
								src/lib/nbt.hpp
								
								
								
								
							
							
						
						
									
										307
									
								
								src/lib/nbt.hpp
								
								
								
								
							|  | @ -1,307 +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:    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> | #include <iostream> | ||||||
| 
 | 
 | ||||||
| #define ASSERT(truth) if ((truth)); else { std::cout << "On line " << __LINE__ << ": Assertion failed: " << #truth << std::endl; return 1; } | #define ASSERT(truth) if ((truth)); else { std::cout << "Assertion failed: " << #truth << std::endl; return 1; } | ||||||
|  | @ -16,14 +16,14 @@ | ||||||
| #include <string> | #include <string> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include "assert.hpp" | #include "assert.h++" | ||||||
| #include "../lib/error.hpp" | #include "../lib/error.h++" | ||||||
| 
 | 
 | ||||||
| #include "../lib/cli.hpp" | #include "../lib/cli.h++" | ||||||
| 
 | 
 | ||||||
| int main() { | int main(int argc, char* argv[]) { | ||||||
|     std::cout << "################################################################################" << std::endl; |     std::cout << "################################################################################" << std::endl; | ||||||
|     std::cout << "CLI argument parsing tests" << std::endl; |     std::cout << "CLI argument parser tests" << std::endl; | ||||||
|     std::cout << "################################################################################" << std::endl; |     std::cout << "################################################################################" << std::endl; | ||||||
| 
 | 
 | ||||||
|     // Valid parameter test ############################################
 |     // Valid parameter test ############################################
 | ||||||
|  | @ -31,7 +31,7 @@ int main() { | ||||||
|     // with many variations of valid input on a single command line.
 |     // with many variations of valid input on a single command line.
 | ||||||
|     //
 |     //
 | ||||||
|     // simulated command line:
 |     // simulated command line:
 | ||||||
|     // 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"
 |     // 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"
 | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Flag> validTestFlags; |     std::vector<CLI::Flag> validTestFlags; | ||||||
|     validTestFlags.push_back(CLI::Flag('0', "00000", "a short flag on its own")); |     validTestFlags.push_back(CLI::Flag('0', "00000", "a short flag on its own")); | ||||||
|  | @ -47,19 +47,19 @@ int main() { | ||||||
|     validTestFlags.push_back(CLI::Flag('g', "ggggg", "short flags concatenated with an argument that has a separate value")); |     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")); |     validTestFlags.push_back(CLI::Flag('6', "66666", "unused flag")); | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Option> validTestOptions; |     std::vector<CLI::UnpositionalArgument> validTestUnpositionalArguments; | ||||||
|     validTestOptions.push_back(CLI::Option('c', "ccccc", "VALUE", "short argument concatenated with its value")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('c', "ccccc", "VALUE", "short argument concatenated with its value")); | ||||||
|     validTestOptions.push_back(CLI::Option('d', "ddddd", " VALUE", "short argument with separate value")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('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")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('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")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('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 =")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('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")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('y', "long-argument-with-value-separated", " VALUE", "long argument with separate value")); | ||||||
|     validTestOptions.push_back(CLI::Option('z', "zzzzz", "NOPE", "unused argument")); |     validTestUnpositionalArguments.push_back(CLI::UnpositionalArgument('z', "zzzzz", "NOPE", "unused argument")); | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Argument> validTestArguments; |     std::vector<CLI::PositionalArgument> validTestPositionalArguments; | ||||||
|     validTestArguments.push_back(CLI::Argument("argument0", "argument between optional parameters")); |     validTestPositionalArguments.push_back(CLI::PositionalArgument("argument0", "positional argument between optional parameters")); | ||||||
|     validTestArguments.push_back(CLI::Argument("argument1", "argument")); |     validTestPositionalArguments.push_back(CLI::PositionalArgument("argument1", "positional argument")); | ||||||
|     validTestArguments.push_back(CLI::Argument("argument2", "argument")); |     validTestPositionalArguments.push_back(CLI::PositionalArgument("argument2", "positional argument")); | ||||||
| 
 | 
 | ||||||
|     const char** validTestParameterList = new const char*[17]; |     const char** validTestParameterList = new const char*[17]; | ||||||
|     validTestParameterList[ 0] = "test"; |     validTestParameterList[ 0] = "test"; | ||||||
|  | @ -71,17 +71,17 @@ int main() { | ||||||
|     validTestParameterList[ 6] = "-d"; |     validTestParameterList[ 6] = "-d"; | ||||||
|     validTestParameterList[ 7] = "separate-value"; |     validTestParameterList[ 7] = "separate-value"; | ||||||
|     validTestParameterList[ 8] = "-efdouble-concatenated"; |     validTestParameterList[ 8] = "-efdouble-concatenated"; | ||||||
|     validTestParameterList[ 9] = "argument 0"; |     validTestParameterList[ 9] = "positional argument 0"; | ||||||
|     validTestParameterList[10] = "-gh"; |     validTestParameterList[10] = "-gh"; | ||||||
|     validTestParameterList[11] = "concatenated-separate-value"; |     validTestParameterList[11] = "concatenated-separate-value"; | ||||||
|     validTestParameterList[12] = "--long-argument-with-value-included=included value"; |     validTestParameterList[12] = "--long-argument-with-value-included=included value"; | ||||||
|     validTestParameterList[13] = "--long-argument-with-value-separated"; |     validTestParameterList[13] = "--long-argument-with-value-separated"; | ||||||
|     validTestParameterList[14] = "separate value"; |     validTestParameterList[14] = "separate value"; | ||||||
|     validTestParameterList[15] = "argument 1"; |     validTestParameterList[15] = "positional argument 1"; | ||||||
|     validTestParameterList[16] = "argument 2"; |     validTestParameterList[16] = "positional argument 2"; | ||||||
|     int validTestParameterCount = 17; |     int validTestParameterCount = 17; | ||||||
| 
 | 
 | ||||||
|     CLI::ArgumentsParser validTestParameterParser = CLI::ArgumentsParser(validTestParameterCount, validTestParameterList, validTestFlags, validTestOptions, validTestArguments); |     CLI::ArgumentsParser validTestParameterParser = CLI::ArgumentsParser(validTestParameterCount, validTestParameterList, validTestFlags, validTestUnpositionalArguments, validTestPositionalArguments); | ||||||
| 
 | 
 | ||||||
|     ASSERT(!validTestParameterParser.wrongUsage); |     ASSERT(!validTestParameterParser.wrongUsage); | ||||||
|     ASSERT(validTestParameterParser.programName == std::string("test")); |     ASSERT(validTestParameterParser.programName == std::string("test")); | ||||||
|  | @ -115,50 +115,49 @@ int main() { | ||||||
|     ASSERT(!validTestParameterParser.getFlag('6').isError); |     ASSERT(!validTestParameterParser.getFlag('6').isError); | ||||||
|     ASSERT(!validTestParameterParser.getFlag('6').value); |     ASSERT(!validTestParameterParser.getFlag('6').value); | ||||||
|     ASSERT(!validTestParameterParser.getFlag(std::string("66666")).value); |     ASSERT(!validTestParameterParser.getFlag(std::string("66666")).value); | ||||||
|     ASSERT(!validTestParameterParser.getOption('c').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('c').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('c').value==std::string("concatenated")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('c').value==std::string("concatenated")); | ||||||
|     ASSERT(validTestParameterParser.getOption(std::string("ccccc")).value==std::string("concatenated")); |     ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("ccccc")).value==std::string("concatenated")); | ||||||
|     ASSERT(!validTestParameterParser.getOption('d').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('d').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('d').value==std::string("separate-value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('d').value==std::string("separate-value")); | ||||||
|     ASSERT(validTestParameterParser.getOption(std::string("ddddd")).value==std::string("separate-value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("ddddd")).value==std::string("separate-value")); | ||||||
|     ASSERT(!validTestParameterParser.getFlag('e').isError); |     ASSERT(!validTestParameterParser.getFlag('e').isError); | ||||||
|     ASSERT(validTestParameterParser.getFlag('e').value); |     ASSERT(validTestParameterParser.getFlag('e').value); | ||||||
|     ASSERT(validTestParameterParser.getFlag(std::string("eeeee")).value); |     ASSERT(validTestParameterParser.getFlag(std::string("eeeee")).value); | ||||||
|     ASSERT(!validTestParameterParser.getOption('f').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('f').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('f').value==std::string("double-concatenated")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('f').value==std::string("double-concatenated")); | ||||||
|     ASSERT(validTestParameterParser.getOption(std::string("fffff")).value==std::string("double-concatenated")); |     ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("fffff")).value==std::string("double-concatenated")); | ||||||
|     ASSERT(!validTestParameterParser.getArgument(0).isError); |     ASSERT(!validTestParameterParser.getPositionalArgument(0).isError); | ||||||
|     ASSERT(validTestParameterParser.getArgument(0).value=="argument 0"); |     ASSERT(validTestParameterParser.getPositionalArgument(0).value=="positional argument 0"); | ||||||
|     ASSERT(!validTestParameterParser.getFlag('g').isError); |     ASSERT(!validTestParameterParser.getFlag('g').isError); | ||||||
|     ASSERT(validTestParameterParser.getFlag('g').value); |     ASSERT(validTestParameterParser.getFlag('g').value); | ||||||
|     ASSERT(validTestParameterParser.getFlag(std::string("ggggg")).value); |     ASSERT(validTestParameterParser.getFlag(std::string("ggggg")).value); | ||||||
|     ASSERT(!validTestParameterParser.getOption('h').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('h').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('h').value==std::string("concatenated-separate-value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('h').value==std::string("concatenated-separate-value")); | ||||||
|     ASSERT(validTestParameterParser.getOption(std::string("hhhhh")).value==std::string("concatenated-separate-value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("hhhhh")).value==std::string("concatenated-separate-value")); | ||||||
|     ASSERT(!validTestParameterParser.getOption('x').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('x').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('x').value==std::string("included value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('x').value==std::string("included value")); | ||||||
|     ASSERT(validTestParameterParser.getOption(std::string("long-argument-with-value-included")).value==std::string("included value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("long-argument-with-value-included")).value==std::string("included value")); | ||||||
|     ASSERT(!validTestParameterParser.getOption('y').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('y').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('y').value==std::string("separate value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('y').value==std::string("separate value")); | ||||||
|     ASSERT(validTestParameterParser.getOption(std::string("long-argument-with-value-separated")).value==std::string("separate value")); |     ASSERT(validTestParameterParser.getUnpositionalArgument(std::string("long-argument-with-value-separated")).value==std::string("separate value")); | ||||||
|     ASSERT(!validTestParameterParser.getArgument(1).isError); |     ASSERT(!validTestParameterParser.getPositionalArgument(1).isError); | ||||||
|     ASSERT(validTestParameterParser.getArgument(1).value=="argument 1"); |     ASSERT(validTestParameterParser.getPositionalArgument(1).value=="positional argument 1"); | ||||||
|     ASSERT(!validTestParameterParser.getArgument(2).isError); |     ASSERT(!validTestParameterParser.getPositionalArgument(2).isError); | ||||||
|     ASSERT(validTestParameterParser.getArgument(2).value=="argument 2"); |     ASSERT(validTestParameterParser.getPositionalArgument(2).value=="positional argument 2"); | ||||||
|     ASSERT(!validTestParameterParser.getOption('z').isError); |     ASSERT(!validTestParameterParser.getUnpositionalArgument('z').isError); | ||||||
|     ASSERT(validTestParameterParser.getOption('z').errorCode == ErrorCodes::NOT_PRESENT); |     ASSERT(validTestParameterParser.getUnpositionalArgument('z').errorCode == ErrorCodes::NOT_PRESENT); | ||||||
|     ASSERT(validTestParameterParser.getOption('z').value == std::string("")); |     ASSERT(validTestParameterParser.getUnpositionalArgument('z').value == std::string("")); | ||||||
|     ASSERT(validTestParameterParser.wrongUsageMessages.size() == 0); |  | ||||||
| 
 | 
 | ||||||
|     delete[] validTestParameterList; |     delete[] validTestParameterList; | ||||||
|     std::cout << "Passed valid command line test." << std::endl; |     std::cout << "Passed valid input test." << std::endl; | ||||||
| 
 | 
 | ||||||
|     // empty input (valid and invalid) #################################
 |     // empty input (valid and invalid) #################################
 | ||||||
|     std::vector<CLI::Flag> emptyTestFlags; |     std::vector<CLI::Flag> emptyTestFlags; | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Option> emptyTestOptions; |     std::vector<CLI::UnpositionalArgument> emptyTestUnpositionalArguments; | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Argument> emptyTestArguments; |     std::vector<CLI::PositionalArgument> emptyTestPositionalArguments; | ||||||
| 
 | 
 | ||||||
|     const char** emptyTestParameterList = new const char*[1]; |     const char** emptyTestParameterList = new const char*[1]; | ||||||
|     // The command is always a part of a command line, even if it is empty
 |     // The command is always a part of a command line, even if it is empty
 | ||||||
|  | @ -168,26 +167,27 @@ int main() { | ||||||
|     int emptyTestParameterCount = 1; |     int emptyTestParameterCount = 1; | ||||||
| 
 | 
 | ||||||
|     // valid
 |     // valid
 | ||||||
|     CLI::ArgumentsParser validEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestOptions, emptyTestArguments); |     CLI::ArgumentsParser validEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestUnpositionalArguments, emptyTestPositionalArguments); | ||||||
|     ASSERT(!validEmptyTestParameterParser.wrongUsage); |     ASSERT(!validEmptyTestParameterParser.wrongUsage); | ||||||
|     ASSERT(validEmptyTestParameterParser.programName == std::string("test")); |     ASSERT(validEmptyTestParameterParser.programName == std::string("test")); | ||||||
|     ASSERT(validEmptyTestParameterParser.wrongUsageMessages.size() == 0); |  | ||||||
| 
 | 
 | ||||||
|     //invalid
 |     //invalid
 | ||||||
|     emptyTestArguments.push_back(CLI::Argument("argument", "argument")); |     emptyTestPositionalArguments.push_back(CLI::PositionalArgument("argument", "positional argument")); | ||||||
| 
 | 
 | ||||||
|     CLI::ArgumentsParser invalidEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestOptions, emptyTestArguments); |     CLI::ArgumentsParser invalidEmptyTestParameterParser = CLI::ArgumentsParser(emptyTestParameterCount, emptyTestParameterList, emptyTestFlags, emptyTestUnpositionalArguments, emptyTestPositionalArguments); | ||||||
|     ASSERT(invalidEmptyTestParameterParser.wrongUsage); |     ASSERT(invalidEmptyTestParameterParser.wrongUsage); | ||||||
|     ASSERT(invalidEmptyTestParameterParser.programName == std::string("test")); |     ASSERT(invalidEmptyTestParameterParser.programName == std::string("test")); | ||||||
|     ASSERT(invalidEmptyTestParameterParser.getArgument(0).isError); |     ASSERT(invalidEmptyTestParameterParser.getPositionalArgument(0).isError); | ||||||
|     ASSERT(invalidEmptyTestParameterParser.getArgument(0).errorCode == ErrorCodes::NOT_PRESENT); |     ASSERT(invalidEmptyTestParameterParser.getPositionalArgument(0).errorCode == ErrorCodes::NOT_PRESENT); | ||||||
|     ASSERT(invalidEmptyTestParameterParser.wrongUsageMessages.size() == 1); |  | ||||||
|     ASSERT(invalidEmptyTestParameterParser.wrongUsageMessages.at(0) == "Too few arguments! Missing: argument"); |  | ||||||
| 
 | 
 | ||||||
|     delete[] emptyTestParameterList; |     delete[] emptyTestParameterList; | ||||||
|     std::cout << "Passed empty command line test." << std::endl; |     std::cout << "Passed empty input test." << std::endl; | ||||||
| 
 | 
 | ||||||
|     // unknown flag ####################################################
 |     //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
 | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Flag> unknownFlagTestFlags; |     std::vector<CLI::Flag> unknownFlagTestFlags; | ||||||
|     unknownFlagTestFlags.push_back(CLI::Flag('0', "zero", "test flag")); |     unknownFlagTestFlags.push_back(CLI::Flag('0', "zero", "test flag")); | ||||||
|  | @ -197,11 +197,11 @@ int main() { | ||||||
|     unknownFlagTestFlags.push_back(CLI::Flag('4', "four", "test flag")); |     unknownFlagTestFlags.push_back(CLI::Flag('4', "four", "test flag")); | ||||||
|     unknownFlagTestFlags.push_back(CLI::Flag('5', "five", "test flag")); |     unknownFlagTestFlags.push_back(CLI::Flag('5', "five", "test flag")); | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Option> unknownFlagTestOptions; |     std::vector<CLI::UnpositionalArgument> unknownFlagTestUnpositionalArguments; | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Argument> unknownFlagTestArguments; |     std::vector<CLI::PositionalArgument> unknownFlagTestPositionalArguments; | ||||||
| 
 | 
 | ||||||
|     const char** unknownFlagTestParameterList = new const char*[7]; |     const char** unknownFlagTestParameterList = new const char*[3]; | ||||||
|     unknownFlagTestParameterList[0] = "test"; |     unknownFlagTestParameterList[0] = "test"; | ||||||
|     unknownFlagTestParameterList[1] = "-a"; |     unknownFlagTestParameterList[1] = "-a"; | ||||||
|     unknownFlagTestParameterList[2] = "-1"; |     unknownFlagTestParameterList[2] = "-1"; | ||||||
|  | @ -211,554 +211,20 @@ int main() { | ||||||
|     unknownFlagTestParameterList[6] = "-5"; |     unknownFlagTestParameterList[6] = "-5"; | ||||||
|     int unknownFlagStandaloneTestParameterCount = 2; |     int unknownFlagStandaloneTestParameterCount = 2; | ||||||
| 
 | 
 | ||||||
|     CLI::ArgumentsParser unknownFlagStandaloneTestParser = CLI::ArgumentsParser(unknownFlagStandaloneTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestOptions, unknownFlagTestArguments); |     CLI::ArgumentsParser unknownFlagStandaloneTestParser = CLI::ArgumentsParser(unknownFlagStandaloneTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestUnpositionalArguments, unknownFlagTestPositionalArguments); | ||||||
|     ASSERT(unknownFlagStandaloneTestParser.getFlag('1').isError); |     ASSERT(unknownFlagStandaloneTestParser.getFlag('1').isError); | ||||||
|     ASSERT(unknownFlagStandaloneTestParser.getFlag('1').errorCode == ErrorCodes::NOT_PRESENT); |     ASSERT(unknownFlagStandaloneTestParser.getFlag('1').errorCode == ErrorCodes::NOT_PRESENT); | ||||||
|     ASSERT(!unknownFlagStandaloneTestParser.getFlag('1').value); |     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; |     int unknownFlagMixedTestParameterCount = 7; | ||||||
| 
 | 
 | ||||||
|     CLI::ArgumentsParser unknownFlagMixedTestParser = CLI::ArgumentsParser(unknownFlagMixedTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestOptions, unknownFlagTestArguments); |     CLI::ArgumentsParser unknownFlagMixedTestParser = CLI::ArgumentsParser(unknownFlagMixedTestParameterCount, unknownFlagTestParameterList, unknownFlagTestFlags, unknownFlagTestUnpositionalArguments, unknownFlagTestPositionalArguments); | ||||||
|     ASSERT(unknownFlagMixedTestParser.getFlag('1').isError); |     ASSERT(unknownFlagMixedTestParser.getFlag('1').isError); | ||||||
|     ASSERT(unknownFlagMixedTestParser.getFlag('1').errorCode == ErrorCodes::WRONG_USAGE); |     ASSERT(unknownFlagMixedTestParser.getFlag('1').errorCode == ErrorCodes::WRONG_USAGE); | ||||||
|     ASSERT(unknownFlagMixedTestParser.getFlag('1').value); |     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; |     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; |     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; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,183 +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 <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.
 | // version 3 along with this program.
 | ||||||
| // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | ||||||
| 
 | 
 | ||||||
|  | #include "assert.h++" | ||||||
|  | #include "../lib/javacompat.h++" | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <tinyutf8/tinyutf8.h> | #include <tinyutf8/tinyutf8.h> | ||||||
| #include <fstream> | #include <fstream> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include "assert.hpp" |  | ||||||
| #include "../lib/javacompat.hpp" |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| int main(){ | int main(){ | ||||||
|  | @ -28,7 +28,7 @@ int main(){ | ||||||
|     // java-style_unicode: 119 bytes, 85 characters ??
 |     // java-style_unicode: 119 bytes, 85 characters ??
 | ||||||
| 
 | 
 | ||||||
|     std::cout << "################################################################################" << std::endl; |     std::cout << "################################################################################" << std::endl; | ||||||
|     std::cout << "Javacompat tests" << std::endl; |     std::cout << "Java String Tests" << std::endl; | ||||||
|     std::cout << "################################################################################" << std::endl; |     std::cout << "################################################################################" << std::endl; | ||||||
| 
 | 
 | ||||||
|     char* nextChar = new char; |     char* nextChar = new char; | ||||||
|  | @ -52,7 +52,7 @@ int main(){ | ||||||
|         return 2; |         return 2; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     tiny_utf8::string importedString = JavaCompat::importJavaString(reinterpret_cast<uint8_t*>(javaStdString.data()), 0x75).value; |     tiny_utf8::string importedString = JavaCompat::importJavaString(reinterpret_cast<uint8_t*>(javaStdString.data())); | ||||||
| 
 | 
 | ||||||
|     std::streampos normalSize; |     std::streampos normalSize; | ||||||
|     std::string normalStdString; |     std::string normalStdString; | ||||||
|  | @ -75,30 +75,9 @@ int main(){ | ||||||
| 
 | 
 | ||||||
|     tiny_utf8::string normalString = tiny_utf8::string(normalStdString); |     tiny_utf8::string normalString = tiny_utf8::string(normalStdString); | ||||||
| 
 | 
 | ||||||
|     // check for normal operation
 |  | ||||||
|     ASSERT(normalString == importedString); |     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; |     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; | return 0; | ||||||
|     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; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,446 @@ | ||||||
|  | // 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; | ||||||
|  | } | ||||||
|  | @ -1,584 +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 <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; |  | ||||||
| } |  | ||||||
|  | @ -1,257 +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 "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
											
										
									
								
							|  | @ -1,116 +0,0 @@ | ||||||
| // 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; |  | ||||||
| } |  | ||||||
|  | @ -1,130 +0,0 @@ | ||||||
| // 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,360 +13,8 @@ | ||||||
| // version 3 along with this program.
 | // version 3 along with this program.
 | ||||||
| // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | ||||||
| 
 | 
 | ||||||
| #include <iostream> | #include "../lib/nbt.h++" | ||||||
| #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[]) { | int main(int argc, char* argv[]) { | ||||||
|     std::vector<CLI::Flag> flags; |     return 0; | ||||||
|     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,8 +1,5 @@ | ||||||
| //Copyright 2022, FOSS-VG Developers and Contributers
 | //Copyright 2022, FOSS-VG Developers and Contributers
 | ||||||
| //
 | //
 | ||||||
| // Author(s):
 |  | ||||||
| //   BodgeMaster, Shwoomple
 |  | ||||||
| //
 |  | ||||||
| //This program is free software: you can redistribute it and/or modify it
 | //This program is free software: you can redistribute it and/or modify it
 | ||||||
| //under the terms of the GNU Affero General Public License as published
 | //under the terms of the GNU Affero General Public License as published
 | ||||||
| //by the Free Software Foundation, version 3.
 | //by the Free Software Foundation, version 3.
 | ||||||
|  | @ -16,479 +13,68 @@ | ||||||
| //version 3 along with this program.
 | //version 3 along with this program.
 | ||||||
| //If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | //If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
 | ||||||
| 
 | 
 | ||||||
| #include <chrono> |  | ||||||
| #include <csignal> |  | ||||||
| #include <iomanip> |  | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <mutex> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <sockpp/tcp_acceptor.h> | #include <cstdint> | ||||||
| #include <sockpp/tcp_connector.h> | #include <cctype> | ||||||
| #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/cli.hpp" | #include "../lib/error.h++" | ||||||
| #include "../lib/error.hpp" | #include "../lib/cli.h++" | ||||||
| 
 | 
 | ||||||
| #define EXIT_SUCCESS 0 | #define EXIT_SUCCESS 0 | ||||||
| #define EXIT_RUNTIME 1 | #define EXIT_RUNTIME 1 | ||||||
| #define EXIT_USAGE 2 | #define EXIT_USAGE 2 | ||||||
| #define EXIT_UNIMPLEMENTED 3 | #define EXIT_UNIMPLEMENTED 3 | ||||||
| #define EXIT_SIGNAL 4 |  | ||||||
| 
 | 
 | ||||||
| // TCP v4 server
 | int main(int argc, char* argv[]){ | ||||||
| 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; |     // Argument parsing ################################################
 | ||||||
| 
 |     bool ipv4 = true; | ||||||
| bool ipv4 = false; |     bool ipv6 = true; | ||||||
| bool ipv6 = false; |     bool tcp = true; | ||||||
| bool tcp = false; |     bool udp = true; | ||||||
| bool udp = false; |     bool listen = false; | ||||||
| bool outgoing = false; |     std::string host; | ||||||
| std::string host; |     uint16_t port; | ||||||
| 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[]) { |  | ||||||
|     std::signal(SIGINT, signalHandler); |  | ||||||
|     std::signal(SIGTERM, signalHandler); |  | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Flag> flags; |     std::vector<CLI::Flag> flags; | ||||||
|     flags.push_back(CLI::Flag('4', "ipv4", "use IPv4, either this or IPv6 has to be specified")); |     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, either this or IPv4 has to be 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, either this or UDP has to be 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, either this or TCP has to be 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('h', "help", "print this information and exit")); |  | ||||||
|     flags.push_back(CLI::Flag('l', "license", "print license information and exit")); |  | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Option> options; |     std::vector<CLI::UnpositionalArgument> unpositionalArguments; | ||||||
|     options.push_back(CLI::Option('c', "connect", "HOST", "make an outgoing connection to HOST instead of listening for an incoming connection")); |     unpositionalArguments.push_back(CLI::UnpositionalArgument('c', "connect", "HOST", "connect to HOST, listen for incoming connections if omitted")); | ||||||
|     options.push_back(CLI::Option('b', "bind", "ADDRESS", "(UDP only) bind to ADDRESS instead of localhost")); |  | ||||||
| 
 | 
 | ||||||
|     std::vector<CLI::Argument> arguments; |     std::vector<CLI::PositionalArgument> positionalArguments; | ||||||
|     arguments.push_back(CLI::Argument("PORT", "the port to lsiten on (or connect to)")); |     positionalArguments.push_back(CLI::PositionalArgument("PORT", "the port to use")); | ||||||
| 
 | 
 | ||||||
|     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."); |     CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, unpositionalArguments, positionalArguments); | ||||||
| 
 | 
 | ||||||
|     if (cliParser.getFlag("help").value) { |  | ||||||
|         std::cout << cliParser.getUsage() << std::endl; |  | ||||||
|         return EXIT_SUCCESS; |  | ||||||
|     } |  | ||||||
|     if (cliParser.getFlag("license").value) { |  | ||||||
|         std::cout |  | ||||||
|             << "Copyright 2022, FOSS-VG Developers and Contributers\n" |  | ||||||
|             << "\n" |  | ||||||
|             << "Hexnet is part of the FOSS-VG development tool suite.\n" |  | ||||||
|             << "\n" |  | ||||||
|             << "This program is free software: you can redistribute it and/or modify it\n" |  | ||||||
|             << "under the terms of the GNU Affero General Public License as published\n" |  | ||||||
|             << "by the Free Software Foundation, version 3.\n" |  | ||||||
|             << "\n" |  | ||||||
|             << "This program is distributed in the hope that it will be useful,\n" |  | ||||||
|             << "but WITHOUT ANY WARRANTY; without even the implied\n" |  | ||||||
|             << "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" |  | ||||||
|             << "See the GNU Affero General Public License for more details.\n" |  | ||||||
|             << "\n" |  | ||||||
|             << "You should have received a copy of the GNU Affero General Public License\n" |  | ||||||
|             << "version 3 along with this program.\n" |  | ||||||
|             << "If not, see https://www.gnu.org/licenses/agpl-3.0.en.html" |  | ||||||
|             << std::endl; |  | ||||||
|         return EXIT_SUCCESS; |  | ||||||
|     } |  | ||||||
|     if (cliParser.wrongUsage) { |     if (cliParser.wrongUsage) { | ||||||
|         std::cout << cliParser.getUsage() << std::endl; |         //TODO: spit out usage information generated by the parser
 | ||||||
|         return EXIT_USAGE; |         return EXIT_USAGE; | ||||||
|     } |     } | ||||||
| 
 |     if (cliParser.getFlag('4').value || cliParser.getFlag('6').value) { | ||||||
|     ipv4 = cliParser.getFlag("ipv4").value; |         ipv4 = cliParser.getFlag('4').value; | ||||||
|     ipv6 = cliParser.getFlag("ipv6").value; |         ipv6 = cliParser.getFlag('6').value; | ||||||
|     tcp = cliParser.getFlag("tcp").value; |  | ||||||
|     udp = cliParser.getFlag("udp").value; |  | ||||||
| 
 |  | ||||||
|     if (cliParser.getOption("connect").errorCode != ErrorCodes::NOT_PRESENT) { |  | ||||||
|         outgoing = true; |  | ||||||
|         host = cliParser.getOption("connect").value; |  | ||||||
|     } |     } | ||||||
| 
 |     if (cliParser.getFlag('t').value || cliParser.getFlag('u').value) { | ||||||
|     if (!(ipv4 || ipv6) || (ipv4 && ipv6) || !(tcp || udp) || (tcp && udp)) { |         tcp = cliParser.getFlag('t').value; | ||||||
|         std::cout << "Please specify which protocols to use (one of IPv4/IPv6, one of TCP/UDP)." << std::endl; |         udp = cliParser.getFlag('u').value; | ||||||
|         return EXIT_USAGE; |  | ||||||
|     } |     } | ||||||
| 
 |     if (cliParser.getUnpositionalArgument('c').errorCode == ErrorCodes::NOT_PRESENT) { | ||||||
|     port = (in_port_t) std::stoi(cliParser.getArgument(0).value); |         listen = true; | ||||||
| 
 |  | ||||||
|     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; |  | ||||||
|     } |     } | ||||||
|  |     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::thread threadReadFromTCP = std::thread(readFromTCP); |     std::cerr << "Port: " << (int) port << std::endl; | ||||||
|                 std::thread threadWriteToTCP = std::thread(writeToTCP); |     std::cerr << (listen? "Listening" : "Host: ") << host << std::endl; | ||||||
| 
 |     std::cerr << "IPv4: " << (ipv4? "yes" : "no") << std::endl; | ||||||
|                 threadReadFromTCP.join(); |     std::cerr << "IPv6: " << (ipv6? "yes" : "no") << std::endl; | ||||||
|                 threadWriteToTCP.join(); |     std::cerr << "TCP:  " << ( tcp? "yes" : "no") << std::endl; | ||||||
| 
 |     std::cerr << "UDP:  " << ( udp? "yes" : "no") << std::endl; | ||||||
|                 std::cout << std::endl; |     return EXIT_UNIMPLEMENTED; | ||||||
|                 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