SDL_rwops.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2022 Sam Lantinga <[email protected]>
  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. #include "SDL_internal.h"
  19. #if defined(__WIN32__) || defined(__GDK__)
  20. #include "../core/windows/SDL_windows.h"
  21. #endif
  22. #ifdef HAVE_STDIO_H
  23. #include <stdio.h>
  24. #endif
  25. #ifdef HAVE_LIMITS_H
  26. #include <limits.h>
  27. #endif
  28. /* This file provides a general interface for SDL to read and write
  29. data sources. It can easily be extended to files, memory, etc.
  30. */
  31. #ifdef __APPLE__
  32. #include "cocoa/SDL_rwopsbundlesupport.h"
  33. #endif /* __APPLE__ */
  34. #ifdef __3DS__
  35. #include "n3ds/SDL_rwopsromfs.h"
  36. #endif /* __3DS__ */
  37. #ifdef __ANDROID__
  38. #include "../core/android/SDL_android.h"
  39. #endif
  40. #if defined(__WIN32__) || defined(__GDK__)
  41. /* Functions to read/write Win32 API file pointers */
  42. #ifndef INVALID_SET_FILE_POINTER
  43. #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
  44. #endif
  45. #define READAHEAD_BUFFER_SIZE 1024
  46. static int SDLCALL windows_file_open(SDL_RWops *context, const char *filename, const char *mode)
  47. {
  48. #if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
  49. UINT old_error_mode;
  50. #endif
  51. HANDLE h;
  52. DWORD r_right, w_right;
  53. DWORD must_exist, truncate;
  54. int a_mode;
  55. if (context == NULL) {
  56. return -1; /* failed (invalid call) */
  57. }
  58. context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
  59. context->hidden.windowsio.buffer.data = NULL;
  60. context->hidden.windowsio.buffer.size = 0;
  61. context->hidden.windowsio.buffer.left = 0;
  62. /* "r" = reading, file must exist */
  63. /* "w" = writing, truncate existing, file may not exist */
  64. /* "r+"= reading or writing, file must exist */
  65. /* "a" = writing, append file may not exist */
  66. /* "a+"= append + read, file may not exist */
  67. /* "w+" = read, write, truncate. file may not exist */
  68. must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
  69. truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
  70. r_right = (SDL_strchr(mode, '+') != NULL || must_exist) ? GENERIC_READ : 0;
  71. a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
  72. w_right = (a_mode || SDL_strchr(mode, '+') || truncate) ? GENERIC_WRITE : 0;
  73. if (!r_right && !w_right) {
  74. return -1; /* inconsistent mode */
  75. }
  76. /* failed (invalid call) */
  77. context->hidden.windowsio.buffer.data =
  78. (char *)SDL_malloc(READAHEAD_BUFFER_SIZE);
  79. if (!context->hidden.windowsio.buffer.data) {
  80. return SDL_OutOfMemory();
  81. }
  82. #if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
  83. /* Do not open a dialog box if failure */
  84. old_error_mode =
  85. SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  86. #endif
  87. {
  88. LPTSTR tstr = WIN_UTF8ToString(filename);
  89. h = CreateFile(tstr, (w_right | r_right),
  90. (w_right) ? 0 : FILE_SHARE_READ, NULL,
  91. (must_exist | truncate | a_mode),
  92. FILE_ATTRIBUTE_NORMAL, NULL);
  93. SDL_free(tstr);
  94. }
  95. #if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
  96. /* restore old behavior */
  97. SetErrorMode(old_error_mode);
  98. #endif
  99. if (h == INVALID_HANDLE_VALUE) {
  100. SDL_free(context->hidden.windowsio.buffer.data);
  101. context->hidden.windowsio.buffer.data = NULL;
  102. SDL_SetError("Couldn't open %s", filename);
  103. return -2; /* failed (CreateFile) */
  104. }
  105. context->hidden.windowsio.h = h;
  106. context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
  107. return 0; /* ok */
  108. }
  109. static Sint64 SDLCALL windows_file_size(SDL_RWops *context)
  110. {
  111. LARGE_INTEGER size;
  112. if (context == NULL || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
  113. return SDL_SetError("windows_file_size: invalid context/file not opened");
  114. }
  115. if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
  116. return WIN_SetError("windows_file_size");
  117. }
  118. return size.QuadPart;
  119. }
  120. static Sint64 SDLCALL windows_file_seek(SDL_RWops *context, Sint64 offset, int whence)
  121. {
  122. DWORD windowswhence;
  123. LARGE_INTEGER windowsoffset;
  124. if (context == NULL || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
  125. return SDL_SetError("windows_file_seek: invalid context/file not opened");
  126. }
  127. /* FIXME: We may be able to satisfy the seek within buffered data */
  128. if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
  129. offset -= (long)context->hidden.windowsio.buffer.left;
  130. }
  131. context->hidden.windowsio.buffer.left = 0;
  132. switch (whence) {
  133. case RW_SEEK_SET:
  134. windowswhence = FILE_BEGIN;
  135. break;
  136. case RW_SEEK_CUR:
  137. windowswhence = FILE_CURRENT;
  138. break;
  139. case RW_SEEK_END:
  140. windowswhence = FILE_END;
  141. break;
  142. default:
  143. return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
  144. }
  145. windowsoffset.QuadPart = offset;
  146. if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
  147. return WIN_SetError("windows_file_seek");
  148. }
  149. return windowsoffset.QuadPart;
  150. }
  151. static Sint64 SDLCALL
  152. windows_file_read(SDL_RWops *context, void *ptr, Sint64 size)
  153. {
  154. size_t total_need = (size_t) size;
  155. size_t total_read = 0;
  156. size_t read_ahead;
  157. DWORD byte_read;
  158. if (context == NULL || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
  159. return SDL_SetError("Invalid file handle");
  160. } else if (!total_need) {
  161. return 0;
  162. }
  163. if (context->hidden.windowsio.buffer.left > 0) {
  164. void *data = (char *)context->hidden.windowsio.buffer.data +
  165. context->hidden.windowsio.buffer.size -
  166. context->hidden.windowsio.buffer.left;
  167. read_ahead =
  168. SDL_min(total_need, context->hidden.windowsio.buffer.left);
  169. SDL_memcpy(ptr, data, read_ahead);
  170. context->hidden.windowsio.buffer.left -= read_ahead;
  171. if (read_ahead == total_need) {
  172. return size;
  173. }
  174. ptr = (char *)ptr + read_ahead;
  175. total_need -= read_ahead;
  176. total_read += read_ahead;
  177. }
  178. if (total_need < READAHEAD_BUFFER_SIZE) {
  179. if (!ReadFile(context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
  180. READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
  181. return SDL_Error(SDL_EFREAD);
  182. }
  183. read_ahead = SDL_min(total_need, (int)byte_read);
  184. SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
  185. context->hidden.windowsio.buffer.size = byte_read;
  186. context->hidden.windowsio.buffer.left = byte_read - read_ahead;
  187. total_read += read_ahead;
  188. } else {
  189. if (!ReadFile(context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
  190. return SDL_Error(SDL_EFREAD);
  191. }
  192. total_read += byte_read;
  193. }
  194. return total_read;
  195. }
  196. static Sint64 SDLCALL
  197. windows_file_write(SDL_RWops *context, const void *ptr, Sint64 size)
  198. {
  199. const size_t total_bytes = (size_t) size;
  200. DWORD byte_written;
  201. if (context == NULL || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
  202. return SDL_SetError("Invalid file handle");
  203. } else if (!total_bytes) {
  204. return 0;
  205. }
  206. if (context->hidden.windowsio.buffer.left) {
  207. SetFilePointer(context->hidden.windowsio.h,
  208. -(LONG)context->hidden.windowsio.buffer.left, NULL,
  209. FILE_CURRENT);
  210. context->hidden.windowsio.buffer.left = 0;
  211. }
  212. /* if in append mode, we must go to the EOF before write */
  213. if (context->hidden.windowsio.append) {
  214. if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
  215. INVALID_SET_FILE_POINTER) {
  216. return SDL_Error(SDL_EFWRITE);
  217. }
  218. }
  219. if (!WriteFile(context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
  220. return SDL_Error(SDL_EFWRITE);
  221. }
  222. return (Sint64) byte_written;
  223. }
  224. static int SDLCALL windows_file_close(SDL_RWops *context)
  225. {
  226. if (context) {
  227. if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
  228. CloseHandle(context->hidden.windowsio.h);
  229. context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
  230. }
  231. SDL_free(context->hidden.windowsio.buffer.data);
  232. context->hidden.windowsio.buffer.data = NULL;
  233. SDL_FreeRW(context);
  234. }
  235. return 0;
  236. }
  237. #endif /* defined(__WIN32__) || defined(__GDK__) */
  238. #if defined(HAVE_STDIO_H) && !(defined(__WIN32__) || defined(__GDK__))
  239. /* Functions to read/write stdio file pointers. Not used for windows. */
  240. #ifdef HAVE_FOPEN64
  241. #define fopen fopen64
  242. #endif
  243. #ifdef HAVE_FSEEKO64
  244. #define fseek_off_t off64_t
  245. #define fseek fseeko64
  246. #define ftell ftello64
  247. #elif defined(HAVE_FSEEKO)
  248. #if defined(OFF_MIN) && defined(OFF_MAX)
  249. #define FSEEK_OFF_MIN OFF_MIN
  250. #define FSEEK_OFF_MAX OFF_MAX
  251. #elif defined(HAVE_LIMITS_H)
  252. /* POSIX doesn't specify the minimum and maximum macros for off_t so
  253. * we have to improvise and dance around implementation-defined
  254. * behavior. This may fail if the off_t type has padding bits or
  255. * is not a two's-complement representation. The compilers will detect
  256. * and eliminate the dead code if off_t has 64 bits.
  257. */
  258. #define FSEEK_OFF_MAX (((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) << 1) + 1)
  259. #define FSEEK_OFF_MIN (-(FSEEK_OFF_MAX)-1)
  260. #endif
  261. #define fseek_off_t off_t
  262. #define fseek fseeko
  263. #define ftell ftello
  264. #elif defined(HAVE__FSEEKI64)
  265. #define fseek_off_t __int64
  266. #define fseek _fseeki64
  267. #define ftell _ftelli64
  268. #else
  269. #ifdef HAVE_LIMITS_H
  270. #define FSEEK_OFF_MIN LONG_MIN
  271. #define FSEEK_OFF_MAX LONG_MAX
  272. #endif
  273. #define fseek_off_t long
  274. #endif
  275. static Sint64 SDLCALL stdio_size(SDL_RWops *context)
  276. {
  277. Sint64 pos, size;
  278. pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
  279. if (pos < 0) {
  280. return -1;
  281. }
  282. size = SDL_RWseek(context, 0, RW_SEEK_END);
  283. SDL_RWseek(context, pos, RW_SEEK_SET);
  284. return size;
  285. }
  286. static Sint64 SDLCALL stdio_seek(SDL_RWops *context, Sint64 offset, int whence)
  287. {
  288. int stdiowhence;
  289. switch (whence) {
  290. case RW_SEEK_SET:
  291. stdiowhence = SEEK_SET;
  292. break;
  293. case RW_SEEK_CUR:
  294. stdiowhence = SEEK_CUR;
  295. break;
  296. case RW_SEEK_END:
  297. stdiowhence = SEEK_END;
  298. break;
  299. default:
  300. return SDL_SetError("Unknown value for 'whence'");
  301. }
  302. #if defined(FSEEK_OFF_MIN) && defined(FSEEK_OFF_MAX)
  303. if (offset < (Sint64)(FSEEK_OFF_MIN) || offset > (Sint64)(FSEEK_OFF_MAX)) {
  304. return SDL_SetError("Seek offset out of range");
  305. }
  306. #endif
  307. if (fseek((FILE *)context->hidden.stdio.fp, (fseek_off_t)offset, stdiowhence) == 0) {
  308. Sint64 pos = ftell((FILE *)context->hidden.stdio.fp);
  309. if (pos < 0) {
  310. return SDL_SetError("Couldn't get stream offset");
  311. }
  312. return pos;
  313. }
  314. return SDL_Error(SDL_EFSEEK);
  315. }
  316. static Sint64 SDLCALL
  317. stdio_read(SDL_RWops *context, void *ptr, Sint64 size)
  318. {
  319. size_t nread;
  320. nread = fread(ptr, 1, size, (FILE *)context->hidden.stdio.fp);
  321. if (nread == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
  322. return SDL_Error(SDL_EFREAD);
  323. }
  324. return (Sint64) nread;
  325. }
  326. static Sint64 SDLCALL
  327. stdio_write(SDL_RWops *context, const void *ptr, Sint64 size)
  328. {
  329. size_t nwrote;
  330. nwrote = fwrite(ptr, 1, size, (FILE *)context->hidden.stdio.fp);
  331. if (nwrote == 0 && ferror((FILE *)context->hidden.stdio.fp)) {
  332. return SDL_Error(SDL_EFWRITE);
  333. }
  334. return (Sint64) nwrote;
  335. }
  336. static int SDLCALL stdio_close(SDL_RWops *context)
  337. {
  338. int status = 0;
  339. if (context) {
  340. if (context->hidden.stdio.autoclose) {
  341. if (fclose((FILE *)context->hidden.stdio.fp) != 0) {
  342. status = SDL_Error(SDL_EFWRITE);
  343. }
  344. }
  345. SDL_FreeRW(context);
  346. }
  347. return status;
  348. }
  349. static SDL_RWops *SDL_RWFromFP(void *fp, SDL_bool autoclose)
  350. {
  351. SDL_RWops *rwops = NULL;
  352. rwops = SDL_AllocRW();
  353. if (rwops != NULL) {
  354. rwops->size = stdio_size;
  355. rwops->seek = stdio_seek;
  356. rwops->read = stdio_read;
  357. rwops->write = stdio_write;
  358. rwops->close = stdio_close;
  359. rwops->hidden.stdio.fp = fp;
  360. rwops->hidden.stdio.autoclose = autoclose;
  361. rwops->type = SDL_RWOPS_STDFILE;
  362. }
  363. return rwops;
  364. }
  365. #endif /* !HAVE_STDIO_H && !(__WIN32__ || __GDK__) */
  366. /* Functions to read/write memory pointers */
  367. static Sint64 SDLCALL mem_size(SDL_RWops *context)
  368. {
  369. return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
  370. }
  371. static Sint64 SDLCALL mem_seek(SDL_RWops *context, Sint64 offset, int whence)
  372. {
  373. Uint8 *newpos;
  374. switch (whence) {
  375. case RW_SEEK_SET:
  376. newpos = context->hidden.mem.base + offset;
  377. break;
  378. case RW_SEEK_CUR:
  379. newpos = context->hidden.mem.here + offset;
  380. break;
  381. case RW_SEEK_END:
  382. newpos = context->hidden.mem.stop + offset;
  383. break;
  384. default:
  385. return SDL_SetError("Unknown value for 'whence'");
  386. }
  387. if (newpos < context->hidden.mem.base) {
  388. newpos = context->hidden.mem.base;
  389. }
  390. if (newpos > context->hidden.mem.stop) {
  391. newpos = context->hidden.mem.stop;
  392. }
  393. context->hidden.mem.here = newpos;
  394. return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
  395. }
  396. static Sint64 mem_io(SDL_RWops *context, void *dst, const void *src, Sint64 size)
  397. {
  398. const Sint64 mem_available = (Sint64) (context->hidden.mem.stop - context->hidden.mem.here);
  399. if (size > mem_available) {
  400. size = mem_available;
  401. }
  402. SDL_memcpy(dst, src, (size_t) size);
  403. context->hidden.mem.here += size;
  404. return size;
  405. }
  406. static Sint64 SDLCALL
  407. mem_read(SDL_RWops *context, void *ptr, Sint64 size)
  408. {
  409. return mem_io(context, ptr, context->hidden.mem.here, size);
  410. }
  411. static Sint64 SDLCALL
  412. mem_write(SDL_RWops *context, const void *ptr, Sint64 size)
  413. {
  414. return mem_io(context, context->hidden.mem.here, ptr, size);
  415. }
  416. static Sint64 SDLCALL
  417. mem_writeconst(SDL_RWops *context, const void *ptr, Sint64 size)
  418. {
  419. return SDL_SetError("Can't write to read-only memory");
  420. }
  421. static int SDLCALL mem_close(SDL_RWops *context)
  422. {
  423. if (context) {
  424. SDL_FreeRW(context);
  425. }
  426. return 0;
  427. }
  428. /* Functions to create SDL_RWops structures from various data sources */
  429. SDL_RWops *
  430. SDL_RWFromFile(const char *file, const char *mode)
  431. {
  432. SDL_RWops *rwops = NULL;
  433. if (file == NULL || !*file || mode == NULL || !*mode) {
  434. SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
  435. return NULL;
  436. }
  437. #if defined(__ANDROID__)
  438. #ifdef HAVE_STDIO_H
  439. /* Try to open the file on the filesystem first */
  440. if (*file == '/') {
  441. FILE *fp = fopen(file, mode);
  442. if (fp) {
  443. return SDL_RWFromFP(fp, 1);
  444. }
  445. } else {
  446. /* Try opening it from internal storage if it's a relative path */
  447. char *path;
  448. FILE *fp;
  449. /* !!! FIXME: why not just "char path[PATH_MAX];" ? */
  450. path = SDL_stack_alloc(char, PATH_MAX);
  451. if (path) {
  452. SDL_snprintf(path, PATH_MAX, "%s/%s",
  453. SDL_AndroidGetInternalStoragePath(), file);
  454. fp = fopen(path, mode);
  455. SDL_stack_free(path);
  456. if (fp) {
  457. return SDL_RWFromFP(fp, 1);
  458. }
  459. }
  460. }
  461. #endif /* HAVE_STDIO_H */
  462. /* Try to open the file from the asset system */
  463. rwops = SDL_AllocRW();
  464. if (rwops == NULL) {
  465. return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
  466. }
  467. if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
  468. SDL_FreeRW(rwops);
  469. return NULL;
  470. }
  471. rwops->size = Android_JNI_FileSize;
  472. rwops->seek = Android_JNI_FileSeek;
  473. rwops->read = Android_JNI_FileRead;
  474. rwops->write = Android_JNI_FileWrite;
  475. rwops->close = Android_JNI_FileClose;
  476. rwops->type = SDL_RWOPS_JNIFILE;
  477. #elif defined(__WIN32__) || defined(__GDK__)
  478. rwops = SDL_AllocRW();
  479. if (rwops == NULL) {
  480. return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
  481. }
  482. if (windows_file_open(rwops, file, mode) < 0) {
  483. SDL_FreeRW(rwops);
  484. return NULL;
  485. }
  486. rwops->size = windows_file_size;
  487. rwops->seek = windows_file_seek;
  488. rwops->read = windows_file_read;
  489. rwops->write = windows_file_write;
  490. rwops->close = windows_file_close;
  491. rwops->type = SDL_RWOPS_WINFILE;
  492. #elif HAVE_STDIO_H
  493. {
  494. #if __APPLE__ && !SDL_FILE_DISABLED // TODO: add dummy?
  495. FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
  496. #elif __WINRT__
  497. FILE *fp = NULL;
  498. fopen_s(&fp, file, mode);
  499. #elif __3DS__
  500. FILE *fp = N3DS_FileOpen(file, mode);
  501. #else
  502. FILE *fp = fopen(file, mode);
  503. #endif
  504. if (fp == NULL) {
  505. SDL_SetError("Couldn't open %s", file);
  506. } else {
  507. rwops = SDL_RWFromFP(fp, SDL_TRUE);
  508. }
  509. }
  510. #else
  511. SDL_SetError("SDL not compiled with stdio support");
  512. #endif /* !HAVE_STDIO_H */
  513. return rwops;
  514. }
  515. SDL_RWops *
  516. SDL_RWFromMem(void *mem, int size)
  517. {
  518. SDL_RWops *rwops = NULL;
  519. if (mem == NULL) {
  520. SDL_InvalidParamError("mem");
  521. return rwops;
  522. }
  523. if (!size) {
  524. SDL_InvalidParamError("size");
  525. return rwops;
  526. }
  527. rwops = SDL_AllocRW();
  528. if (rwops != NULL) {
  529. rwops->size = mem_size;
  530. rwops->seek = mem_seek;
  531. rwops->read = mem_read;
  532. rwops->write = mem_write;
  533. rwops->close = mem_close;
  534. rwops->hidden.mem.base = (Uint8 *)mem;
  535. rwops->hidden.mem.here = rwops->hidden.mem.base;
  536. rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
  537. rwops->type = SDL_RWOPS_MEMORY;
  538. }
  539. return rwops;
  540. }
  541. SDL_RWops *
  542. SDL_RWFromConstMem(const void *mem, int size)
  543. {
  544. SDL_RWops *rwops = NULL;
  545. if (mem == NULL) {
  546. SDL_InvalidParamError("mem");
  547. return rwops;
  548. }
  549. if (!size) {
  550. SDL_InvalidParamError("size");
  551. return rwops;
  552. }
  553. rwops = SDL_AllocRW();
  554. if (rwops != NULL) {
  555. rwops->size = mem_size;
  556. rwops->seek = mem_seek;
  557. rwops->read = mem_read;
  558. rwops->write = mem_writeconst;
  559. rwops->close = mem_close;
  560. rwops->hidden.mem.base = (Uint8 *)mem;
  561. rwops->hidden.mem.here = rwops->hidden.mem.base;
  562. rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
  563. rwops->type = SDL_RWOPS_MEMORY_RO;
  564. }
  565. return rwops;
  566. }
  567. SDL_RWops *
  568. SDL_AllocRW(void)
  569. {
  570. SDL_RWops *area;
  571. area = (SDL_RWops *)SDL_malloc(sizeof *area);
  572. if (area == NULL) {
  573. SDL_OutOfMemory();
  574. } else {
  575. area->type = SDL_RWOPS_UNKNOWN;
  576. }
  577. return area;
  578. }
  579. void SDL_FreeRW(SDL_RWops *area)
  580. {
  581. SDL_free(area);
  582. }
  583. /* Load all the data from an SDL data stream */
  584. void *
  585. SDL_LoadFile_RW(SDL_RWops *src, size_t *datasize, int freesrc)
  586. {
  587. static const Sint64 FILE_CHUNK_SIZE = 1024;
  588. Sint64 size;
  589. Sint64 size_read, size_total;
  590. void *data = NULL, *newdata;
  591. if (src == NULL) {
  592. SDL_InvalidParamError("src");
  593. return NULL;
  594. }
  595. size = SDL_RWsize(src);
  596. if (size < 0) {
  597. size = FILE_CHUNK_SIZE;
  598. }
  599. data = SDL_malloc((size_t)(size + 1));
  600. size_total = 0;
  601. for (;;) {
  602. if ((size_total + FILE_CHUNK_SIZE) > size) {
  603. size = (size_total + FILE_CHUNK_SIZE);
  604. newdata = SDL_realloc(data, (size_t)(size + 1));
  605. if (newdata == NULL) {
  606. SDL_free(data);
  607. data = NULL;
  608. SDL_OutOfMemory();
  609. goto done;
  610. }
  611. data = newdata;
  612. }
  613. size_read = SDL_RWread(src, (char *)data + size_total, size - size_total);
  614. if (size_read == 0) {
  615. break;
  616. }
  617. size_total += size_read;
  618. }
  619. if (datasize) {
  620. *datasize = (size_t) size_total;
  621. }
  622. ((char *)data)[size_total] = '\0';
  623. done:
  624. if (freesrc && src) {
  625. SDL_RWclose(src);
  626. }
  627. return data;
  628. }
  629. void *
  630. SDL_LoadFile(const char *file, size_t *datasize)
  631. {
  632. return SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1);
  633. }
  634. Sint64
  635. SDL_RWsize(SDL_RWops *context)
  636. {
  637. return context->size(context);
  638. }
  639. Sint64
  640. SDL_RWseek(SDL_RWops *context, Sint64 offset, int whence)
  641. {
  642. return context->seek(context, offset, whence);
  643. }
  644. Sint64
  645. SDL_RWtell(SDL_RWops *context)
  646. {
  647. return context->seek(context, 0, RW_SEEK_CUR);
  648. }
  649. Sint64
  650. SDL_RWread(SDL_RWops *context, void *ptr, Sint64 size)
  651. {
  652. return context->read(context, ptr, size);
  653. }
  654. Sint64
  655. SDL_RWwrite(SDL_RWops *context, const void *ptr, Sint64 size)
  656. {
  657. return context->write(context, ptr, size);
  658. }
  659. int SDL_RWclose(SDL_RWops *context)
  660. {
  661. return context->close(context);
  662. }
  663. /* Functions for dynamically reading and writing endian-specific values */
  664. Uint8 SDL_ReadU8(SDL_RWops *src)
  665. {
  666. Uint8 value = 0;
  667. SDL_RWread(src, &value, sizeof(value));
  668. return value;
  669. }
  670. Uint16
  671. SDL_ReadLE16(SDL_RWops *src)
  672. {
  673. Uint16 value = 0;
  674. SDL_RWread(src, &value, sizeof(value));
  675. return SDL_SwapLE16(value);
  676. }
  677. Uint16
  678. SDL_ReadBE16(SDL_RWops *src)
  679. {
  680. Uint16 value = 0;
  681. SDL_RWread(src, &value, sizeof(value));
  682. return SDL_SwapBE16(value);
  683. }
  684. Uint32
  685. SDL_ReadLE32(SDL_RWops *src)
  686. {
  687. Uint32 value = 0;
  688. SDL_RWread(src, &value, sizeof(value));
  689. return SDL_SwapLE32(value);
  690. }
  691. Uint32
  692. SDL_ReadBE32(SDL_RWops *src)
  693. {
  694. Uint32 value = 0;
  695. SDL_RWread(src, &value, sizeof(value));
  696. return SDL_SwapBE32(value);
  697. }
  698. Uint64
  699. SDL_ReadLE64(SDL_RWops *src)
  700. {
  701. Uint64 value = 0;
  702. SDL_RWread(src, &value, sizeof(value));
  703. return SDL_SwapLE64(value);
  704. }
  705. Uint64
  706. SDL_ReadBE64(SDL_RWops *src)
  707. {
  708. Uint64 value = 0;
  709. SDL_RWread(src, &value, sizeof(value));
  710. return SDL_SwapBE64(value);
  711. }
  712. size_t
  713. SDL_WriteU8(SDL_RWops *dst, Uint8 value)
  714. {
  715. return (SDL_RWwrite(dst, &value, sizeof(value)) == sizeof(value)) ? 1 : 0;
  716. }
  717. size_t
  718. SDL_WriteLE16(SDL_RWops *dst, Uint16 value)
  719. {
  720. const Uint16 swapped = SDL_SwapLE16(value);
  721. return (SDL_RWwrite(dst, &swapped, sizeof(swapped)) == sizeof(swapped)) ? 1 : 0;
  722. }
  723. size_t
  724. SDL_WriteBE16(SDL_RWops *dst, Uint16 value)
  725. {
  726. const Uint16 swapped = SDL_SwapBE16(value);
  727. return (SDL_RWwrite(dst, &swapped, sizeof(swapped)) == sizeof(swapped)) ? 1 : 0;
  728. }
  729. size_t
  730. SDL_WriteLE32(SDL_RWops *dst, Uint32 value)
  731. {
  732. const Uint32 swapped = SDL_SwapLE32(value);
  733. return (SDL_RWwrite(dst, &swapped, sizeof(swapped)) == sizeof(swapped)) ? 1 : 0;
  734. }
  735. size_t
  736. SDL_WriteBE32(SDL_RWops *dst, Uint32 value)
  737. {
  738. const Uint32 swapped = SDL_SwapBE32(value);
  739. return (SDL_RWwrite(dst, &swapped, sizeof(swapped)) == sizeof(swapped)) ? 1 : 0;
  740. }
  741. size_t
  742. SDL_WriteLE64(SDL_RWops *dst, Uint64 value)
  743. {
  744. const Uint64 swapped = SDL_SwapLE64(value);
  745. return (SDL_RWwrite(dst, &swapped, sizeof(swapped)) == sizeof(swapped)) ? 1 : 0;
  746. }
  747. size_t
  748. SDL_WriteBE64(SDL_RWops *dst, Uint64 value)
  749. {
  750. const Uint64 swapped = SDL_SwapBE64(value);
  751. return (SDL_RWwrite(dst, &swapped, sizeof(swapped)) == sizeof(swapped)) ? 1 : 0;
  752. }
  753. /* vi: set ts=4 sw=4 expandtab: */