Coverage Report

Created: 2024-06-20 06:28

/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[] = { { GNUTLS_COMP_NULL, "NULL" },
44
#ifdef HAVE_LIBZ
45
          { GNUTLS_COMP_ZLIB, "ZLIB" },
46
#endif
47
#ifdef HAVE_LIBBROTLI
48
          { GNUTLS_COMP_BROTLI, "BROTLI" },
49
#endif
50
#ifdef HAVE_LIBZSTD
51
          { GNUTLS_COMP_ZSTD, "ZSTD" },
52
#endif
53
          { GNUTLS_COMP_UNKNOWN, NULL } };
54
55
static const gnutls_compression_method_t alg_list[] = { GNUTLS_COMP_NULL,
56
#ifdef HAVE_LIBZ
57
              GNUTLS_COMP_ZLIB,
58
#endif
59
#ifdef HAVE_LIBBROTLI
60
              GNUTLS_COMP_BROTLI,
61
#endif
62
#ifdef HAVE_LIBZSTD
63
              GNUTLS_COMP_ZSTD,
64
#endif
65
              0 };
66
67
/**
68
 * gnutls_compression_get_name:
69
 * @algorithm: is a Compression algorithm
70
 *
71
 * Convert a #gnutls_compression_method_t value to a string.
72
 *
73
 * Returns: a pointer to a string that contains the name of the
74
 *   specified compression algorithm, or %NULL.
75
 **/
76
const char *gnutls_compression_get_name(gnutls_compression_method_t algorithm)
77
0
{
78
0
  const comp_entry *p;
79
80
0
  for (p = comp_algs; p->name; ++p)
81
0
    if (p->id == algorithm)
82
0
      return p->name;
83
84
0
  return NULL;
85
0
}
86
87
/**
88
 * gnutls_compression_get_id:
89
 * @name: is a compression method name
90
 *
91
 * The names are compared in a case insensitive way.
92
 *
93
 * Returns: an id of the specified in a string compression method, or
94
 *   %GNUTLS_COMP_UNKNOWN on error.
95
 **/
96
gnutls_compression_method_t gnutls_compression_get_id(const char *name)
97
0
{
98
0
  const comp_entry *p;
99
100
0
  for (p = comp_algs; p->name; ++p)
101
0
    if (!strcasecmp(p->name, name))
102
0
      return p->id;
103
104
0
  return GNUTLS_COMP_UNKNOWN;
105
0
}
106
107
/**
108
 * gnutls_compression_list:
109
 *
110
 * Get a list of compression methods.
111
 *
112
 * Returns: a zero-terminated list of #gnutls_compression_method_t
113
 *   integers indicating the available compression methods.
114
 **/
115
const gnutls_compression_method_t *gnutls_compression_list(void)
116
0
{
117
0
  return alg_list;
118
0
}
119
120
/*************************/
121
/* Compression functions */
122
/*************************/
123
124
size_t _gnutls_compress_bound(gnutls_compression_method_t alg, size_t src_len)
125
0
{
126
0
  switch (alg) {
127
#ifdef HAVE_LIBZ
128
  case GNUTLS_COMP_ZLIB:
129
    return compressBound(src_len);
130
#endif
131
#ifdef HAVE_LIBBROTLI
132
  case GNUTLS_COMP_BROTLI:
133
    return BrotliEncoderMaxCompressedSize(src_len);
134
#endif
135
#ifdef HAVE_LIBZSTD
136
  case GNUTLS_COMP_ZSTD:
137
    return ZSTD_compressBound(src_len);
138
#endif
139
0
  default:
140
0
    return 0;
141
0
  }
142
0
  return 0;
143
0
}
144
145
int _gnutls_compress(gnutls_compression_method_t alg, uint8_t *dst,
146
         size_t dst_len, const uint8_t *src, size_t src_len)
147
0
{
148
0
  int ret = GNUTLS_E_COMPRESSION_FAILED;
149
150
0
  switch (alg) {
151
#ifdef HAVE_LIBZ
152
  case GNUTLS_COMP_ZLIB: {
153
    int err;
154
    uLongf comp_len = dst_len;
155
156
    err = compress(dst, &comp_len, src, src_len);
157
    if (err != Z_OK)
158
      return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED);
159
    ret = comp_len;
160
  } break;
161
#endif
162
#ifdef HAVE_LIBBROTLI
163
  case GNUTLS_COMP_BROTLI: {
164
    BROTLI_BOOL err;
165
    size_t comp_len = dst_len;
166
167
    err = BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY,
168
              BROTLI_DEFAULT_WINDOW,
169
              BROTLI_DEFAULT_MODE, src_len, src,
170
              &comp_len, dst);
171
    if (!err)
172
      return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED);
173
    ret = comp_len;
174
  } break;
175
#endif
176
#ifdef HAVE_LIBZSTD
177
  case GNUTLS_COMP_ZSTD: {
178
    size_t comp_len;
179
180
    comp_len = ZSTD_compress(dst, dst_len, src, src_len,
181
           ZSTD_CLEVEL_DEFAULT);
182
    if (ZSTD_isError(comp_len))
183
      return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED);
184
    ret = comp_len;
185
  } break;
186
#endif
187
0
  default:
188
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
189
0
  }
190
191
#ifdef COMPRESSION_DEBUG
192
  _gnutls_debug_log("Compression ratio: %f\n",
193
        (float)((float)ret / (float)src_len));
194
#endif
195
196
0
  return ret;
197
0
}
198
199
int _gnutls_decompress(gnutls_compression_method_t alg, uint8_t *dst,
200
           size_t dst_len, const uint8_t *src, size_t src_len)
201
0
{
202
0
  int ret = GNUTLS_E_DECOMPRESSION_FAILED;
203
204
0
  switch (alg) {
205
#ifdef HAVE_LIBZ
206
  case GNUTLS_COMP_ZLIB: {
207
    int err;
208
    uLongf plain_len = dst_len;
209
210
    err = uncompress(dst, &plain_len, src, src_len);
211
    if (err != Z_OK)
212
      return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);
213
    ret = plain_len;
214
  } break;
215
#endif
216
#ifdef HAVE_LIBBROTLI
217
  case GNUTLS_COMP_BROTLI: {
218
    BrotliDecoderResult err;
219
    size_t plain_len = dst_len;
220
221
    err = BrotliDecoderDecompress(src_len, src, &plain_len, dst);
222
    if (err != BROTLI_DECODER_RESULT_SUCCESS)
223
      return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);
224
    ret = plain_len;
225
  } break;
226
#endif
227
#ifdef HAVE_LIBZSTD
228
  case GNUTLS_COMP_ZSTD: {
229
    size_t plain_len;
230
231
    plain_len = ZSTD_decompress(dst, dst_len, src, src_len);
232
    if (ZSTD_isError(plain_len))
233
      return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);
234
    ret = plain_len;
235
  } break;
236
#endif
237
0
  default:
238
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
239
0
  }
240
241
0
  return ret;
242
0
}