}
}
+static struct istream_snapshot *
+i_stream_chain_snapshot(struct istream_private *stream,
+ struct istream_snapshot *prev_snapshot)
+{
+ if (stream->buffer == stream->w_buffer) {
+ /* Two or more istreams have been combined. Snapshot the
+ w_buffer's contents that contains their data. */
+ i_assert(stream->memarea != NULL);
+ return i_stream_default_snapshot(stream, prev_snapshot);
+ }
+ /* Individual istreams are being read. Snapshot the istream directly. */
+ struct chain_istream *cstream =
+ container_of(stream, struct chain_istream, istream);
+ struct istream_chain_link *link = cstream->chain.head;
+ if (link == NULL || link->stream == NULL)
+ return prev_snapshot;
+
+ struct istream_private *_link_stream = link->stream->real_stream;
+ struct istream_snapshot *snapshot = i_new(struct istream_snapshot, 1);
+ snapshot->prev_snapshot =
+ _link_stream->snapshot(_link_stream, prev_snapshot);
+ if (snapshot->prev_snapshot == prev_snapshot) {
+ /* The link stream didn't implement snapshotting in any way.
+ This could cause trouble if the link stream is freed while
+ it's still referred to in this snapshot. Fix this by
+ referencing the link istream. Normally avoid doing this,
+ since the extra references can cause unexpected problems. */
+ snapshot->istream = link->stream;
+ i_stream_ref(snapshot->istream);
+ }
+ return snapshot;
+}
+
struct istream *i_stream_create_chain(struct istream_chain **chain_r)
{
struct chain_istream *cstream;
i_stream_chain_set_max_buffer_size;
cstream->istream.read = i_stream_chain_read;
+ cstream->istream.snapshot = i_stream_chain_snapshot;
cstream->istream.istream.readable_fd = FALSE;
cstream->istream.istream.blocking = FALSE;
static void test_istream_chain_accumulate(void)
{
- struct istream *input;
- struct istream *test_input, *test_input2, *test_input3, *test_input4,
- *test_input5;
+ struct istream *input, *tmp_istream;
+ struct istream *test_istreams[5];
struct istream_chain *chain;
const unsigned char *data;
size_t size;
test_begin("istream chain accumulate");
- test_input = test_istream_create("abcdefghijklmnopqrst");
- test_input2 = test_istream_create("ABCDEFGHIJKLMNOPQRSTUVWXY");
- test_input3 = test_istream_create("!\"#$%&'()*+,-./01234567890:;<=");
- test_input4 = test_istream_create("z1y2x3w4v5u6t7s8r9q0p.o,n");
- test_input5 = test_istream_create("aAbBcCdDeEfFgGhHiIjJ");
+ test_istreams[0] = test_istream_create("abcdefghijklmnopqrst");
+ test_istreams[1] = test_istream_create("ABCDEFGHIJKLMNOPQRSTUVWXY");
+ test_istreams[2] = test_istream_create("!\"#$%&'()*+,-./01234567890:;<=");
+ test_istreams[3] = test_istream_create("z1y2x3w4v5u6t7s8r9q0p.o,n");
+ test_istreams[4] = test_istream_create("aAbBcCdDeEfFgGhHiIjJ");
input = i_stream_create_chain(&chain);
/* no input */
test_assert(i_stream_read(input) == 0);
/* first stream */
- i_stream_chain_append(chain, test_input);
+ i_stream_chain_append(chain, test_istreams[0]);
+ tmp_istream = test_istreams[0]; i_stream_unref(&tmp_istream);
test_assert(i_stream_read_data(input, &data, &size, 0) == 1);
test_assert(size == 20);
test_assert(memcmp(data, "abcdefghijklmnopqrst", 20) == 0);
i_stream_skip(input, 12);
/* second stream */
- i_stream_chain_append(chain, test_input2);
- test_istream_set_size(test_input2, 0);
+ i_stream_chain_append(chain, test_istreams[1]);
+ tmp_istream = test_istreams[1]; i_stream_unref(&tmp_istream);
+ test_istream_set_size(test_istreams[1], 0);
test_assert(i_stream_read_data(input, &data, &size, 10) == 0);
test_assert(size == 8);
- test_istream_set_size(test_input2, 10);
+ test_istream_set_size(test_istreams[1], 10);
test_assert(i_stream_read_data(input, &data, &size, 10) == 1);
test_assert(size == 18);
- test_istream_set_allow_eof(test_input2, FALSE);
+ test_istream_set_allow_eof(test_istreams[1], FALSE);
test_assert(i_stream_read(input) == 0);
- test_istream_set_size(test_input2, 25);
- test_istream_set_allow_eof(test_input2, TRUE);
+ test_istream_set_size(test_istreams[1], 25);
+ test_istream_set_allow_eof(test_istreams[1], TRUE);
test_assert(i_stream_read_data(input, &data, &size, 30) == 1);
test_assert(size == 33);
test_assert(memcmp(data, "mnopqrst"
i_stream_skip(input, 12);
/* third stream */
- i_stream_chain_append(chain, test_input3);
- test_istream_set_size(test_input3, 0);
+ i_stream_chain_append(chain, test_istreams[2]);
+ tmp_istream = test_istreams[2]; i_stream_unref(&tmp_istream);
+ test_istream_set_size(test_istreams[2], 0);
test_assert(i_stream_read(input) == 0);
- test_istream_set_size(test_input3, 30);
+ test_istream_set_size(test_istreams[2], 30);
test_assert(i_stream_read_data(input, &data, &size, 25) == 1);
test_assert(size == 51);
test_assert(memcmp(data, "EFGHIJKLMNOPQRSTUVWXY"
i_stream_skip(input, 12);
/* forth stream */
- i_stream_chain_append(chain, test_input4);
+ i_stream_chain_append(chain, test_istreams[3]);
+ tmp_istream = test_istreams[3]; i_stream_unref(&tmp_istream);
test_assert(i_stream_read_data(input, &data, &size, 40) == 1);
test_assert(size == 64);
test_assert(memcmp(data, "QRSTUVWXY"
i_stream_skip(input, 6);
/* fifth stream */
- i_stream_chain_append(chain, test_input5);
+ i_stream_chain_append(chain, test_istreams[4]);
+ tmp_istream = test_istreams[4]; i_stream_unref(&tmp_istream);
test_assert(i_stream_read_data(input, &data, &size, 60) == 1);
test_assert(size == 78);
test_assert(memcmp(data, "WXY"
test_assert(size == 0);
i_stream_unref(&input);
-
- i_stream_unref(&test_input);
- i_stream_unref(&test_input2);
- i_stream_unref(&test_input3);
- i_stream_unref(&test_input4);
- i_stream_unref(&test_input5);
test_end();
}