123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800 |
- /*
- * Copyright 1998-2023 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- *
- * Uses brotli compression library from https://github.com/google/brotli
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/objects.h>
- #include "internal/comp.h"
- #include <openssl/err.h>
- #include "crypto/cryptlib.h"
- #include "internal/bio.h"
- #include "internal/thread_once.h"
- #include "comp_local.h"
- COMP_METHOD *COMP_brotli(void);
- #ifdef OPENSSL_NO_BROTLI
- # undef BROTLI_SHARED
- #else
- # include <brotli/decode.h>
- # include <brotli/encode.h>
- /* memory allocations functions for brotli initialisation */
- static void *brotli_alloc(void *opaque, size_t size)
- {
- return OPENSSL_zalloc(size);
- }
- static void brotli_free(void *opaque, void *address)
- {
- OPENSSL_free(address);
- }
- /*
- * When OpenSSL is built on Windows, we do not want to require that
- * the BROTLI.DLL be available in order for the OpenSSL DLLs to
- * work. Therefore, all BROTLI routines are loaded at run time
- * and we do not link to a .LIB file when BROTLI_SHARED is set.
- */
- # if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
- # include <windows.h>
- # endif
- # ifdef BROTLI_SHARED
- # include "internal/dso.h"
- /* Function pointers */
- typedef BrotliEncoderState *(*encode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
- typedef BROTLI_BOOL (*encode_stream_ft)(BrotliEncoderState *, BrotliEncoderOperation, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
- typedef BROTLI_BOOL (*encode_has_more_ft)(BrotliEncoderState *);
- typedef void (*encode_end_ft)(BrotliEncoderState *);
- typedef BROTLI_BOOL (*encode_oneshot_ft)(int, int, BrotliEncoderMode, size_t, const uint8_t in[], size_t *, uint8_t out[]);
- typedef BrotliDecoderState *(*decode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
- typedef BROTLI_BOOL (*decode_stream_ft)(BrotliDecoderState *, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
- typedef BROTLI_BOOL (*decode_has_more_ft)(BrotliDecoderState *);
- typedef void (*decode_end_ft)(BrotliDecoderState *);
- typedef BrotliDecoderErrorCode (*decode_error_ft)(BrotliDecoderState *);
- typedef const char *(*decode_error_string_ft)(BrotliDecoderErrorCode);
- typedef BROTLI_BOOL (*decode_is_finished_ft)(BrotliDecoderState *);
- typedef BrotliDecoderResult (*decode_oneshot_ft)(size_t, const uint8_t in[], size_t *, uint8_t out[]);
- static encode_init_ft p_encode_init = NULL;
- static encode_stream_ft p_encode_stream = NULL;
- static encode_has_more_ft p_encode_has_more = NULL;
- static encode_end_ft p_encode_end = NULL;
- static encode_oneshot_ft p_encode_oneshot = NULL;
- static decode_init_ft p_decode_init = NULL;
- static decode_stream_ft p_decode_stream = NULL;
- static decode_has_more_ft p_decode_has_more = NULL;
- static decode_end_ft p_decode_end = NULL;
- static decode_error_ft p_decode_error = NULL;
- static decode_error_string_ft p_decode_error_string = NULL;
- static decode_is_finished_ft p_decode_is_finished = NULL;
- static decode_oneshot_ft p_decode_oneshot = NULL;
- static DSO *brotli_encode_dso = NULL;
- static DSO *brotli_decode_dso = NULL;
- # define BrotliEncoderCreateInstance p_encode_init
- # define BrotliEncoderCompressStream p_encode_stream
- # define BrotliEncoderHasMoreOutput p_encode_has_more
- # define BrotliEncoderDestroyInstance p_encode_end
- # define BrotliEncoderCompress p_encode_oneshot
- # define BrotliDecoderCreateInstance p_decode_init
- # define BrotliDecoderDecompressStream p_decode_stream
- # define BrotliDecoderHasMoreOutput p_decode_has_more
- # define BrotliDecoderDestroyInstance p_decode_end
- # define BrotliDecoderGetErrorCode p_decode_error
- # define BrotliDecoderErrorString p_decode_error_string
- # define BrotliDecoderIsFinished p_decode_is_finished
- # define BrotliDecoderDecompress p_decode_oneshot
- # endif /* ifdef BROTLI_SHARED */
- struct brotli_state {
- BrotliEncoderState *encoder;
- BrotliDecoderState *decoder;
- };
- static int brotli_stateful_init(COMP_CTX *ctx)
- {
- struct brotli_state *state = OPENSSL_zalloc(sizeof(*state));
- if (state == NULL)
- return 0;
- state->encoder = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
- if (state->encoder == NULL)
- goto err;
- state->decoder = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
- if (state->decoder == NULL)
- goto err;
- ctx->data = state;
- return 1;
- err:
- BrotliDecoderDestroyInstance(state->decoder);
- BrotliEncoderDestroyInstance(state->encoder);
- OPENSSL_free(state);
- return 0;
- }
- static void brotli_stateful_finish(COMP_CTX *ctx)
- {
- struct brotli_state *state = ctx->data;
- if (state != NULL) {
- BrotliDecoderDestroyInstance(state->decoder);
- BrotliEncoderDestroyInstance(state->encoder);
- OPENSSL_free(state);
- ctx->data = NULL;
- }
- }
- static ossl_ssize_t brotli_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
- size_t olen, unsigned char *in,
- size_t ilen)
- {
- BROTLI_BOOL done;
- struct brotli_state *state = ctx->data;
- size_t in_avail = ilen;
- size_t out_avail = olen;
- if (state == NULL || olen > OSSL_SSIZE_MAX)
- return -1;
- if (ilen == 0)
- return 0;
- /*
- * The finish API does not provide a final output buffer,
- * so each compress operation has to be flushed, if all
- * the input data can't be accepted, or there is more output,
- * this has to be considered an error, since there is no more
- * output buffer space
- */
- done = BrotliEncoderCompressStream(state->encoder, BROTLI_OPERATION_FLUSH,
- &in_avail, (const uint8_t**)&in,
- &out_avail, &out, NULL);
- if (done == BROTLI_FALSE
- || in_avail != 0
- || BrotliEncoderHasMoreOutput(state->encoder))
- return -1;
- if (out_avail > olen)
- return -1;
- return (ossl_ssize_t)(olen - out_avail);
- }
- static ossl_ssize_t brotli_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
- size_t olen, unsigned char *in,
- size_t ilen)
- {
- BrotliDecoderResult result;
- struct brotli_state *state = ctx->data;
- size_t in_avail = ilen;
- size_t out_avail = olen;
- if (state == NULL || olen > OSSL_SSIZE_MAX)
- return -1;
- if (ilen == 0)
- return 0;
- result = BrotliDecoderDecompressStream(state->decoder, &in_avail,
- (const uint8_t**)&in, &out_avail,
- &out, NULL);
- if (result == BROTLI_DECODER_RESULT_ERROR
- || in_avail != 0
- || BrotliDecoderHasMoreOutput(state->decoder))
- return -1;
- if (out_avail > olen)
- return -1;
- return (ossl_ssize_t)(olen - out_avail);
- }
- static COMP_METHOD brotli_stateful_method = {
- NID_brotli,
- LN_brotli,
- brotli_stateful_init,
- brotli_stateful_finish,
- brotli_stateful_compress_block,
- brotli_stateful_expand_block
- };
- static int brotli_oneshot_init(COMP_CTX *ctx)
- {
- return 1;
- }
- static void brotli_oneshot_finish(COMP_CTX *ctx)
- {
- }
- static ossl_ssize_t brotli_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out,
- size_t olen, unsigned char *in,
- size_t ilen)
- {
- size_t out_size = olen;
- ossl_ssize_t ret;
- if (ilen == 0)
- return 0;
- if (BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW,
- BROTLI_DEFAULT_MODE, ilen, in,
- &out_size, out) == BROTLI_FALSE)
- return -1;
- if (out_size > OSSL_SSIZE_MAX)
- return -1;
- ret = (ossl_ssize_t)out_size;
- if (ret < 0)
- return -1;
- return ret;
- }
- static ossl_ssize_t brotli_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out,
- size_t olen, unsigned char *in,
- size_t ilen)
- {
- size_t out_size = olen;
- ossl_ssize_t ret;
- if (ilen == 0)
- return 0;
- if (BrotliDecoderDecompress(ilen, in, &out_size, out) != BROTLI_DECODER_RESULT_SUCCESS)
- return -1;
- if (out_size > OSSL_SSIZE_MAX)
- return -1;
- ret = (ossl_ssize_t)out_size;
- if (ret < 0)
- return -1;
- return ret;
- }
- static COMP_METHOD brotli_oneshot_method = {
- NID_brotli,
- LN_brotli,
- brotli_oneshot_init,
- brotli_oneshot_finish,
- brotli_oneshot_compress_block,
- brotli_oneshot_expand_block
- };
- static CRYPTO_ONCE brotli_once = CRYPTO_ONCE_STATIC_INIT;
- DEFINE_RUN_ONCE_STATIC(ossl_comp_brotli_init)
- {
- # ifdef BROTLI_SHARED
- # if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
- # define LIBBROTLIENC "BROTLIENC"
- # define LIBBROTLIDEC "BROTLIDEC"
- # else
- # define LIBBROTLIENC "brotlienc"
- # define LIBBROTLIDEC "brotlidec"
- # endif
- brotli_encode_dso = DSO_load(NULL, LIBBROTLIENC, NULL, 0);
- if (brotli_encode_dso != NULL) {
- p_encode_init = (encode_init_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCreateInstance");
- p_encode_stream = (encode_stream_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompressStream");
- p_encode_has_more = (encode_has_more_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderHasMoreOutput");
- p_encode_end = (encode_end_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderDestroyInstance");
- p_encode_oneshot = (encode_oneshot_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompress");
- }
- brotli_decode_dso = DSO_load(NULL, LIBBROTLIDEC, NULL, 0);
- if (brotli_decode_dso != NULL) {
- p_decode_init = (decode_init_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderCreateInstance");
- p_decode_stream = (decode_stream_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompressStream");
- p_decode_has_more = (decode_has_more_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderHasMoreOutput");
- p_decode_end = (decode_end_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDestroyInstance");
- p_decode_error = (decode_error_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderGetErrorCode");
- p_decode_error_string = (decode_error_string_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderErrorString");
- p_decode_is_finished = (decode_is_finished_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderIsFinished");
- p_decode_oneshot = (decode_oneshot_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompress");
- }
- if (p_encode_init == NULL || p_encode_stream == NULL || p_encode_has_more == NULL
- || p_encode_end == NULL || p_encode_oneshot == NULL || p_decode_init == NULL
- || p_decode_stream == NULL || p_decode_has_more == NULL || p_decode_end == NULL
- || p_decode_error == NULL || p_decode_error_string == NULL || p_decode_is_finished == NULL
- || p_decode_oneshot == NULL) {
- ossl_comp_brotli_cleanup();
- return 0;
- }
- # endif
- return 1;
- }
- #endif /* ifndef BROTLI / else */
- COMP_METHOD *COMP_brotli(void)
- {
- COMP_METHOD *meth = NULL;
- #ifndef OPENSSL_NO_BROTLI
- if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
- meth = &brotli_stateful_method;
- #endif
- return meth;
- }
- COMP_METHOD *COMP_brotli_oneshot(void)
- {
- COMP_METHOD *meth = NULL;
- #ifndef OPENSSL_NO_BROTLI
- if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
- meth = &brotli_oneshot_method;
- #endif
- return meth;
- }
- /* Also called from OPENSSL_cleanup() */
- void ossl_comp_brotli_cleanup(void)
- {
- #ifdef BROTLI_SHARED
- DSO_free(brotli_encode_dso);
- brotli_encode_dso = NULL;
- DSO_free(brotli_decode_dso);
- brotli_decode_dso = NULL;
- p_encode_init = NULL;
- p_encode_stream = NULL;
- p_encode_has_more = NULL;
- p_encode_end = NULL;
- p_encode_oneshot = NULL;
- p_decode_init = NULL;
- p_decode_stream = NULL;
- p_decode_has_more = NULL;
- p_decode_end = NULL;
- p_decode_error = NULL;
- p_decode_error_string = NULL;
- p_decode_is_finished = NULL;
- p_decode_oneshot = NULL;
- #endif
- }
- #ifndef OPENSSL_NO_BROTLI
- /* Brotli-based compression/decompression filter BIO */
- typedef struct {
- struct { /* input structure */
- size_t avail_in;
- unsigned char *next_in;
- size_t avail_out;
- unsigned char *next_out;
- unsigned char *buf;
- size_t bufsize;
- BrotliDecoderState *state;
- } decode;
- struct { /* output structure */
- size_t avail_in;
- unsigned char *next_in;
- size_t avail_out;
- unsigned char *next_out;
- unsigned char *buf;
- size_t bufsize;
- BrotliEncoderState *state;
- int mode; /* Encoder mode to use */
- int done;
- unsigned char *ptr;
- size_t count;
- } encode;
- } BIO_BROTLI_CTX;
- # define BROTLI_DEFAULT_BUFSIZE 1024
- static int bio_brotli_new(BIO *bi);
- static int bio_brotli_free(BIO *bi);
- static int bio_brotli_read(BIO *b, char *out, int outl);
- static int bio_brotli_write(BIO *b, const char *in, int inl);
- static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr);
- static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
- static const BIO_METHOD bio_meth_brotli = {
- BIO_TYPE_COMP,
- "brotli",
- /* TODO: Convert to new style write function */
- bwrite_conv,
- bio_brotli_write,
- /* TODO: Convert to new style read function */
- bread_conv,
- bio_brotli_read,
- NULL, /* bio_brotli_puts, */
- NULL, /* bio_brotli_gets, */
- bio_brotli_ctrl,
- bio_brotli_new,
- bio_brotli_free,
- bio_brotli_callback_ctrl
- };
- #endif
- const BIO_METHOD *BIO_f_brotli(void)
- {
- #ifndef OPENSSL_NO_BROTLI
- if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
- return &bio_meth_brotli;
- #endif
- return NULL;
- }
- #ifndef OPENSSL_NO_BROTLI
- static int bio_brotli_new(BIO *bi)
- {
- BIO_BROTLI_CTX *ctx;
- # ifdef BROTLI_SHARED
- if (!RUN_ONCE(&brotli_once, ossl_comp_brotli_init)) {
- ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_NOT_SUPPORTED);
- return 0;
- }
- # endif
- ctx = OPENSSL_zalloc(sizeof(*ctx));
- if (ctx == NULL) {
- ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- ctx->decode.bufsize = BROTLI_DEFAULT_BUFSIZE;
- ctx->decode.state = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
- if (ctx->decode.state == NULL)
- goto err;
- ctx->encode.bufsize = BROTLI_DEFAULT_BUFSIZE;
- ctx->encode.state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
- if (ctx->encode.state == NULL)
- goto err;
- ctx->encode.mode = BROTLI_DEFAULT_MODE;
- BIO_set_init(bi, 1);
- BIO_set_data(bi, ctx);
- return 1;
- err:
- ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
- BrotliDecoderDestroyInstance(ctx->decode.state);
- BrotliEncoderDestroyInstance(ctx->encode.state);
- OPENSSL_free(ctx);
- return 0;
- }
- static int bio_brotli_free(BIO *bi)
- {
- BIO_BROTLI_CTX *ctx;
- if (bi == NULL)
- return 0;
- ctx = BIO_get_data(bi);
- if (ctx != NULL) {
- BrotliDecoderDestroyInstance(ctx->decode.state);
- OPENSSL_free(ctx->decode.buf);
- BrotliEncoderDestroyInstance(ctx->encode.state);
- OPENSSL_free(ctx->encode.buf);
- OPENSSL_free(ctx);
- }
- BIO_set_data(bi, NULL);
- BIO_set_init(bi, 0);
- return 1;
- }
- static int bio_brotli_read(BIO *b, char *out, int outl)
- {
- BIO_BROTLI_CTX *ctx;
- BrotliDecoderResult bret;
- int ret;
- BIO *next = BIO_next(b);
- if (out == NULL || outl <= 0) {
- ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
- return 0;
- }
- #if INT_MAX > SIZE_MAX
- if ((unsigned int)outl > SIZE_MAX) {
- ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
- return 0;
- }
- #endif
- ctx = BIO_get_data(b);
- BIO_clear_retry_flags(b);
- if (ctx->decode.buf == NULL) {
- ctx->decode.buf = OPENSSL_malloc(ctx->decode.bufsize);
- if (ctx->decode.buf == NULL) {
- ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- ctx->decode.next_in = ctx->decode.buf;
- ctx->decode.avail_in = 0;
- }
- /* Copy output data directly to supplied buffer */
- ctx->decode.next_out = (unsigned char *)out;
- ctx->decode.avail_out = (size_t)outl;
- for (;;) {
- /* Decompress while data available */
- while (ctx->decode.avail_in > 0 || BrotliDecoderHasMoreOutput(ctx->decode.state)) {
- bret = BrotliDecoderDecompressStream(ctx->decode.state, &ctx->decode.avail_in, (const uint8_t**)&ctx->decode.next_in,
- &ctx->decode.avail_out, &ctx->decode.next_out, NULL);
- if (bret == BROTLI_DECODER_RESULT_ERROR) {
- ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
- ERR_add_error_data(1, BrotliDecoderErrorString(BrotliDecoderGetErrorCode(ctx->decode.state)));
- return 0;
- }
- /* If EOF or we've read everything then return */
- if (BrotliDecoderIsFinished(ctx->decode.state) || ctx->decode.avail_out == 0)
- return (int)(outl - ctx->decode.avail_out);
- }
- /* If EOF */
- if (BrotliDecoderIsFinished(ctx->decode.state))
- return 0;
- /*
- * No data in input buffer try to read some in, if an error then
- * return the total data read.
- */
- ret = BIO_read(next, ctx->decode.buf, ctx->decode.bufsize);
- if (ret <= 0) {
- /* Total data read */
- int tot = outl - ctx->decode.avail_out;
- BIO_copy_next_retry(b);
- if (ret < 0)
- return (tot > 0) ? tot : ret;
- return tot;
- }
- ctx->decode.avail_in = ret;
- ctx->decode.next_in = ctx->decode.buf;
- }
- }
- static int bio_brotli_write(BIO *b, const char *in, int inl)
- {
- BIO_BROTLI_CTX *ctx;
- BROTLI_BOOL brret;
- int ret;
- BIO *next = BIO_next(b);
- if (in == NULL || inl <= 0) {
- ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
- return 0;
- }
- #if INT_MAX > SIZE_MAX
- if ((unsigned int)inl > SIZE_MAX) {
- ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
- return 0;
- }
- #endif
- ctx = BIO_get_data(b);
- if (ctx->encode.done)
- return 0;
- BIO_clear_retry_flags(b);
- if (ctx->encode.buf == NULL) {
- ctx->encode.buf = OPENSSL_malloc(ctx->encode.bufsize);
- if (ctx->encode.buf == NULL) {
- ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- ctx->encode.ptr = ctx->encode.buf;
- ctx->encode.count = 0;
- ctx->encode.next_out = ctx->encode.buf;
- ctx->encode.avail_out = ctx->encode.bufsize;
- }
- /* Obtain input data directly from supplied buffer */
- ctx->encode.next_in = (unsigned char *)in;
- ctx->encode.avail_in = (size_t)inl;
- for (;;) {
- /* If data in output buffer write it first */
- while (ctx->encode.count > 0) {
- ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
- if (ret <= 0) {
- /* Total data written */
- int tot = inl - ctx->encode.avail_in;
- BIO_copy_next_retry(b);
- if (ret < 0)
- return (tot > 0) ? tot : ret;
- return tot;
- }
- ctx->encode.ptr += ret;
- ctx->encode.count -= ret;
- }
- /* Have we consumed all supplied data? */
- if (ctx->encode.avail_in == 0 && !BrotliEncoderHasMoreOutput(ctx->encode.state))
- return inl;
- /* Compress some more */
- /* Reset buffer */
- ctx->encode.ptr = ctx->encode.buf;
- ctx->encode.next_out = ctx->encode.buf;
- ctx->encode.avail_out = ctx->encode.bufsize;
- /* Compress some more */
- brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FLUSH, &ctx->encode.avail_in, (const uint8_t**)&ctx->encode.next_in,
- &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
- if (brret != BROTLI_TRUE) {
- ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_ENCODE_ERROR);
- ERR_add_error_data(1, "brotli encoder error");
- return 0;
- }
- ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
- }
- }
- static int bio_brotli_flush(BIO *b)
- {
- BIO_BROTLI_CTX *ctx;
- BROTLI_BOOL brret;
- int ret;
- BIO *next = BIO_next(b);
- ctx = BIO_get_data(b);
- /* If no data written or already flush show success */
- if (ctx->encode.buf == NULL || (ctx->encode.done && ctx->encode.count == 0))
- return 1;
- BIO_clear_retry_flags(b);
- /* No more input data */
- ctx->encode.next_in = NULL;
- ctx->encode.avail_in = 0;
- for (;;) {
- /* If data in output buffer write it first */
- while (ctx->encode.count > 0) {
- ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
- if (ret <= 0) {
- BIO_copy_next_retry(b);
- return ret;
- }
- ctx->encode.ptr += ret;
- ctx->encode.count -= ret;
- }
- if (ctx->encode.done)
- return 1;
- /* Compress some more */
- /* Reset buffer */
- ctx->encode.ptr = ctx->encode.buf;
- ctx->encode.next_out = ctx->encode.buf;
- ctx->encode.avail_out = ctx->encode.bufsize;
- /* Compress some more */
- brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FINISH, &ctx->encode.avail_in,
- (const uint8_t**)&ctx->encode.next_in, &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
- if (brret != BROTLI_TRUE) {
- ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
- ERR_add_error_data(1, "brotli encoder error");
- return 0;
- }
- if (!BrotliEncoderHasMoreOutput(ctx->encode.state) && ctx->encode.avail_in == 0)
- ctx->encode.done = 1;
- ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
- }
- }
- static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr)
- {
- BIO_BROTLI_CTX *ctx;
- unsigned char *tmp;
- int ret = 0, *ip;
- size_t ibs, obs;
- BIO *next = BIO_next(b);
- if (next == NULL)
- return 0;
- ctx = BIO_get_data(b);
- switch (cmd) {
- case BIO_CTRL_RESET:
- ctx->encode.count = 0;
- ctx->encode.done = 0;
- ret = 1;
- break;
- case BIO_CTRL_FLUSH:
- ret = bio_brotli_flush(b);
- if (ret > 0) {
- ret = BIO_flush(next);
- BIO_copy_next_retry(b);
- }
- break;
- case BIO_C_SET_BUFF_SIZE:
- ibs = ctx->decode.bufsize;
- obs = ctx->encode.bufsize;
- if (ptr != NULL) {
- ip = ptr;
- if (*ip == 0)
- ibs = (size_t)num;
- else
- obs = (size_t)num;
- } else {
- ibs = (size_t)num;
- obs = ibs;
- }
- if (ibs > 0 && ibs != ctx->decode.bufsize) {
- /* Do not free/alloc, only reallocate */
- if (ctx->decode.buf != NULL) {
- tmp = OPENSSL_realloc(ctx->decode.buf, ibs);
- if (tmp == NULL)
- return 0;
- ctx->decode.buf = tmp;
- }
- ctx->decode.bufsize = ibs;
- }
- if (obs > 0 && obs != ctx->encode.bufsize) {
- /* Do not free/alloc, only reallocate */
- if (ctx->encode.buf != NULL) {
- tmp = OPENSSL_realloc(ctx->encode.buf, obs);
- if (tmp == NULL)
- return 0;
- ctx->encode.buf = tmp;
- }
- ctx->encode.bufsize = obs;
- }
- ret = 1;
- break;
- case BIO_C_DO_STATE_MACHINE:
- BIO_clear_retry_flags(b);
- ret = BIO_ctrl(next, cmd, num, ptr);
- BIO_copy_next_retry(b);
- break;
- case BIO_CTRL_WPENDING:
- if (BrotliEncoderHasMoreOutput(ctx->encode.state))
- ret = 1;
- else
- ret = BIO_ctrl(next, cmd, num, ptr);
- break;
- case BIO_CTRL_PENDING:
- if (!BrotliDecoderIsFinished(ctx->decode.state))
- ret = 1;
- else
- ret = BIO_ctrl(next, cmd, num, ptr);
- break;
- default:
- ret = BIO_ctrl(next, cmd, num, ptr);
- break;
- }
- return ret;
- }
- static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
- {
- BIO *next = BIO_next(b);
- if (next == NULL)
- return 0;
- return BIO_callback_ctrl(next, cmd, fp);
- }
- #endif
|