VirtualBox

source: vbox/trunk/src/libs/openssl-3.4.1/crypto/comp/c_brotli.c

Last change on this file was 109052, checked in by vboxsync, 3 weeks ago

openssl-3.4.1: Applied our changes, regenerated files, added missing files and functions. This time with a three way merge. ​bugref:10890

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette