physfssdl3.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * This code provides a glue layer between PhysicsFS and Simple Directmedia
  3. * Layer 3's (SDL3) SDL_IOStream and SDL_Storage i/o abstractions.
  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. * SDL3 is zlib-licensed, like PhysicsFS. You can get SDL at
  19. * https://www.libsdl.org/
  20. *
  21. * This file was written by Ryan C. Gordon. (icculus@icculus.org).
  22. */
  23. /* This works with SDL3. For SDL1 and SDL2, use physfsrwops.h */
  24. #include "physfssdl3.h"
  25. /* SDL_IOStream -> PhysicsFS bridge ... */
  26. static Sint64 SDLCALL physfsiostream_size(void *userdata)
  27. {
  28. return (Sint64) PHYSFS_fileLength((PHYSFS_File *) userdata);
  29. }
  30. static Sint64 SDLCALL physfsiostream_seek(void *userdata, Sint64 offset, SDL_IOWhence whence)
  31. {
  32. PHYSFS_File *handle = (PHYSFS_File *) userdata;
  33. PHYSFS_sint64 pos = 0;
  34. if (whence == SDL_IO_SEEK_SET) {
  35. pos = (PHYSFS_sint64) offset;
  36. } else if (whence == SDL_IO_SEEK_CUR) {
  37. const PHYSFS_sint64 current = PHYSFS_tell(handle);
  38. if (current == -1) {
  39. return SDL_SetError("Can't find position in file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  40. }
  41. if (offset == 0) { /* this is a "tell" call. We're done. */
  42. return (Sint64) current;
  43. }
  44. pos = current + ((PHYSFS_sint64) offset);
  45. } else if (whence == SDL_IO_SEEK_END) {
  46. const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
  47. if (len == -1) {
  48. return SDL_SetError("Can't find end of file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  49. }
  50. pos = len + ((PHYSFS_sint64) offset);
  51. } else {
  52. return SDL_SetError("Invalid 'whence' parameter.");
  53. }
  54. if ( pos < 0 ) {
  55. return SDL_SetError("Attempt to seek past start of file.");
  56. }
  57. if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos)) {
  58. return SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  59. }
  60. return (Sint64) pos;
  61. }
  62. static size_t SDLCALL physfsiostream_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
  63. {
  64. PHYSFS_File *handle = (PHYSFS_File *) userdata;
  65. const PHYSFS_uint64 readlen = (PHYSFS_uint64) size;
  66. const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
  67. if (rc != ((PHYSFS_sint64) readlen)) {
  68. if (!PHYSFS_eof(handle)) { /* not EOF? Must be an error. */
  69. /* Setting an SDL error makes SDL take care of `status` for you. */
  70. SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  71. return 0;
  72. }
  73. }
  74. return (size_t) rc;
  75. }
  76. static size_t SDLCALL physfsiostream_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
  77. {
  78. PHYSFS_File *handle = (PHYSFS_File *) userdata;
  79. const PHYSFS_uint64 writelen = (PHYSFS_uint64) size;
  80. const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
  81. if (rc != ((PHYSFS_sint64) writelen)) {
  82. /* Setting an SDL error makes SDL take care of `status` for you. */
  83. SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  84. }
  85. return (size_t) rc;
  86. }
  87. static bool SDLCALL physfsiostream_close(void *userdata)
  88. {
  89. if (!PHYSFS_close((PHYSFS_File *) userdata)) {
  90. return SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  91. }
  92. return true;
  93. }
  94. static SDL_IOStream *create_iostream(PHYSFS_File *handle)
  95. {
  96. SDL_IOStream *retval = NULL;
  97. if (handle == NULL) {
  98. SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  99. } else {
  100. SDL_IOStreamInterface iface;
  101. SDL_INIT_INTERFACE(&iface);
  102. iface.size = physfsiostream_size;
  103. iface.seek = physfsiostream_seek;
  104. iface.read = physfsiostream_read;
  105. iface.write = physfsiostream_write;
  106. iface.close = physfsiostream_close;
  107. retval = SDL_OpenIO(&iface, handle);
  108. }
  109. return retval;
  110. }
  111. SDL_IOStream *PHYSFSSDL3_makeIOStream(PHYSFS_File *handle)
  112. {
  113. SDL_IOStream *retval = NULL;
  114. if (handle == NULL) {
  115. SDL_SetError("NULL pointer passed to PHYSFSSDL3_makeRWops().");
  116. } else {
  117. retval = create_iostream(handle);
  118. }
  119. return retval;
  120. }
  121. SDL_IOStream *PHYSFSSDL3_openRead(const char *fname)
  122. {
  123. return create_iostream(PHYSFS_openRead(fname));
  124. }
  125. SDL_IOStream *PHYSFSSDL3_openWrite(const char *fname)
  126. {
  127. return create_iostream(PHYSFS_openWrite(fname));
  128. }
  129. SDL_IOStream *PHYSFSSDL3_openAppend(const char *fname)
  130. {
  131. return create_iostream(PHYSFS_openAppend(fname));
  132. }
  133. /* SDL_Storage -> PhysicsFS bridge ... */
  134. static bool SDLCALL physfssdl3storage_close(void *userdata)
  135. {
  136. return false; /* this doesn't do anything, we didn't allocate anything specific to this object. */
  137. }
  138. static bool SDLCALL physfssdl3storage_ready(void *userdata)
  139. {
  140. return true;
  141. }
  142. /* this is a really obnoxious symbol name... */
  143. typedef struct physfssdl3storage_enumerate_callback_data
  144. {
  145. SDL_EnumerateDirectoryCallback sdlcallback;
  146. void *sdluserdata;
  147. } physfssdl3storage_enumerate_callback_data;
  148. static PHYSFS_EnumerateCallbackResult physfssdl3storage_enumerate_callback(void *userdata, const char *origdir, const char *fname)
  149. {
  150. const physfssdl3storage_enumerate_callback_data *data = (physfssdl3storage_enumerate_callback_data *) userdata;
  151. const int rc = data->sdlcallback(data->sdluserdata, origdir, fname);
  152. if (rc < 0) {
  153. return PHYSFS_ENUM_ERROR;
  154. } else if (rc == 0) {
  155. return PHYSFS_ENUM_STOP;
  156. }
  157. return PHYSFS_ENUM_OK;
  158. }
  159. static bool SDLCALL physfssdl3storage_enumerate(void *userdata, const char *path, SDL_EnumerateDirectoryCallback callback, void *callback_userdata)
  160. {
  161. physfssdl3storage_enumerate_callback_data data;
  162. data.sdlcallback = callback;
  163. data.sdluserdata = callback_userdata;
  164. return PHYSFS_enumerate(path, physfssdl3storage_enumerate_callback, &data) ? true : false;
  165. }
  166. static bool SDLCALL physfssdl3storage_info(void *userdata, const char *path, SDL_PathInfo *info)
  167. {
  168. PHYSFS_Stat statbuf;
  169. if (!PHYSFS_stat(path, &statbuf)) {
  170. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  171. }
  172. if (info) {
  173. switch (statbuf.filetype) {
  174. case PHYSFS_FILETYPE_REGULAR: info->type = SDL_PATHTYPE_FILE; break;
  175. case PHYSFS_FILETYPE_DIRECTORY: info->type = SDL_PATHTYPE_DIRECTORY; break;
  176. default: info->type = SDL_PATHTYPE_OTHER; break;
  177. }
  178. info->size = (Uint64) statbuf.filesize;
  179. info->create_time = (SDL_Time) ((statbuf.createtime < 0) ? 0 : SDL_SECONDS_TO_NS(statbuf.createtime));
  180. info->modify_time = (SDL_Time) ((statbuf.modtime < 0) ? 0 : SDL_SECONDS_TO_NS(statbuf.modtime));
  181. info->access_time = (SDL_Time) ((statbuf.accesstime < 0) ? 0 : SDL_SECONDS_TO_NS(statbuf.accesstime));
  182. }
  183. return true;
  184. }
  185. static bool SDLCALL physfssdl3storage_read_file(void *userdata, const char *path, void *destination, Uint64 length)
  186. {
  187. PHYSFS_file *f = PHYSFS_openRead(path);
  188. PHYSFS_sint64 br;
  189. if (!f) {
  190. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  191. }
  192. br = PHYSFS_readBytes(f, destination, length);
  193. PHYSFS_close(f);
  194. if (br != (Sint64) length) {
  195. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  196. }
  197. return true;
  198. }
  199. static bool SDLCALL physfssdl3storage_write_file(void *userdata, const char *path, const void *source, Uint64 length)
  200. {
  201. PHYSFS_file *f = PHYSFS_openWrite(path);
  202. PHYSFS_sint64 bw;
  203. if (!f) {
  204. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  205. }
  206. bw = PHYSFS_writeBytes(f, source, length);
  207. PHYSFS_close(f);
  208. if (bw != (Sint64) length) {
  209. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  210. }
  211. return true;
  212. }
  213. static bool SDLCALL physfssdl3storage_mkdir(void *userdata, const char *path)
  214. {
  215. if (!PHYSFS_mkdir(path)) {
  216. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  217. }
  218. return true;
  219. }
  220. static bool SDLCALL physfssdl3storage_remove(void *userdata, const char *path)
  221. {
  222. if (!PHYSFS_delete(path)) {
  223. return SDL_SetError("%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
  224. }
  225. return true;
  226. }
  227. static bool SDLCALL physfssdl3storage_rename(void *userdata, const char *oldpath, const char *newpath)
  228. {
  229. return SDL_Unsupported(); /* no rename operation in PhysicsFS. */
  230. }
  231. static Uint64 SDLCALL physfssdl3storage_space_remaining(void *userdata)
  232. {
  233. return SDL_MAX_UINT64; /* we don't track this in PhysicsFS. */
  234. }
  235. SDL_Storage *PHYSFSSDL3_makeStorage(void)
  236. {
  237. SDL_StorageInterface iface;
  238. SDL_INIT_INTERFACE(&iface);
  239. iface.close = physfssdl3storage_close;
  240. iface.ready = physfssdl3storage_ready;
  241. iface.enumerate = physfssdl3storage_enumerate;
  242. iface.info = physfssdl3storage_info;
  243. iface.read_file = physfssdl3storage_read_file;
  244. iface.write_file = physfssdl3storage_write_file;
  245. iface.mkdir = physfssdl3storage_mkdir;
  246. iface.remove = physfssdl3storage_remove;
  247. iface.rename = physfssdl3storage_rename;
  248. iface.space_remaining = physfssdl3storage_space_remaining;
  249. return SDL_OpenStorage(&iface, NULL);
  250. }
  251. /* end of physfssdl3.c ... */