Compare commits

..

11 Commits

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

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

Splitting one of Joca’s commits by topic - Bodge

Add zlibutil.cpp and zlib to the project's dependencies. - Joca
2024-06-08 15:06:50 +02:00
22 changed files with 323 additions and 209 deletions

View File

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

View File

@ -59,3 +59,9 @@ Usage: `check_endianness > header_file`
Note that, while this tool should in theory be able to detect
PDP and Honeywell-316-style endianness, the FOSS-VG project itself
does not support these.
## region_files
Exactly what the name says. At this point just a random region file I grabbed
from Minecraft, will probably contain synthetic files for test cases in the
future as well.

Binary file not shown.

View File

@ -5,9 +5,18 @@ else
VERBOSE=false
fi
if [ "$1" = "-n" ]; then
DECOMPRESS=false
shift
else
DECOMPRESS=true
fi
if [ ! -f "$1" ]; then
echo "Usage: $0 [-v] FILE"
echo "Usage: $0 [-v] [-n] FILE"
echo " -v display raw content and NBT dump"
echo " -n don't decompress"
exit 1
fi
@ -62,13 +71,20 @@ sys.stdout.buffer.flush()
esac
echo " format: $FORMAT ($FORMAT_HEX)"
if $DECOMPRESS; then
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null | UNCOMPRESS > /tmp/chunk_uncompressed_nbt
else
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null > /tmp/chunk_compressed_nbt
fi
if $VERBOSE; then
echo "Raw chunk data:"
echo "$DATA"
echo "NBT dump:"
#TODO: use pipes instead of a file
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null | UNCOMPRESS > /tmp/chunk_uncompressed_nbt
#TODO: fix this up to work with both compressed and uncompressed NBT
dumpnbt /tmp/chunk_uncompressed_nbt
rm /tmp/chunk_uncompressed_nbt
fi

View File

@ -35,10 +35,19 @@ fi
# dynamically linked libraries.
echo ">>> Building libs..."
create_directory bin/lib
for lib in $(find ./src/lib -name "*.cpp"); do
COMPILE_COMMAND="$CXX_WITH_FLAGS -I ./include -fPIC -shared -o $(sed -e 's/^.\/src/.\/bin/;s/cpp$/so/' <<< $lib) $lib"
echo $COMPILE_COMMAND
$COMPILE_COMMAND &
COMPILE_COMMANDS=(
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/net/connection.so ./src/lib/net/connection.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/cli.so ./src/lib/cli.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/file.so ./src/lib/file.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/game/block.so ./src/lib/game/block.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/game/entity.so ./src/lib/game/entity.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/nbt.so ./src/lib/nbt.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -o ./bin/lib/region.so ./src/lib/region.cpp"
"$CXX_WITH_FLAGS -I ./include -fPIC -shared -l:libz.so -o ./bin/lib/zlibutil.so ./src/lib/zlibutil.cpp"
)
for command in ${!COMPILE_COMMANDS[@]}; do
echo "${COMPILE_COMMANDS[command]}"
${COMPILE_COMMANDS[command]} &
$WAIT_ANYWAY
done
@ -62,7 +71,7 @@ COMPILE_COMMANDS=(
"$CXX_WITH_FLAGS src/tools/dumpnbt.cpp -I./include -Lbin/lib -l:nbt.so -l:cli.so -o bin/tools/dumpnbt"
"$CXX_WITH_FLAGS src/tools/arraydump.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -o bin/tools/arraydump"
"$CXX_WITH_FLAGS src/tools/baseconvert.cpp -I./include -Lbin/lib -l:cli.so -o bin/tools/baseconvert"
"$CXX_WITH_FLAGS src/tools/zlibutil.cpp -I./include -Lbin/lib -l:cli.so -l:libz.so -l:file.so -l:zlibutil.so -o bin/tools/zlibutil"
"$CXX_WITH_FLAGS src/tools/zlibutil.cpp -I./include -Lbin/lib -l:cli.so -l:file.so -l:zlibutil.so -l:libz.so -o bin/tools/zlibutil"
"$CXX_WITH_FLAGS -pthread src/tools/hexnet.cpp -I./include -Lbin/lib -l:cli.so -l:libsockpp.so -o bin/tools/hexnet"
"$CXX_WITH_FLAGS -DFOSSVG_DEBUG src/fossvg.cpp -I./include -Lbin/lib -l:file.so -l:cli.so -lglfw -lvulkan -o bin/fossvg"
"$CXX_WITH_FLAGS src/fossvgd.cpp -I./include -Lbin/lib -l:cli.so -o bin/fossvgd"

View File

@ -39,6 +39,7 @@ fi
ln -vs ../dependencies/sockpp-0.8.1/include/sockpp/ ./include/
ln -vs ../dependencies/tiny-utf8-4.4.3/include/tinyutf8/ ./include/
ln -vs ../dependencies/zlib-1.3.1/ ./include/zlib
create_file ./bin/.placeholder
create_file ./include/.placeholder

View File

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

61
scripts/download.sh Executable file
View File

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

View File

@ -59,16 +59,16 @@ fi
function remove {
local USE_FORCE=""
if [ "$1" = "-f" ]; then
USE_FORCE="-f"
USE_FORCE="f"
shift
echo "Forcefully removing $1..."
else
echo "Removing $1..."
fi;
shift
if [ -d "$1" ]; then
rm "$USE_FORCE" -rv "$1"
rm -"$USE_FORCE"rv "$1"
else
rm "$USE_FORCE" -v "$1"
rm -"$USE_FORCE"v "$1"
fi
}

View File

@ -17,74 +17,19 @@
source scripts/lib.sh
echo -n "Wget or curl? "
if command -v wget >/dev/null 2>&1; then
USE_WGET=yes
echo "wget"
else
if command -v curl >/dev/null 2>&1; then
USE_WGET=no
echo "curl"
else
echo "Found neither wget nor curl. Aborting."
exit 1
fi
fi
function download {
URL="$1"
DESTINATION="$2"
SHA256SUM="$3"
if [ ! -d .download_cache ]; then
echo "Cache directory missing."
create_directory .download_cache
fi
if [ -f ".download_cache/$SHA256SUM" ]; then
if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then
echo "Using locally cached file for $DESTINATION"
cp ".download_cache/$SHA256SUM" "$DESTINATION"
return 0
else
echo "Locally cached file for $DESTINATION is corrupted."
rm ".download_cache/$SHA256SUM"
download "$URL" "$DESTINATION" "$SHA256SUM"
return $?
fi
else
echo -n "Downloading $URL to $DESTINATION... "
if [ $USE_WGET = yes ]; then
wget -O ".download_cache/$SHA256SUM" "$URL" >/dev/null 2>&1
else
curl -L "$URL" --output ".download_cache/$SHA256SUM" >/dev/null 2>&1
fi
if check_sha256 ".download_cache/$SHA256SUM" "$SHA256SUM"; then
cp ".download_cache/$SHA256SUM" "$DESTINATION"
echo "done."
return 0
else
echo "error."
echo "Checksum verification failed. Your download is either corrupted or the file has been altered. Removing file."
rm ".download_cache/$SHA256SUM"
return 1
fi
fi
}
scripts/clean.sh
scripts/clean_dependencies.sh
set -e # failures are not acceptable here
create_directory dependencies/tmp
download https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f
download https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.8.1.tar.gz dependencies/tmp/sockpp.tar.gz a8aedff8bd8c1da530b91be650352008fddabc9f1df0d19701d76cbc359c8651
download https://www.zlib.net/zlib-1.3.tar.gz dependencies/tmp/zlib-1.3.tar.gz ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e
scripts/download.sh https://github.com/DuffsDevice/tiny-utf8/archive/refs/tags/v4.4.3.tar.gz dependencies/tmp/tiny-utf8.tar.gz 8e3f61651909c9f3105d3501932a96aa65733127fb6e7cf94cb1b0a2dff42c8f
scripts/download.sh https://github.com/fpagliughi/sockpp/archive/refs/tags/v0.8.1.tar.gz dependencies/tmp/sockpp.tar.gz a8aedff8bd8c1da530b91be650352008fddabc9f1df0d19701d76cbc359c8651
scripts/download.sh https://www.zlib.net/zlib-1.3.1.tar.xz dependencies/tmp/zlib.tar.xz 38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32
#TODO: figure out how to cache shaderc
#also TODO: target a specific commit
git clone --branch known-good https://github.com/google/shaderc.git dependencies/tmp/shaderc
#download https://github.com/google/shaderc/archive/refs/tags/v2023.7.tar.gz dependencies/tmp/shaderc.tar.gz 681e1340726a0bf46bea7e31f10cbfe78e01e4446a35d90fedc2b78d400fcdeb
#scripts/download.sh https://github.com/google/shaderc/archive/refs/tags/v2023.7.tar.gz dependencies/tmp/shaderc.tar.gz 681e1340726a0bf46bea7e31f10cbfe78e01e4446a35d90fedc2b78d400fcdeb
echo -n ">>> Extracting tiny-utf8... "
gzip -d dependencies/tmp/tiny-utf8.tar.gz
@ -97,11 +42,8 @@ tar -xf dependencies/tmp/sockpp.tar -C dependencies
echo "done"
echo -n ">>> Extracting zlib... "
gzip -d dependencies/tmp/zlib-1.3.tar.gz
tar -xf dependencies/tmp/zlib-1.3.tar -C dependencies
cd include/
ln -vs ../dependencies/zlib-1.3/ zlib
cd ..
xz -d dependencies/tmp/zlib.tar.xz
tar -xf dependencies/tmp/zlib.tar -C dependencies
echo "done"
echo ">>> Building sockpp..."
@ -148,9 +90,10 @@ cp -v "dependencies/tmp/shaderc/$SHADERC_BUILD/glslc/glslc" dependencies/shaderc
echo ">>> done"
echo ">>> Building zlib..."
cd dependencies/zlib-1.3/
pushd dependencies/zlib-1.3.1/
./configure
make
popd
echo "done"
echo ">>> Cleaning up..."

View File

@ -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

View File

@ -1,26 +1,46 @@
#!/usr/bin/env bash
echo "================================================================================"
echo -n "Testing \`zlibutil\`... "
echo "Testing \`zlibutil\`:"
echo "--------------------------------------------------------------------------------"
TMPDIR="$(mktemp -d -t fossvg-zlibutil-XXXXX)"
TMPDATA="$(dd if=/dev/urandom bs=33 count=1 2>/dev/null | base64)"
echo "abc" >> testfile
echo -n "Compression test... "
bin/tools/zlibutil -c testfile
echo -n "$TMPDATA" >> "$TMPDIR/compress"
zlibutil "$TMPDIR/compress"
if [ "$(bin/tools/arraydump --binary testfile.compressed)" = "{0b01111000, 0b10011100, 0b01001011, 0b01001100, 0b01001010, 0b11100110, 0b00000010, 0b00000000, 0b00000011, 0b01111110, 0b00000001, 0b00110001}" ]; then
echo -n "Compression Test: PASS... "
python3 <<< "
import zlib, sys
tmpfile = open('$TMPDIR/compress.zz', 'rb')
data = tmpfile.read()
tmpfile.close()
try:
if zlib.decompress(data)==b'$TMPDATA':
print('PASS')
else:
print('FAIL: Wrong data.')
except:
print('FAIL: Exception.')
"
echo -n "Decompression test... "
#TODO: create a compressed file using another implementation (Python)
python3 <<< "
import zlib
tmpfile = open('$TMPDIR/decompress.zz', 'wb')
tmpfile.write(zlib.compress(b'$TMPDATA'))
tmpfile.close()
"
zlibutil -d "$TMPDIR/decompress.zz"
if [ "$(cat "$TMPDIR/decompress")" = "$TMPDATA" ]; then
echo "PASS"
else
echo -n "Compression Test: FAILED... "
echo "FAIL"
fi
bin/tools/zlibutil -d testfile.compressed
if [ "$(bin/tools/arraydump --binary testfile.compressed.uncompressed)" = "{0b01100001, 0b01100010, 0b01100011, 0b00001010}" ]; then
echo "Decompression Test: PASS"
else
echo "Decompression Test: FAILED"
fi
rm testfile testfile.compressed testfile.compressed.uncompressed
rm -r "$TMPDIR"
echo "================================================================================"

View File

@ -17,6 +17,11 @@
#include <cstdint>
//TODO: needed macros:
// TRY: takes a variable, a function call, and the ErrorOr return type of the calling function - intended to automatically unwrap the ErrorOr data type or propagate the error upwards
// RAISE: takes an error code and optionally a message to produce something like `return ErrorOr<T>(true, errorCode, file, lineNumber, message)`
template <typename T>
struct ErrorOr {
bool isError;
@ -100,6 +105,9 @@ namespace ErrorCodes {
// when too much data is available
const uint8_t OVERFLOW = 13;
const uint8_t COMPRESSION = 14;
const uint8_t DECOMPRESSION = 15;
const uint8_t UNIMPLEMENTED = 254;
const uint8_t UNKNOWN = 255;

View File

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

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

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

View File

@ -16,92 +16,101 @@
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include "../lib/zlibutil.hpp"
// includes vector and error.hpp
#include "zlibutil.hpp"
#include <bitset>
#include <iomanip>
#include <iostream>
#include <vector>
#include <tinyutf8/tinyutf8.h>
#include <zlib/zlib.h>
#include <cstring>
#include "../lib/cli.hpp"
#include "../lib/file.hpp"
#define EXIT_SUCCESS 0
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#include <iostream>
#include <fstream>
#include <vector>
#include <zlib.h>
#define CHUNK_SIZE 16384 // Chunk size
namespace zlib {
std::vector<char> compressData(const char* data, int size) {
z_stream zs;
memset(&zs, 0, sizeof(zs));
ErrorOr<std::vector<uint8_t>> compressData(std::vector<uint8_t> data) {
// I, too, love the fact that raw bytes are signed and therefore can have negative values. -_-
std::vector<int8_t> signedData = std::vector<int8_t>(data.begin(), data.end());
if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK)
throw(std::runtime_error("deflateInit failed while compressing."));
z_stream zs;
memset(&zs, 0, sizeof(zs));
zs.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
zs.avail_in = size;
if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::COMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("deflateInit failed while compressing."));
}
int ret;
char outbuffer[CHUNK_SIZE];
std::vector<char> compressedData;
zs.next_in = reinterpret_cast<Bytef*>(reinterpret_cast<char*>(signedData.data()));
zs.avail_in = signedData.size();
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = CHUNK_SIZE;
int ret;
char outbuffer[CHUNK_SIZE];
std::vector<char> compressedData;
ret = deflate(&zs, Z_FINISH);
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = CHUNK_SIZE;
if (compressedData.size() < zs.total_out)
compressedData.insert(compressedData.end(), outbuffer, outbuffer + CHUNK_SIZE - zs.avail_out);
} while (ret == Z_OK);
ret = deflate(&zs, Z_FINISH);
deflateEnd(&zs);
if (compressedData.size() < zs.total_out)
compressedData.insert(compressedData.end(), outbuffer, outbuffer + CHUNK_SIZE - zs.avail_out);
} while (ret == Z_OK);
if (ret != Z_STREAM_END)
throw(std::runtime_error("Error while compressing: " + std::to_string(ret)));
deflateEnd(&zs);
if (ret != Z_STREAM_END) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::COMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("Error while compressing: " + std::to_string(ret)));
}
return ErrorOr<std::vector<uint8_t>>(std::vector<uint8_t>(compressedData.begin(), compressedData.end()));
}
ErrorOr<std::vector<uint8_t>> decompressData(std::vector<uint8_t> data) {
// I, too, love the fact that raw bytes are signed and therefore can have negative values. -_-
std::vector<int8_t> signedData = std::vector<int8_t>(data.begin(), data.end());
z_stream zs;
memset(&zs, 0, sizeof(zs));
if (inflateInit(&zs) != Z_OK) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::DECOMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("inflateInit failed while decompressing."));
}
zs.next_in = reinterpret_cast<Bytef*>(reinterpret_cast<char*>(signedData.data()));
zs.avail_in = signedData.size();
int ret;
char outbuffer[CHUNK_SIZE];
std::vector<char> decompressedData;
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = CHUNK_SIZE;
ret = inflate(&zs, 0);
if (decompressedData.size() < zs.total_out)
decompressedData.insert(decompressedData.end(), outbuffer, outbuffer + CHUNK_SIZE - zs.avail_out);
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::DECOMPRESSION);
//TODO: include error message once implemented
//throw(std::runtime_error("Error while decompressing: " + std::to_string(ret)));
}
return ErrorOr<std::vector<uint8_t>>(std::vector<uint8_t>(decompressedData.begin(), decompressedData.end()));
}
return compressedData;
}
std::vector<char> decompressData(const char* data, int size) {
z_stream zs;
memset(&zs, 0, sizeof(zs));
if (inflateInit(&zs) != Z_OK)
throw(std::runtime_error("inflateInit failed while decompressing."));
zs.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
zs.avail_in = size;
int ret;
char outbuffer[CHUNK_SIZE];
std::vector<char> decompressedData;
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = CHUNK_SIZE;
ret = inflate(&zs, 0);
if (decompressedData.size() < zs.total_out)
decompressedData.insert(decompressedData.end(), outbuffer, outbuffer + CHUNK_SIZE - zs.avail_out);
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END)
throw(std::runtime_error("Error while decompressing: " + std::to_string(ret)));
return decompressedData;
}

View File

@ -16,12 +16,12 @@
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#pragma once
#include <vector>
#include "error.hpp"
#ifndef ZLIBUTIL_H
#define ZLIBUTIL_H
std::vector<char> compressData(const char* data, int size);
std::vector<char> decompressData(const char* data, int size);
#endif // ZLIBUTIL_H
namespace zlib {
ErrorOr<std::vector<uint8_t>> compressData(std::vector<uint8_t> data);
ErrorOr<std::vector<uint8_t>> decompressData(std::vector<uint8_t> data);
}

View File

@ -23,6 +23,7 @@
#include <tinyutf8/tinyutf8.h>
#include <zlib/zlib.h>
#include <cstring>
#include <fstream>
#include "../lib/cli.hpp"
#include "../lib/file.hpp"
@ -32,10 +33,10 @@
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#define CHUNK_SIZE 16384 // Chunk size
/*
Finnaly, the main file
Finally, the main file
@ -65,8 +66,7 @@ Finnaly, the main file
int main(int argc, char* argv[]) {
std::vector<CLI::Flag> flags;
flags.push_back(CLI::Flag('c', "compress", "compress a file"));
flags.push_back(CLI::Flag('d', "decompress", "descompress a file"));
flags.push_back(CLI::Flag('d', "decompress", "descompress a file"));
std::vector<CLI::Option> options;
std::vector<CLI::Argument> arguments;
arguments.push_back(CLI::Argument("FILE", "path of the file to compress/decompress"));
@ -104,32 +104,39 @@ int main(int argc, char* argv[]) {
return EXIT_USAGE;
}
std::string filename = cliParser.getArgument(0).value;
ErrorOr<File*> filePointer = File::open(cliParser.getArgument(0).value, 'r');
ErrorOr<File*> filePointer = File::open(filename, 'r');
if (filePointer.isError) {
std::cout << "Failed to open file: " << cliParser.getArgument(0).value << std::endl;
std::cout << "Failed to open file: " << filename << std::endl;
return EXIT_RUNTIME;
}
File* file = filePointer.value;
File *writeFile;
if (cliParser.getFlag("compress").value) {
std::vector<uint8_t> bytes = file->read(file->size.value).value; // this is what you get from lib/file IIRC
std::vector<char> differentBytes = std::vector<char>(bytes.begin(), bytes.end());
std::vector<char> compressed = compressData(differentBytes.data(), file->size.value);
std::vector<unsigned char> unsigneddata = std::vector<unsigned char>(compressed.begin(), compressed.end());
writeFile = File::open(cliParser.getArgument(0).value + ".compressed", 'w').value;
writeFile->write(unsigneddata);
writeFile->close();
} else if (cliParser.getFlag("decompress").value) {
if (cliParser.getFlag("decompress").value) {
std::vector<uint8_t> bytes = file->read(file->size.value).value; // this is what you get from lib/file IIRC
std::vector<char> differentBytes = std::vector<char>(bytes.begin(), bytes.end());
std::vector<char> compressed = decompressData(differentBytes.data(), file->size.value);
std::vector<unsigned char> unsigneddata = std::vector<unsigned char>(compressed.begin(), compressed.end());
writeFile = File::open(cliParser.getArgument(0).value + ".uncompressed", 'w').value;
std::string outFilename;
if (filename.length() > 3 && filename.rfind(".zz") == filename.length()-3) {
outFilename = filename.substr(0, filename.length()-3);
} else {
outFilename = filename + ".uncompressed";
}
writeFile = File::open(outFilename, 'w').value;
writeFile->write(unsigneddata);
writeFile->close();
} else {
std::vector<uint8_t> bytes = file->read(file->size.value).value; // this is what you get from lib/file IIRC
std::vector<char> differentBytes = std::vector<char>(bytes.begin(), bytes.end());
std::vector<char> compressed = compressData(differentBytes.data(), file->size.value);
std::vector<unsigned char> unsigneddata = std::vector<unsigned char>(compressed.begin(), compressed.end());
writeFile = File::open(filename + ".zz", 'w').value;
writeFile->write(unsigneddata);
writeFile->close();
}