/* * This software is licensed under the terms of the MIT License. * See COPYING for further information. * --- * Copyright (c) 2011-2024, Lukas Weber . * Copyright (c) 2012-2024, Andrei Alexeyev . */ #include "io.h" #include "assert.h" #include "log.h" #include "rwops/rwops_autobuf.h" #include "stringops.h" #include "vfs/public.h" #ifdef TAISEI_BUILDCONF_HAVE_POSIX #include #endif char *SDL_RWgets(SDL_RWops *rwops, char *buf, size_t bufsize) { char c, *ptr = buf, *end = buf + bufsize - 1; assert(end > ptr); while((c = SDL_ReadU8(rwops)) && ptr <= end) { if((*ptr++ = c) == '\n') break; } if(ptr == buf) return NULL; if(ptr > end) { *end = 0; log_warn("Line too long (%zu bytes max): %s", bufsize, buf); } else { *ptr = 0; } return buf; } char *SDL_RWgets_realloc(SDL_RWops *rwops, char **buf, size_t *bufsize) { char c, *ptr = *buf, *end = *buf + *bufsize - 1; assert(end >= ptr); while((c = SDL_ReadU8(rwops))) { *ptr++ = c; if(ptr > end) { ptrdiff_t ofs = ptr - *buf; *bufsize *= 2; *buf = mem_realloc(*buf, *bufsize); end = *buf + *bufsize - 1; ptr = *buf + ofs; *end = 0; } if(c == '\n') { break; } } if(ptr == *buf) return NULL; assert(ptr <= end); *ptr = 0; return *buf; } size_t SDL_RWprintf(SDL_RWops *rwops, const char* fmt, ...) { va_list args; va_start(args, fmt); char *str = vstrfmt(fmt, args); va_end(args); size_t ret = SDL_RWwrite(rwops, str, 1, strlen(str)); mem_free(str); return ret; } void tsfprintf(FILE *out, const char *restrict fmt, ...) { va_list args; va_start(args, fmt); vfprintf(out, fmt, args); va_end(args); } char *try_path(const char *prefix, const char *name, const char *ext) { char *p = strjoin(prefix, name, ext, NULL); if(vfs_query(p).exists) { return p; } mem_free(p); return NULL; } static void *SDL_RWreadAll_known_size(SDL_RWops *rwops, size_t file_size, size_t *out_size) { char *start = mem_alloc(file_size); char *end = start + file_size; char *pbuf = start; assert(end >= start); for(;;) { size_t read = SDL_RWread(rwops, pbuf, 1, end - pbuf); assert(read <= end - pbuf); if(read == 0) { *out_size = pbuf - start; return start; } pbuf += read; } } void *SDL_RWreadAll(SDL_RWops *rwops, size_t *out_size, size_t max_size) { ssize_t file_size = SDL_RWsize(rwops); if(file_size >= 0) { if(max_size && file_size > max_size) { SDL_SetError("File is too large (%zu bytes; max is %zu)", file_size, max_size); return NULL; } size_t sz; void *result = SDL_RWreadAll_known_size(rwops, file_size, &sz); if(result) { *out_size = sz; } return result; } static const size_t chunk_size = BUFSIZ; void *buf; SDL_RWops *autobuf = NOT_NULL(SDL_RWAutoBuffer(&buf, chunk_size)); void *chunk = mem_alloc(chunk_size); size_t total_size = 0; for(;;) { size_t read = SDL_RWread(rwops, chunk, 1, chunk_size); if(read == 0) { mem_free(chunk); SDL_RWclose(rwops); buf = memdup(buf, total_size); SDL_RWclose(autobuf); *out_size = total_size; return buf; } size_t write = SDL_RWwrite(autobuf, chunk, 1, chunk_size); if(UNLIKELY(write != read)) { mem_free(chunk); SDL_RWclose(rwops); SDL_RWclose(autobuf); return NULL; } total_size += write; if(max_size && UNLIKELY(total_size > max_size)) { SDL_SetError("File is too large (%zu bytes read so far; max is %zu)", total_size, max_size); mem_free(chunk); SDL_RWclose(rwops); SDL_RWclose(autobuf); return NULL; } } } void SDL_RWsync(SDL_RWops *rwops) { #if HAVE_STDIO_H if(rwops->type == SDL_RWOPS_STDFILE) { FILE *fp = rwops->hidden.stdio.fp; if(UNLIKELY(!fp)) { return; } fflush(fp); #ifdef TAISEI_BUILDCONF_HAVE_POSIX fsync(fileno(fp)); #endif } #endif }