taisei/src/rwops/rwops_util.c
2024-05-17 14:11:48 +02:00

83 lines
1.8 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "rwops_util.h"
#include "util/miscmath.h"
int64_t rwutil_compute_seek_pos(int64_t offset, int whence, int64_t pos, int64_t size) {
int64_t new_pos;
assert(pos >= 0);
assert(size < 0 || pos <= size);
switch(whence) {
case RW_SEEK_SET: new_pos = offset; break;
case RW_SEEK_CUR: new_pos = pos + offset; break;
case RW_SEEK_END:
if(size < 0) {
return -1;
}
new_pos = size - offset;
break;
default: UNREACHABLE;
}
if(new_pos < 0) {
new_pos = 0;
}
if(size > 0 && new_pos > size) {
new_pos = size;
}
return new_pos;
}
int64_t rwutil_seek_emulated(
SDL_RWops *rw, int64_t offset, int whence,
int64_t *pos, rwutil_reopen_func reopen, size_t readbuf_size, void *readbuf
) {
int64_t sz = SDL_RWsize(rw);
int64_t new_pos = rwutil_compute_seek_pos(offset, whence, *pos, sz);
if(new_pos < 0) {
assert(sz < 0);
return sz; // assume SDL_RWsize set an error;
}
return rwutil_seek_emulated_abs(rw, new_pos, pos, reopen, readbuf_size, readbuf);
}
int64_t rwutil_seek_emulated_abs(
SDL_RWops *rw, int64_t new_pos, int64_t *pos,
rwutil_reopen_func reopen, size_t readbuf_size, void *readbuf
) {
assert(new_pos >= 0);
if(new_pos < *pos) {
int status;
if((status = reopen(rw)) < 0) {
return status;
}
assert(*pos == 0);
}
while(new_pos > *pos) {
size_t want_read_size = min(new_pos - *pos, readbuf_size);
size_t read_size = SDL_RWread(rw, readbuf, 1, want_read_size);
assert(read_size <= want_read_size);
if(read_size < readbuf_size) {
break;
}
}
assert(new_pos == *pos);
return *pos;
}