Coverage Report

Created: 2026-10-28 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl35/crypto/comp/c_brotli.c
Line
Count
Source
1
/*
2
 * Copyright 1998-2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 *
9
 * Uses brotli compression library from https://github.com/google/brotli
10
 */
11
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <string.h>
15
#include <openssl/objects.h>
16
#include "internal/comp.h"
17
#include <openssl/err.h>
18
#include "crypto/cryptlib.h"
19
#include "internal/bio.h"
20
#include "internal/thread_once.h"
21
#include "comp_local.h"
22
23
COMP_METHOD *COMP_brotli(void);
24
25
#ifdef OPENSSL_NO_BROTLI
26
#undef BROTLI_SHARED
27
#else
28
29
#include <brotli/decode.h>
30
#include <brotli/encode.h>
31
32
/* memory allocations functions for brotli initialisation */
33
static void *brotli_alloc(void *opaque, size_t size)
34
{
35
    return OPENSSL_zalloc(size);
36
}
37
38
static void brotli_free(void *opaque, void *address)
39
{
40
    OPENSSL_free(address);
41
}
42
43
/*
44
 * When OpenSSL is built on Windows, we do not want to require that
45
 * the BROTLI.DLL be available in order for the OpenSSL DLLs to
46
 * work.  Therefore, all BROTLI routines are loaded at run time
47
 * and we do not link to a .LIB file when BROTLI_SHARED is set.
48
 */
49
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
50
#include <windows.h>
51
#endif
52
53
#ifdef BROTLI_SHARED
54
#include "internal/dso.h"
55
56
/* Function pointers */
57
typedef BrotliEncoderState *(*encode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
58
typedef BROTLI_BOOL (*encode_stream_ft)(BrotliEncoderState *, BrotliEncoderOperation, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
59
typedef BROTLI_BOOL (*encode_has_more_ft)(BrotliEncoderState *);
60
typedef void (*encode_end_ft)(BrotliEncoderState *);
61
typedef BROTLI_BOOL (*encode_oneshot_ft)(int, int, BrotliEncoderMode, size_t, const uint8_t in[], size_t *, uint8_t out[]);
62
63
typedef BrotliDecoderState *(*decode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
64
typedef BROTLI_BOOL (*decode_stream_ft)(BrotliDecoderState *, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
65
typedef BROTLI_BOOL (*decode_has_more_ft)(BrotliDecoderState *);
66
typedef void (*decode_end_ft)(BrotliDecoderState *);
67
typedef BrotliDecoderErrorCode (*decode_error_ft)(BrotliDecoderState *);
68
typedef const char *(*decode_error_string_ft)(BrotliDecoderErrorCode);
69
typedef BROTLI_BOOL (*decode_is_finished_ft)(BrotliDecoderState *);
70
typedef BrotliDecoderResult (*decode_oneshot_ft)(size_t, const uint8_t in[], size_t *, uint8_t out[]);
71
72
static encode_init_ft p_encode_init = NULL;
73
static encode_stream_ft p_encode_stream = NULL;
74
static encode_has_more_ft p_encode_has_more = NULL;
75
static encode_end_ft p_encode_end = NULL;
76
static encode_oneshot_ft p_encode_oneshot = NULL;
77
78
static decode_init_ft p_decode_init = NULL;
79
static decode_stream_ft p_decode_stream = NULL;
80
static decode_has_more_ft p_decode_has_more = NULL;
81
static decode_end_ft p_decode_end = NULL;
82
static decode_error_ft p_decode_error = NULL;
83
static decode_error_string_ft p_decode_error_string = NULL;
84
static decode_is_finished_ft p_decode_is_finished = NULL;
85
static decode_oneshot_ft p_decode_oneshot = NULL;
86
87
static DSO *brotli_encode_dso = NULL;
88
static DSO *brotli_decode_dso = NULL;
89
90
#define BrotliEncoderCreateInstance p_encode_init
91
#define BrotliEncoderCompressStream p_encode_stream
92
#define BrotliEncoderHasMoreOutput p_encode_has_more
93
#define BrotliEncoderDestroyInstance p_encode_end
94
#define BrotliEncoderCompress p_encode_oneshot
95
96
#define BrotliDecoderCreateInstance p_decode_init
97
#define BrotliDecoderDecompressStream p_decode_stream
98
#define BrotliDecoderHasMoreOutput p_decode_has_more
99
#define BrotliDecoderDestroyInstance p_decode_end
100
#define BrotliDecoderGetErrorCode p_decode_error
101
#define BrotliDecoderErrorString p_decode_error_string
102
#define BrotliDecoderIsFinished p_decode_is_finished
103
#define BrotliDecoderDecompress p_decode_oneshot
104
105
#endif /* ifdef BROTLI_SHARED */
106
107
struct brotli_state {
108
    BrotliEncoderState *encoder;
109
    BrotliDecoderState *decoder;
110
};
111
112
static int brotli_stateful_init(COMP_CTX *ctx)
113
{
114
    struct brotli_state *state = OPENSSL_zalloc(sizeof(*state));
115
116
    if (state == NULL)
117
        return 0;
118
119
    state->encoder = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
120
    if (state->encoder == NULL)
121
        goto err;
122
123
    state->decoder = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
124
    if (state->decoder == NULL)
125
        goto err;
126
127
    ctx->data = state;
128
    return 1;
129
err:
130
    BrotliDecoderDestroyInstance(state->decoder);
131
    BrotliEncoderDestroyInstance(state->encoder);
132
    OPENSSL_free(state);
133
    return 0;
134
}
135
136
static void brotli_stateful_finish(COMP_CTX *ctx)
137
{
138
    struct brotli_state *state = ctx->data;
139
140
    if (state != NULL) {
141
        BrotliDecoderDestroyInstance(state->decoder);
142
        BrotliEncoderDestroyInstance(state->encoder);
143
        OPENSSL_free(state);
144
        ctx->data = NULL;
145
    }
146
}
147
148
static ossl_ssize_t brotli_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
149
    size_t olen, unsigned char *in,
150
    size_t ilen)
151
{
152
    BROTLI_BOOL done;
153
    struct brotli_state *state = ctx->data;
154
    size_t in_avail = ilen;
155
    size_t out_avail = olen;
156
157
    if (state == NULL || olen > OSSL_SSIZE_MAX)
158
        return -1;
159
160
    if (ilen == 0)
161
        return 0;
162
163
    /*
164
     * The finish API does not provide a final output buffer,
165
     * so each compress operation has to be flushed, if all
166
     * the input data can't be accepted, or there is more output,
167
     * this has to be considered an error, since there is no more
168
     * output buffer space
169
     */
170
    done = BrotliEncoderCompressStream(state->encoder, BROTLI_OPERATION_FLUSH,
171
        &in_avail, (const uint8_t **)&in,
172
        &out_avail, &out, NULL);
173
    if (done == BROTLI_FALSE
174
        || in_avail != 0
175
        || BrotliEncoderHasMoreOutput(state->encoder))
176
        return -1;
177
178
    if (out_avail > olen)
179
        return -1;
180
    return (ossl_ssize_t)(olen - out_avail);
181
}
182
183
static ossl_ssize_t brotli_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
184
    size_t olen, unsigned char *in,
185
    size_t ilen)
186
{
187
    BrotliDecoderResult result;
188
    struct brotli_state *state = ctx->data;
189
    size_t in_avail = ilen;
190
    size_t out_avail = olen;
191
192
    if (state == NULL || olen > OSSL_SSIZE_MAX)
193
        return -1;
194
195
    if (ilen == 0)
196
        return 0;
197
198
    result = BrotliDecoderDecompressStream(state->decoder, &in_avail,
199
        (const uint8_t **)&in, &out_avail,
200
        &out, NULL);
201
    if (result == BROTLI_DECODER_RESULT_ERROR
202
        || in_avail != 0
203
        || BrotliDecoderHasMoreOutput(state->decoder))
204
        return -1;
205
206
    if (out_avail > olen)
207
        return -1;
208
    return (ossl_ssize_t)(olen - out_avail);
209
}
210
211
static COMP_METHOD brotli_stateful_method = {
212
    NID_brotli,
213
    LN_brotli,
214
    brotli_stateful_init,
215
    brotli_stateful_finish,
216
    brotli_stateful_compress_block,
217
    brotli_stateful_expand_block
218
};
219
220
static int brotli_oneshot_init(COMP_CTX *ctx)
221
{
222
    return 1;
223
}
224
225
static void brotli_oneshot_finish(COMP_CTX *ctx)
226
{
227
}
228
229
static ossl_ssize_t brotli_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out,
230
    size_t olen, unsigned char *in,
231
    size_t ilen)
232
{
233
    size_t out_size = olen;
234
    ossl_ssize_t ret;
235
236
    if (ilen == 0)
237
        return 0;
238
239
    if (BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW,
240
            BROTLI_DEFAULT_MODE, ilen, in,
241
            &out_size, out)
242
        == BROTLI_FALSE)
243
        return -1;
244
245
    if (out_size > OSSL_SSIZE_MAX)
246
        return -1;
247
    ret = (ossl_ssize_t)out_size;
248
    if (ret < 0)
249
        return -1;
250
    return ret;
251
}
252
253
static ossl_ssize_t brotli_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out,
254
    size_t olen, unsigned char *in,
255
    size_t ilen)
256
{
257
    size_t out_size = olen;
258
    ossl_ssize_t ret;
259
260
    if (ilen == 0)
261
        return 0;
262
263
    if (BrotliDecoderDecompress(ilen, in, &out_size, out) != BROTLI_DECODER_RESULT_SUCCESS)
264
        return -1;
265
266
    if (out_size > OSSL_SSIZE_MAX)
267
        return -1;
268
    ret = (ossl_ssize_t)out_size;
269
    if (ret < 0)
270
        return -1;
271
    return ret;
272
}
273
274
static COMP_METHOD brotli_oneshot_method = {
275
    NID_brotli,
276
    LN_brotli,
277
    brotli_oneshot_init,
278
    brotli_oneshot_finish,
279
    brotli_oneshot_compress_block,
280
    brotli_oneshot_expand_block
281
};
282
283
static CRYPTO_ONCE brotli_once = CRYPTO_ONCE_STATIC_INIT;
284
DEFINE_RUN_ONCE_STATIC(ossl_comp_brotli_init)
285
{
286
#ifdef BROTLI_SHARED
287
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
288
#define LIBBROTLIENC "BROTLIENC"
289
#define LIBBROTLIDEC "BROTLIDEC"
290
#else
291
#define LIBBROTLIENC "brotlienc"
292
#define LIBBROTLIDEC "brotlidec"
293
#endif
294
295
    ERR_set_mark();
296
    brotli_encode_dso = DSO_load(NULL, LIBBROTLIENC, NULL, 0);
297
    if (brotli_encode_dso != NULL) {
298
        p_encode_init = (encode_init_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCreateInstance");
299
        p_encode_stream = (encode_stream_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompressStream");
300
        p_encode_has_more = (encode_has_more_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderHasMoreOutput");
301
        p_encode_end = (encode_end_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderDestroyInstance");
302
        p_encode_oneshot = (encode_oneshot_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompress");
303
    }
304
305
    brotli_decode_dso = DSO_load(NULL, LIBBROTLIDEC, NULL, 0);
306
    if (brotli_decode_dso != NULL) {
307
        p_decode_init = (decode_init_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderCreateInstance");
308
        p_decode_stream = (decode_stream_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompressStream");
309
        p_decode_has_more = (decode_has_more_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderHasMoreOutput");
310
        p_decode_end = (decode_end_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDestroyInstance");
311
        p_decode_error = (decode_error_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderGetErrorCode");
312
        p_decode_error_string = (decode_error_string_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderErrorString");
313
        p_decode_is_finished = (decode_is_finished_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderIsFinished");
314
        p_decode_oneshot = (decode_oneshot_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompress");
315
    }
316
317
    if (p_encode_init == NULL || p_encode_stream == NULL || p_encode_has_more == NULL
318
        || p_encode_end == NULL || p_encode_oneshot == NULL || p_decode_init == NULL
319
        || p_decode_stream == NULL || p_decode_has_more == NULL || p_decode_end == NULL
320
        || p_decode_error == NULL || p_decode_error_string == NULL || p_decode_is_finished == NULL
321
        || p_decode_oneshot == NULL) {
322
        ERR_clear_last_mark();
323
        ossl_comp_brotli_cleanup();
324
        return 0;
325
    }
326
    /* Do not leave errors behind on success. */
327
    ERR_pop_to_mark();
328
#endif
329
    return 1;
330
}
331
#endif /* ifndef BROTLI / else */
332
333
COMP_METHOD *COMP_brotli(void)
334
0
{
335
0
    COMP_METHOD *meth = NULL;
336
337
#ifndef OPENSSL_NO_BROTLI
338
    if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
339
        meth = &brotli_stateful_method;
340
#endif
341
0
    return meth;
342
0
}
343
344
COMP_METHOD *COMP_brotli_oneshot(void)
345
0
{
346
0
    COMP_METHOD *meth = NULL;
347
348
#ifndef OPENSSL_NO_BROTLI
349
    if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
350
        meth = &brotli_oneshot_method;
351
#endif
352
0
    return meth;
353
0
}
354
355
/* Also called from OPENSSL_cleanup() */
356
void ossl_comp_brotli_cleanup(void)
357
154
{
358
#ifdef BROTLI_SHARED
359
    DSO_free(brotli_encode_dso);
360
    brotli_encode_dso = NULL;
361
    DSO_free(brotli_decode_dso);
362
    brotli_decode_dso = NULL;
363
    p_encode_init = NULL;
364
    p_encode_stream = NULL;
365
    p_encode_has_more = NULL;
366
    p_encode_end = NULL;
367
    p_encode_oneshot = NULL;
368
    p_decode_init = NULL;
369
    p_decode_stream = NULL;
370
    p_decode_has_more = NULL;
371
    p_decode_end = NULL;
372
    p_decode_error = NULL;
373
    p_decode_error_string = NULL;
374
    p_decode_is_finished = NULL;
375
    p_decode_oneshot = NULL;
376
#endif
377
154
}
378
379
#ifndef OPENSSL_NO_BROTLI
380
381
/* Brotli-based compression/decompression filter BIO */
382
383
typedef struct {
384
    struct { /* input structure */
385
        size_t avail_in;
386
        unsigned char *next_in;
387
        size_t avail_out;
388
        unsigned char *next_out;
389
        unsigned char *buf;
390
        size_t bufsize;
391
        BrotliDecoderState *state;
392
    } decode;
393
    struct { /* output structure */
394
        size_t avail_in;
395
        unsigned char *next_in;
396
        size_t avail_out;
397
        unsigned char *next_out;
398
        unsigned char *buf;
399
        size_t bufsize;
400
        BrotliEncoderState *state;
401
        int mode; /* Encoder mode to use */
402
        int done;
403
        unsigned char *ptr;
404
        size_t count;
405
    } encode;
406
} BIO_BROTLI_CTX;
407
408
#define BROTLI_DEFAULT_BUFSIZE 1024
409
410
static int bio_brotli_new(BIO *bi);
411
static int bio_brotli_free(BIO *bi);
412
static int bio_brotli_read(BIO *b, char *out, int outl);
413
static int bio_brotli_write(BIO *b, const char *in, int inl);
414
static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr);
415
static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
416
417
static const BIO_METHOD bio_meth_brotli = {
418
    BIO_TYPE_COMP,
419
    "brotli",
420
    /* TODO: Convert to new style write function */
421
    bwrite_conv,
422
    bio_brotli_write,
423
    /* TODO: Convert to new style read function */
424
    bread_conv,
425
    bio_brotli_read,
426
    NULL, /* bio_brotli_puts, */
427
    NULL, /* bio_brotli_gets, */
428
    bio_brotli_ctrl,
429
    bio_brotli_new,
430
    bio_brotli_free,
431
    bio_brotli_callback_ctrl
432
};
433
#endif
434
435
const BIO_METHOD *BIO_f_brotli(void)
436
0
{
437
#ifndef OPENSSL_NO_BROTLI
438
    if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
439
        return &bio_meth_brotli;
440
#endif
441
    return NULL;
442
0
}
443
444
#ifndef OPENSSL_NO_BROTLI
445
446
static int bio_brotli_new(BIO *bi)
447
{
448
    BIO_BROTLI_CTX *ctx;
449
450
#ifdef BROTLI_SHARED
451
    if (!RUN_ONCE(&brotli_once, ossl_comp_brotli_init)) {
452
        ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_NOT_SUPPORTED);
453
        return 0;
454
    }
455
#endif
456
    ctx = OPENSSL_zalloc(sizeof(*ctx));
457
    if (ctx == NULL) {
458
        ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
459
        return 0;
460
    }
461
    ctx->decode.bufsize = BROTLI_DEFAULT_BUFSIZE;
462
    ctx->decode.state = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
463
    if (ctx->decode.state == NULL)
464
        goto err;
465
    ctx->encode.bufsize = BROTLI_DEFAULT_BUFSIZE;
466
    ctx->encode.state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
467
    if (ctx->encode.state == NULL)
468
        goto err;
469
    ctx->encode.mode = BROTLI_DEFAULT_MODE;
470
    BIO_set_init(bi, 1);
471
    BIO_set_data(bi, ctx);
472
473
    return 1;
474
475
err:
476
    ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
477
    BrotliDecoderDestroyInstance(ctx->decode.state);
478
    BrotliEncoderDestroyInstance(ctx->encode.state);
479
    OPENSSL_free(ctx);
480
    return 0;
481
}
482
483
static int bio_brotli_free(BIO *bi)
484
{
485
    BIO_BROTLI_CTX *ctx;
486
487
    if (bi == NULL)
488
        return 0;
489
490
    ctx = BIO_get_data(bi);
491
    if (ctx != NULL) {
492
        BrotliDecoderDestroyInstance(ctx->decode.state);
493
        OPENSSL_free(ctx->decode.buf);
494
        BrotliEncoderDestroyInstance(ctx->encode.state);
495
        OPENSSL_free(ctx->encode.buf);
496
        OPENSSL_free(ctx);
497
    }
498
    BIO_set_data(bi, NULL);
499
    BIO_set_init(bi, 0);
500
501
    return 1;
502
}
503
504
static int bio_brotli_read(BIO *b, char *out, int outl)
505
{
506
    BIO_BROTLI_CTX *ctx;
507
    BrotliDecoderResult bret;
508
    int ret;
509
    BIO *next = BIO_next(b);
510
511
    if (out == NULL || outl <= 0) {
512
        ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
513
        return 0;
514
    }
515
#if INT_MAX > SIZE_MAX
516
    if ((unsigned int)outl > SIZE_MAX) {
517
        ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
518
        return 0;
519
    }
520
#endif
521
522
    ctx = BIO_get_data(b);
523
    BIO_clear_retry_flags(b);
524
    if (ctx->decode.buf == NULL) {
525
        ctx->decode.buf = OPENSSL_malloc(ctx->decode.bufsize);
526
        if (ctx->decode.buf == NULL) {
527
            ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
528
            return 0;
529
        }
530
        ctx->decode.next_in = ctx->decode.buf;
531
        ctx->decode.avail_in = 0;
532
    }
533
534
    /* Copy output data directly to supplied buffer */
535
    ctx->decode.next_out = (unsigned char *)out;
536
    ctx->decode.avail_out = (size_t)outl;
537
    for (;;) {
538
        /* Decompress while data available */
539
        while (ctx->decode.avail_in > 0 || BrotliDecoderHasMoreOutput(ctx->decode.state)) {
540
            bret = BrotliDecoderDecompressStream(ctx->decode.state, &ctx->decode.avail_in, (const uint8_t **)&ctx->decode.next_in,
541
                &ctx->decode.avail_out, &ctx->decode.next_out, NULL);
542
            if (bret == BROTLI_DECODER_RESULT_ERROR) {
543
                ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
544
                ERR_add_error_data(1, BrotliDecoderErrorString(BrotliDecoderGetErrorCode(ctx->decode.state)));
545
                return 0;
546
            }
547
            /* If EOF or we've read everything then return */
548
            if (BrotliDecoderIsFinished(ctx->decode.state) || ctx->decode.avail_out == 0)
549
                return (int)(outl - ctx->decode.avail_out);
550
        }
551
552
        /* If EOF */
553
        if (BrotliDecoderIsFinished(ctx->decode.state))
554
            return 0;
555
556
        /*
557
         * No data in input buffer try to read some in, if an error then
558
         * return the total data read.
559
         */
560
        ret = BIO_read(next, ctx->decode.buf, ctx->decode.bufsize);
561
        if (ret <= 0) {
562
            /* Total data read */
563
            int tot = outl - ctx->decode.avail_out;
564
565
            BIO_copy_next_retry(b);
566
            if (ret < 0)
567
                return (tot > 0) ? tot : ret;
568
            return tot;
569
        }
570
        ctx->decode.avail_in = ret;
571
        ctx->decode.next_in = ctx->decode.buf;
572
    }
573
}
574
575
static int bio_brotli_write(BIO *b, const char *in, int inl)
576
{
577
    BIO_BROTLI_CTX *ctx;
578
    BROTLI_BOOL brret;
579
    int ret;
580
    BIO *next = BIO_next(b);
581
582
    if (in == NULL || inl <= 0) {
583
        ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
584
        return 0;
585
    }
586
#if INT_MAX > SIZE_MAX
587
    if ((unsigned int)inl > SIZE_MAX) {
588
        ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
589
        return 0;
590
    }
591
#endif
592
593
    ctx = BIO_get_data(b);
594
    if (ctx->encode.done)
595
        return 0;
596
597
    BIO_clear_retry_flags(b);
598
    if (ctx->encode.buf == NULL) {
599
        ctx->encode.buf = OPENSSL_malloc(ctx->encode.bufsize);
600
        if (ctx->encode.buf == NULL) {
601
            ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
602
            return 0;
603
        }
604
        ctx->encode.ptr = ctx->encode.buf;
605
        ctx->encode.count = 0;
606
        ctx->encode.next_out = ctx->encode.buf;
607
        ctx->encode.avail_out = ctx->encode.bufsize;
608
    }
609
    /* Obtain input data directly from supplied buffer */
610
    ctx->encode.next_in = (unsigned char *)in;
611
    ctx->encode.avail_in = (size_t)inl;
612
    for (;;) {
613
        /* If data in output buffer write it first */
614
        while (ctx->encode.count > 0) {
615
            ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
616
            if (ret <= 0) {
617
                /* Total data written */
618
                int tot = inl - ctx->encode.avail_in;
619
620
                BIO_copy_next_retry(b);
621
                if (ret < 0)
622
                    return (tot > 0) ? tot : ret;
623
                return tot;
624
            }
625
            ctx->encode.ptr += ret;
626
            ctx->encode.count -= ret;
627
        }
628
629
        /* Have we consumed all supplied data? */
630
        if (ctx->encode.avail_in == 0 && !BrotliEncoderHasMoreOutput(ctx->encode.state))
631
            return inl;
632
633
        /* Compress some more */
634
635
        /* Reset buffer */
636
        ctx->encode.ptr = ctx->encode.buf;
637
        ctx->encode.next_out = ctx->encode.buf;
638
        ctx->encode.avail_out = ctx->encode.bufsize;
639
        /* Compress some more */
640
        brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FLUSH, &ctx->encode.avail_in, (const uint8_t **)&ctx->encode.next_in,
641
            &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
642
        if (brret != BROTLI_TRUE) {
643
            ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_ENCODE_ERROR);
644
            ERR_add_error_data(1, "brotli encoder error");
645
            return 0;
646
        }
647
        ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
648
    }
649
}
650
651
static int bio_brotli_flush(BIO *b)
652
{
653
    BIO_BROTLI_CTX *ctx;
654
    BROTLI_BOOL brret;
655
    int ret;
656
    BIO *next = BIO_next(b);
657
658
    ctx = BIO_get_data(b);
659
660
    /* If no data written or already flush show success */
661
    if (ctx->encode.buf == NULL || (ctx->encode.done && ctx->encode.count == 0))
662
        return 1;
663
664
    BIO_clear_retry_flags(b);
665
    /* No more input data */
666
    ctx->encode.next_in = NULL;
667
    ctx->encode.avail_in = 0;
668
    for (;;) {
669
        /* If data in output buffer write it first */
670
        while (ctx->encode.count > 0) {
671
            ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
672
            if (ret <= 0) {
673
                BIO_copy_next_retry(b);
674
                return ret;
675
            }
676
            ctx->encode.ptr += ret;
677
            ctx->encode.count -= ret;
678
        }
679
        if (ctx->encode.done)
680
            return 1;
681
682
        /* Compress some more */
683
684
        /* Reset buffer */
685
        ctx->encode.ptr = ctx->encode.buf;
686
        ctx->encode.next_out = ctx->encode.buf;
687
        ctx->encode.avail_out = ctx->encode.bufsize;
688
        /* Compress some more */
689
        brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FINISH, &ctx->encode.avail_in,
690
            (const uint8_t **)&ctx->encode.next_in, &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
691
        if (brret != BROTLI_TRUE) {
692
            ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_ENCODE_ERROR);
693
            ERR_add_error_data(1, "brotli encoder error");
694
            return 0;
695
        }
696
        if (!BrotliEncoderHasMoreOutput(ctx->encode.state) && ctx->encode.avail_in == 0)
697
            ctx->encode.done = 1;
698
        ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
699
    }
700
}
701
702
static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr)
703
{
704
    BIO_BROTLI_CTX *ctx;
705
    unsigned char *tmp;
706
    int ret = 0, *ip;
707
    size_t ibs, obs;
708
    BIO *next = BIO_next(b);
709
710
    if (next == NULL)
711
        return 0;
712
    ctx = BIO_get_data(b);
713
    switch (cmd) {
714
715
    case BIO_CTRL_RESET:
716
        ctx->encode.count = 0;
717
        ctx->encode.done = 0;
718
        ret = 1;
719
        break;
720
721
    case BIO_CTRL_FLUSH:
722
        ret = bio_brotli_flush(b);
723
        if (ret > 0) {
724
            ret = BIO_flush(next);
725
            BIO_copy_next_retry(b);
726
        }
727
        break;
728
729
    case BIO_C_SET_BUFF_SIZE:
730
        ibs = ctx->decode.bufsize;
731
        obs = ctx->encode.bufsize;
732
        if (ptr != NULL) {
733
            ip = ptr;
734
            if (*ip == 0)
735
                ibs = (size_t)num;
736
            else
737
                obs = (size_t)num;
738
        } else {
739
            ibs = (size_t)num;
740
            obs = ibs;
741
        }
742
743
        if (ibs > 0 && ibs != ctx->decode.bufsize) {
744
            /* Do not free/alloc, only reallocate */
745
            if (ctx->decode.buf != NULL) {
746
                tmp = OPENSSL_realloc(ctx->decode.buf, ibs);
747
                if (tmp == NULL)
748
                    return 0;
749
                ctx->decode.buf = tmp;
750
            }
751
            ctx->decode.bufsize = ibs;
752
        }
753
754
        if (obs > 0 && obs != ctx->encode.bufsize) {
755
            /* Do not free/alloc, only reallocate */
756
            if (ctx->encode.buf != NULL) {
757
                tmp = OPENSSL_realloc(ctx->encode.buf, obs);
758
                if (tmp == NULL)
759
                    return 0;
760
                ctx->encode.buf = tmp;
761
            }
762
            ctx->encode.bufsize = obs;
763
        }
764
        ret = 1;
765
        break;
766
767
    case BIO_C_DO_STATE_MACHINE:
768
        BIO_clear_retry_flags(b);
769
        ret = BIO_ctrl(next, cmd, num, ptr);
770
        BIO_copy_next_retry(b);
771
        break;
772
773
    case BIO_CTRL_WPENDING:
774
        if (BrotliEncoderHasMoreOutput(ctx->encode.state))
775
            ret = 1;
776
        else
777
            ret = BIO_ctrl(next, cmd, num, ptr);
778
        break;
779
780
    case BIO_CTRL_PENDING:
781
        if (!BrotliDecoderIsFinished(ctx->decode.state))
782
            ret = 1;
783
        else
784
            ret = BIO_ctrl(next, cmd, num, ptr);
785
        break;
786
787
    default:
788
        ret = BIO_ctrl(next, cmd, num, ptr);
789
        break;
790
    }
791
792
    return ret;
793
}
794
795
static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
796
{
797
    BIO *next = BIO_next(b);
798
    if (next == NULL)
799
        return 0;
800
    return BIO_callback_ctrl(next, cmd, fp);
801
}
802
803
#endif