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 | |
17 | namespace 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 | |