LibCompress: Add LibCompress

For now this only contains DEFLATE, and a very simple Zlib
Eventually GZip, etc. can go here as well.
This commit is contained in:
stelar7 2020-08-01 22:01:39 +02:00 committed by Andreas Kling
parent 567845c480
commit 98e18d7339
Notes: sideshowbarker 2024-07-19 04:20:16 +09:00
9 changed files with 764 additions and 1 deletions

View File

@ -3,6 +3,7 @@ add_subdirectory(LibC)
add_subdirectory(LibCore)
add_subdirectory(LibCrypt)
add_subdirectory(LibCrypto)
add_subdirectory(LibCompress)
add_subdirectory(LibDebug)
add_subdirectory(LibDesktop)
add_subdirectory(LibGemini)

View File

@ -0,0 +1,7 @@
set(SOURCES
Deflate.cpp
Zlib.cpp
)
serenity_lib(LibCompress compression)
target_link_libraries(LibCompress LibC)

View File

@ -0,0 +1,428 @@
/*
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/Assertions.h>
#include <AK/LogStream.h>
#include <AK/Span.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibCompress/Deflate.h>
namespace Compress {
Vector<u8> Deflate::decompress()
{
bool is_final_block = false;
do {
is_final_block = m_reader.read();
auto block_type = m_reader.read_bits(2);
switch (block_type) {
case 0:
decompress_uncompressed_block();
break;
case 1:
decompress_static_block();
break;
case 2:
decompress_dynamic_block();
break;
case 3:
dbg() << "Block contains reserved block type...";
ASSERT_NOT_REACHED();
break;
default:
dbg() << "Invalid block type was read...";
ASSERT_NOT_REACHED();
break;
}
} while (!is_final_block);
return m_output_buffer;
}
void Deflate::decompress_uncompressed_block()
{
// Align to the next byte boundary.
while (m_reader.get_bit_byte_offset() != 0) {
m_reader.read();
}
auto length = m_reader.read_bits(16) & 0xFFFF;
auto negated_length = m_reader.read_bits(16) & 0xFFFF;
if ((length ^ 0xFFFF) != negated_length) {
dbg() << "Block length is invalid...";
ASSERT_NOT_REACHED();
}
for (size_t i = 0; i < length; i++) {
auto byte = m_reader.read_byte();
if (byte < 0) {
dbg() << "Ran out of bytes while reading uncompressed block...";
ASSERT_NOT_REACHED();
}
m_output_buffer.append(byte);
m_history_buffer.enqueue(byte);
}
}
void Deflate::decompress_static_block()
{
decompress_huffman_block(m_literal_length_codes, &m_fixed_distance_codes);
}
void Deflate::decompress_dynamic_block()
{
auto codes = decode_huffman_codes();
if (codes.size() == 2) {
decompress_huffman_block(codes[0], &codes[1]);
} else {
decompress_huffman_block(codes[0], nullptr);
}
}
void Deflate::decompress_huffman_block(CanonicalCode& length_codes, CanonicalCode* distance_codes)
{
for (;;) {
u32 symbol = length_codes.next_symbol(m_reader);
// End of block.
if (symbol == 256) {
break;
}
// literal byte.
if (symbol < 256) {
m_history_buffer.enqueue(symbol);
m_output_buffer.append(symbol);
continue;
}
// Length and distance for copying.
ASSERT(distance_codes);
auto run = decode_run_length(symbol);
if (run < 3 || run > 258) {
dbg() << "Invalid run length";
ASSERT_NOT_REACHED();
}
auto distance_symbol = distance_codes->next_symbol(m_reader);
auto distance = decode_distance(distance_symbol);
if (distance < 1 || distance > 32768) {
dbg() << "Invalid distance";
ASSERT_NOT_REACHED();
}
copy_from_history(distance, run);
}
}
Vector<CanonicalCode> Deflate::decode_huffman_codes()
{
// FIXME: This path is not tested.
Vector<CanonicalCode> result;
auto length_code_count = m_reader.read_bits(5) + 257;
auto distance_code_count = m_reader.read_bits(5) + 1;
size_t length_code_code_length = m_reader.read_bits(4) + 4;
Vector<u8> code_length_code_length;
code_length_code_length.resize(19);
code_length_code_length[16] = m_reader.read_bits(3);
code_length_code_length[17] = m_reader.read_bits(3);
code_length_code_length[18] = m_reader.read_bits(3);
code_length_code_length[0] = m_reader.read_bits(3);
for (size_t i = 0; i < length_code_code_length; i++) {
auto index = (i % 2 == 0) ? (8 + (i / 2)) : (7 - (i / 2));
code_length_code_length[index] = m_reader.read_bits(3);
}
auto code_length_code = CanonicalCode(code_length_code_length);
Vector<u32> code_lens;
code_lens.resize(length_code_count + distance_code_count);
for (size_t index = 0; index < code_lens.capacity();) {
auto symbol = code_length_code.next_symbol(m_reader);
if (symbol <= 15) {
code_lens[index] = symbol;
index++;
continue;
}
u32 run_length;
u32 run_value = 0;
if (symbol == 16) {
if (index == 0) {
dbg() << "No code length value avaliable";
ASSERT_NOT_REACHED();
}
run_length = m_reader.read_bits(2) + 3;
run_value = code_lens[index - 1];
} else if (symbol == 17) {
run_length = m_reader.read_bits(3) + 3;
} else if (symbol == 18) {
run_length = m_reader.read_bits(7) + 11;
} else {
dbg() << "Code symbol is out of range!";
ASSERT_NOT_REACHED();
}
u32 end = index + run_length;
if (end > code_lens.capacity()) {
dbg() << "Code run is out of range!";
ASSERT_NOT_REACHED();
}
memset(code_lens.data() + index, run_value, run_length);
index = end;
}
Vector<u8> literal_codes;
literal_codes.resize(length_code_count);
memcpy(literal_codes.data(), code_lens.data(), literal_codes.capacity());
result.append(CanonicalCode(literal_codes));
Vector<u8> distance_codes;
distance_codes.resize(distance_code_count);
memcpy(distance_codes.data(), code_lens.data() + length_code_count, distance_codes.capacity());
if (distance_code_count == 1 && distance_codes[0] == 0) {
return result;
}
u8 one_count = 0;
u8 other_count = 0;
for (size_t i = 0; i < distance_codes.capacity(); i++) {
u8 value = distance_codes.at(i);
if (value == 1) {
one_count++;
} else if (value > 1) {
other_count++;
}
}
if (one_count == 1 && other_count == 0) {
distance_codes.resize(32);
distance_codes[31] = 1;
}
result.append(CanonicalCode(distance_codes));
return result;
}
u32 Deflate::decode_run_length(u32 symbol)
{
if (symbol <= 264) {
return symbol - 254;
}
if (symbol <= 284) {
auto extra_bits = (symbol - 261) / 4;
return ((((symbol - 265) % 4) + 4) << extra_bits) + 3 + m_reader.read_bits(extra_bits);
}
if (symbol == 285) {
return 258;
}
dbg() << "Found invalid symbol in run length " << symbol;
ASSERT_NOT_REACHED();
}
u32 Deflate::decode_distance(u32 symbol)
{
if (symbol <= 3) {
return symbol + 1;
}
if (symbol <= 29) {
auto extra_bits = (symbol / 2) - 1;
return (((symbol % 2) + 2) << extra_bits) + 1 + m_reader.read_bits(extra_bits);
}
dbg() << "Found invalid symbol in distance" << symbol;
ASSERT_NOT_REACHED();
}
void Deflate::copy_from_history(u32 distance, u32 run)
{
auto head_index = (m_history_buffer.head_index() + m_history_buffer.size()) % m_history_buffer.capacity();
auto read_index = (head_index - distance + m_history_buffer.capacity()) % m_history_buffer.capacity();
for (size_t i = 0; i < run; i++) {
auto data = m_history_buffer.at(read_index++);
m_output_buffer.append(data);
m_history_buffer.enqueue(data);
}
}
i8 BitStreamReader::read()
{
if (m_current_byte == -1) {
return -1;
}
if (m_remaining_bits == 0) {
if (m_data_index + 1 > m_data.size())
return -1;
m_current_byte = m_data.at(m_data_index++);
m_remaining_bits = 8;
}
m_remaining_bits--;
return (m_current_byte >> (7 - m_remaining_bits)) & 1;
}
i8 BitStreamReader::read_byte()
{
m_current_byte = 0;
m_remaining_bits = 0;
if (m_data_index + 1 > m_data.size())
return -1;
return m_data.at(m_data_index++);
}
u8 BitStreamReader::get_bit_byte_offset()
{
return (8 - m_remaining_bits) % 8;
}
u32 BitStreamReader::read_bits(u8 count)
{
ASSERT(count > 0 && count < 32);
u32 result = 0;
for (size_t i = 0; i < count; i++) {
result |= read() << i;
}
return result;
}
Vector<u8> Deflate::generate_literal_length_codes()
{
Vector<u8> ll_codes;
ll_codes.resize(288);
memset(ll_codes.data() + 0, 8, 144 - 0);
memset(ll_codes.data() + 144, 9, 256 - 144);
memset(ll_codes.data() + 256, 7, 280 - 256);
memset(ll_codes.data() + 280, 8, 288 - 280);
return ll_codes;
}
Vector<u8> Deflate::generate_fixed_distance_codes()
{
Vector<u8> fd_codes;
fd_codes.resize(32);
memset(fd_codes.data(), 5, 32);
return fd_codes;
}
CanonicalCode::CanonicalCode(Vector<u8> codes)
{
m_symbol_codes.resize(codes.size());
m_symbol_values.resize(codes.size());
auto allocated_symbols_count = 0;
auto next_code = 0;
for (size_t code_length = 1; code_length <= 15; code_length++) {
next_code <<= 1;
auto start_bit = 1 << code_length;
for (size_t symbol = 0; symbol < codes.size(); symbol++) {
if (codes.at(symbol) != code_length) {
continue;
}
if (next_code > start_bit) {
dbg() << "Canonical code overflows the huffman tree";
ASSERT_NOT_REACHED();
}
m_symbol_codes[allocated_symbols_count] = start_bit | next_code;
m_symbol_values[allocated_symbols_count] = symbol;
allocated_symbols_count++;
next_code++;
}
}
if (next_code != (1 << 15)) {
dbg() << "Canonical code underflows the huffman tree " << next_code;
ASSERT_NOT_REACHED();
}
}
i32 binary_search(Vector<u32>& heystack, u32 needle)
{
i32 low = 0;
i32 high = heystack.size();
while (low <= high) {
u32 mid = (low + high) >> 1;
u32 value = heystack.at(mid);
if (value < needle) {
low = mid + 1;
} else if (value > needle) {
high = mid - 1;
} else {
return mid;
}
}
return -1;
}
u32 CanonicalCode::next_symbol(BitStreamReader& reader)
{
auto code_bits = 1;
for (;;) {
code_bits = code_bits << 1 | reader.read();
i32 index = binary_search(m_symbol_codes, code_bits);
if (index >= 0) {
return m_symbol_values.at(index);
}
}
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/CircularQueue.h>
#include <AK/Span.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <cstring>
namespace Compress {
// Reads one bit at a time starting with the rightmost bit
class BitStreamReader {
public:
BitStreamReader(ReadonlyBytes data)
: m_data(data)
{
}
i8 read();
i8 read_byte();
u32 read_bits(u8);
u8 get_bit_byte_offset();
private:
ReadonlyBytes m_data;
size_t m_data_index { 0 };
i8 m_current_byte { 0 };
u8 m_remaining_bits { 0 };
};
class CanonicalCode {
public:
CanonicalCode(Vector<u8>);
u32 next_symbol(BitStreamReader&);
private:
Vector<u32> m_symbol_codes;
Vector<u32> m_symbol_values;
};
class Deflate {
public:
Deflate(ReadonlyBytes data)
: m_reader(data)
, m_literal_length_codes(generate_literal_length_codes())
, m_fixed_distance_codes(generate_fixed_distance_codes())
{
}
Vector<u8> decompress();
private:
void decompress_uncompressed_block();
void decompress_static_block();
void decompress_dynamic_block();
void decompress_huffman_block(CanonicalCode&, CanonicalCode*);
Vector<CanonicalCode> decode_huffman_codes();
void copy_from_history(u32, u32);
u32 decode_run_length(u32);
u32 decode_distance(u32);
Vector<u8> generate_literal_length_codes();
Vector<u8> generate_fixed_distance_codes();
BitStreamReader m_reader;
CircularQueue<u8, 32 * 1024> m_history_buffer;
Vector<u8, 256> m_output_buffer;
CanonicalCode m_literal_length_codes;
CanonicalCode m_fixed_distance_codes;
};
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/Assertions.h>
#include <AK/Span.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibCompress/Deflate.h>
#include <LibCompress/Zlib.h>
namespace Compress {
Zlib::Zlib(ReadonlyBytes data)
{
m_input_data = data;
u8 compression_info = data.at(0);
u8 flags = data.at(1);
m_compression_method = compression_info & 0xF;
m_compression_info = (compression_info >> 4) & 0xF;
m_check_bits = flags & 0xF;
m_has_dictionary = (flags >> 5) & 0x1;
m_compression_level = (flags >> 6) & 0x3;
ASSERT(m_compression_method == 8);
ASSERT(m_compression_info == 7);
ASSERT(!m_has_dictionary);
ASSERT((compression_info * 256 + flags) % 31 == 0);
m_data_bytes = data.slice(2, data.size() - 2 - 4);
}
Vector<u8> Zlib::decompress()
{
return Deflate(m_data_bytes).decompress();
}
u32 Zlib::checksum()
{
if (!m_checksum) {
auto bytes = m_input_data.slice(m_input_data.size() - 4, 4);
m_checksum = bytes.at(0) << 24 | bytes.at(1) << 16 | bytes.at(2) << 8 || bytes.at(3);
}
return m_checksum;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/Span.h>
#include <AK/Types.h>
#include <AK/Vector.h>
namespace Compress {
class Zlib {
public:
Zlib(ReadonlyBytes data);
Vector<u8> decompress();
u32 checksum();
private:
u8 m_compression_method;
u8 m_compression_info;
u8 m_check_bits;
u8 m_has_dictionary;
u8 m_compression_level;
u32 m_checksum;
ReadonlyBytes m_input_data;
ReadonlyBytes m_data_bytes;
};
}

View File

@ -49,6 +49,7 @@ file(GLOB LIBMARKDOWN_SOURCES "../../Libraries/LibMarkdown/*.cpp")
file(GLOB LIBX86_SOURCES "../../Libraries/LibX86/*.cpp")
file(GLOB LIBJS_SOURCES "../../Libraries/LibJS/*.cpp")
file(GLOB LIBJS_SUBDIR_SOURCES "../../Libraries/LibJS/*/*.cpp")
file(GLOB LIBCOMPRESS_SOURCES "../../Libraries/LibCompress/*.cpp")
file(GLOB LIBCRYPTO_SOURCES "../../Libraries/LibCrypto/*.cpp")
file(GLOB LIBCRYPTO_SUBDIR_SOURCES "../../Libraries/LibCrypto/*/*.cpp")
file(GLOB LIBTLS_SOURCES "../../Libraries/LibTLS/*.cpp")
@ -56,7 +57,7 @@ file(GLOB SHELL_SOURCES "../../Shell/*.cpp")
file(GLOB SHELL_TESTS "../../Shell/Tests/*.sh")
set(LAGOM_CORE_SOURCES ${AK_SOURCES} ${LIBCORE_SOURCES})
set(LAGOM_MORE_SOURCES ${LIBIPC_SOURCES} ${LIBLINE_SOURCES} ${LIBJS_SOURCES} ${LIBJS_SUBDIR_SOURCES} ${LIBX86_SOURCES} ${LIBCRYPTO_SOURCES} ${LIBCRYPTO_SUBDIR_SOURCES} ${LIBTLS_SOURCES} ${LIBMARKDOWN_SOURCES} ${LIBGEMINI_SOURCES} ${LIBGFX_SOURCES})
set(LAGOM_MORE_SOURCES ${LIBIPC_SOURCES} ${LIBLINE_SOURCES} ${LIBJS_SOURCES} ${LIBJS_SUBDIR_SOURCES} ${LIBX86_SOURCES} ${LIBCRYPTO_SOURCES} ${LIBCOMPRESS_SOURCES} ${LIBCRYPTO_SUBDIR_SOURCES} ${LIBTLS_SOURCES} ${LIBMARKDOWN_SOURCES} ${LIBGEMINI_SOURCES} ${LIBGFX_SOURCES})
include_directories (../../)
include_directories (../../Libraries/)

View File

@ -34,6 +34,7 @@ target_link_libraries(paste LibGUI)
target_link_libraries(pro LibProtocol)
target_link_libraries(su LibCrypt)
target_link_libraries(test-crypto LibCrypto LibTLS LibLine)
target_link_libraries(test-compress LibCompress)
target_link_libraries(test-js LibJS LibLine LibCore)
target_link_libraries(test-web LibWeb)
target_link_libraries(tt LibPthread)

103
Userland/test-compress.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2020, the SerenityOS developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <LibCompress/Deflate.h>
#include <LibCompress/Zlib.h>
#include <LibCore/ArgsParser.h>
auto main(int argc, char** argv) -> int
{
const char* mode = nullptr;
const char* type = nullptr;
Core::ArgsParser parser;
parser.add_positional_argument(type, "Type of algorithm to apply (Only Zlib and DEFLATE is present at the moment)", "type", Core::ArgsParser::Required::No);
parser.add_positional_argument(mode, "Mode to operate in (compress|decompress; Only decompress is valid at the moment)", "mode", Core::ArgsParser::Required::No);
parser.parse(argc, argv);
if (type == nullptr) {
type = "deflate";
}
if (mode == nullptr) {
mode = "decompress";
}
StringView mode_sv { mode };
StringView type_sv { type };
if (mode_sv == "decompress") {
if (type_sv == "deflate") {
// Deflated bytes for the string "This is a simple text file :)"
u8 data_bytes[] = {
0x0B, 0xC9, 0xC8, 0x2C,
0x56, 0x00, 0xA2, 0x44,
0x85, 0xE2, 0xCC, 0xDC,
0x82, 0x9C, 0x54, 0x85,
0x92, 0xD4, 0x8A, 0x12,
0x85, 0xB4, 0x4C, 0x20,
0xCB, 0x4A, 0x13, 0x00
};
auto deflater = Compress::Deflate({ data_bytes, 4 * 7 });
auto deflated = deflater.decompress();
auto decompressed = String((const char*)deflated.data(), deflated.size());
if (decompressed.equals_ignoring_case("This is a simple text file :)")) {
printf("Test PASSED");
return 0;
} else {
printf("Test FAILED");
return 1;
}
}
if (type_sv == "zlib") {
// zlib bytes for the string "This is a simple text file :)"
u8 data_bytes[] = {
0x78, 0x01, 0x01, 0x1D, 0x00, 0xE2, 0xFF, 0x54,
0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61,
0x20, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20,
0x74, 0x65, 0x78, 0x74, 0x20, 0x66, 0x69, 0x6C,
0x65, 0x20, 0x3A, 0x29, 0x99, 0x5E, 0x09, 0xE8
};
auto deflater = Compress::Zlib({ data_bytes, 8 * 5 });
auto deflated = deflater.decompress();
auto decompressed = String((const char*)deflated.data(), deflated.size());
if (decompressed.equals_ignoring_case("This is a simple text file :)")) {
printf("Test PASSED");
return 0;
} else {
printf("Test FAILED");
return 1;
}
}
}
printf("Unknown arguments passed to test!");
return 1;
}