istream-qp-encoder.c revision 869e8af5b722032920698743b27e89e6abd170e7
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "lib.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "buffer.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "hex-binary.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "qp-encoder.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "istream-private.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "istream-qp.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystruct qp_encoder_istream {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct istream_private istream;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny buffer_t *buf;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct qp_encoder *qp;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny};
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic void i_stream_qp_encoder_close(struct iostream_private *stream,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny bool close_parent)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct qp_encoder_istream *bstream =
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny (struct qp_encoder_istream *)stream;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (bstream->qp != NULL)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny qp_encoder_deinit(&bstream->qp);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (bstream->buf != NULL)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny buffer_free(&bstream->buf);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (close_parent)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_stream_close(bstream->istream.parent);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstatic ssize_t i_stream_qp_encoder_read(struct istream_private *stream)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek struct qp_encoder_istream *bstream =
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek (struct qp_encoder_istream *)stream;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek const unsigned char *data;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek size_t size;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek int ret;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek for(;;) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (stream->skip > 0) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_assert(stream->skip <= bstream->buf->used);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek buffer_delete(bstream->buf, 0, stream->skip);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->pos -= stream->skip;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->skip = 0;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->buffer = bstream->buf->data;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_assert(stream->pos <= bstream->buf->used);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (stream->pos >= bstream->istream.max_buffer_size) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek /* stream buffer still at maximum */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return -2;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek /* if something is already interpolated, return as much of it as
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek we can */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (bstream->buf->used > 0) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek size_t new_pos, bytes;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek /* only return up to max_buffer_size bytes, even when buffer
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek actually has more, as not to confuse the caller */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (bstream->buf->used <= bstream->istream.max_buffer_size) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek new_pos = bstream->buf->used;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (stream->parent->eof)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->istream.eof = TRUE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek } else {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek new_pos = bstream->istream.max_buffer_size;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bytes = new_pos - stream->pos;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->pos = new_pos;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return (ssize_t)bytes;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek /* need to read more input */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek ret = i_stream_read_more(stream->parent, &data, &size);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (ret == 0)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return ret;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (size == 0 && ret == -1) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->istream.stream_errno =
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->parent->stream_errno;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->istream.eof = stream->parent->eof;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return ret;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek qp_encoder_more(bstream->qp, data, size);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_stream_skip(stream->parent, size);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstatic void
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozeki_stream_qp_encoder_seek(struct istream_private *stream,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek uoff_t v_offset, bool mark)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek struct qp_encoder_istream *bstream =
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek (struct qp_encoder_istream *)stream;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (v_offset < stream->istream.v_offset) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek /* seeking backwards - go back to beginning and seek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek forward from there. */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->parent_expected_offset = stream->parent_start_offset;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->skip = stream->pos = 0;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek stream->istream.v_offset = 0;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_stream_seek(stream->parent, 0);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek qp_encoder_finish(bstream->qp);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek buffer_set_used_size(bstream->buf, 0);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_stream_default_seek_nonseekable(stream, v_offset, mark);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstruct istream *i_stream_create_qp_encoder(struct istream *input,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek enum qp_encoder_flag flags)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek struct qp_encoder_istream *bstream;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream = i_new(struct qp_encoder_istream, 1);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->buf = buffer_create_dynamic(default_pool, 128);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->qp = qp_encoder_init(bstream->buf, ISTREAM_QP_ENCODER_MAX_LINE_LENGTH, flags);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.iostream.close = i_stream_qp_encoder_close;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.read = i_stream_qp_encoder_read;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.seek = i_stream_qp_encoder_seek;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.istream.readable_fd = FALSE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.istream.blocking = input->blocking;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek bstream->istream.istream.seekable = input->seekable;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return i_stream_create(&bstream->istream, input,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_stream_get_fd(input));
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek