/src/gnutls/lib/compress.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2017-2022 Red Hat, Inc. |
3 | | * |
4 | | * Author: Nikos Mavrogiannopoulos |
5 | | * |
6 | | * This file is part of GnuTLS. |
7 | | * |
8 | | * The GnuTLS is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public License |
10 | | * as published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
20 | | * |
21 | | */ |
22 | | |
23 | | #include "compress.h" |
24 | | |
25 | | #ifdef HAVE_LIBZ |
26 | | # include <zlib.h> |
27 | | #endif |
28 | | |
29 | | #ifdef HAVE_LIBBROTLI |
30 | | # include <brotli/decode.h> |
31 | | # include <brotli/encode.h> |
32 | | #endif |
33 | | |
34 | | #ifdef HAVE_LIBZSTD |
35 | | # include <zstd.h> |
36 | | #endif |
37 | | |
38 | | typedef struct { |
39 | | gnutls_compression_method_t id; |
40 | | const char *name; |
41 | | } comp_entry; |
42 | | |
43 | | static const comp_entry comp_algs[] = { |
44 | | {GNUTLS_COMP_NULL, "NULL"}, |
45 | | #ifdef HAVE_LIBZ |
46 | | {GNUTLS_COMP_ZLIB, "ZLIB"}, |
47 | | #endif |
48 | | #ifdef HAVE_LIBBROTLI |
49 | | {GNUTLS_COMP_BROTLI, "BROTLI"}, |
50 | | #endif |
51 | | #ifdef HAVE_LIBZSTD |
52 | | {GNUTLS_COMP_ZSTD, "ZSTD"}, |
53 | | #endif |
54 | | {GNUTLS_COMP_UNKNOWN, NULL} |
55 | | }; |
56 | | |
57 | | static const gnutls_compression_method_t alg_list[] = { |
58 | | GNUTLS_COMP_NULL, |
59 | | #ifdef HAVE_LIBZ |
60 | | GNUTLS_COMP_ZLIB, |
61 | | #endif |
62 | | #ifdef HAVE_LIBBROTLI |
63 | | GNUTLS_COMP_BROTLI, |
64 | | #endif |
65 | | #ifdef HAVE_LIBZSTD |
66 | | GNUTLS_COMP_ZSTD, |
67 | | #endif |
68 | | 0 |
69 | | }; |
70 | | |
71 | | /** |
72 | | * gnutls_compression_get_name: |
73 | | * @algorithm: is a Compression algorithm |
74 | | * |
75 | | * Convert a #gnutls_compression_method_t value to a string. |
76 | | * |
77 | | * Returns: a pointer to a string that contains the name of the |
78 | | * specified compression algorithm, or %NULL. |
79 | | **/ |
80 | | const char *gnutls_compression_get_name(gnutls_compression_method_t algorithm) |
81 | 0 | { |
82 | 0 | const comp_entry *p; |
83 | |
|
84 | 0 | for (p = comp_algs; p->name; ++p) |
85 | 0 | if (p->id == algorithm) |
86 | 0 | return p->name; |
87 | | |
88 | 0 | return NULL; |
89 | 0 | } |
90 | | |
91 | | /** |
92 | | * gnutls_compression_get_id: |
93 | | * @name: is a compression method name |
94 | | * |
95 | | * The names are compared in a case insensitive way. |
96 | | * |
97 | | * Returns: an id of the specified in a string compression method, or |
98 | | * %GNUTLS_COMP_UNKNOWN on error. |
99 | | **/ |
100 | | gnutls_compression_method_t gnutls_compression_get_id(const char *name) |
101 | 0 | { |
102 | 0 | const comp_entry *p; |
103 | |
|
104 | 0 | for (p = comp_algs; p->name; ++p) |
105 | 0 | if (!strcasecmp(p->name, name)) |
106 | 0 | return p->id; |
107 | | |
108 | 0 | return GNUTLS_COMP_UNKNOWN; |
109 | 0 | } |
110 | | |
111 | | /** |
112 | | * gnutls_compression_list: |
113 | | * |
114 | | * Get a list of compression methods. |
115 | | * |
116 | | * Returns: a zero-terminated list of #gnutls_compression_method_t |
117 | | * integers indicating the available compression methods. |
118 | | **/ |
119 | | const gnutls_compression_method_t *gnutls_compression_list(void) |
120 | 0 | { |
121 | 0 | return alg_list; |
122 | 0 | } |
123 | | |
124 | | /*************************/ |
125 | | /* Compression functions */ |
126 | | /*************************/ |
127 | | |
128 | | size_t _gnutls_compress_bound(gnutls_compression_method_t alg, size_t src_len) |
129 | 0 | { |
130 | 0 | switch (alg) { |
131 | 0 | #ifdef HAVE_LIBZ |
132 | 0 | case GNUTLS_COMP_ZLIB: |
133 | 0 | return compressBound(src_len); |
134 | 0 | #endif |
135 | | #ifdef HAVE_LIBBROTLI |
136 | | case GNUTLS_COMP_BROTLI: |
137 | | return BrotliEncoderMaxCompressedSize(src_len); |
138 | | #endif |
139 | | #ifdef HAVE_LIBZSTD |
140 | | case GNUTLS_COMP_ZSTD: |
141 | | return ZSTD_compressBound(src_len); |
142 | | #endif |
143 | 0 | default: |
144 | 0 | return 0; |
145 | 0 | } |
146 | 0 | return 0; |
147 | 0 | } |
148 | | |
149 | | int |
150 | | _gnutls_compress(gnutls_compression_method_t alg, |
151 | | uint8_t * dst, size_t dst_len, |
152 | | const uint8_t * src, size_t src_len) |
153 | 0 | { |
154 | 0 | int ret = GNUTLS_E_COMPRESSION_FAILED; |
155 | |
|
156 | 0 | switch (alg) { |
157 | 0 | #ifdef HAVE_LIBZ |
158 | 0 | case GNUTLS_COMP_ZLIB: |
159 | 0 | { |
160 | 0 | int err; |
161 | 0 | uLongf comp_len = dst_len; |
162 | |
|
163 | 0 | err = compress(dst, &comp_len, src, src_len); |
164 | 0 | if (err != Z_OK) |
165 | 0 | return |
166 | 0 | gnutls_assert_val |
167 | 0 | (GNUTLS_E_COMPRESSION_FAILED); |
168 | 0 | ret = comp_len; |
169 | 0 | } |
170 | 0 | break; |
171 | 0 | #endif |
172 | | #ifdef HAVE_LIBBROTLI |
173 | | case GNUTLS_COMP_BROTLI: |
174 | | { |
175 | | BROTLI_BOOL err; |
176 | | size_t comp_len = dst_len; |
177 | | |
178 | | err = BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, |
179 | | BROTLI_DEFAULT_WINDOW, |
180 | | BROTLI_DEFAULT_MODE, |
181 | | src_len, src, &comp_len, |
182 | | dst); |
183 | | if (!err) |
184 | | return |
185 | | gnutls_assert_val |
186 | | (GNUTLS_E_COMPRESSION_FAILED); |
187 | | ret = comp_len; |
188 | | } |
189 | | break; |
190 | | #endif |
191 | | #ifdef HAVE_LIBZSTD |
192 | | case GNUTLS_COMP_ZSTD: |
193 | | { |
194 | | size_t comp_len; |
195 | | |
196 | | comp_len = |
197 | | ZSTD_compress(dst, dst_len, src, src_len, |
198 | | ZSTD_CLEVEL_DEFAULT); |
199 | | if (ZSTD_isError(comp_len)) |
200 | | return |
201 | | gnutls_assert_val |
202 | | (GNUTLS_E_COMPRESSION_FAILED); |
203 | | ret = comp_len; |
204 | | } |
205 | | break; |
206 | | #endif |
207 | 0 | default: |
208 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
209 | 0 | } |
210 | | |
211 | | #ifdef COMPRESSION_DEBUG |
212 | | _gnutls_debug_log("Compression ratio: %f\n", |
213 | | (float)((float)ret / (float)src_len)); |
214 | | #endif |
215 | | |
216 | 0 | return ret; |
217 | 0 | } |
218 | | |
219 | | int |
220 | | _gnutls_decompress(gnutls_compression_method_t alg, |
221 | | uint8_t * dst, size_t dst_len, |
222 | | const uint8_t * src, size_t src_len) |
223 | 0 | { |
224 | 0 | int ret = GNUTLS_E_DECOMPRESSION_FAILED; |
225 | |
|
226 | 0 | switch (alg) { |
227 | 0 | #ifdef HAVE_LIBZ |
228 | 0 | case GNUTLS_COMP_ZLIB: |
229 | 0 | { |
230 | 0 | int err; |
231 | 0 | uLongf plain_len = dst_len; |
232 | |
|
233 | 0 | err = uncompress(dst, &plain_len, src, src_len); |
234 | 0 | if (err != Z_OK) |
235 | 0 | return |
236 | 0 | gnutls_assert_val |
237 | 0 | (GNUTLS_E_DECOMPRESSION_FAILED); |
238 | 0 | ret = plain_len; |
239 | 0 | } |
240 | 0 | break; |
241 | 0 | #endif |
242 | | #ifdef HAVE_LIBBROTLI |
243 | | case GNUTLS_COMP_BROTLI: |
244 | | { |
245 | | BrotliDecoderResult err; |
246 | | size_t plain_len = dst_len; |
247 | | |
248 | | err = |
249 | | BrotliDecoderDecompress(src_len, src, &plain_len, |
250 | | dst); |
251 | | if (err != BROTLI_DECODER_RESULT_SUCCESS) |
252 | | return |
253 | | gnutls_assert_val |
254 | | (GNUTLS_E_DECOMPRESSION_FAILED); |
255 | | ret = plain_len; |
256 | | } |
257 | | break; |
258 | | #endif |
259 | | #ifdef HAVE_LIBZSTD |
260 | | case GNUTLS_COMP_ZSTD: |
261 | | { |
262 | | size_t plain_len; |
263 | | |
264 | | plain_len = ZSTD_decompress(dst, dst_len, src, src_len); |
265 | | if (ZSTD_isError(plain_len)) |
266 | | return |
267 | | gnutls_assert_val |
268 | | (GNUTLS_E_DECOMPRESSION_FAILED); |
269 | | ret = plain_len; |
270 | | } |
271 | | break; |
272 | | #endif |
273 | 0 | default: |
274 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
275 | 0 | } |
276 | | |
277 | 0 | return ret; |
278 | 0 | } |