1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 2017-2021, The LegacyClonk Team and contributors
5 *
6 * Distributed under the terms of the ISC license; see accompanying file
7 * "COPYING" for details.
8 *
9 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10 * See accompanying file "TRADEMARK" for details.
11 *
12 * To redistribute this file separately, substitute the full license texts
13 * for the above references.
14 */
15
16// wraps zlib's inflate for reading and deflate for writing gzip compressed group files with C4Group magic bytes
17
18#pragma once
19
20#include "Standard.h"
21
22#include <cstdio>
23#include <cstdint>
24#include <memory>
25#include <stdexcept>
26#include <string>
27
28#include <zlib.h>
29
30namespace StdGzCompressedFile
31{
32using Exception = std::runtime_error;
33
34static constexpr uint8_t C4GroupMagic[2] = {0x1e, 0x8c};
35static constexpr uint8_t GZMagic[2] = {0x1f, 0x8b};
36static constexpr auto ChunkSize = 1024 * 1024;
37
38class Read
39{
40 std::unique_ptr<uint8_t[]> buffer{new uint8_t[ChunkSize]};
41 uint8_t *bufferPtr = nullptr;
42
43 // the gzip struct only has size fields of unsigned int
44 // and this value is bounded by ChunkSize anyway
45 unsigned int bufferedSize = 0;
46
47 FILE *file;
48 size_t position = 0;
49 z_stream gzStream;
50 bool gzStreamValid = false;
51
52public:
53 Read(const std::string &filename);
54 ~Read();
55 size_t UncompressedSize();
56 size_t ReadData(uint8_t *toBuffer, size_t size);
57 void Rewind();
58
59private:
60 void CheckMagicBytes();
61 void PrepareInflate();
62 void RefillBuffer();
63};
64
65class Write
66{
67 FILE *file;
68 z_stream gzStream;
69 std::unique_ptr<uint8_t[]> buffer{new uint8_t[ChunkSize]};
70 // the gzip struct only has size fields of unsigned int
71 // and this value is bounded by ChunkSize anyway
72 unsigned int bufferedSize = 0;
73 bool magicBytesDone = false;
74
75public:
76 Write(const std::string &filename);
77 ~Write() noexcept(false);
78 void WriteData(const uint8_t *const fromBuffer, const size_t size);
79
80private:
81 void FlushBuffer();
82 void DeflateToBuffer(const uint8_t *const fromBuffer, const size_t size, int flushMode, int expectedRet);
83
84private:
85 static constexpr auto CompressionLevel = 2;
86};
87}
88