From 702ee932a58d84d3ae3d2735d826f6499fdc189a Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 3 Nov 2012 18:43:36 -0700 Subject: [PATCH] Added an API to get the size of a file - WARNING! ABI CHANGE! --- configure | 2 +- configure.in | 2 +- include/SDL_config.h.in | 2 + include/SDL_rwops.h | 18 ++++--- src/core/android/SDL_android.cpp | 24 +++++---- src/core/android/SDL_android.h | 3 +- src/file/SDL_rwops.c | 89 +++++++++++++++++++++++++------- 7 files changed, 102 insertions(+), 38 deletions(-) diff --git a/configure b/configure index 11b424cb4..4e3e30639 100755 --- a/configure +++ b/configure @@ -16688,7 +16688,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - for ac_func in malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep sysconf sysctlbyname + for ac_func in malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index 2c47f8c03..3b520d644 100644 --- a/configure.in +++ b/configure.in @@ -237,7 +237,7 @@ if test x$enable_libc = xyes; then AC_DEFINE(HAVE_MPROTECT, 1, [ ]) ]), ) - AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep sysconf sysctlbyname) + AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) AC_CHECK_FUNCS(atan atan2 ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt) diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index be6b5cf47..0e271a83c 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -139,6 +139,8 @@ #undef HAVE_SIN #undef HAVE_SINF #undef HAVE_SQRT +#undef HAVE_FSEEKO +#undef HAVE_FSEEKO64 #undef HAVE_SIGACTION #undef HAVE_SA_SIGACTION #undef HAVE_SETJMP diff --git a/include/SDL_rwops.h b/include/SDL_rwops.h index 87715f5ba..023baa68d 100644 --- a/include/SDL_rwops.h +++ b/include/SDL_rwops.h @@ -45,14 +45,19 @@ extern "C" { */ typedef struct SDL_RWops { + /** + * Return the size of the file in this rwops, or -1 if unknown + */ + Sint64 (SDLCALL * size) (struct SDL_RWops * context); + /** * Seek to \c offset relative to \c whence, one of stdio's whence values: * RW_SEEK_SET, RW_SEEK_CUR, RW_SEEK_END * * \return the final offset in the data stream. */ - long (SDLCALL * seek) (struct SDL_RWops * context, long offset, - int whence); + Sint64 (SDLCALL * seek) (struct SDL_RWops * context, Sint64 offset, + int whence); /** * Read up to \c maxnum objects each of size \c size from the data @@ -60,8 +65,8 @@ typedef struct SDL_RWops * * \return the number of objects read, or 0 at error or end of file. */ - size_t(SDLCALL * read) (struct SDL_RWops * context, void *ptr, - size_t size, size_t maxnum); + size_t (SDLCALL * read) (struct SDL_RWops * context, void *ptr, + size_t size, size_t maxnum); /** * Write exactly \c num objects each of size \c size from the area @@ -69,8 +74,8 @@ typedef struct SDL_RWops * * \return the number of objects written, or 0 at error or end of file. */ - size_t(SDLCALL * write) (struct SDL_RWops * context, const void *ptr, - size_t size, size_t num); + size_t (SDLCALL * write) (struct SDL_RWops * context, const void *ptr, + size_t size, size_t num); /** * Close and free an allocated SDL_RWops structure. @@ -166,6 +171,7 @@ extern DECLSPEC void SDLCALL SDL_FreeRW(SDL_RWops * area); * Macros to easily read and write from an SDL_RWops structure. */ /*@{*/ +#define SDL_RWsize(ctx) (ctx)->size(ctx) #define SDL_RWseek(ctx, offset, whence) (ctx)->seek(ctx, offset, whence) #define SDL_RWtell(ctx) (ctx)->seek(ctx, 0, RW_SEEK_CUR) #define SDL_RWread(ctx, ptr, size, n) (ctx)->read(ctx, ptr, size, n) diff --git a/src/core/android/SDL_android.cpp b/src/core/android/SDL_android.cpp index f78a721fe..b7fe7c5c0 100644 --- a/src/core/android/SDL_android.cpp +++ b/src/core/android/SDL_android.cpp @@ -696,9 +696,14 @@ static int Android_JNI_FileClose(SDL_RWops* ctx, bool release) } -extern "C" long Android_JNI_FileSeek(SDL_RWops* ctx, long offset, int whence) +extern "C" Sint64 Android_JNI_FileSize(SDL_RWops* ctx) { - long newPosition; + return ctx->hidden.androidio.size; +} + +extern "C" Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) +{ + Sint64 newPosition; switch (whence) { case RW_SEEK_SET: @@ -714,27 +719,27 @@ extern "C" long Android_JNI_FileSeek(SDL_RWops* ctx, long offset, int whence) SDL_SetError("Unknown value for 'whence'"); return -1; } + + /* Validate the new position */ if (newPosition < 0) { - newPosition = 0; + SDL_Error(SDL_EFSEEK); + return -1; } if (newPosition > ctx->hidden.androidio.size) { newPosition = ctx->hidden.androidio.size; } - long movement = newPosition - ctx->hidden.androidio.position; - jobject inputStream = (jobject)ctx->hidden.androidio.inputStreamRef; - + Sint64 movement = newPosition - ctx->hidden.androidio.position; if (movement > 0) { unsigned char buffer[1024]; // The easy case where we're seeking forwards while (movement > 0) { - long amount = (long) sizeof (buffer); + Sint64 amount = sizeof (buffer); if (amount > movement) { amount = movement; } size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount); - if (result <= 0) { // Failed to read/skip the required amount, so fail return -1; @@ -742,6 +747,7 @@ extern "C" long Android_JNI_FileSeek(SDL_RWops* ctx, long offset, int whence) movement -= result; } + } else if (movement < 0) { // We can't seek backwards so we have to reopen the file and seek // forwards which obviously isn't very efficient @@ -750,8 +756,6 @@ extern "C" long Android_JNI_FileSeek(SDL_RWops* ctx, long offset, int whence) Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET); } - ctx->hidden.androidio.position = newPosition; - return ctx->hidden.androidio.position; } diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index 637e465bc..505e92b69 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -45,7 +45,8 @@ extern void Android_JNI_CloseAudioDevice(); #include "SDL_rwops.h" int Android_JNI_FileOpen(SDL_RWops* ctx, const char* fileName, const char* mode); -long Android_JNI_FileSeek(SDL_RWops* ctx, long offset, int whence); +Sint64 Android_JNI_FileSize(SDL_RWops* ctx); +Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence); size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t maxnum); size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, size_t num); int Android_JNI_FileClose(SDL_RWops* ctx); diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index e2a9bf16b..df6b8fbca 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -121,11 +121,29 @@ windows_file_open(SDL_RWops * context, const char *filename, const char *mode) return 0; /* ok */ } -static long SDLCALL -windows_file_seek(SDL_RWops * context, long offset, int whence) +static Sint64 SDLCALL +windows_file_size(SDL_RWops * context) +{ + LARGE_INTEGER size; + + if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) { + SDL_SetError("windows_file_size: invalid context/file not opened"); + return -1; + } + + if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) { + WIN_SetError("windows_file_size"); + return -1; + } + + return size.QuadPart; +} + +static Sint64 SDLCALL +windows_file_seek(SDL_RWops * context, Sint64 offset, int whence) { DWORD windowswhence; - long file_pos; + LARGE_INTEGER windowsoffset; if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) { SDL_SetError("windows_file_seek: invalid context/file not opened"); @@ -153,14 +171,12 @@ windows_file_seek(SDL_RWops * context, long offset, int whence) return -1; } - file_pos = - SetFilePointer(context->hidden.windowsio.h, offset, NULL, windowswhence); - - if (file_pos != INVALID_SET_FILE_POINTER) - return file_pos; /* success */ - - SDL_Error(SDL_EFSEEK); - return -1; /* error */ + windowsoffset.QuadPart = offset; + if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) { + WIN_SetError("windows_file_seek"); + return -1; + } + return windowsoffset.QuadPart; } static size_t SDLCALL @@ -281,15 +297,39 @@ windows_file_close(SDL_RWops * context) /* Functions to read/write stdio file pointers */ -static long SDLCALL -stdio_seek(SDL_RWops * context, long offset, int whence) +static Sint64 SDLCALL +stdio_size(SDL_RWops * context) +{ + Sint64 pos, size; + + pos = SDL_RWseek(context, 0, RW_SEEK_CUR); + if (pos < 0) { + return -1; + } + size = SDL_RWseek(context, 0, RW_SEEK_END); + + SDL_RWseek(context, pos, RW_SEEK_SET); + return size; +} + +static Sint64 SDLCALL +stdio_seek(SDL_RWops * context, Sint64 offset, int whence) { +#ifdef HAVE_FSEEKO64 + if (fseek64o(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) { + return ftell64o(context->hidden.stdio.fp); + } +#elif defined(HAVE_FSEEKO) + if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) { + return ftello(context->hidden.stdio.fp); + } +#else if (fseek(context->hidden.stdio.fp, offset, whence) == 0) { return (ftell(context->hidden.stdio.fp)); - } else { - SDL_Error(SDL_EFSEEK); - return (-1); } +#endif + SDL_Error(SDL_EFSEEK); + return (-1); } static size_t SDLCALL @@ -336,8 +376,14 @@ stdio_close(SDL_RWops * context) /* Functions to read/write memory pointers */ -static long SDLCALL -mem_seek(SDL_RWops * context, long offset, int whence) +static Sint64 SDLCALL +mem_size(SDL_RWops * context) +{ + return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base); +} + +static Sint64 SDLCALL +mem_seek(SDL_RWops * context, Sint64 offset, int whence) { Uint8 *newpos; @@ -362,7 +408,7 @@ mem_seek(SDL_RWops * context, long offset, int whence) newpos = context->hidden.mem.stop; } context->hidden.mem.here = newpos; - return (long)(context->hidden.mem.here - context->hidden.mem.base); + return (Sint64)(context->hidden.mem.here - context->hidden.mem.base); } static size_t SDLCALL @@ -460,6 +506,7 @@ SDL_RWFromFile(const char *file, const char *mode) SDL_FreeRW(rwops); return NULL; } + rwops->size = Android_JNI_FileSize; rwops->seek = Android_JNI_FileSeek; rwops->read = Android_JNI_FileRead; rwops->write = Android_JNI_FileWrite; @@ -473,6 +520,7 @@ SDL_RWFromFile(const char *file, const char *mode) SDL_FreeRW(rwops); return NULL; } + rwops->size = windows_file_size; rwops->seek = windows_file_seek; rwops->read = windows_file_read; rwops->write = windows_file_write; @@ -513,6 +561,7 @@ SDL_RWFromFP(FILE * fp, SDL_bool autoclose) rwops = SDL_AllocRW(); if (rwops != NULL) { + rwops->size = stdio_size; rwops->seek = stdio_seek; rwops->read = stdio_read; rwops->write = stdio_write; @@ -538,6 +587,7 @@ SDL_RWFromMem(void *mem, int size) rwops = SDL_AllocRW(); if (rwops != NULL) { + rwops->size = mem_size; rwops->seek = mem_seek; rwops->read = mem_read; rwops->write = mem_write; @@ -556,6 +606,7 @@ SDL_RWFromConstMem(const void *mem, int size) rwops = SDL_AllocRW(); if (rwops != NULL) { + rwops->size = mem_size; rwops->seek = mem_seek; rwops->read = mem_read; rwops->write = mem_writeconst;