istream-chain.c revision d730192e34fbedbc590a5abc7351e5af5e120c5f
a11689fe3fbb3bca11b9cb4ae5faf27db96401ccTimo Sirainen/* Copyright (c) 2003-2013 Dovecot authors, see the included COPYING file */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Siraineni_stream_chain_append_internal(struct istream_chain *chain,
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen if (stream == NULL && chain->tail != NULL && chain->tail->stream == NULL)
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen if (chain->stream->istream.max_buffer_size == 0) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen DLLIST2_APPEND(&chain->head, &chain->tail, link);
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainenvoid i_stream_chain_append(struct istream_chain *chain, struct istream *stream)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen i_stream_chain_append_internal(chain, stream);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenvoid i_stream_chain_append_eof(struct istream_chain *chain)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Siraineni_stream_chain_set_max_buffer_size(struct iostream_private *stream,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen struct istream_chain_link *link = cstream->chain.head;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen i_stream_set_max_buffer_size(link->stream, max_size);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic void i_stream_chain_destroy(struct iostream_private *stream)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen struct istream_chain_link *link = cstream->chain.head;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic void i_stream_chain_read_next(struct chain_istream *cstream)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const unsigned char *data;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(link != NULL && link->stream != NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen data = i_stream_get_data(prev_input, &data_size);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen DLLIST2_REMOVE(&cstream->chain.head, &cstream->chain.tail, link);
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* a) we have more streams, b) we have EOF, c) we need to wait
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen for more streams */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen if (cstream->istream.buffer == cstream->istream.w_buffer) {
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* we've already buffered the prev_input */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* we already verified that the data size is less than the
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen maximum buffer size */
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen if (!i_stream_try_alloc(&cstream->istream, data_size, &size))
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen memcpy(cstream->istream.w_buffer, data, data_size);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainenstatic ssize_t i_stream_chain_read(struct istream_private *stream)
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen const unsigned char *data;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen size_t size, data_size, cur_data_pos, new_pos, bytes_skipped;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen bytes_skipped = stream->skip - cstream->prev_skip;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* no need to worry about buffers, skip everything */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen } else if (bytes_skipped < cstream->prev_stream_left) {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* we're still skipping inside buffer */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* done with the buffer */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen cur_data_pos = stream->pos - (stream->skip + cstream->prev_stream_left);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen data = i_stream_get_data(link->stream, &data_size);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* need to read more */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* EOF of this stream, go to next stream */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* we read something */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen data = i_stream_get_data(link->stream, &data_size);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* we can point directly to the current stream's buffers */
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen /* nothing new read */
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen /* we still have some of the previous stream left. merge the
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen new data with it. */
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen if (!i_stream_try_alloc(stream, new_bytes_count, &size)) {
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen ret = new_pos > stream->pos ? (ssize_t)(new_pos - stream->pos) :
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainenstruct istream *i_stream_create_chain(struct istream_chain **chain_r)
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen cstream->istream.iostream.destroy = i_stream_chain_destroy;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen cstream->istream.iostream.set_max_buffer_size =