istream.c revision fe363b433b8038a69b55169da9dca27892ad7d18
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2003 Timo Sirainen */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "lib.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "ioloop.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "str.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "istream-internal.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenvoid i_stream_destroy(struct istream **stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_stream_close(*stream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_stream_unref(stream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainenvoid i_stream_ref(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _io_stream_ref(&stream->real_stream->iostream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid i_stream_unref(struct istream **stream)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen struct _istream *_stream = (*stream)->real_stream;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (_stream->iostream.refcount == 1) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (_stream->line_str != NULL)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen str_free(&_stream->line_str);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _io_stream_unref(&(*stream)->real_stream->iostream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *stream = NULL;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenint i_stream_get_fd(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen struct _istream *_stream = stream->real_stream;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen return _stream->fd;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid i_stream_close(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _io_stream_close(&stream->real_stream->iostream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen stream->closed = TRUE;
7b032348d7bbb93ff96188289d3dfc1899b9abb3Josef 'Jeff' Sipek}
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _io_stream_set_max_buffer_size(&stream->real_stream->iostream,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen max_size);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenssize_t i_stream_read(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct _istream *_stream = stream->real_stream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (stream->closed)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen stream->eof = FALSE;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return _stream->read(_stream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen struct _istream *_stream = stream->real_stream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t data_size;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen data_size = _stream->pos - _stream->skip;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (count <= data_size) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* within buffer */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen stream->v_offset += count;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->skip += count;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return;
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen }
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen /* have to seek forward */
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen count -= data_size;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->skip = _stream->pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen stream->v_offset += data_size;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (stream->closed)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen}
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen{
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen struct _istream *_stream = stream->real_stream;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen if (v_offset >= stream->v_offset) {
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen }
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen if (stream->closed)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen stream->eof = FALSE;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen}
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen{
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen struct _istream *_stream = stream->real_stream;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen if (stream->closed)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen stream->eof = FALSE;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen _stream->seek(_stream, v_offset, TRUE);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid i_stream_sync(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct _istream *_stream = stream->real_stream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (!stream->closed && _stream->sync != NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->sync(_stream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainenconst struct stat *i_stream_stat(struct istream *stream, bool exact)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen{
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen struct _istream *_stream = stream->real_stream;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen if (stream->closed)
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return NULL;
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen return _stream->stat(_stream, exact);
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen}
d97f081a3de44852197ced772e21560c108895a6Timo Sirainen
d97f081a3de44852197ced772e21560c108895a6Timo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct _istream *_stream = stream->real_stream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic char *i_stream_next_line_finish(struct _istream *stream, size_t i)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t end;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r')
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen end = i - 1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen else
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen end = i;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (stream->w_buffer != NULL) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* modify the buffer directly */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen stream->w_buffer[end] = '\0';
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen ret = (char *)stream->w_buffer + stream->skip;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen } else {
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen /* use a temporary string to return it */
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen if (stream->line_str == NULL)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen stream->line_str = str_new(default_pool, 256);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen str_truncate(stream->line_str, 0);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen end - stream->skip);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen ret = str_c_modifiable(stream->line_str);
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
adea69875046ece77dc36abd3f88a241a3f17ad9Timo Sirainen i++;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen stream->istream.v_offset += i - stream->skip;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen stream->skip = i;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return ret;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenchar *i_stream_next_line(struct istream *stream)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct _istream *_stream = stream->real_stream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char *ret_buf;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t i;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (_stream->skip >= _stream->pos) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen stream->stream_errno = 0;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (_stream->w_buffer == NULL) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_error("i_stream_next_line() called for unmodifiable stream");
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* @UNSAFE */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen ret_buf = NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen for (i = _stream->skip; i < _stream->pos; i++) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (_stream->buffer[i] == 10) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* got it */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen ret_buf = i_stream_next_line_finish(_stream, i);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return ret_buf;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen char *line;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen line = i_stream_next_line(stream);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (line != NULL)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return line;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (i_stream_read(stream) > 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen line = i_stream_next_line(stream);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return line;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenconst unsigned char *i_stream_get_data(struct istream *stream, size_t *size_r)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen struct _istream *_stream = stream->real_stream;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (_stream->skip >= _stream->pos) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen *size_r = 0;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *size_r = _stream->pos - _stream->skip;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return _stream->buffer + _stream->skip;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen size_t *size_r)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct _istream *_stream = stream->real_stream;
61d57efe9dee0dd38b0f726ef85e3c710cb655fcTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *size_r = 0;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *size_r = _stream->pos - _stream->skip;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return _stream->w_buffer + _stream->skip;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen size_t *size_r, size_t threshold)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen ssize_t ret = 0;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen bool read_more = FALSE;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen do {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (*size_r > threshold)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return 1;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* we need more data */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen ret = i_stream_read(stream);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (ret > 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen read_more = TRUE;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen } while (ret > 0);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (ret == -2)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return -2;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
e20f5920759215f328ce12dcca071b4e7dda3d48Timo Sirainen if (read_more || ret == 0) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(!stream->blocking || stream->eof);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return 0;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen return -1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainenvoid _i_stream_compress(struct _istream *stream)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen{
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen stream->pos - stream->skip);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen stream->pos -= stream->skip;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen stream->skip = 0;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen}
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainenvoid _i_stream_grow_buffer(struct _istream *stream, size_t bytes)
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen{
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen size_t old_size;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen old_size = stream->buffer_size;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen stream->buffer_size = stream->pos + bytes;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen if (stream->buffer_size <= I_STREAM_MIN_SIZE)
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen stream->buffer_size = I_STREAM_MIN_SIZE;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen else
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen if (stream->max_buffer_size > 0 &&
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen stream->buffer_size > stream->max_buffer_size)
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen stream->buffer_size = stream->max_buffer_size;
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen stream->buffer = stream->w_buffer =
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen i_realloc(stream->w_buffer, old_size, stream->buffer_size);
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen struct _istream *_stream = (struct _istream *) stream;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen _stream->max_buffer_size = max_size;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenstatic const struct stat *
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen_stat(struct _istream *stream, bool exact __attr_unused__)
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen return &stream->statbuf;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen}
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainenstruct istream *
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen_i_stream_create(struct _istream *_stream, int fd, uoff_t abs_start_offset)
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen _stream->fd = fd;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->abs_start_offset = abs_start_offset;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->istream.real_stream = _stream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (_stream->stat == NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->stat = _stat;
da574ef2db96f258d24bc4c89a77833036d13a95Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->iostream.set_max_buffer_size = _set_max_buffer_size;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen _stream->statbuf.st_size = -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->statbuf.st_atime =
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _stream->statbuf.st_mtime =
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen _stream->statbuf.st_ctime = ioloop_time;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _io_stream_init(&_stream->iostream);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return &_stream->istream;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen#ifdef STREAM_TEST
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen/* gcc istream.c -o teststream liblib.a -Wall -DHAVE_CONFIG_H -DSTREAM_TEST -g */
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen#include <fcntl.h>
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen#include <unistd.h>
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen#include "ostream.h"
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen#define BUF_VALUE(offset) \
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen (((offset) % 256) ^ ((offset) / 256))
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic void check_buffer(const unsigned char *data, size_t size, size_t offset)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t i;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen for (i = 0; i < size; i++)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(data[i] == BUF_VALUE(i+offset));
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenint main(void)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct istream *input, *l_input;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct ostream *output1, *output2;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen int i, fd1, fd2;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen unsigned char buf[1024];
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const unsigned char *data;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t size;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen lib_init();
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen fd1 = open("teststream.1", O_RDWR | O_CREAT | O_TRUNC, 0600);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen if (fd1 < 0)
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen i_fatal("open() failed: %m");
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen fd2 = open("teststream.2", O_RDWR | O_CREAT | O_TRUNC, 0600);
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen if (fd2 < 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_fatal("open() failed: %m");
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* write initial data */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen for (i = 0; i < sizeof(buf); i++)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen buf[i] = BUF_VALUE(i);
b3f4c31f1533e25380f49f77d5bb1251bf43db2aTimo Sirainen write(fd1, buf, sizeof(buf));
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen /* test reading */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen input = i_stream_create_file(fd1, 512, FALSE);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(i_stream_get_size(input) == sizeof(buf));
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen i_assert(size == 512);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen check_buffer(data, size, 0);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_stream_seek(input, 256);
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen i_assert(size == 512);
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen check_buffer(data, size, 256);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen i_stream_seek(input, 0);
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 512) == -2);
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen i_assert(size == 512);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen check_buffer(data, size, 0);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_stream_skip(input, 900);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(size == sizeof(buf) - 900);
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen check_buffer(data, size, 900);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen /* test moving data */
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen output1 = o_stream_create_file(fd1, 512, FALSE);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen output2 = o_stream_create_file(fd2, 512, FALSE);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_stream_seek(input, 1); size = sizeof(buf)-1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(o_stream_send_istream(output2, input) == size);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen o_stream_flush(output2);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
lseek(fd2, 0, SEEK_SET);
i_assert(read(fd2, buf, sizeof(buf)) == size);
check_buffer(buf, size, 1);
i_stream_seek(input, 0);
o_stream_seek(output1, sizeof(buf));
i_assert(o_stream_send_istream(output1, input) == sizeof(buf));
/* test moving with limits */
l_input = i_stream_create_limit(input, sizeof(buf)/2, 512);
i_stream_seek(l_input, 0);
o_stream_seek(output1, 10);
i_assert(o_stream_send_istream(output1, l_input) == 512);
i_stream_set_max_buffer_size(input, sizeof(buf));
i_stream_seek(input, 0);
i_assert(i_stream_read_data(input, &data, &size, sizeof(buf)-1) > 0);
i_assert(size == sizeof(buf));
check_buffer(data, 10, 0);
check_buffer(data + 10, 512, sizeof(buf)/2);
check_buffer(data + 10 + 512,
size - (10 + 512), 10 + 512);
/* reading within limits */
i_stream_seek(l_input, 0);
i_assert(i_stream_read_data(l_input, &data, &size, 511) > 0);
i_assert(size == 512);
i_assert(i_stream_read_data(l_input, &data, &size, 512) == -2);
i_assert(size == 512);
i_stream_skip(l_input, 511);
i_assert(i_stream_read_data(l_input, &data, &size, 0) > 0);
i_assert(size == 1);
i_stream_skip(l_input, 1);
i_assert(i_stream_read_data(l_input, &data, &size, 0) == -1);
i_assert(size == 0);
unlink("teststream.1");
unlink("teststream.2");
return 0;
}
#endif