istream.c revision 2526d52441ef368215ab6bf04fd0356d3b09d235
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (c) 2002-2003 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "str.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream-internal.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenvoid i_stream_destroy(struct istream **stream)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen{
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_close(*stream);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_unref(stream);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_ref(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
daf029d2a627daa39d05507140f385162828172eTimo Sirainen _io_stream_ref(&stream->real_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid i_stream_unref(struct istream **stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct _istream *_stream = (*stream)->real_stream;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (_stream->iostream.refcount == 1) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (_stream->line_str != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_free(&_stream->line_str);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen _io_stream_unref(&(*stream)->real_stream->iostream);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *stream = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint i_stream_get_fd(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->fd;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_close(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
daf029d2a627daa39d05507140f385162828172eTimo Sirainen _io_stream_close(&stream->real_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->closed = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
daf029d2a627daa39d05507140f385162828172eTimo Sirainen _io_stream_set_max_buffer_size(&stream->real_stream->iostream,
daf029d2a627daa39d05507140f385162828172eTimo Sirainen max_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenssize_t i_stream_read(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->closed)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen stream->eof = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->read(_stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t data_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen data_size = _stream->pos - _stream->skip;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (count <= data_size) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* within buffer */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->v_offset += count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->skip += count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* have to seek forward */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen count -= data_size;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen _stream->skip = _stream->pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->v_offset += data_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (stream->closed)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
35df1dd606c5ef21068ab4fe4be305859d4fad4bTimo Sirainen if (v_offset >= stream->v_offset) {
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen return;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen }
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->closed)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen stream->eof = FALSE;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, v_offset, FALSE);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen struct _istream *_stream = stream->real_stream;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (stream->closed)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen stream->eof = FALSE;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, v_offset, TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenvoid i_stream_sync(struct istream *stream)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct _istream *_stream = stream->real_stream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (!stream->closed && _stream->sync != NULL)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->sync(_stream);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenconst struct stat *i_stream_stat(struct istream *stream, bool exact)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct _istream *_stream = stream->real_stream;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen if (stream->closed)
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen return NULL;
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen return _stream->stat(_stream, exact);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen{
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen struct _istream *_stream = stream->real_stream;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen}
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenstatic char *i_stream_next_line_finish(struct _istream *stream, size_t i)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen char *ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen size_t end;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r')
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end = i - 1;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen else
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end = i;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (stream->w_buffer != NULL) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* modify the buffer directly */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->w_buffer[end] = '\0';
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen } else {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* use a temporary string to return it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (stream->line_str == NULL)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->line_str = str_new(default_pool, 256);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_truncate(stream->line_str, 0);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end - stream->skip);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ret = str_c_modifiable(stream->line_str);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i++;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->istream.v_offset += i - stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->skip = i;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenchar *i_stream_next_line(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen char *ret_buf;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t i;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen if (_stream->skip >= _stream->pos) {
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen stream->stream_errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->w_buffer == NULL) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_error("i_stream_next_line() called for unmodifiable stream");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* @UNSAFE */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret_buf = NULL;
3e25b17126e9536736d5da03697613e4c3af5f76Timo Sirainen for (i = _stream->skip; i < _stream->pos; i++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->buffer[i] == 10) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* got it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret_buf = i_stream_next_line_finish(_stream, i);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret_buf;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen{
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen char *line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen line = i_stream_next_line(stream);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (line != NULL)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (i_stream_read(stream) > 0)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen line = i_stream_next_line(stream);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenconst unsigned char *i_stream_get_data(struct istream *stream, size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = _stream->pos - _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = _stream->pos - _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->w_buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r, size_t threshold)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t ret = 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool read_more = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen do {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (*size_r > threshold)
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen return 1;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we need more data */
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen ret = i_stream_read(stream);
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen if (ret > 0)
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen read_more = TRUE;
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen } while (ret > 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (ret == -2)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return -2;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (read_more || ret == 0) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen i_assert(!stream->blocking || stream->eof);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return 0;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainenvoid _i_stream_compress(struct _istream *stream)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos - stream->skip);
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos -= stream->skip;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->skip = 0;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen}
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenvoid _i_stream_grow_buffer(struct _istream *stream, size_t bytes)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen size_t old_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen old_size = stream->buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->pos + bytes;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (stream->buffer_size <= I_STREAM_MIN_SIZE)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = I_STREAM_MIN_SIZE;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen else
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (stream->max_buffer_size > 0 &&
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size > stream->max_buffer_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->max_buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer = stream->w_buffer =
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen i_realloc(stream->w_buffer, old_size, stream->buffer_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen struct _istream *_stream = (struct _istream *) stream;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen _stream->max_buffer_size = max_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenstatic const struct stat *
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen_stat(struct _istream *stream, bool exact __attr_unused__)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return &stream->statbuf;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct istream *
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen_i_stream_create(struct _istream *_stream, int fd, uoff_t abs_start_offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->fd = fd;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen _stream->abs_start_offset = abs_start_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->istream.real_stream = _stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (_stream->stat == NULL)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen _stream->stat = _stat;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (_stream->iostream.set_max_buffer_size == NULL)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen _stream->iostream.set_max_buffer_size = _set_max_buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_size = -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_atime =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_mtime =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_ctime = ioloop_time;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen _io_stream_init(&_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return &_stream->istream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#ifdef STREAM_TEST
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen/* gcc istream.c -o teststream liblib.a -Wall -DHAVE_CONFIG_H -DSTREAM_TEST -g */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include <fcntl.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include <unistd.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "ostream.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#define BUF_VALUE(offset) \
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (((offset) % 256) ^ ((offset) / 256))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void check_buffer(const unsigned char *data, size_t size, size_t offset)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen size_t i;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < size; i++)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(data[i] == BUF_VALUE(i+offset));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint main(void)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct istream *input, *l_input;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct ostream *output1, *output2;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int i, fd1, fd2;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned char buf[1024];
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const unsigned char *data;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen size_t size;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen lib_init();
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd1 = open("teststream.1", O_RDWR | O_CREAT | O_TRUNC, 0600);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (fd1 < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_fatal("open() failed: %m");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd2 = open("teststream.2", O_RDWR | O_CREAT | O_TRUNC, 0600);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (fd2 < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_fatal("open() failed: %m");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* write initial data */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < sizeof(buf); i++)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen buf[i] = BUF_VALUE(i);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen write(fd1, buf, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test reading */
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen input = i_stream_create_fd(fd1, 512, FALSE);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_get_size(input) == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 256);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 256);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 512) == -2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_skip(input, 900);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == sizeof(buf) - 900);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 900);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test moving data */
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen output1 = o_stream_create_fd(fd1, 512, FALSE);
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen output2 = o_stream_create_fd(fd2, 512, FALSE);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 1); size = sizeof(buf)-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output2, input) == size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen o_stream_flush(output2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen lseek(fd2, 0, SEEK_SET);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(read(fd2, buf, sizeof(buf)) == size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(buf, size, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen o_stream_seek(output1, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output1, input) == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test moving with limits */
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen l_input = i_stream_create_limit(input, sizeof(buf)/2, 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(l_input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen o_stream_seek(output1, 10);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output1, l_input) == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_set_max_buffer_size(input, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, sizeof(buf)-1) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, 10, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data + 10, 512, sizeof(buf)/2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data + 10 + 512,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen size - (10 + 512), 10 + 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* reading within limits */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(l_input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 511) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 512) == -2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_skip(l_input, 511);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_skip(l_input, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 0) == -1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unlink("teststream.1");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unlink("teststream.2");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#endif