summaryrefslogtreecommitdiffstats
path: root/stream/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream/stream.c')
-rw-r--r--stream/stream.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/stream/stream.c b/stream/stream.c
index 5e27e5827c..6b015ff2fd 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -136,7 +136,7 @@ static const stream_info_t *const auto_open_streams[] = {
NULL
};
-static stream_t *new_stream(void);
+static stream_t *new_stream(size_t min_size);
static int stream_seek_unbuffered(stream_t *s, int64_t newpos);
static stream_t *open_stream_plugin(const stream_info_t *sinfo,
@@ -166,7 +166,7 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo,
}
}
}
- s = new_stream();
+ s = new_stream(0);
s->opts = options;
s->url = strdup(filename);
s->flags |= mode;
@@ -378,7 +378,9 @@ static int stream_read_unbuffered(stream_t *s, void *buf, int len)
default:
len = s->fill_buffer ? s->fill_buffer(s, buf, len) : 0;
}
- if (len <= 0) {
+ if (len < 0)
+ len = 0;
+ if (len == 0) {
// do not retry if this looks like proper eof
if (s->eof || (s->end_pos && s->pos == s->end_pos))
goto eof_out;
@@ -402,35 +404,16 @@ eof_out:
return len;
}
-// This works like stdio's ungetc(), but for more than one byte. Rewind the
-// file position by buffer_size, and make all future reads/buffer fills read
-// from the given buffer, until the buffer is exhausted or a seek outside of
-// the buffer happens.
-// You can unread at most STREAM_MAX_BUFFER_SIZE bytes.
-void stream_unread_buffer(stream_t *s, void *buffer, size_t buffer_size)
-{
- assert(stream_tell(s) >= buffer_size); // can't unread to before file start
- assert(buffer_size <= STREAM_MAX_BUFFER_SIZE);
- // Need to include the remaining buffer to ensure no data is lost.
- int remainder = s->buf_len - s->buf_pos;
- // Successive buffer unreading might trigger this.
- assert(buffer_size + remainder <= TOTAL_BUFFER_SIZE);
- memmove(&s->buffer[buffer_size], &s->buffer[s->buf_pos], remainder);
- memcpy(s->buffer, buffer, buffer_size);
- s->buf_pos = 0;
- s->buf_len = buffer_size + remainder;
-}
-
int stream_fill_buffer(stream_t *s)
{
int len = stream_read_unbuffered(s, s->buffer, STREAM_BUFFER_SIZE);
s->buf_pos = 0;
- s->buf_len = len < 0 ? 0 : len;
+ s->buf_len = len;
return s->buf_len;
}
// Read between 1..buf_size bytes of data, return how much data has been read.
-// Return <= 0 on EOF, error, of if buf_size was 0.
+// Return 0 on EOF, error, of if buf_size was 0.
int stream_read_partial(stream_t *s, char *buf, int buf_size)
{
assert(s->buf_pos <= s->buf_len);
@@ -463,6 +446,39 @@ int stream_read(stream_t *s, char *mem, int total)
return total - len;
}
+// Read ahead at most len bytes without changing the read position. Return a
+// pointer to the internal buffer, starting from the current read position.
+// Can read ahead at most STREAM_MAX_BUFFER_SIZE bytes.
+// The returned buffer becomes invalid on the next stream call, and you must
+// not write to it.
+struct bstr stream_peek(stream_t *s, int len)
+{
+ assert(len >= 0);
+ assert(len <= STREAM_MAX_BUFFER_SIZE);
+ if (s->buf_len - s->buf_pos < len) {
+ // Move to front to guarantee we really can read up to max size.
+ int buf_valid = s->buf_len - s->buf_pos;
+ memmove(s->buffer, &s->buffer[s->buf_pos], buf_valid);
+ // Fill rest of the buffer.
+ while (buf_valid < len) {
+ int chunk = len - buf_valid;
+ if (s->sector_size)
+ chunk = STREAM_BUFFER_SIZE;
+ assert(buf_valid + chunk <= TOTAL_BUFFER_SIZE);
+ int read = stream_read_unbuffered(s, &s->buffer[buf_valid], chunk);
+ if (read == 0)
+ break; // EOF
+ buf_valid += read;
+ }
+ s->buf_pos = 0;
+ s->buf_len = buf_valid;
+ if (s->buf_len)
+ s->eof = 0;
+ }
+ return (bstr){.start = &s->buffer[s->buf_pos],
+ .len = FFMIN(len, s->buf_len - s->buf_pos)};
+}
+
int stream_write_buffer(stream_t *s, unsigned char *buf, int len)
{
int rd;
@@ -646,9 +662,10 @@ void stream_update_size(stream_t *s)
}
}
-static stream_t *new_stream(void)
+static stream_t *new_stream(size_t min_size)
{
- stream_t *s = talloc_size(NULL, sizeof(stream_t) + TOTAL_BUFFER_SIZE);
+ min_size = FFMAX(min_size, TOTAL_BUFFER_SIZE);
+ stream_t *s = talloc_size(NULL, sizeof(stream_t) + min_size);
memset(s, 0, sizeof(stream_t));
#if HAVE_WINSOCK2_H
@@ -705,6 +722,20 @@ int stream_check_interrupt(int time)
return stream_check_interrupt_cb(stream_check_interrupt_ctx, time);
}
+stream_t *open_memory_stream(void *data, int len)
+{
+ assert(len >= 0);
+ stream_t *s = new_stream(len);
+
+ s->buf_pos = 0;
+ s->buf_len = len;
+ s->start_pos = 0;
+ s->end_pos = len;
+ s->pos = len;
+ memcpy(s->buffer, data, len);
+ return s;
+}
+
int stream_enable_cache_percent(stream_t **stream, int64_t stream_cache_size,
float stream_cache_min_percent,
float stream_cache_seek_min_percent)
@@ -737,7 +768,7 @@ int stream_enable_cache(stream_t **stream, int64_t size, int64_t min,
// Can't handle a loaded buffer.
orig->buf_len = orig->buf_pos = 0;
- stream_t *cache = new_stream();
+ stream_t *cache = new_stream(0);
cache->type = STREAMTYPE_CACHE;
cache->uncached_type = orig->type;
cache->uncached_stream = orig;
@@ -897,20 +928,27 @@ unsigned char *stream_read_line(stream_t *s, unsigned char *mem, int max,
return mem;
}
+// Read the rest of the stream into memory (current pos to EOF), and return it.
+// talloc_ctx: used as talloc parent for the returned allocation
+// max_size: must be set to >0. If the file is larger than that, it is treated
+// as error. This is a minor robustness measure.
+// returns: stream contents, or .start/.len set to NULL on error
+// If the file was empty, but no error happened, .start will be non-NULL and
+// .len will be 0.
+// For convenience, the returned buffer is padded with a 0 byte. The padding
+// is not included in the returned length.
struct bstr stream_read_complete(struct stream *s, void *talloc_ctx,
- int max_size, int padding_bytes)
+ int max_size)
{
if (max_size > 1000000000)
abort();
int bufsize;
int total_read = 0;
- int padding = FFMAX(padding_bytes, 1);
+ int padding = 1;
char *buf = NULL;
if (s->end_pos > max_size)
- return (struct bstr){
- NULL, 0
- };
+ return (struct bstr){NULL, 0};
if (s->end_pos > 0)
bufsize = s->end_pos + padding;
else
@@ -923,16 +961,13 @@ struct bstr stream_read_complete(struct stream *s, void *talloc_ctx,
break;
if (bufsize > max_size) {
talloc_free(buf);
- return (struct bstr){
- NULL, 0
- };
+ return (struct bstr){NULL, 0};
}
bufsize = FFMIN(bufsize + (bufsize >> 1), max_size + padding);
}
buf = talloc_realloc_size(talloc_ctx, buf, total_read + padding);
- return (struct bstr){
- buf, total_read
- };
+ memset(&buf[total_read], 0, padding);
+ return (struct bstr){buf, total_read};
}
bool stream_manages_timeline(struct stream *s)