SDL_rwops.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. /* We won't get fseeko64 on QNX if _LARGEFILE64_SOURCE is defined, but the
  19. configure script knows the C runtime has it and enables it. */
  20. #ifndef __QNXNTO__
  21. /* Need this so Linux systems define fseek64o, ftell64o and off64_t */
  22. #ifndef _LARGEFILE64_SOURCE
  23. #define _LARGEFILE64_SOURCE
  24. #endif
  25. #endif
  26. #include "../SDL_internal.h"
  27. #if defined(__WIN32__)
  28. #include "../core/windows/SDL_windows.h"
  29. #endif
  30. #ifdef HAVE_STDIO_H
  31. #include <stdio.h>
  32. #endif
  33. #ifdef HAVE_LIMITS_H
  34. #include <limits.h>
  35. #endif
  36. /* This file provides a general interface for SDL to read and write
  37. data sources. It can easily be extended to files, memory, etc.
  38. */
  39. #include "SDL_endian.h"
  40. #include "SDL_rwops.h"
  41. #ifdef __APPLE__
  42. #include "cocoa/SDL_rwopsbundlesupport.h"
  43. #endif /* __APPLE__ */
  44. #ifdef __ANDROID__
  45. #include "../core/android/SDL_android.h"
  46. #include "SDL_system.h"
  47. #endif
  48. #if __NACL__
  49. #include "nacl_io/nacl_io.h"
  50. #endif
  51. #ifdef __VITA__
  52. #include <psp2/io/fcntl.h>
  53. #include <psp2/io/stat.h>
  54. #define READAHEAD_BUFFER_SIZE 1024
  55. static int SDLCALL
  56. vita_file_open(SDL_RWops * context, const char *filename, const char *mode)
  57. {
  58. int h;
  59. int open_flags;
  60. SDL_bool has_r;
  61. SDL_bool has_w;
  62. SDL_bool has_a;
  63. SDL_bool has_plus;
  64. if (!context)
  65. return -1; /* failed (invalid call) */
  66. context->hidden.vitaio.h = -1; /* mark this as unusable */
  67. context->hidden.vitaio.buffer.data = NULL;
  68. context->hidden.vitaio.buffer.size = 0;
  69. context->hidden.vitaio.buffer.left = 0;
  70. open_flags = 0;
  71. /* "r" = reading, file must exist */
  72. /* "w" = writing, truncate existing, file may not exist */
  73. /* "r+"= reading or writing, file must exist */
  74. /* "a" = writing, append file may not exist */
  75. /* "a+"= append + read, file may not exist */
  76. /* "w+" = read, write, truncate. file may not exist */
  77. has_r = SDL_strchr(mode, 'r') != NULL;
  78. has_w = SDL_strchr(mode, 'w') != NULL;
  79. has_a = SDL_strchr(mode, 'a') != NULL;
  80. has_plus = SDL_strchr(mode, '+') != NULL;
  81. if (has_plus)
  82. {
  83. if (has_r || has_w || has_a)
  84. {
  85. open_flags |= SCE_O_RDWR;
  86. }
  87. }
  88. else
  89. {
  90. if (has_r)
  91. {
  92. open_flags |= SCE_O_RDONLY;
  93. }
  94. if (has_w || has_a)
  95. {
  96. open_flags |= SCE_O_WRONLY;
  97. }
  98. }
  99. if (has_w || has_a)
  100. {
  101. open_flags |= SCE_O_CREAT;
  102. }
  103. if (has_w)
  104. {
  105. open_flags |= SCE_O_TRUNC;
  106. }
  107. if (has_a)
  108. {
  109. open_flags |= SCE_O_APPEND;
  110. }
  111. context->hidden.vitaio.buffer.data =
  112. (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
  113. if (!context->hidden.vitaio.buffer.data) {
  114. return SDL_OutOfMemory();
  115. }
  116. /* Try to open the file on the filesystem first */
  117. h = sceIoOpen(filename, open_flags, 0777);
  118. if (h < 0) {
  119. /* Try opening it from app0:/ container if it's a relative path */
  120. char path[4096];
  121. SDL_snprintf(path, 4096, "app0:/%s", filename);
  122. h = sceIoOpen(path, open_flags, 0777);
  123. }
  124. if (h < 0) {
  125. SDL_free(context->hidden.vitaio.buffer.data);
  126. context->hidden.vitaio.buffer.data = NULL;
  127. SDL_SetError("Couldn't open %s", filename);
  128. return -2; /* failed (sceIoOpen) */
  129. }
  130. context->hidden.vitaio.h = h;
  131. return 0; /* ok */
  132. }
  133. static Sint64 SDLCALL
  134. vita_file_size(SDL_RWops * context)
  135. {
  136. SceIoStat st;
  137. if (!context || context->hidden.vitaio.h < 0) {
  138. return SDL_SetError("vita_file_size: invalid context/file not opened");
  139. }
  140. if (sceIoGetstatByFd(context->hidden.vitaio.h, &st) < 0)
  141. {
  142. return SDL_SetError("vita_file_size: could not get file size");
  143. }
  144. return st.st_size;
  145. }
  146. static Sint64 SDLCALL
  147. vita_file_seek(SDL_RWops * context, Sint64 offset, int whence)
  148. {
  149. int vitawhence;
  150. if (!context || context->hidden.vitaio.h < 0) {
  151. return SDL_SetError("vita_file_seek: invalid context/file not opened");
  152. }
  153. /* FIXME: We may be able to satisfy the seek within buffered data */
  154. if (whence == RW_SEEK_CUR && context->hidden.vitaio.buffer.left) {
  155. offset -= (long)context->hidden.vitaio.buffer.left;
  156. }
  157. context->hidden.vitaio.buffer.left = 0;
  158. switch (whence) {
  159. case RW_SEEK_SET:
  160. vitawhence = SCE_SEEK_SET;
  161. break;
  162. case RW_SEEK_CUR:
  163. vitawhence = SCE_SEEK_CUR;
  164. break;
  165. case RW_SEEK_END:
  166. vitawhence = SCE_SEEK_END;
  167. break;
  168. default:
  169. return SDL_SetError("vita_file_seek: Unknown value for 'whence'");
  170. }
  171. return sceIoLseek(context->hidden.vitaio.h, offset, vitawhence);
  172. }
  173. static size_t SDLCALL
  174. vita_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
  175. {
  176. size_t total_need;
  177. size_t total_read = 0;
  178. size_t read_ahead;
  179. size_t byte_read;
  180. total_need = size * maxnum;
  181. if (!context || context->hidden.vitaio.h < 0
  182. || !total_need)
  183. return 0;
  184. if (context->hidden.vitaio.buffer.left > 0) {
  185. void *data = (char *) context->hidden.vitaio.buffer.data +
  186. context->hidden.vitaio.buffer.size -
  187. context->hidden.vitaio.buffer.left;
  188. read_ahead =
  189. SDL_min(total_need, context->hidden.vitaio.buffer.left);
  190. SDL_memcpy(ptr, data, read_ahead);
  191. context->hidden.vitaio.buffer.left -= read_ahead;
  192. if (read_ahead == total_need) {
  193. return maxnum;
  194. }
  195. ptr = (char *) ptr + read_ahead;
  196. total_need -= read_ahead;
  197. total_read += read_ahead;
  198. }
  199. if (total_need < READAHEAD_BUFFER_SIZE) {
  200. byte_read = sceIoRead(context->hidden.vitaio.h, context->hidden.vitaio.buffer.data, READAHEAD_BUFFER_SIZE);
  201. read_ahead = SDL_min(total_need, (int) byte_read);
  202. SDL_memcpy(ptr, context->hidden.vitaio.buffer.data, read_ahead);
  203. context->hidden.vitaio.buffer.size = byte_read;
  204. context->hidden.vitaio.buffer.left = byte_read - read_ahead;
  205. total_read += read_ahead;
  206. } else {
  207. byte_read = sceIoRead(context->hidden.vitaio.h, ptr, total_need);
  208. total_read += byte_read;
  209. }
  210. return (total_read / size);
  211. }
  212. static size_t SDLCALL
  213. vita_file_write(SDL_RWops * context, const void *ptr, size_t size,
  214. size_t num)
  215. {
  216. size_t total_bytes;
  217. size_t byte_written;
  218. size_t nwritten;
  219. total_bytes = size * num;
  220. if (!context || context->hidden.vitaio.h < 0
  221. || total_bytes <= 0 || !size)
  222. return 0;
  223. if (context->hidden.vitaio.buffer.left) {
  224. sceIoLseek(context->hidden.vitaio.h, -(SceOff)context->hidden.vitaio.buffer.left, SCE_SEEK_CUR);
  225. context->hidden.vitaio.buffer.left = 0;
  226. }
  227. byte_written = sceIoWrite(context->hidden.vitaio.h, ptr, total_bytes);
  228. nwritten = byte_written / size;
  229. return nwritten;
  230. }
  231. static int SDLCALL
  232. vita_file_close(SDL_RWops * context)
  233. {
  234. if (context) {
  235. if (context->hidden.vitaio.h >= 0) {
  236. sceIoClose(context->hidden.vitaio.h);
  237. context->hidden.vitaio.h = -1; /* to be sure */
  238. }
  239. SDL_free(context->hidden.vitaio.buffer.data);
  240. context->hidden.vitaio.buffer.data = NULL;
  241. SDL_FreeRW(context);
  242. }
  243. return 0;
  244. }
  245. #endif
  246. #ifdef __WIN32__
  247. /* Functions to read/write Win32 API file pointers */
  248. #ifndef INVALID_SET_FILE_POINTER
  249. #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
  250. #endif
  251. #define READAHEAD_BUFFER_SIZE 1024
  252. static int SDLCALL
  253. windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
  254. {
  255. UINT old_error_mode;
  256. HANDLE h;
  257. DWORD r_right, w_right;
  258. DWORD must_exist, truncate;
  259. int a_mode;
  260. if (!context)
  261. return -1; /* failed (invalid call) */
  262. context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
  263. context->hidden.windowsio.buffer.data = NULL;
  264. context->hidden.windowsio.buffer.size = 0;
  265. context->hidden.windowsio.buffer.left = 0;
  266. /* "r" = reading, file must exist */
  267. /* "w" = writing, truncate existing, file may not exist */
  268. /* "r+"= reading or writing, file must exist */
  269. /* "a" = writing, append file may not exist */
  270. /* "a+"= append + read, file may not exist */
  271. /* "w+" = read, write, truncate. file may not exist */
  272. must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
  273. truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
  274. r_right = (SDL_strchr(mode, '+') != NULL
  275. || must_exist) ? GENERIC_READ : 0;
  276. a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
  277. w_right = (a_mode || SDL_strchr(mode, '+')
  278. || truncate) ? GENERIC_WRITE : 0;
  279. if (!r_right && !w_right) /* inconsistent mode */
  280. return -1; /* failed (invalid call) */
  281. context->hidden.windowsio.buffer.data =
  282. (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
  283. if (!context->hidden.windowsio.buffer.data) {
  284. return SDL_OutOfMemory();
  285. }
  286. /* Do not open a dialog box if failure */
  287. old_error_mode =
  288. SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  289. {
  290. LPTSTR tstr = WIN_UTF8ToString(filename);
  291. h = CreateFile(tstr, (w_right | r_right),
  292. (w_right) ? 0 : FILE_SHARE_READ, NULL,
  293. (must_exist | truncate | a_mode),
  294. FILE_ATTRIBUTE_NORMAL, NULL);
  295. SDL_free(tstr);
  296. }
  297. /* restore old behavior */
  298. SetErrorMode(old_error_mode);
  299. if (h == INVALID_HANDLE_VALUE) {
  300. SDL_free(context->hidden.windowsio.buffer.data);
  301. context->hidden.windowsio.buffer.data = NULL;
  302. SDL_SetError("Couldn't open %s", filename);
  303. return -2; /* failed (CreateFile) */
  304. }
  305. context->hidden.windowsio.h = h;
  306. context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
  307. return 0; /* ok */
  308. }
  309. static Sint64 SDLCALL
  310. windows_file_size(SDL_RWops * context)
  311. {
  312. LARGE_INTEGER size;
  313. if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
  314. return SDL_SetError("windows_file_size: invalid context/file not opened");
  315. }
  316. if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
  317. return WIN_SetError("windows_file_size");
  318. }
  319. return size.QuadPart;
  320. }
  321. static Sint64 SDLCALL
  322. windows_file_seek(SDL_RWops * context, Sint64 offset, int whence)
  323. {
  324. DWORD windowswhence;
  325. LARGE_INTEGER windowsoffset;
  326. if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
  327. return SDL_SetError("windows_file_seek: invalid context/file not opened");
  328. }
  329. /* FIXME: We may be able to satisfy the seek within buffered data */
  330. if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
  331. offset -= (long)context->hidden.windowsio.buffer.left;
  332. }
  333. context->hidden.windowsio.buffer.left = 0;
  334. switch (whence) {
  335. case RW_SEEK_SET:
  336. windowswhence = FILE_BEGIN;
  337. break;
  338. case RW_SEEK_CUR:
  339. windowswhence = FILE_CURRENT;
  340. break;
  341. case RW_SEEK_END:
  342. windowswhence = FILE_END;
  343. break;
  344. default:
  345. return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
  346. }
  347. windowsoffset.QuadPart = offset;
  348. if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
  349. return WIN_SetError("windows_file_seek");
  350. }
  351. return windowsoffset.QuadPart;
  352. }
  353. static size_t SDLCALL
  354. windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
  355. {
  356. size_t total_need;
  357. size_t total_read = 0;
  358. size_t read_ahead;
  359. DWORD byte_read;
  360. total_need = size * maxnum;
  361. if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
  362. || !total_need)
  363. return 0;
  364. if (context->hidden.windowsio.buffer.left > 0) {
  365. void *data = (char *) context->hidden.windowsio.buffer.data +
  366. context->hidden.windowsio.buffer.size -
  367. context->hidden.windowsio.buffer.left;
  368. read_ahead =
  369. SDL_min(total_need, context->hidden.windowsio.buffer.left);
  370. SDL_memcpy(ptr, data, read_ahead);
  371. context->hidden.windowsio.buffer.left -= read_ahead;
  372. if (read_ahead == total_need) {
  373. return maxnum;
  374. }
  375. ptr = (char *) ptr + read_ahead;
  376. total_need -= read_ahead;
  377. total_read += read_ahead;
  378. }
  379. if (total_need < READAHEAD_BUFFER_SIZE) {
  380. if (!ReadFile
  381. (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
  382. READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
  383. SDL_Error(SDL_EFREAD);
  384. return 0;
  385. }
  386. read_ahead = SDL_min(total_need, (int) byte_read);
  387. SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
  388. context->hidden.windowsio.buffer.size = byte_read;
  389. context->hidden.windowsio.buffer.left = byte_read - read_ahead;
  390. total_read += read_ahead;
  391. } else {
  392. if (!ReadFile
  393. (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
  394. SDL_Error(SDL_EFREAD);
  395. return 0;
  396. }
  397. total_read += byte_read;
  398. }
  399. return (total_read / size);
  400. }
  401. static size_t SDLCALL
  402. windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
  403. size_t num)
  404. {
  405. size_t total_bytes;
  406. DWORD byte_written;
  407. size_t nwritten;
  408. total_bytes = size * num;
  409. if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
  410. || total_bytes <= 0 || !size)
  411. return 0;
  412. if (context->hidden.windowsio.buffer.left) {
  413. SetFilePointer(context->hidden.windowsio.h,
  414. -(LONG)context->hidden.windowsio.buffer.left, NULL,
  415. FILE_CURRENT);
  416. context->hidden.windowsio.buffer.left = 0;
  417. }
  418. /* if in append mode, we must go to the EOF before write */
  419. if (context->hidden.windowsio.append) {
  420. if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
  421. INVALID_SET_FILE_POINTER) {
  422. SDL_Error(SDL_EFWRITE);
  423. return 0;
  424. }
  425. }
  426. if (!WriteFile
  427. (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
  428. SDL_Error(SDL_EFWRITE);
  429. return 0;
  430. }
  431. nwritten = byte_written / size;
  432. return nwritten;
  433. }
  434. static int SDLCALL
  435. windows_file_close(SDL_RWops * context)
  436. {
  437. if (context) {
  438. if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
  439. CloseHandle(context->hidden.windowsio.h);
  440. context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
  441. }
  442. SDL_free(context->hidden.windowsio.buffer.data);
  443. context->hidden.windowsio.buffer.data = NULL;
  444. SDL_FreeRW(context);
  445. }
  446. return 0;
  447. }
  448. #endif /* __WIN32__ */
  449. #ifdef HAVE_STDIO_H
  450. #ifdef HAVE_FOPEN64
  451. #define fopen fopen64
  452. #endif
  453. #ifdef HAVE_FSEEKO64
  454. #define fseek_off_t off64_t
  455. #define fseek fseeko64
  456. #define ftell ftello64
  457. #elif defined(HAVE_FSEEKO)
  458. #if defined(OFF_MIN) && defined(OFF_MAX)
  459. #define FSEEK_OFF_MIN OFF_MIN
  460. #define FSEEK_OFF_MAX OFF_MAX
  461. #elif defined(HAVE_LIMITS_H)
  462. /* POSIX doesn't specify the minimum and maximum macros for off_t so
  463. * we have to improvise and dance around implementation-defined
  464. * behavior. This may fail if the off_t type has padding bits or
  465. * is not a two's-complement representation. The compilers will detect
  466. * and eliminate the dead code if off_t has 64 bits.
  467. */
  468. #define FSEEK_OFF_MAX (((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) << 1) + 1)
  469. #define FSEEK_OFF_MIN (-(FSEEK_OFF_MAX) - 1)
  470. #endif
  471. #define fseek_off_t off_t
  472. #define fseek fseeko
  473. #define ftell ftello
  474. #elif defined(HAVE__FSEEKI64)
  475. #define fseek_off_t __int64
  476. #define fseek _fseeki64
  477. #define ftell _ftelli64
  478. #else
  479. #ifdef HAVE_LIMITS_H
  480. #define FSEEK_OFF_MIN LONG_MIN
  481. #define FSEEK_OFF_MAX LONG_MAX
  482. #endif
  483. #define fseek_off_t long
  484. #endif
  485. /* Functions to read/write stdio file pointers */
  486. static Sint64 SDLCALL
  487. stdio_size(SDL_RWops * context)
  488. {
  489. Sint64 pos, size;
  490. pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
  491. if (pos < 0) {
  492. return -1;
  493. }
  494. size = SDL_RWseek(context, 0, RW_SEEK_END);
  495. SDL_RWseek(context, pos, RW_SEEK_SET);
  496. return size;
  497. }
  498. static Sint64 SDLCALL
  499. stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
  500. {
  501. int stdiowhence;
  502. switch (whence) {
  503. case RW_SEEK_SET:
  504. stdiowhence = SEEK_SET;
  505. break;
  506. case RW_SEEK_CUR:
  507. stdiowhence = SEEK_CUR;
  508. break;
  509. case RW_SEEK_END:
  510. stdiowhence = SEEK_END;
  511. break;
  512. default:
  513. return SDL_SetError("Unknown value for 'whence'");
  514. }
  515. #if defined(FSEEK_OFF_MIN) && defined(FSEEK_OFF_MAX)
  516. if (offset < (Sint64)(FSEEK_OFF_MIN) || offset > (Sint64)(FSEEK_OFF_MAX)) {
  517. return SDL_SetError("Seek offset out of range");
  518. }
  519. #endif
  520. if (fseek(context->hidden.stdio.fp, (fseek_off_t)offset, stdiowhence) == 0) {
  521. Sint64 pos = ftell(context->hidden.stdio.fp);
  522. if (pos < 0) {
  523. return SDL_SetError("Couldn't get stream offset");
  524. }
  525. return pos;
  526. }
  527. return SDL_Error(SDL_EFSEEK);
  528. }
  529. static size_t SDLCALL
  530. stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
  531. {
  532. size_t nread;
  533. nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
  534. if (nread == 0 && ferror(context->hidden.stdio.fp)) {
  535. SDL_Error(SDL_EFREAD);
  536. }
  537. return nread;
  538. }
  539. static size_t SDLCALL
  540. stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
  541. {
  542. size_t nwrote;
  543. nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
  544. if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
  545. SDL_Error(SDL_EFWRITE);
  546. }
  547. return nwrote;
  548. }
  549. static int SDLCALL
  550. stdio_close(SDL_RWops * context)
  551. {
  552. int status = 0;
  553. if (context) {
  554. if (context->hidden.stdio.autoclose) {
  555. /* WARNING: Check the return value here! */
  556. if (fclose(context->hidden.stdio.fp) != 0) {
  557. status = SDL_Error(SDL_EFWRITE);
  558. }
  559. }
  560. SDL_FreeRW(context);
  561. }
  562. return status;
  563. }
  564. #endif /* !HAVE_STDIO_H */
  565. /* Functions to read/write memory pointers */
  566. static Sint64 SDLCALL
  567. mem_size(SDL_RWops * context)
  568. {
  569. return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
  570. }
  571. static Sint64 SDLCALL
  572. mem_seek(SDL_RWops * context, Sint64 offset, int whence)
  573. {
  574. Uint8 *newpos;
  575. switch (whence) {
  576. case RW_SEEK_SET:
  577. newpos = context->hidden.mem.base + offset;
  578. break;
  579. case RW_SEEK_CUR:
  580. newpos = context->hidden.mem.here + offset;
  581. break;
  582. case RW_SEEK_END:
  583. newpos = context->hidden.mem.stop + offset;
  584. break;
  585. default:
  586. return SDL_SetError("Unknown value for 'whence'");
  587. }
  588. if (newpos < context->hidden.mem.base) {
  589. newpos = context->hidden.mem.base;
  590. }
  591. if (newpos > context->hidden.mem.stop) {
  592. newpos = context->hidden.mem.stop;
  593. }
  594. context->hidden.mem.here = newpos;
  595. return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
  596. }
  597. static size_t SDLCALL
  598. mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
  599. {
  600. size_t total_bytes;
  601. size_t mem_available;
  602. total_bytes = (maxnum * size);
  603. if ((maxnum <= 0) || (size <= 0)
  604. || ((total_bytes / maxnum) != size)) {
  605. return 0;
  606. }
  607. mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
  608. if (total_bytes > mem_available) {
  609. total_bytes = mem_available;
  610. }
  611. SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
  612. context->hidden.mem.here += total_bytes;
  613. return (total_bytes / size);
  614. }
  615. static size_t SDLCALL
  616. mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
  617. {
  618. if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
  619. num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
  620. }
  621. SDL_memcpy(context->hidden.mem.here, ptr, num * size);
  622. context->hidden.mem.here += num * size;
  623. return num;
  624. }
  625. static size_t SDLCALL
  626. mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
  627. {
  628. SDL_SetError("Can't write to read-only memory");
  629. return 0;
  630. }
  631. static int SDLCALL
  632. mem_close(SDL_RWops * context)
  633. {
  634. if (context) {
  635. SDL_FreeRW(context);
  636. }
  637. return 0;
  638. }
  639. /* Functions to create SDL_RWops structures from various data sources */
  640. SDL_RWops *
  641. SDL_RWFromFile(const char *file, const char *mode)
  642. {
  643. SDL_RWops *rwops = NULL;
  644. if (!file || !*file || !mode || !*mode) {
  645. SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
  646. return NULL;
  647. }
  648. #if defined(__ANDROID__)
  649. #ifdef HAVE_STDIO_H
  650. /* Try to open the file on the filesystem first */
  651. if (*file == '/') {
  652. FILE *fp = fopen(file, mode);
  653. if (fp) {
  654. return SDL_RWFromFP(fp, 1);
  655. }
  656. } else {
  657. /* Try opening it from internal storage if it's a relative path */
  658. char *path;
  659. FILE *fp;
  660. /* !!! FIXME: why not just "char path[PATH_MAX];" ? */
  661. path = SDL_stack_alloc(char, PATH_MAX);
  662. if (path) {
  663. SDL_snprintf(path, PATH_MAX, "%s/%s",
  664. SDL_AndroidGetInternalStoragePath(), file);
  665. fp = fopen(path, mode);
  666. SDL_stack_free(path);
  667. if (fp) {
  668. return SDL_RWFromFP(fp, 1);
  669. }
  670. }
  671. }
  672. #endif /* HAVE_STDIO_H */
  673. /* Try to open the file from the asset system */
  674. rwops = SDL_AllocRW();
  675. if (!rwops)
  676. return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
  677. if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
  678. SDL_FreeRW(rwops);
  679. return NULL;
  680. }
  681. rwops->size = Android_JNI_FileSize;
  682. rwops->seek = Android_JNI_FileSeek;
  683. rwops->read = Android_JNI_FileRead;
  684. rwops->write = Android_JNI_FileWrite;
  685. rwops->close = Android_JNI_FileClose;
  686. rwops->type = SDL_RWOPS_JNIFILE;
  687. #elif defined(__WIN32__)
  688. rwops = SDL_AllocRW();
  689. if (!rwops)
  690. return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
  691. if (windows_file_open(rwops, file, mode) < 0) {
  692. SDL_FreeRW(rwops);
  693. return NULL;
  694. }
  695. rwops->size = windows_file_size;
  696. rwops->seek = windows_file_seek;
  697. rwops->read = windows_file_read;
  698. rwops->write = windows_file_write;
  699. rwops->close = windows_file_close;
  700. rwops->type = SDL_RWOPS_WINFILE;
  701. #elif defined(__VITA__)
  702. rwops = SDL_AllocRW();
  703. if (!rwops)
  704. return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
  705. if (vita_file_open(rwops, file, mode) < 0) {
  706. SDL_FreeRW(rwops);
  707. return NULL;
  708. }
  709. rwops->size = vita_file_size;
  710. rwops->seek = vita_file_seek;
  711. rwops->read = vita_file_read;
  712. rwops->write = vita_file_write;
  713. rwops->close = vita_file_close;
  714. rwops->type = SDL_RWOPS_VITAFILE;
  715. #elif HAVE_STDIO_H
  716. {
  717. #ifdef __APPLE__
  718. FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
  719. #elif __WINRT__
  720. FILE *fp = NULL;
  721. fopen_s(&fp, file, mode);
  722. #else
  723. FILE *fp = fopen(file, mode);
  724. #endif
  725. if (fp == NULL) {
  726. SDL_SetError("Couldn't open %s", file);
  727. } else {
  728. rwops = SDL_RWFromFP(fp, SDL_TRUE);
  729. }
  730. }
  731. #else
  732. SDL_SetError("SDL not compiled with stdio support");
  733. #endif /* !HAVE_STDIO_H */
  734. return rwops;
  735. }
  736. #ifdef HAVE_STDIO_H
  737. SDL_RWops *
  738. SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
  739. {
  740. SDL_RWops *rwops = NULL;
  741. rwops = SDL_AllocRW();
  742. if (rwops != NULL) {
  743. rwops->size = stdio_size;
  744. rwops->seek = stdio_seek;
  745. rwops->read = stdio_read;
  746. rwops->write = stdio_write;
  747. rwops->close = stdio_close;
  748. rwops->hidden.stdio.fp = fp;
  749. rwops->hidden.stdio.autoclose = autoclose;
  750. rwops->type = SDL_RWOPS_STDFILE;
  751. }
  752. return rwops;
  753. }
  754. #else
  755. SDL_RWops *
  756. SDL_RWFromFP(void * fp, SDL_bool autoclose)
  757. {
  758. SDL_SetError("SDL not compiled with stdio support");
  759. return NULL;
  760. }
  761. #endif /* HAVE_STDIO_H */
  762. SDL_RWops *
  763. SDL_RWFromMem(void *mem, int size)
  764. {
  765. SDL_RWops *rwops = NULL;
  766. if (!mem) {
  767. SDL_InvalidParamError("mem");
  768. return rwops;
  769. }
  770. if (!size) {
  771. SDL_InvalidParamError("size");
  772. return rwops;
  773. }
  774. rwops = SDL_AllocRW();
  775. if (rwops != NULL) {
  776. rwops->size = mem_size;
  777. rwops->seek = mem_seek;
  778. rwops->read = mem_read;
  779. rwops->write = mem_write;
  780. rwops->close = mem_close;
  781. rwops->hidden.mem.base = (Uint8 *) mem;
  782. rwops->hidden.mem.here = rwops->hidden.mem.base;
  783. rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
  784. rwops->type = SDL_RWOPS_MEMORY;
  785. }
  786. return rwops;
  787. }
  788. SDL_RWops *
  789. SDL_RWFromConstMem(const void *mem, int size)
  790. {
  791. SDL_RWops *rwops = NULL;
  792. if (!mem) {
  793. SDL_InvalidParamError("mem");
  794. return rwops;
  795. }
  796. if (!size) {
  797. SDL_InvalidParamError("size");
  798. return rwops;
  799. }
  800. rwops = SDL_AllocRW();
  801. if (rwops != NULL) {
  802. rwops->size = mem_size;
  803. rwops->seek = mem_seek;
  804. rwops->read = mem_read;
  805. rwops->write = mem_writeconst;
  806. rwops->close = mem_close;
  807. rwops->hidden.mem.base = (Uint8 *) mem;
  808. rwops->hidden.mem.here = rwops->hidden.mem.base;
  809. rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
  810. rwops->type = SDL_RWOPS_MEMORY_RO;
  811. }
  812. return rwops;
  813. }
  814. SDL_RWops *
  815. SDL_AllocRW(void)
  816. {
  817. SDL_RWops *area;
  818. area = (SDL_RWops *) SDL_malloc(sizeof *area);
  819. if (area == NULL) {
  820. SDL_OutOfMemory();
  821. } else {
  822. area->type = SDL_RWOPS_UNKNOWN;
  823. }
  824. return area;
  825. }
  826. void
  827. SDL_FreeRW(SDL_RWops * area)
  828. {
  829. SDL_free(area);
  830. }
  831. /* Load all the data from an SDL data stream */
  832. void *
  833. SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize, int freesrc)
  834. {
  835. const int FILE_CHUNK_SIZE = 1024;
  836. Sint64 size;
  837. size_t size_read, size_total;
  838. void *data = NULL, *newdata;
  839. if (!src) {
  840. SDL_InvalidParamError("src");
  841. return NULL;
  842. }
  843. size = SDL_RWsize(src);
  844. if (size < 0) {
  845. size = FILE_CHUNK_SIZE;
  846. }
  847. data = SDL_malloc((size_t)(size + 1));
  848. size_total = 0;
  849. for (;;) {
  850. if ((((Sint64)size_total) + FILE_CHUNK_SIZE) > size) {
  851. size = (size_total + FILE_CHUNK_SIZE);
  852. newdata = SDL_realloc(data, (size_t)(size + 1));
  853. if (!newdata) {
  854. SDL_free(data);
  855. data = NULL;
  856. SDL_OutOfMemory();
  857. goto done;
  858. }
  859. data = newdata;
  860. }
  861. size_read = SDL_RWread(src, (char *)data+size_total, 1, (size_t)(size-size_total));
  862. if (size_read == 0) {
  863. break;
  864. }
  865. size_total += size_read;
  866. }
  867. if (datasize) {
  868. *datasize = size_total;
  869. }
  870. ((char *)data)[size_total] = '\0';
  871. done:
  872. if (freesrc && src) {
  873. SDL_RWclose(src);
  874. }
  875. return data;
  876. }
  877. void *
  878. SDL_LoadFile(const char *file, size_t *datasize)
  879. {
  880. return SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1);
  881. }
  882. Sint64
  883. SDL_RWsize(SDL_RWops *context)
  884. {
  885. return context->size(context);
  886. }
  887. Sint64
  888. SDL_RWseek(SDL_RWops *context, Sint64 offset, int whence)
  889. {
  890. return context->seek(context, offset, whence);
  891. }
  892. Sint64
  893. SDL_RWtell(SDL_RWops *context)
  894. {
  895. return context->seek(context, 0, RW_SEEK_CUR);
  896. }
  897. size_t
  898. SDL_RWread(SDL_RWops *context, void *ptr, size_t size, size_t maxnum)
  899. {
  900. return context->read(context, ptr, size, maxnum);
  901. }
  902. size_t
  903. SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t num)
  904. {
  905. return context->write(context, ptr, size, num);
  906. }
  907. int
  908. SDL_RWclose(SDL_RWops *context)
  909. {
  910. return context->close(context);
  911. }
  912. /* Functions for dynamically reading and writing endian-specific values */
  913. Uint8
  914. SDL_ReadU8(SDL_RWops * src)
  915. {
  916. Uint8 value = 0;
  917. SDL_RWread(src, &value, sizeof (value), 1);
  918. return value;
  919. }
  920. Uint16
  921. SDL_ReadLE16(SDL_RWops * src)
  922. {
  923. Uint16 value = 0;
  924. SDL_RWread(src, &value, sizeof (value), 1);
  925. return SDL_SwapLE16(value);
  926. }
  927. Uint16
  928. SDL_ReadBE16(SDL_RWops * src)
  929. {
  930. Uint16 value = 0;
  931. SDL_RWread(src, &value, sizeof (value), 1);
  932. return SDL_SwapBE16(value);
  933. }
  934. Uint32
  935. SDL_ReadLE32(SDL_RWops * src)
  936. {
  937. Uint32 value = 0;
  938. SDL_RWread(src, &value, sizeof (value), 1);
  939. return SDL_SwapLE32(value);
  940. }
  941. Uint32
  942. SDL_ReadBE32(SDL_RWops * src)
  943. {
  944. Uint32 value = 0;
  945. SDL_RWread(src, &value, sizeof (value), 1);
  946. return SDL_SwapBE32(value);
  947. }
  948. Uint64
  949. SDL_ReadLE64(SDL_RWops * src)
  950. {
  951. Uint64 value = 0;
  952. SDL_RWread(src, &value, sizeof (value), 1);
  953. return SDL_SwapLE64(value);
  954. }
  955. Uint64
  956. SDL_ReadBE64(SDL_RWops * src)
  957. {
  958. Uint64 value = 0;
  959. SDL_RWread(src, &value, sizeof (value), 1);
  960. return SDL_SwapBE64(value);
  961. }
  962. size_t
  963. SDL_WriteU8(SDL_RWops * dst, Uint8 value)
  964. {
  965. return SDL_RWwrite(dst, &value, sizeof (value), 1);
  966. }
  967. size_t
  968. SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
  969. {
  970. const Uint16 swapped = SDL_SwapLE16(value);
  971. return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
  972. }
  973. size_t
  974. SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
  975. {
  976. const Uint16 swapped = SDL_SwapBE16(value);
  977. return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
  978. }
  979. size_t
  980. SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
  981. {
  982. const Uint32 swapped = SDL_SwapLE32(value);
  983. return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
  984. }
  985. size_t
  986. SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
  987. {
  988. const Uint32 swapped = SDL_SwapBE32(value);
  989. return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
  990. }
  991. size_t
  992. SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
  993. {
  994. const Uint64 swapped = SDL_SwapLE64(value);
  995. return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
  996. }
  997. size_t
  998. SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
  999. {
  1000. const Uint64 swapped = SDL_SwapBE64(value);
  1001. return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
  1002. }
  1003. /* vi: set ts=4 sw=4 expandtab: */