Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This code provides a glue layer between PhysicsFS and Simple Directmedia
  3.  *  Layer's (SDL) RWops i/o abstraction.
  4.  *
  5.  * License: this code is public domain. I make no warranty that it is useful,
  6.  *  correct, harmless, or environmentally safe.
  7.  *
  8.  * This particular file may be used however you like, including copying it
  9.  *  verbatim into a closed-source project, exploiting it commercially, and
  10.  *  removing any trace of my name from the source (although I hope you won't
  11.  *  do that). I welcome enhancements and corrections to this file, but I do
  12.  *  not require you to send me patches if you make changes. This code has
  13.  *  NO WARRANTY.
  14.  *
  15.  * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
  16.  *  Please see LICENSE.txt in the root of the source tree.
  17.  *
  18.  * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS.
  19.  *  You can get SDL at https://www.libsdl.org/
  20.  *
  21.  *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
  22.  */
  23.  
  24. #include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
  25. #include "physfsrwops.h"
  26.  
  27. /* SDL's RWOPS interface changed a little in SDL 2.0... */
  28. #if defined(SDL_VERSION_ATLEAST)
  29. #if SDL_VERSION_ATLEAST(2, 0, 0)
  30. #define TARGET_SDL2 1
  31. #endif
  32. #endif
  33.  
  34. #if !TARGET_SDL2
  35. #ifndef RW_SEEK_SET
  36. #define RW_SEEK_SET SEEK_SET
  37. #endif
  38. #ifndef RW_SEEK_CUR
  39. #define RW_SEEK_CUR SEEK_CUR
  40. #endif
  41. #ifndef RW_SEEK_END
  42. #define RW_SEEK_END SEEK_END
  43. #endif
  44. #endif
  45.  
  46. #if TARGET_SDL2
  47. static Sint64 SDLCALL physfsrwops_size(struct SDL_RWops *rw)
  48. {
  49.     PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
  50.     return (Sint64) PHYSFS_fileLength(handle);
  51. } /* physfsrwops_size */
  52. #endif
  53.  
  54.  
  55. #if TARGET_SDL2
  56. static Sint64 SDLCALL physfsrwops_seek(struct SDL_RWops *rw, Sint64 offset, int whence)
  57. #else
  58. static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
  59. #endif
  60. {
  61.     PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
  62.     PHYSFS_sint64 pos = 0;
  63.  
  64.     if (whence == RW_SEEK_SET)
  65.         pos = (PHYSFS_sint64) offset;
  66.  
  67.     else if (whence == RW_SEEK_CUR)
  68.     {
  69.         const PHYSFS_sint64 current = PHYSFS_tell(handle);
  70.         if (current == -1)
  71.         {
  72.             SDL_SetError("Can't find position in file: %s",
  73.                           PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  74.             return -1;
  75.         } /* if */
  76.  
  77.         if (offset == 0)  /* this is a "tell" call. We're done. */
  78.         {
  79.             #if TARGET_SDL2
  80.             return (Sint64) current;
  81.             #else
  82.             return (int) current;
  83.             #endif
  84.         } /* if */
  85.  
  86.         pos = current + ((PHYSFS_sint64) offset);
  87.     } /* else if */
  88.  
  89.     else if (whence == RW_SEEK_END)
  90.     {
  91.         const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
  92.         if (len == -1)
  93.         {
  94.             SDL_SetError("Can't find end of file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  95.             return -1;
  96.         } /* if */
  97.  
  98.         pos = len + ((PHYSFS_sint64) offset);
  99.     } /* else if */
  100.  
  101.     else
  102.     {
  103.         SDL_SetError("Invalid 'whence' parameter.");
  104.         return -1;
  105.     } /* else */
  106.  
  107.     if ( pos < 0 )
  108.     {
  109.         SDL_SetError("Attempt to seek past start of file.");
  110.         return -1;
  111.     } /* if */
  112.    
  113.     if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
  114.     {
  115.         SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  116.         return -1;
  117.     } /* if */
  118.  
  119.     #if TARGET_SDL2
  120.     return (Sint64) pos;
  121.     #else
  122.     return (int) pos;
  123.     #endif
  124. } /* physfsrwops_seek */
  125.  
  126.  
  127. #if TARGET_SDL2
  128. static size_t SDLCALL physfsrwops_read(struct SDL_RWops *rw, void *ptr,
  129.                                        size_t size, size_t maxnum)
  130. #else
  131. static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
  132. #endif
  133. {
  134.     PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
  135.     const PHYSFS_uint64 readlen = (PHYSFS_uint64) (maxnum * size);
  136.     const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
  137.     if (rc != ((PHYSFS_sint64) readlen))
  138.     {
  139.         if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
  140.         {
  141.             SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  142.  
  143.             #if TARGET_SDL2
  144.             return 0;
  145.             #else
  146.             return -1;
  147.             #endif
  148.         } /* if */
  149.     } /* if */
  150.  
  151.     #if TARGET_SDL2
  152.     return (size_t) rc / size;
  153.     #else
  154.     return (int) rc / size;
  155.     #endif
  156. } /* physfsrwops_read */
  157.  
  158.  
  159. #if TARGET_SDL2
  160. static size_t SDLCALL physfsrwops_write(struct SDL_RWops *rw, const void *ptr,
  161.                                         size_t size, size_t num)
  162. #else
  163. static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
  164. #endif
  165. {
  166.     PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
  167.     const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size);
  168.     const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
  169.     if (rc != ((PHYSFS_sint64) writelen))
  170.         SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  171.  
  172.     #if TARGET_SDL2
  173.     return (size_t) rc;
  174.     #else
  175.     return (int) rc;
  176.     #endif
  177. } /* physfsrwops_write */
  178.  
  179.  
  180. static int physfsrwops_close(SDL_RWops *rw)
  181. {
  182.     PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
  183.     if (!PHYSFS_close(handle))
  184.     {
  185.         SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  186.         return -1;
  187.     } /* if */
  188.  
  189.     SDL_FreeRW(rw);
  190.     return 0;
  191. } /* physfsrwops_close */
  192.  
  193.  
  194. static SDL_RWops *create_rwops(PHYSFS_File *handle)
  195. {
  196.     SDL_RWops *retval = NULL;
  197.  
  198.     if (handle == NULL)
  199.         SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  200.     else
  201.     {
  202.         retval = SDL_AllocRW();
  203.         if (retval != NULL)
  204.         {
  205.             #if TARGET_SDL2
  206.             retval->size  = physfsrwops_size;
  207.             #endif
  208.             retval->seek  = physfsrwops_seek;
  209.             retval->read  = physfsrwops_read;
  210.             retval->write = physfsrwops_write;
  211.             retval->close = physfsrwops_close;
  212.             retval->hidden.unknown.data1 = handle;
  213.         } /* if */
  214.     } /* else */
  215.  
  216.     return retval;
  217. } /* create_rwops */
  218.  
  219.  
  220. SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
  221. {
  222.     SDL_RWops *retval = NULL;
  223.     if (handle == NULL)
  224.         SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
  225.     else
  226.         retval = create_rwops(handle);
  227.  
  228.     return retval;
  229. } /* PHYSFSRWOPS_makeRWops */
  230.  
  231.  
  232. SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
  233. {
  234.     return create_rwops(PHYSFS_openRead(fname));
  235. } /* PHYSFSRWOPS_openRead */
  236.  
  237.  
  238. SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
  239. {
  240.     return create_rwops(PHYSFS_openWrite(fname));
  241. } /* PHYSFSRWOPS_openWrite */
  242.  
  243.  
  244. SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
  245. {
  246.     return create_rwops(PHYSFS_openAppend(fname));
  247. } /* PHYSFSRWOPS_openAppend */
  248.  
  249.  
  250. /* end of physfsrwops.c ... */
  251.  
  252.