stream: stream_seek will do clamped movement if offset is invalid

If a forward/backward offset is too big, we'll clamp to the edges of
the file rather than failing completely.  We return the number of
bytes moved so callers can still validate, but the stream API can now
deal with these situations a bit more effectively.
This commit is contained in:
2026-02-06 04:53:10 +00:00
parent 5a78b01a57
commit 5bb83cfab7
2 changed files with 19 additions and 14 deletions

View File

@@ -66,9 +66,9 @@ char stream_next(stream_t *);
// Peek current character, do not push position // Peek current character, do not push position
char stream_peek(stream_t *); char stream_peek(stream_t *);
// Move forward or backward in the stream, return success of operation // Move forward or backward in the stream, return success of operation
bool stream_seek(stream_t *, i64); u64 stream_seek(stream_t *, i64);
bool stream_seek_forward(stream_t *, u64); u64 stream_seek_forward(stream_t *, u64);
bool stream_seek_backward(stream_t *, u64); u64 stream_seek_backward(stream_t *, u64);
// Return a relative substring of a given size // Return a relative substring of a given size
sv_t stream_substr(stream_t *, u64); sv_t stream_substr(stream_t *, u64);

View File

@@ -235,7 +235,7 @@ char stream_peek(stream_t *stream)
} }
} }
bool stream_seek(stream_t *stream, i64 offset) u64 stream_seek(stream_t *stream, i64 offset)
{ {
if (offset < 0) if (offset < 0)
return stream_seek_backward(stream, offset * -1); return stream_seek_backward(stream, offset * -1);
@@ -246,20 +246,20 @@ bool stream_seek(stream_t *stream, i64 offset)
return true; return true;
} }
bool stream_seek_forward(stream_t *stream, u64 offset) u64 stream_seek_forward(stream_t *stream, u64 offset)
{ {
if (stream_eoc(stream)) if (stream_eoc(stream))
return false; return 0;
switch (stream->type) switch (stream->type)
{ {
case STREAM_TYPE_STRING: case STREAM_TYPE_STRING:
{ {
if (stream->position + offset >= stream->string.size) if (stream->position + offset >= stream->string.size)
return false; return 0;
stream->position += offset; stream->position += offset;
return true; return offset;
} }
case STREAM_TYPE_PIPE: case STREAM_TYPE_PIPE:
case STREAM_TYPE_FILE: case STREAM_TYPE_FILE:
@@ -270,7 +270,7 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
if (stream->position + offset < stream->pipe.cache.size) if (stream->position + offset < stream->pipe.cache.size)
{ {
stream->position += offset; stream->position += offset;
return true; return offset;
} }
// Try to read chunks in till we've reached it or we're at the end of the // Try to read chunks in till we've reached it or we're at the end of the
@@ -282,9 +282,11 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
// Same principle as the stream_eoc(stream) check. // Same principle as the stream_eoc(stream) check.
if (stream->position + offset > stream->pipe.cache.size) if (stream->position + offset > stream->pipe.cache.size)
return false; {
offset = stream->pipe.cache.size - stream->position;
}
stream->position += offset; stream->position += offset;
return true; return offset;
} }
default: default:
FAIL("Unreachable"); FAIL("Unreachable");
@@ -292,13 +294,16 @@ bool stream_seek_forward(stream_t *stream, u64 offset)
} }
} }
bool stream_seek_backward(stream_t *stream, u64 offset) u64 stream_seek_backward(stream_t *stream, u64 offset)
{ {
assert(stream); assert(stream);
if (stream->position < offset) if (stream->position < offset)
return false; {
offset = stream->position;
}
stream->position -= offset; stream->position -= offset;
return true; return offset;
} }
sv_t stream_substr(stream_t *stream, u64 size) sv_t stream_substr(stream_t *stream, u64 size)