SDL_iostream.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 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(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK) || defined(SDL_PLATFORM_WINRT)
  20. #include "../core/windows/SDL_windows.h"
  21. #endif
  22. #ifdef HAVE_STDIO_H
  23. #include <stdio.h>
  24. #include <sys/stat.h>
  25. #endif
  26. #ifdef HAVE_LIMITS_H
  27. #include <limits.h>
  28. #endif
  29. /* This file provides a general interface for SDL to read and write
  30. data sources. It can easily be extended to files, memory, etc.
  31. */
  32. struct SDL_IOStream
  33. {
  34. SDL_IOStreamInterface iface;
  35. void *userdata;
  36. SDL_IOStatus status;
  37. SDL_PropertiesID props;
  38. };
  39. #ifdef SDL_PLATFORM_APPLE
  40. #include "cocoa/SDL_iostreambundlesupport.h"
  41. #endif /* SDL_PLATFORM_APPLE */
  42. #ifdef SDL_PLATFORM_3DS
  43. #include "n3ds/SDL_iostreamromfs.h"
  44. #endif /* SDL_PLATFORM_3DS */
  45. #ifdef SDL_PLATFORM_ANDROID
  46. #include "../core/android/SDL_android.h"
  47. #endif
  48. #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK) || defined(SDL_PLATFORM_WINRT)
  49. typedef struct IOStreamWindowsData
  50. {
  51. SDL_bool append;
  52. HANDLE h;
  53. void *data;
  54. size_t size;
  55. size_t left;
  56. } IOStreamWindowsData;
  57. /* Functions to read/write Win32 API file pointers */
  58. #ifndef INVALID_SET_FILE_POINTER
  59. #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
  60. #endif
  61. #define READAHEAD_BUFFER_SIZE 1024
  62. static int SDLCALL windows_file_open(IOStreamWindowsData *iodata, const char *filename, const char *mode)
  63. {
  64. #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) && !defined(SDL_PLATFORM_WINRT)
  65. UINT old_error_mode;
  66. #endif
  67. HANDLE h;
  68. DWORD r_right, w_right;
  69. DWORD must_exist, truncate;
  70. int a_mode;
  71. SDL_zerop(iodata);
  72. iodata->h = INVALID_HANDLE_VALUE; /* mark this as unusable */
  73. /* "r" = reading, file must exist */
  74. /* "w" = writing, truncate existing, file may not exist */
  75. /* "r+"= reading or writing, file must exist */
  76. /* "a" = writing, append file may not exist */
  77. /* "a+"= append + read, file may not exist */
  78. /* "w+" = read, write, truncate. file may not exist */
  79. must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
  80. truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
  81. r_right = (SDL_strchr(mode, '+') != NULL || must_exist) ? GENERIC_READ : 0;
  82. a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
  83. w_right = (a_mode || SDL_strchr(mode, '+') || truncate) ? GENERIC_WRITE : 0;
  84. if (!r_right && !w_right) {
  85. return -1; /* inconsistent mode */
  86. }
  87. /* failed (invalid call) */
  88. iodata->data = (char *)SDL_malloc(READAHEAD_BUFFER_SIZE);
  89. if (!iodata->data) {
  90. return -1;
  91. }
  92. #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) && !defined(SDL_PLATFORM_WINRT)
  93. /* Do not open a dialog box if failure */
  94. old_error_mode =
  95. SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  96. #endif
  97. {
  98. LPTSTR tstr = WIN_UTF8ToString(filename);
  99. #if defined(SDL_PLATFORM_WINRT)
  100. CREATEFILE2_EXTENDED_PARAMETERS extparams;
  101. SDL_zero(extparams);
  102. extparams.dwSize = sizeof(extparams);
  103. extparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  104. h = CreateFile2(tstr,
  105. (w_right | r_right),
  106. (w_right) ? 0 : FILE_SHARE_READ,
  107. (must_exist | truncate | a_mode),
  108. &extparams);
  109. #else
  110. h = CreateFile(tstr,
  111. (w_right | r_right),
  112. (w_right) ? 0 : FILE_SHARE_READ,
  113. NULL,
  114. (must_exist | truncate | a_mode),
  115. FILE_ATTRIBUTE_NORMAL,
  116. NULL);
  117. #endif
  118. SDL_free(tstr);
  119. }
  120. #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) && !defined(SDL_PLATFORM_WINRT)
  121. /* restore old behavior */
  122. SetErrorMode(old_error_mode);
  123. #endif
  124. if (h == INVALID_HANDLE_VALUE) {
  125. SDL_free(iodata->data);
  126. iodata->data = NULL;
  127. SDL_SetError("Couldn't open %s", filename);
  128. return -2; /* failed (CreateFile) */
  129. }
  130. iodata->h = h;
  131. iodata->append = a_mode ? SDL_TRUE : SDL_FALSE;
  132. return 0; /* ok */
  133. }
  134. static Sint64 SDLCALL windows_file_size(void *userdata)
  135. {
  136. IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
  137. LARGE_INTEGER size;
  138. if (!GetFileSizeEx(iodata->h, &size)) {
  139. return WIN_SetError("windows_file_size");
  140. }
  141. return size.QuadPart;
  142. }
  143. static Sint64 SDLCALL windows_file_seek(void *userdata, Sint64 offset, int whence)
  144. {
  145. IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
  146. DWORD windowswhence;
  147. LARGE_INTEGER windowsoffset;
  148. // FIXME: We may be able to satisfy the seek within buffered data
  149. if ((whence == SDL_IO_SEEK_CUR) && (iodata->left)) {
  150. offset -= iodata->left;
  151. }
  152. iodata->left = 0;
  153. switch (whence) {
  154. case SDL_IO_SEEK_SET:
  155. windowswhence = FILE_BEGIN;
  156. break;
  157. case SDL_IO_SEEK_CUR:
  158. windowswhence = FILE_CURRENT;
  159. break;
  160. case SDL_IO_SEEK_END:
  161. windowswhence = FILE_END;
  162. break;
  163. default:
  164. return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
  165. }
  166. windowsoffset.QuadPart = offset;
  167. if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, windowswhence)) {
  168. return WIN_SetError("windows_file_seek");
  169. }
  170. return windowsoffset.QuadPart;
  171. }
  172. static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
  173. {
  174. IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
  175. size_t total_need = size;
  176. size_t total_read = 0;
  177. size_t read_ahead;
  178. DWORD bytes;
  179. if (iodata->left > 0) {
  180. void *data = (char *)iodata->data +
  181. iodata->size -
  182. iodata->left;
  183. read_ahead = SDL_min(total_need, iodata->left);
  184. SDL_memcpy(ptr, data, read_ahead);
  185. iodata->left -= read_ahead;
  186. if (read_ahead == total_need) {
  187. return size;
  188. }
  189. ptr = (char *)ptr + read_ahead;
  190. total_need -= read_ahead;
  191. total_read += read_ahead;
  192. }
  193. if (total_need < READAHEAD_BUFFER_SIZE) {
  194. if (!ReadFile(iodata->h, iodata->data, READAHEAD_BUFFER_SIZE, &bytes, NULL)) {
  195. SDL_Error(SDL_EFREAD);
  196. return 0;
  197. }
  198. read_ahead = SDL_min(total_need, bytes);
  199. SDL_memcpy(ptr, iodata->data, read_ahead);
  200. iodata->size = bytes;
  201. iodata->left = bytes - read_ahead;
  202. total_read += read_ahead;
  203. } else {
  204. if (!ReadFile(iodata->h, ptr, (DWORD)total_need, &bytes, NULL)) {
  205. SDL_Error(SDL_EFREAD);
  206. return 0;
  207. }
  208. total_read += bytes;
  209. }
  210. return total_read;
  211. }
  212. static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
  213. {
  214. IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
  215. const size_t total_bytes = size;
  216. DWORD bytes;
  217. if (iodata->left) {
  218. if (!SetFilePointer(iodata->h, -(LONG)iodata->left, NULL, FILE_CURRENT)) {
  219. SDL_Error(SDL_EFSEEK);
  220. return 0;
  221. }
  222. iodata->left = 0;
  223. }
  224. /* if in append mode, we must go to the EOF before write */
  225. if (iodata->append) {
  226. LARGE_INTEGER windowsoffset;
  227. windowsoffset.QuadPart = 0;
  228. if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, FILE_END)) {
  229. SDL_Error(SDL_EFSEEK);
  230. return 0;
  231. }
  232. }
  233. if (!WriteFile(iodata->h, ptr, (DWORD)total_bytes, &bytes, NULL)) {
  234. SDL_Error(SDL_EFWRITE);
  235. return 0;
  236. }
  237. return bytes;
  238. }
  239. static int SDLCALL windows_file_close(void *userdata)
  240. {
  241. IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
  242. if (iodata->h != INVALID_HANDLE_VALUE) {
  243. CloseHandle(iodata->h);
  244. iodata->h = INVALID_HANDLE_VALUE; /* to be sure */
  245. }
  246. SDL_free(iodata->data);
  247. SDL_free(iodata);
  248. return 0;
  249. }
  250. #endif /* defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK) */
  251. #if defined(HAVE_STDIO_H) && !(defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK))
  252. /* Functions to read/write stdio file pointers. Not used for windows. */
  253. typedef struct IOStreamStdioData
  254. {
  255. FILE *fp;
  256. SDL_bool autoclose;
  257. } IOStreamStdioData;
  258. #ifdef HAVE_FOPEN64
  259. #define fopen fopen64
  260. #endif
  261. #ifdef HAVE_FSEEKO64
  262. #define fseek_off_t off64_t
  263. #define fseek fseeko64
  264. #define ftell ftello64
  265. #elif defined(HAVE_FSEEKO)
  266. #if defined(OFF_MIN) && defined(OFF_MAX)
  267. #define FSEEK_OFF_MIN OFF_MIN
  268. #define FSEEK_OFF_MAX OFF_MAX
  269. #elif defined(HAVE_LIMITS_H)
  270. /* POSIX doesn't specify the minimum and maximum macros for off_t so
  271. * we have to improvise and dance around implementation-defined
  272. * behavior. This may fail if the off_t type has padding bits or
  273. * is not a two's-complement representation. The compilers will detect
  274. * and eliminate the dead code if off_t has 64 bits.
  275. */
  276. #define FSEEK_OFF_MAX (((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) << 1) + 1)
  277. #define FSEEK_OFF_MIN (-(FSEEK_OFF_MAX)-1)
  278. #endif
  279. #define fseek_off_t off_t
  280. #define fseek fseeko
  281. #define ftell ftello
  282. #elif defined(HAVE__FSEEKI64)
  283. #define fseek_off_t __int64
  284. #define fseek _fseeki64
  285. #define ftell _ftelli64
  286. #else
  287. #ifdef HAVE_LIMITS_H
  288. #define FSEEK_OFF_MIN LONG_MIN
  289. #define FSEEK_OFF_MAX LONG_MAX
  290. #endif
  291. #define fseek_off_t long
  292. #endif
  293. static Sint64 SDLCALL stdio_seek(void *userdata, Sint64 offset, int whence)
  294. {
  295. IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
  296. int stdiowhence;
  297. switch (whence) {
  298. case SDL_IO_SEEK_SET:
  299. stdiowhence = SEEK_SET;
  300. break;
  301. case SDL_IO_SEEK_CUR:
  302. stdiowhence = SEEK_CUR;
  303. break;
  304. case SDL_IO_SEEK_END:
  305. stdiowhence = SEEK_END;
  306. break;
  307. default:
  308. return SDL_SetError("Unknown value for 'whence'");
  309. }
  310. #if defined(FSEEK_OFF_MIN) && defined(FSEEK_OFF_MAX)
  311. if (offset < (Sint64)(FSEEK_OFF_MIN) || offset > (Sint64)(FSEEK_OFF_MAX)) {
  312. return SDL_SetError("Seek offset out of range");
  313. }
  314. #endif
  315. if (fseek(iodata->fp, (fseek_off_t)offset, stdiowhence) == 0) {
  316. const Sint64 pos = ftell(iodata->fp);
  317. if (pos < 0) {
  318. return SDL_SetError("Couldn't get stream offset");
  319. }
  320. return pos;
  321. }
  322. return SDL_Error(SDL_EFSEEK);
  323. }
  324. static size_t SDLCALL stdio_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
  325. {
  326. IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
  327. const size_t bytes = fread(ptr, 1, size, iodata->fp);
  328. if (bytes == 0 && ferror(iodata->fp)) {
  329. SDL_Error(SDL_EFREAD);
  330. }
  331. return bytes;
  332. }
  333. static size_t SDLCALL stdio_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
  334. {
  335. IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
  336. const size_t bytes = fwrite(ptr, 1, size, iodata->fp);
  337. if (bytes == 0 && ferror(iodata->fp)) {
  338. SDL_Error(SDL_EFWRITE);
  339. }
  340. return bytes;
  341. }
  342. static int SDLCALL stdio_close(void *userdata)
  343. {
  344. IOStreamStdioData *iodata = (IOStreamStdioData *) userdata;
  345. int status = 0;
  346. if (iodata->autoclose) {
  347. if (fclose(iodata->fp) != 0) {
  348. status = SDL_Error(SDL_EFWRITE);
  349. }
  350. }
  351. SDL_free(iodata);
  352. return status;
  353. }
  354. static SDL_IOStream *SDL_IOFromFP(FILE *fp, SDL_bool autoclose)
  355. {
  356. IOStreamStdioData *iodata = (IOStreamStdioData *) SDL_malloc(sizeof (*iodata));
  357. if (!iodata) {
  358. return NULL;
  359. }
  360. SDL_IOStreamInterface iface;
  361. SDL_zero(iface);
  362. // There's no stdio_size because SDL_SizeIO emulates it the same way we'd do it for stdio anyhow.
  363. iface.seek = stdio_seek;
  364. iface.read = stdio_read;
  365. iface.write = stdio_write;
  366. iface.close = stdio_close;
  367. iodata->fp = fp;
  368. iodata->autoclose = autoclose;
  369. SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
  370. if (!iostr) {
  371. iface.close(iodata);
  372. } else {
  373. const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
  374. if (props) {
  375. SDL_SetProperty(props, SDL_PROP_IOSTREAM_STDIO_HANDLE_POINTER, fp);
  376. }
  377. }
  378. return iostr;
  379. }
  380. #endif /* !HAVE_STDIO_H && !(SDL_PLATFORM_WIN32 || SDL_PLATFORM_GDK) */
  381. /* Functions to read/write memory pointers */
  382. typedef struct IOStreamMemData
  383. {
  384. Uint8 *base;
  385. Uint8 *here;
  386. Uint8 *stop;
  387. } IOStreamMemData;
  388. static Sint64 SDLCALL mem_size(void *userdata)
  389. {
  390. const IOStreamMemData *iodata = (IOStreamMemData *) userdata;
  391. return (iodata->stop - iodata->base);
  392. }
  393. static Sint64 SDLCALL mem_seek(void *userdata, Sint64 offset, int whence)
  394. {
  395. IOStreamMemData *iodata = (IOStreamMemData *) userdata;
  396. Uint8 *newpos;
  397. switch (whence) {
  398. case SDL_IO_SEEK_SET:
  399. newpos = iodata->base + offset;
  400. break;
  401. case SDL_IO_SEEK_CUR:
  402. newpos = iodata->here + offset;
  403. break;
  404. case SDL_IO_SEEK_END:
  405. newpos = iodata->stop + offset;
  406. break;
  407. default:
  408. return SDL_SetError("Unknown value for 'whence'");
  409. }
  410. if (newpos < iodata->base) {
  411. newpos = iodata->base;
  412. }
  413. if (newpos > iodata->stop) {
  414. newpos = iodata->stop;
  415. }
  416. iodata->here = newpos;
  417. return (Sint64)(iodata->here - iodata->base);
  418. }
  419. static size_t mem_io(void *userdata, void *dst, const void *src, size_t size)
  420. {
  421. IOStreamMemData *iodata = (IOStreamMemData *) userdata;
  422. const size_t mem_available = (iodata->stop - iodata->here);
  423. if (size > mem_available) {
  424. size = mem_available;
  425. }
  426. SDL_memcpy(dst, src, size);
  427. iodata->here += size;
  428. return size;
  429. }
  430. static size_t SDLCALL mem_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
  431. {
  432. IOStreamMemData *iodata = (IOStreamMemData *) userdata;
  433. return mem_io(userdata, ptr, iodata->here, size);
  434. }
  435. static size_t SDLCALL mem_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
  436. {
  437. IOStreamMemData *iodata = (IOStreamMemData *) userdata;
  438. return mem_io(userdata, iodata->here, ptr, size);
  439. }
  440. static int SDLCALL mem_close(void *userdata)
  441. {
  442. SDL_free(userdata);
  443. return 0;
  444. }
  445. /* Functions to create SDL_IOStream structures from various data sources */
  446. #if defined(HAVE_STDIO_H) && !defined(SDL_PLATFORM_WINDOWS)
  447. static SDL_bool IsRegularFileOrPipe(FILE *f)
  448. {
  449. #ifdef SDL_PLATFORM_WINRT
  450. struct __stat64 st;
  451. if (_fstat64(_fileno(f), &st) < 0 ||
  452. !((st.st_mode & _S_IFMT) == _S_IFREG || (st.st_mode & _S_IFMT) == _S_IFIFO)) {
  453. return SDL_FALSE;
  454. }
  455. #else
  456. struct stat st;
  457. if (fstat(fileno(f), &st) < 0 || !(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode))) {
  458. return SDL_FALSE;
  459. }
  460. #endif
  461. return SDL_TRUE;
  462. }
  463. #endif
  464. SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
  465. {
  466. SDL_IOStream *iostr = NULL;
  467. if (!file || !*file || !mode || !*mode) {
  468. SDL_SetError("SDL_IOFromFile(): No file or no mode specified");
  469. return NULL;
  470. }
  471. #ifdef SDL_PLATFORM_ANDROID
  472. #ifdef HAVE_STDIO_H
  473. /* Try to open the file on the filesystem first */
  474. if (*file == '/') {
  475. FILE *fp = fopen(file, mode);
  476. if (fp) {
  477. if (!IsRegularFileOrPipe(fp)) {
  478. fclose(fp);
  479. SDL_SetError("%s is not a regular file or pipe", file);
  480. return NULL;
  481. }
  482. return SDL_IOFromFP(fp, 1);
  483. }
  484. } else {
  485. /* Try opening it from internal storage if it's a relative path */
  486. // !!! FIXME: why not just "char path[PATH_MAX];"
  487. char *path = SDL_stack_alloc(char, PATH_MAX);
  488. if (path) {
  489. SDL_snprintf(path, PATH_MAX, "%s/%s",
  490. SDL_AndroidGetInternalStoragePath(), file);
  491. FILE *fp = fopen(path, mode);
  492. SDL_stack_free(path);
  493. if (fp) {
  494. if (!IsRegularFileOrPipe(fp)) {
  495. fclose(fp);
  496. SDL_SetError("%s is not a regular file or pipe", path);
  497. return NULL;
  498. }
  499. return SDL_IOFromFP(fp, 1);
  500. }
  501. }
  502. }
  503. #endif /* HAVE_STDIO_H */
  504. /* Try to open the file from the asset system */
  505. void *iodata = NULL;
  506. if (Android_JNI_FileOpen(&iodata, file, mode) < 0) {
  507. SDL_CloseIO(iostr);
  508. return NULL;
  509. }
  510. SDL_IOStreamInterface iface;
  511. SDL_zero(iface);
  512. iface.size = Android_JNI_FileSize;
  513. iface.seek = Android_JNI_FileSeek;
  514. iface.read = Android_JNI_FileRead;
  515. iface.write = Android_JNI_FileWrite;
  516. iface.close = Android_JNI_FileClose;
  517. iostr = SDL_OpenIO(&iface, iodata);
  518. if (!iostr) {
  519. iface.close(iodata);
  520. } else {
  521. const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
  522. if (props) {
  523. SDL_SetProperty(props, SDL_PROP_IOSTREAM_ANDROID_AASSET_POINTER, iodata);
  524. }
  525. }
  526. return iostr;
  527. #elif defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK) || defined(SDL_PLATFORM_WINRT)
  528. IOStreamWindowsData *iodata = (IOStreamWindowsData *) SDL_malloc(sizeof (*iodata));
  529. if (!iodata) {
  530. return NULL;
  531. }
  532. if (windows_file_open(iodata, file, mode) < 0) {
  533. SDL_CloseIO(iostr);
  534. return NULL;
  535. }
  536. SDL_IOStreamInterface iface;
  537. SDL_zero(iface);
  538. iface.size = windows_file_size;
  539. iface.seek = windows_file_seek;
  540. iface.read = windows_file_read;
  541. iface.write = windows_file_write;
  542. iface.close = windows_file_close;
  543. iostr = SDL_OpenIO(&iface, iodata);
  544. if (!iostr) {
  545. windows_file_close(iodata);
  546. } else {
  547. const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
  548. if (props) {
  549. SDL_SetProperty(props, SDL_PROP_IOSTREAM_WINDOWS_HANDLE_POINTER, iodata->h);
  550. }
  551. }
  552. return iostr;
  553. #elif defined(HAVE_STDIO_H)
  554. {
  555. #if defined(SDL_PLATFORM_APPLE)
  556. FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
  557. #elif defined(SDL_PLATFORM_WINRT)
  558. FILE *fp = NULL;
  559. fopen_s(&fp, file, mode);
  560. #elif defined(SDL_PLATFORM_3DS)
  561. FILE *fp = N3DS_FileOpen(file, mode);
  562. #else
  563. FILE *fp = fopen(file, mode);
  564. #endif
  565. if (!fp) {
  566. SDL_SetError("Couldn't open %s", file);
  567. } else if (!IsRegularFileOrPipe(fp)) {
  568. fclose(fp);
  569. fp = NULL;
  570. SDL_SetError("%s is not a regular file or pipe", file);
  571. } else {
  572. iostr = SDL_IOFromFP(fp, SDL_TRUE);
  573. }
  574. }
  575. #else
  576. SDL_SetError("SDL not compiled with stdio support");
  577. #endif /* !HAVE_STDIO_H */
  578. return iostr;
  579. }
  580. SDL_IOStream *SDL_IOFromMem(void *mem, size_t size)
  581. {
  582. if (!mem) {
  583. SDL_InvalidParamError("mem");
  584. return NULL;
  585. } else if (!size) {
  586. SDL_InvalidParamError("size");
  587. return NULL;
  588. }
  589. IOStreamMemData *iodata = (IOStreamMemData *) SDL_malloc(sizeof (*iodata));
  590. if (!iodata) {
  591. return NULL;
  592. }
  593. SDL_IOStreamInterface iface;
  594. SDL_zero(iface);
  595. iface.size = mem_size;
  596. iface.seek = mem_seek;
  597. iface.read = mem_read;
  598. iface.write = mem_write;
  599. iface.close = mem_close;
  600. iodata->base = (Uint8 *)mem;
  601. iodata->here = iodata->base;
  602. iodata->stop = iodata->base + size;
  603. SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
  604. if (!iostr) {
  605. SDL_free(iodata);
  606. }
  607. return iostr;
  608. }
  609. SDL_IOStream *SDL_IOFromConstMem(const void *mem, size_t size)
  610. {
  611. if (!mem) {
  612. SDL_InvalidParamError("mem");
  613. return NULL;
  614. } else if (!size) {
  615. SDL_InvalidParamError("size");
  616. return NULL;
  617. }
  618. IOStreamMemData *iodata = (IOStreamMemData *) SDL_malloc(sizeof (*iodata));
  619. if (!iodata) {
  620. return NULL;
  621. }
  622. SDL_IOStreamInterface iface;
  623. SDL_zero(iface);
  624. iface.size = mem_size;
  625. iface.seek = mem_seek;
  626. iface.read = mem_read;
  627. // leave iface.write as NULL.
  628. iface.close = mem_close;
  629. iodata->base = (Uint8 *)mem;
  630. iodata->here = iodata->base;
  631. iodata->stop = iodata->base + size;
  632. SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
  633. if (!iostr) {
  634. SDL_free(iodata);
  635. }
  636. return iostr;
  637. }
  638. typedef struct IOStreamDynamicMemData
  639. {
  640. SDL_IOStream *stream;
  641. IOStreamMemData data;
  642. Uint8 *end;
  643. } IOStreamDynamicMemData;
  644. static Sint64 SDLCALL dynamic_mem_size(void *userdata)
  645. {
  646. IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) userdata;
  647. return mem_size(&iodata->data);
  648. }
  649. static Sint64 SDLCALL dynamic_mem_seek(void *userdata, Sint64 offset, int whence)
  650. {
  651. IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) userdata;
  652. return mem_seek(&iodata->data, offset, whence);
  653. }
  654. static size_t SDLCALL dynamic_mem_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
  655. {
  656. IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) userdata;
  657. return mem_io(&iodata->data, ptr, iodata->data.here, size);
  658. }
  659. static int dynamic_mem_realloc(IOStreamDynamicMemData *iodata, size_t size)
  660. {
  661. size_t chunksize = (size_t)SDL_GetNumberProperty(SDL_GetIOProperties(iodata->stream), SDL_PROP_IOSTREAM_DYNAMIC_CHUNKSIZE_NUMBER, 0);
  662. if (!chunksize) {
  663. chunksize = 1024;
  664. }
  665. // We're intentionally allocating more memory than needed so it can be null terminated
  666. size_t chunks = (((iodata->end - iodata->data.base) + size) / chunksize) + 1;
  667. size_t length = (chunks * chunksize);
  668. Uint8 *base = (Uint8 *)SDL_realloc(iodata->data.base, length);
  669. if (!base) {
  670. return -1;
  671. }
  672. size_t here_offset = (iodata->data.here - iodata->data.base);
  673. size_t stop_offset = (iodata->data.stop - iodata->data.base);
  674. iodata->data.base = base;
  675. iodata->data.here = base + here_offset;
  676. iodata->data.stop = base + stop_offset;
  677. iodata->end = base + length;
  678. return SDL_SetProperty(SDL_GetIOProperties(iodata->stream), SDL_PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER, base);
  679. }
  680. static size_t SDLCALL dynamic_mem_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
  681. {
  682. IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) userdata;
  683. if (size > (iodata->data.stop - iodata->data.here)) {
  684. if (size > (iodata->end - iodata->data.here)) {
  685. if (dynamic_mem_realloc(iodata, size) < 0) {
  686. return 0;
  687. }
  688. }
  689. iodata->data.stop = iodata->data.here + size;
  690. }
  691. return mem_io(&iodata->data, iodata->data.here, ptr, size);
  692. }
  693. static int SDLCALL dynamic_mem_close(void *userdata)
  694. {
  695. const IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) userdata;
  696. void *mem = SDL_GetProperty(SDL_GetIOProperties(iodata->stream), SDL_PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER, NULL);
  697. if (mem) {
  698. SDL_free(mem);
  699. }
  700. SDL_free(userdata);
  701. return 0;
  702. }
  703. SDL_IOStream *SDL_IOFromDynamicMem(void)
  704. {
  705. IOStreamDynamicMemData *iodata = (IOStreamDynamicMemData *) SDL_malloc(sizeof (*iodata));
  706. if (!iodata) {
  707. return NULL;
  708. }
  709. SDL_IOStreamInterface iface;
  710. SDL_zero(iface);
  711. iface.size = dynamic_mem_size;
  712. iface.seek = dynamic_mem_seek;
  713. iface.read = dynamic_mem_read;
  714. iface.write = dynamic_mem_write;
  715. iface.close = dynamic_mem_close;
  716. iodata->data.base = NULL;
  717. iodata->data.here = NULL;
  718. iodata->data.stop = NULL;
  719. iodata->end = NULL;
  720. SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
  721. if (iostr) {
  722. iodata->stream = iostr;
  723. } else {
  724. SDL_free(iodata);
  725. }
  726. return iostr;
  727. }
  728. SDL_IOStatus SDL_GetIOStatus(SDL_IOStream *context)
  729. {
  730. if (!context) {
  731. SDL_InvalidParamError("context");
  732. return SDL_IO_STATUS_ERROR;
  733. }
  734. return context->status;
  735. }
  736. SDL_IOStream *SDL_OpenIO(const SDL_IOStreamInterface *iface, void *userdata)
  737. {
  738. if (!iface) {
  739. SDL_InvalidParamError("iface");
  740. return NULL;
  741. }
  742. SDL_IOStream *iostr = (SDL_IOStream *)SDL_calloc(1, sizeof(*iostr));
  743. if (iostr) {
  744. SDL_copyp(&iostr->iface, iface);
  745. iostr->userdata = userdata;
  746. }
  747. return iostr;
  748. }
  749. int SDL_CloseIO(SDL_IOStream *iostr)
  750. {
  751. int retval = 0;
  752. if (iostr) {
  753. if (iostr->iface.close) {
  754. retval = iostr->iface.close(iostr->userdata);
  755. }
  756. SDL_DestroyProperties(iostr->props);
  757. SDL_free(iostr);
  758. }
  759. return retval;
  760. }
  761. /* Load all the data from an SDL data stream */
  762. void *SDL_LoadFile_IO(SDL_IOStream *src, size_t *datasize, SDL_bool closeio)
  763. {
  764. const int FILE_CHUNK_SIZE = 1024;
  765. Sint64 size, size_total = 0;
  766. size_t size_read;
  767. char *data = NULL, *newdata;
  768. SDL_bool loading_chunks = SDL_FALSE;
  769. if (!src) {
  770. SDL_InvalidParamError("src");
  771. goto done;
  772. }
  773. size = SDL_SizeIO(src);
  774. if (size < 0) {
  775. size = FILE_CHUNK_SIZE;
  776. loading_chunks = SDL_TRUE;
  777. }
  778. if (size >= SDL_SIZE_MAX) {
  779. goto done;
  780. }
  781. data = (char *)SDL_malloc((size_t)(size + 1));
  782. if (!data) {
  783. goto done;
  784. }
  785. size_total = 0;
  786. for (;;) {
  787. if (loading_chunks) {
  788. if ((size_total + FILE_CHUNK_SIZE) > size) {
  789. size = (size_total + FILE_CHUNK_SIZE);
  790. if (size >= SDL_SIZE_MAX) {
  791. newdata = NULL;
  792. } else {
  793. newdata = (char *)SDL_realloc(data, (size_t)(size + 1));
  794. }
  795. if (!newdata) {
  796. SDL_free(data);
  797. data = NULL;
  798. goto done;
  799. }
  800. data = newdata;
  801. }
  802. }
  803. size_read = SDL_ReadIO(src, data + size_total, (size_t)(size - size_total));
  804. if (size_read > 0) {
  805. size_total += size_read;
  806. continue;
  807. }
  808. /* The stream status will remain set for the caller to check */
  809. break;
  810. }
  811. data[size_total] = '\0';
  812. done:
  813. if (datasize) {
  814. *datasize = (size_t)size_total;
  815. }
  816. if (closeio && src) {
  817. SDL_CloseIO(src);
  818. }
  819. return data;
  820. }
  821. void *SDL_LoadFile(const char *file, size_t *datasize)
  822. {
  823. return SDL_LoadFile_IO(SDL_IOFromFile(file, "rb"), datasize, SDL_TRUE);
  824. }
  825. SDL_PropertiesID SDL_GetIOProperties(SDL_IOStream *context)
  826. {
  827. if (!context) {
  828. SDL_InvalidParamError("context");
  829. return 0;
  830. }
  831. if (context->props == 0) {
  832. context->props = SDL_CreateProperties();
  833. }
  834. return context->props;
  835. }
  836. Sint64 SDL_SizeIO(SDL_IOStream *context)
  837. {
  838. if (!context) {
  839. return SDL_InvalidParamError("context");
  840. }
  841. if (!context->iface.size) {
  842. Sint64 pos, size;
  843. pos = SDL_SeekIO(context, 0, SDL_IO_SEEK_CUR);
  844. if (pos < 0) {
  845. return -1;
  846. }
  847. size = SDL_SeekIO(context, 0, SDL_IO_SEEK_END);
  848. SDL_SeekIO(context, pos, SDL_IO_SEEK_SET);
  849. return size;
  850. }
  851. return context->iface.size(context->userdata);
  852. }
  853. Sint64 SDL_SeekIO(SDL_IOStream *context, Sint64 offset, int whence)
  854. {
  855. if (!context) {
  856. return SDL_InvalidParamError("context");
  857. } else if (!context->iface.seek) {
  858. return SDL_Unsupported();
  859. }
  860. return context->iface.seek(context->userdata, offset, whence);
  861. }
  862. Sint64 SDL_TellIO(SDL_IOStream *context)
  863. {
  864. return SDL_SeekIO(context, 0, SDL_IO_SEEK_CUR);
  865. }
  866. size_t SDL_ReadIO(SDL_IOStream *context, void *ptr, size_t size)
  867. {
  868. size_t bytes;
  869. if (!context) {
  870. SDL_InvalidParamError("context");
  871. return 0;
  872. } else if (!context->iface.read) {
  873. context->status = SDL_IO_STATUS_WRITEONLY;
  874. SDL_Unsupported();
  875. return 0;
  876. }
  877. context->status = SDL_IO_STATUS_READY;
  878. SDL_ClearError();
  879. if (size == 0) {
  880. return 0;
  881. }
  882. bytes = context->iface.read(context->userdata, ptr, size, &context->status);
  883. if (bytes == 0 && context->status == SDL_IO_STATUS_READY) {
  884. if (*SDL_GetError()) {
  885. context->status = SDL_IO_STATUS_ERROR;
  886. } else {
  887. context->status = SDL_IO_STATUS_EOF;
  888. }
  889. }
  890. return bytes;
  891. }
  892. size_t SDL_WriteIO(SDL_IOStream *context, const void *ptr, size_t size)
  893. {
  894. size_t bytes;
  895. if (!context) {
  896. SDL_InvalidParamError("context");
  897. return 0;
  898. } else if (!context->iface.write) {
  899. context->status = SDL_IO_STATUS_READONLY;
  900. SDL_Unsupported();
  901. return 0;
  902. }
  903. context->status = SDL_IO_STATUS_READY;
  904. SDL_ClearError();
  905. if (size == 0) {
  906. return 0;
  907. }
  908. bytes = context->iface.write(context->userdata, ptr, size, &context->status);
  909. if ((bytes == 0) && (context->status == SDL_IO_STATUS_READY)) {
  910. context->status = SDL_IO_STATUS_ERROR;
  911. }
  912. return bytes;
  913. }
  914. size_t SDL_IOprintf(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
  915. {
  916. va_list ap;
  917. int size;
  918. char *string;
  919. size_t bytes;
  920. va_start(ap, fmt);
  921. size = SDL_vasprintf(&string, fmt, ap);
  922. va_end(ap);
  923. if (size < 0) {
  924. return 0;
  925. }
  926. bytes = SDL_WriteIO(context, string, (size_t)size);
  927. SDL_free(string);
  928. return bytes;
  929. }
  930. size_t SDL_IOvprintf(SDL_IOStream *context, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
  931. {
  932. int size;
  933. char *string;
  934. size_t bytes;
  935. size = SDL_vasprintf(&string, fmt, ap);
  936. if (size < 0) {
  937. return 0;
  938. }
  939. bytes = SDL_WriteIO(context, string, (size_t)size);
  940. SDL_free(string);
  941. return bytes;
  942. }
  943. /* Functions for dynamically reading and writing endian-specific values */
  944. SDL_bool SDL_ReadU8(SDL_IOStream *src, Uint8 *value)
  945. {
  946. Uint8 data = 0;
  947. SDL_bool result = SDL_FALSE;
  948. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  949. result = SDL_TRUE;
  950. }
  951. if (value) {
  952. *value = data;
  953. }
  954. return result;
  955. }
  956. SDL_bool SDL_ReadU16LE(SDL_IOStream *src, Uint16 *value)
  957. {
  958. Uint16 data = 0;
  959. SDL_bool result = SDL_FALSE;
  960. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  961. result = SDL_TRUE;
  962. }
  963. if (value) {
  964. *value = SDL_SwapLE16(data);
  965. }
  966. return result;
  967. }
  968. SDL_bool SDL_ReadS16LE(SDL_IOStream *src, Sint16 *value)
  969. {
  970. return SDL_ReadU16LE(src, (Uint16 *)value);
  971. }
  972. SDL_bool SDL_ReadU16BE(SDL_IOStream *src, Uint16 *value)
  973. {
  974. Uint16 data = 0;
  975. SDL_bool result = SDL_FALSE;
  976. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  977. result = SDL_TRUE;
  978. }
  979. if (value) {
  980. *value = SDL_SwapBE16(data);
  981. }
  982. return result;
  983. }
  984. SDL_bool SDL_ReadS16BE(SDL_IOStream *src, Sint16 *value)
  985. {
  986. return SDL_ReadU16BE(src, (Uint16 *)value);
  987. }
  988. SDL_bool SDL_ReadU32LE(SDL_IOStream *src, Uint32 *value)
  989. {
  990. Uint32 data = 0;
  991. SDL_bool result = SDL_FALSE;
  992. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  993. result = SDL_TRUE;
  994. }
  995. if (value) {
  996. *value = SDL_SwapLE32(data);
  997. }
  998. return result;
  999. }
  1000. SDL_bool SDL_ReadS32LE(SDL_IOStream *src, Sint32 *value)
  1001. {
  1002. return SDL_ReadU32LE(src, (Uint32 *)value);
  1003. }
  1004. SDL_bool SDL_ReadU32BE(SDL_IOStream *src, Uint32 *value)
  1005. {
  1006. Uint32 data = 0;
  1007. SDL_bool result = SDL_FALSE;
  1008. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  1009. result = SDL_TRUE;
  1010. }
  1011. if (value) {
  1012. *value = SDL_SwapBE32(data);
  1013. }
  1014. return result;
  1015. }
  1016. SDL_bool SDL_ReadS32BE(SDL_IOStream *src, Sint32 *value)
  1017. {
  1018. return SDL_ReadU32BE(src, (Uint32 *)value);
  1019. }
  1020. SDL_bool SDL_ReadU64LE(SDL_IOStream *src, Uint64 *value)
  1021. {
  1022. Uint64 data = 0;
  1023. SDL_bool result = SDL_FALSE;
  1024. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  1025. result = SDL_TRUE;
  1026. }
  1027. if (value) {
  1028. *value = SDL_SwapLE64(data);
  1029. }
  1030. return result;
  1031. }
  1032. SDL_bool SDL_ReadS64LE(SDL_IOStream *src, Sint64 *value)
  1033. {
  1034. return SDL_ReadU64LE(src, (Uint64 *)value);
  1035. }
  1036. SDL_bool SDL_ReadU64BE(SDL_IOStream *src, Uint64 *value)
  1037. {
  1038. Uint64 data = 0;
  1039. SDL_bool result = SDL_FALSE;
  1040. if (SDL_ReadIO(src, &data, sizeof(data)) == sizeof(data)) {
  1041. result = SDL_TRUE;
  1042. }
  1043. if (value) {
  1044. *value = SDL_SwapBE64(data);
  1045. }
  1046. return result;
  1047. }
  1048. SDL_bool SDL_ReadS64BE(SDL_IOStream *src, Sint64 *value)
  1049. {
  1050. return SDL_ReadU64BE(src, (Uint64 *)value);
  1051. }
  1052. SDL_bool SDL_WriteU8(SDL_IOStream *dst, Uint8 value)
  1053. {
  1054. return (SDL_WriteIO(dst, &value, sizeof(value)) == sizeof(value));
  1055. }
  1056. SDL_bool SDL_WriteU16LE(SDL_IOStream *dst, Uint16 value)
  1057. {
  1058. const Uint16 swapped = SDL_SwapLE16(value);
  1059. return (SDL_WriteIO(dst, &swapped, sizeof(swapped)) == sizeof(swapped));
  1060. }
  1061. SDL_bool SDL_WriteS16LE(SDL_IOStream *dst, Sint16 value)
  1062. {
  1063. return SDL_WriteU16LE(dst, (Uint16)value);
  1064. }
  1065. SDL_bool SDL_WriteU16BE(SDL_IOStream *dst, Uint16 value)
  1066. {
  1067. const Uint16 swapped = SDL_SwapBE16(value);
  1068. return (SDL_WriteIO(dst, &swapped, sizeof(swapped)) == sizeof(swapped));
  1069. }
  1070. SDL_bool SDL_WriteS16BE(SDL_IOStream *dst, Sint16 value)
  1071. {
  1072. return SDL_WriteU16BE(dst, (Uint16)value);
  1073. }
  1074. SDL_bool SDL_WriteU32LE(SDL_IOStream *dst, Uint32 value)
  1075. {
  1076. const Uint32 swapped = SDL_SwapLE32(value);
  1077. return (SDL_WriteIO(dst, &swapped, sizeof(swapped)) == sizeof(swapped));
  1078. }
  1079. SDL_bool SDL_WriteS32LE(SDL_IOStream *dst, Sint32 value)
  1080. {
  1081. return SDL_WriteU32LE(dst, (Uint32)value);
  1082. }
  1083. SDL_bool SDL_WriteU32BE(SDL_IOStream *dst, Uint32 value)
  1084. {
  1085. const Uint32 swapped = SDL_SwapBE32(value);
  1086. return (SDL_WriteIO(dst, &swapped, sizeof(swapped)) == sizeof(swapped));
  1087. }
  1088. SDL_bool SDL_WriteS32BE(SDL_IOStream *dst, Sint32 value)
  1089. {
  1090. return SDL_WriteU32BE(dst, (Uint32)value);
  1091. }
  1092. SDL_bool SDL_WriteU64LE(SDL_IOStream *dst, Uint64 value)
  1093. {
  1094. const Uint64 swapped = SDL_SwapLE64(value);
  1095. return (SDL_WriteIO(dst, &swapped, sizeof(swapped)) == sizeof(swapped));
  1096. }
  1097. SDL_bool SDL_WriteS64LE(SDL_IOStream *dst, Sint64 value)
  1098. {
  1099. return SDL_WriteU64LE(dst, (Uint64)value);
  1100. }
  1101. SDL_bool SDL_WriteU64BE(SDL_IOStream *dst, Uint64 value)
  1102. {
  1103. const Uint64 swapped = SDL_SwapBE64(value);
  1104. return (SDL_WriteIO(dst, &swapped, sizeof(swapped)) == sizeof(swapped));
  1105. }
  1106. SDL_bool SDL_WriteS64BE(SDL_IOStream *dst, Sint64 value)
  1107. {
  1108. return SDL_WriteU64BE(dst, (Uint64)value);
  1109. }