1/*
2 * IXGzipCodec.cpp
3 * Author: Benjamin Sergeant
4 * Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
5 */
6
7#include "IXGzipCodec.h"
8
9#include "IXBench.h"
10#include <array>
11#include <string.h>
12
13#ifdef IXWEBSOCKET_USE_ZLIB
14#include <zlib.h>
15#endif
16
17namespace ix
18{
19 std::string gzipCompress(const std::string& str)
20 {
21#ifndef IXWEBSOCKET_USE_ZLIB
22 return std::string();
23#else
24 z_stream zs; // z_stream is zlib's control structure
25 memset(&zs, 0, sizeof(zs));
26
27 // deflateInit2 configure the file format: request gzip instead of deflate
28 const int windowBits = 15;
29 const int GZIP_ENCODING = 16;
30
31 deflateInit2(&zs,
32 Z_DEFAULT_COMPRESSION,
33 Z_DEFLATED,
34 windowBits | GZIP_ENCODING,
35 8,
36 Z_DEFAULT_STRATEGY);
37
38 zs.next_in = (Bytef*) str.data();
39 zs.avail_in = (uInt) str.size(); // set the z_stream's input
40
41 int ret;
42 char outbuffer[32768];
43 std::string outstring;
44
45 // retrieve the compressed bytes blockwise
46 do
47 {
48 zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
49 zs.avail_out = sizeof(outbuffer);
50
51 ret = deflate(&zs, Z_FINISH);
52
53 if (outstring.size() < zs.total_out)
54 {
55 // append the block to the output string
56 outstring.append(outbuffer, zs.total_out - outstring.size());
57 }
58 } while (ret == Z_OK);
59
60 deflateEnd(&zs);
61
62 return outstring;
63#endif // IXWEBSOCKET_USE_ZLIB
64 }
65
66#ifdef IXWEBSOCKET_USE_DEFLATE
67 static uint32_t loadDecompressedGzipSize(const uint8_t* p)
68 {
69 return ((uint32_t) p[0] << 0) | ((uint32_t) p[1] << 8) | ((uint32_t) p[2] << 16) |
70 ((uint32_t) p[3] << 24);
71 }
72#endif
73
74 bool gzipDecompress(const std::string& in, std::string& out)
75 {
76#ifndef IXWEBSOCKET_USE_ZLIB
77 return false;
78#else
79 z_stream inflateState;
80 memset(&inflateState, 0, sizeof(inflateState));
81
82 inflateState.zalloc = Z_NULL;
83 inflateState.zfree = Z_NULL;
84 inflateState.opaque = Z_NULL;
85 inflateState.avail_in = 0;
86 inflateState.next_in = Z_NULL;
87
88 if (inflateInit2(&inflateState, 16 + MAX_WBITS) != Z_OK)
89 {
90 return false;
91 }
92
93 inflateState.avail_in = (uInt) in.size();
94 inflateState.next_in = (unsigned char*) (const_cast<char*>(in.data()));
95
96 const int kBufferSize = 1 << 14;
97 std::array<unsigned char, kBufferSize> compressBuffer;
98
99 do
100 {
101 inflateState.avail_out = (uInt) kBufferSize;
102 inflateState.next_out = &compressBuffer.front();
103
104 int ret = inflate(&inflateState, Z_SYNC_FLUSH);
105
106 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
107 {
108 inflateEnd(&inflateState);
109 return false;
110 }
111
112 out.append(reinterpret_cast<char*>(&compressBuffer.front()),
113 kBufferSize - inflateState.avail_out);
114 } while (inflateState.avail_out == 0);
115
116 inflateEnd(&inflateState);
117 return true;
118#endif // IXWEBSOCKET_USE_ZLIB
119 }
120} // namespace ix
121