From 319cee9e2fc6fcf6ad865564eccdac4c55e92c0a Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 27 Nov 2019 16:02:33 +0100 Subject: BIO: Add BIO_f_prefix(), a text line prefixing filter Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10531) --- crypto/bio/bf_prefix.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++ crypto/bio/build.info | 2 +- 2 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 crypto/bio/bf_prefix.c (limited to 'crypto/bio') diff --git a/crypto/bio/bf_prefix.c b/crypto/bio/bf_prefix.c new file mode 100644 index 0000000000..5727c14950 --- /dev/null +++ b/crypto/bio/bf_prefix.c @@ -0,0 +1,207 @@ +/* + * Copyright 2018-2019 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 + */ + +#include +#include +#include +#include "bio_local.h" + +static int prefix_write(BIO *b, const char *out, size_t outl, + size_t *numwritten); +static int prefix_read(BIO *b, char *buf, size_t size, size_t *numread); +static int prefix_puts(BIO *b, const char *str); +static int prefix_gets(BIO *b, char *str, int size); +static long prefix_ctrl(BIO *b, int cmd, long arg1, void *arg2); +static int prefix_create(BIO *b); +static int prefix_destroy(BIO *b); +static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp); + +static const BIO_METHOD prefix_meth = { + BIO_TYPE_BUFFER, + "prefix", + prefix_write, + NULL, + prefix_read, + NULL, + prefix_puts, + prefix_gets, + prefix_ctrl, + prefix_create, + prefix_destroy, + prefix_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_prefix(void) +{ + return &prefix_meth; +} + +typedef struct prefix_ctx_st { + char *prefix; /* Text prefix, given by user */ + unsigned int indent; /* Indentation amount, given by user */ + + int linestart; /* flag to indicate we're at the line start */ +} PREFIX_CTX; + +static int prefix_create(BIO *b) +{ + PREFIX_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx == NULL) + return 0; + + ctx->prefix = NULL; + ctx->indent = 0; + ctx->linestart = 1; + BIO_set_data(b, ctx); + BIO_set_init(b, 1); + return 1; +} + +static int prefix_destroy(BIO *b) +{ + PREFIX_CTX *ctx = BIO_get_data(b); + + OPENSSL_free(ctx->prefix); + OPENSSL_free(ctx); + return 1; +} + +static int prefix_read(BIO *b, char *in, size_t size, size_t *numread) +{ + return BIO_read_ex(BIO_next(b), in, size, numread); +} + +static int prefix_write(BIO *b, const char *out, size_t outl, + size_t *numwritten) +{ + PREFIX_CTX *ctx = BIO_get_data(b); + + if (ctx == NULL) + return 0; + + /* + * If no prefix is set or if it's empty, and no indentation amount is set, + * we've got nothing to do here + */ + if ((ctx->prefix == NULL || *ctx->prefix == '\0') + && ctx->indent == 0) { + /* + * We do note if what comes next will be a new line, though, so we're + * prepared to handle prefix and indentation the next time around. + */ + if (outl > 0) + ctx->linestart = (out[outl-1] == '\n'); + return BIO_write_ex(BIO_next(b), out, outl, numwritten); + } + + *numwritten = 0; + + while (outl > 0) { + size_t i; + char c; + + /* + * If we know that we're at the start of the line, output prefix and + * indentation. + */ + if (ctx->linestart) { + size_t dontcare; + + if (ctx->prefix != NULL + && !BIO_write_ex(BIO_next(b), ctx->prefix, strlen(ctx->prefix), + &dontcare)) + return 0; + BIO_printf(BIO_next(b), "%*s", ctx->indent, ""); + ctx->linestart = 0; + } + + /* Now, go look for the next LF, or the end of the string */ + for (i = 0, c = '\0'; i < outl && (c = out[i]) != '\n'; i++) + continue; + if (c == '\n') + i++; + + /* Output what we found so far */ + while (i > 0) { + size_t num = 0; + + if (!BIO_write_ex(BIO_next(b), out, i, &num)) + return 0; + out += num; + outl -= num; + *numwritten += num; + i -= num; + } + + /* If we found a LF, what follows is a new line, so take note */ + if (c == '\n') + ctx->linestart = 1; + } + + return 1; +} + +static long prefix_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 0; + PREFIX_CTX *ctx = BIO_get_data(b); + + if (ctx == NULL) + return -1; + + switch (cmd) { + case BIO_CTRL_SET_PREFIX: + OPENSSL_free(ctx->prefix); + if (ptr == NULL) { + ctx->prefix = NULL; + ret = 1; + } else { + ctx->prefix = OPENSSL_strdup((const char *)ptr); + ret = ctx->prefix != NULL; + } + break; + case BIO_CTRL_SET_INDENT: + if (num >= 0) { + ctx->indent = (unsigned int)num; + ret = 1; + } + break; + case BIO_CTRL_GET_INDENT: + ret = (long)ctx->indent; + break; + default: + /* Commands that we intercept before passing them along */ + switch (cmd) { + case BIO_C_FILE_SEEK: + case BIO_CTRL_RESET: + ctx->linestart = 1; + break; + } + if (BIO_next(b) != NULL) + ret = BIO_ctrl(BIO_next(b), cmd, num, ptr); + break; + } + return ret; +} + +static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + return BIO_callback_ctrl(BIO_next(b), cmd, fp); +} + +static int prefix_gets(BIO *b, char *buf, int size) +{ + return BIO_gets(BIO_next(b), buf, size); +} + +static int prefix_puts(BIO *b, const char *str) +{ + return BIO_write(b, str, strlen(str)); +} diff --git a/crypto/bio/build.info b/crypto/bio/build.info index 3f84bb824c..8e3f530f88 100644 --- a/crypto/bio/build.info +++ b/crypto/bio/build.info @@ -15,4 +15,4 @@ SOURCE[../../libcrypto]=\ # Filters SOURCE[../../libcrypto]=\ - bf_null.c bf_buff.c bf_lbuf.c bf_nbio.c + bf_null.c bf_buff.c bf_lbuf.c bf_nbio.c bf_prefix.c -- cgit v1.2.3