1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | |
22 | /** |
23 | * # CategoryStorage |
24 | * |
25 | * The storage API is a high-level API designed to abstract away the |
26 | * portability issues that come up when using something lower-level (in SDL's |
27 | * case, this sits on top of the [Filesystem](CategoryFilesystem) and |
28 | * [IOStream](CategoryIOStream) subsystems). It is significantly more |
29 | * restrictive than a typical filesystem API, for a number of reasons: |
30 | * |
31 | * 1. **What to Access:** A common pitfall with existing filesystem APIs is |
32 | * the assumption that all storage is monolithic. However, many other |
33 | * platforms (game consoles in particular) are more strict about what _type_ |
34 | * of filesystem is being accessed; for example, game content and user data |
35 | * are usually two separate storage devices with entirely different |
36 | * characteristics (and possibly different low-level APIs altogether!). |
37 | * |
38 | * 2. **How to Access:** Another common mistake is applications assuming that |
39 | * all storage is universally writeable - again, many platforms treat game |
40 | * content and user data as two separate storage devices, and only user data |
41 | * is writeable while game content is read-only. |
42 | * |
43 | * 3. **When to Access:** The most common portability issue with filesystem |
44 | * access is _timing_ - you cannot always assume that the storage device is |
45 | * always accessible all of the time, nor can you assume that there are no |
46 | * limits to how long you have access to a particular device. |
47 | * |
48 | * Consider the following example: |
49 | * |
50 | * ```c |
51 | * void ReadGameData(void) |
52 | * { |
53 | * extern char** fileNames; |
54 | * extern size_t numFiles; |
55 | * for (size_t i = 0; i < numFiles; i += 1) { |
56 | * FILE *data = fopen(fileNames[i], "rwb"); |
57 | * if (data == NULL) { |
58 | * // Something bad happened! |
59 | * } else { |
60 | * // A bunch of stuff happens here |
61 | * fclose(data); |
62 | * } |
63 | * } |
64 | * } |
65 | * |
66 | * void ReadSave(void) |
67 | * { |
68 | * FILE *save = fopen("saves/save0.sav", "rb"); |
69 | * if (save == NULL) { |
70 | * // Something bad happened! |
71 | * } else { |
72 | * // A bunch of stuff happens here |
73 | * fclose(save); |
74 | * } |
75 | * } |
76 | * |
77 | * void WriteSave(void) |
78 | * { |
79 | * FILE *save = fopen("saves/save0.sav", "wb"); |
80 | * if (save == NULL) { |
81 | * // Something bad happened! |
82 | * } else { |
83 | * // A bunch of stuff happens here |
84 | * fclose(save); |
85 | * } |
86 | * } |
87 | * ``` |
88 | * |
89 | * Going over the bullet points again: |
90 | * |
91 | * 1. **What to Access:** This code accesses a global filesystem; game data |
92 | * and saves are all presumed to be in the current working directory (which |
93 | * may or may not be the game's installation folder!). |
94 | * |
95 | * 2. **How to Access:** This code assumes that content paths are writeable, |
96 | * and that save data is also writeable despite being in the same location as |
97 | * the game data. |
98 | * |
99 | * 3. **When to Access:** This code assumes that they can be called at any |
100 | * time, since the filesystem is always accessible and has no limits on how |
101 | * long the filesystem is being accessed. |
102 | * |
103 | * Due to these assumptions, the filesystem code is not portable and will fail |
104 | * under these common scenarios: |
105 | * |
106 | * - The game is installed on a device that is read-only, both content loading |
107 | * and game saves will fail or crash outright |
108 | * - Game/User storage is not implicitly mounted, so no files will be found |
109 | * for either scenario when a platform requires explicitly mounting |
110 | * filesystems |
111 | * - Save data may not be safe since the I/O is not being flushed or |
112 | * validated, so an error occurring elsewhere in the program may result in |
113 | * missing/corrupted save data |
114 | * |
115 | * When using SDL_Storage, these types of problems are virtually impossible to |
116 | * trip over: |
117 | * |
118 | * ```c |
119 | * void ReadGameData(void) |
120 | * { |
121 | * extern char** fileNames; |
122 | * extern size_t numFiles; |
123 | * |
124 | * SDL_Storage *title = SDL_OpenTitleStorage(NULL, 0); |
125 | * if (title == NULL) { |
126 | * // Something bad happened! |
127 | * } |
128 | * while (!SDL_StorageReady(title)) { |
129 | * SDL_Delay(1); |
130 | * } |
131 | * |
132 | * for (size_t i = 0; i < numFiles; i += 1) { |
133 | * void* dst; |
134 | * Uint64 dstLen = 0; |
135 | * |
136 | * if (SDL_GetStorageFileSize(title, fileNames[i], &dstLen) && dstLen > 0) { |
137 | * dst = SDL_malloc(dstLen); |
138 | * if (SDL_ReadStorageFile(title, fileNames[i], dst, dstLen)) { |
139 | * // A bunch of stuff happens here |
140 | * } else { |
141 | * // Something bad happened! |
142 | * } |
143 | * SDL_free(dst); |
144 | * } else { |
145 | * // Something bad happened! |
146 | * } |
147 | * } |
148 | * |
149 | * SDL_CloseStorage(title); |
150 | * } |
151 | * |
152 | * void ReadSave(void) |
153 | * { |
154 | * SDL_Storage *user = SDL_OpenUserStorage("libsdl", "Storage Example", 0); |
155 | * if (user == NULL) { |
156 | * // Something bad happened! |
157 | * } |
158 | * while (!SDL_StorageReady(user)) { |
159 | * SDL_Delay(1); |
160 | * } |
161 | * |
162 | * Uint64 saveLen = 0; |
163 | * if (SDL_GetStorageFileSize(user, "save0.sav", &saveLen) && saveLen > 0) { |
164 | * void* dst = SDL_malloc(saveLen); |
165 | * if (SDL_ReadStorageFile(user, "save0.sav", dst, saveLen)) { |
166 | * // A bunch of stuff happens here |
167 | * } else { |
168 | * // Something bad happened! |
169 | * } |
170 | * SDL_free(dst); |
171 | * } else { |
172 | * // Something bad happened! |
173 | * } |
174 | * |
175 | * SDL_CloseStorage(user); |
176 | * } |
177 | * |
178 | * void WriteSave(void) |
179 | * { |
180 | * SDL_Storage *user = SDL_OpenUserStorage("libsdl", "Storage Example", 0); |
181 | * if (user == NULL) { |
182 | * // Something bad happened! |
183 | * } |
184 | * while (!SDL_StorageReady(user)) { |
185 | * SDL_Delay(1); |
186 | * } |
187 | * |
188 | * extern void *saveData; // A bunch of stuff happened here... |
189 | * extern Uint64 saveLen; |
190 | * if (!SDL_WriteStorageFile(user, "save0.sav", saveData, saveLen)) { |
191 | * // Something bad happened! |
192 | * } |
193 | * |
194 | * SDL_CloseStorage(user); |
195 | * } |
196 | * ``` |
197 | * |
198 | * Note the improvements that SDL_Storage makes: |
199 | * |
200 | * 1. **What to Access:** This code explicitly reads from a title or user |
201 | * storage device based on the context of the function. |
202 | * |
203 | * 2. **How to Access:** This code explicitly uses either a read or write |
204 | * function based on the context of the function. |
205 | * |
206 | * 3. **When to Access:** This code explicitly opens the device when it needs |
207 | * to, and closes it when it is finished working with the filesystem. |
208 | * |
209 | * The result is an application that is significantly more robust against the |
210 | * increasing demands of platforms and their filesystems! |
211 | * |
212 | * A publicly available example of an SDL_Storage backend is the |
213 | * [Steam Cloud](https://partner.steamgames.com/doc/features/cloud) |
214 | * backend - you can initialize Steamworks when starting the program, and then |
215 | * SDL will recognize that Steamworks is initialized and automatically use |
216 | * ISteamRemoteStorage when the application opens user storage. More |
217 | * importantly, when you _open_ storage it knows to begin a "batch" of |
218 | * filesystem operations, and when you _close_ storage it knows to end and |
219 | * flush the batch. This is used by Steam to support |
220 | * [Dynamic Cloud Sync](https://steamcommunity.com/groups/steamworks/announcements/detail/3142949576401813670) |
221 | * ; users can save data on one PC, put the device to sleep, and then continue |
222 | * playing on another PC (and vice versa) with the save data fully |
223 | * synchronized across all devices, allowing for a seamless experience without |
224 | * having to do full restarts of the program. |
225 | * |
226 | * ## Notes on valid paths |
227 | * |
228 | * All paths in the Storage API use Unix-style path separators ('/'). Using a |
229 | * different path separator will not work, even if the underlying platform |
230 | * would otherwise accept it. This is to keep code using the Storage API |
231 | * portable between platforms and Storage implementations and simplify app |
232 | * code. |
233 | * |
234 | * Paths with relative directories ("." and "..") are forbidden by the Storage |
235 | * API. |
236 | * |
237 | * All valid UTF-8 strings (discounting the NULL terminator character and the |
238 | * '/' path separator) are usable for filenames, however, an underlying |
239 | * Storage implementation may not support particularly strange sequences and |
240 | * refuse to create files with those names, etc. |
241 | */ |
242 | |
243 | #ifndef SDL_storage_h_ |
244 | #define SDL_storage_h_ |
245 | |
246 | #include <SDL3/SDL_stdinc.h> |
247 | #include <SDL3/SDL_error.h> |
248 | #include <SDL3/SDL_filesystem.h> |
249 | #include <SDL3/SDL_properties.h> |
250 | |
251 | #include <SDL3/SDL_begin_code.h> |
252 | |
253 | /* Set up for C function definitions, even when using C++ */ |
254 | #ifdef __cplusplus |
255 | extern "C" { |
256 | #endif |
257 | |
258 | /** |
259 | * Function interface for SDL_Storage. |
260 | * |
261 | * Apps that want to supply a custom implementation of SDL_Storage will fill |
262 | * in all the functions in this struct, and then pass it to SDL_OpenStorage to |
263 | * create a custom SDL_Storage object. |
264 | * |
265 | * It is not usually necessary to do this; SDL provides standard |
266 | * implementations for many things you might expect to do with an SDL_Storage. |
267 | * |
268 | * This structure should be initialized using SDL_INIT_INTERFACE() |
269 | * |
270 | * \since This struct is available since SDL 3.2.0. |
271 | * |
272 | * \sa SDL_INIT_INTERFACE |
273 | */ |
274 | typedef struct SDL_StorageInterface |
275 | { |
276 | /* The version of this interface */ |
277 | Uint32 version; |
278 | |
279 | /* Called when the storage is closed */ |
280 | bool (SDLCALL *close)(void *userdata); |
281 | |
282 | /* Optional, returns whether the storage is currently ready for access */ |
283 | bool (SDLCALL *ready)(void *userdata); |
284 | |
285 | /* Enumerate a directory, optional for write-only storage */ |
286 | bool (SDLCALL *enumerate)(void *userdata, const char *path, SDL_EnumerateDirectoryCallback callback, void *callback_userdata); |
287 | |
288 | /* Get path information, optional for write-only storage */ |
289 | bool (SDLCALL *info)(void *userdata, const char *path, SDL_PathInfo *info); |
290 | |
291 | /* Read a file from storage, optional for write-only storage */ |
292 | bool (SDLCALL *read_file)(void *userdata, const char *path, void *destination, Uint64 length); |
293 | |
294 | /* Write a file to storage, optional for read-only storage */ |
295 | bool (SDLCALL *write_file)(void *userdata, const char *path, const void *source, Uint64 length); |
296 | |
297 | /* Create a directory, optional for read-only storage */ |
298 | bool (SDLCALL *mkdir)(void *userdata, const char *path); |
299 | |
300 | /* Remove a file or empty directory, optional for read-only storage */ |
301 | bool (SDLCALL *remove)(void *userdata, const char *path); |
302 | |
303 | /* Rename a path, optional for read-only storage */ |
304 | bool (SDLCALL *rename)(void *userdata, const char *oldpath, const char *newpath); |
305 | |
306 | /* Copy a file, optional for read-only storage */ |
307 | bool (SDLCALL *copy)(void *userdata, const char *oldpath, const char *newpath); |
308 | |
309 | /* Get the space remaining, optional for read-only storage */ |
310 | Uint64 (SDLCALL *space_remaining)(void *userdata); |
311 | } SDL_StorageInterface; |
312 | |
313 | /* Check the size of SDL_StorageInterface |
314 | * |
315 | * If this assert fails, either the compiler is padding to an unexpected size, |
316 | * or the interface has been updated and this should be updated to match and |
317 | * the code using this interface should be updated to handle the old version. |
318 | */ |
319 | SDL_COMPILE_TIME_ASSERT(SDL_StorageInterface_SIZE, |
320 | (sizeof(void *) == 4 && sizeof(SDL_StorageInterface) == 48) || |
321 | (sizeof(void *) == 8 && sizeof(SDL_StorageInterface) == 96)); |
322 | |
323 | /** |
324 | * An abstract interface for filesystem access. |
325 | * |
326 | * This is an opaque datatype. One can create this object using standard SDL |
327 | * functions like SDL_OpenTitleStorage or SDL_OpenUserStorage, etc, or create |
328 | * an object with a custom implementation using SDL_OpenStorage. |
329 | * |
330 | * \since This struct is available since SDL 3.2.0. |
331 | */ |
332 | typedef struct SDL_Storage SDL_Storage; |
333 | |
334 | /** |
335 | * Opens up a read-only container for the application's filesystem. |
336 | * |
337 | * \param override a path to override the backend's default title root. |
338 | * \param props a property list that may contain backend-specific information. |
339 | * \returns a title storage container on success or NULL on failure; call |
340 | * SDL_GetError() for more information. |
341 | * |
342 | * \since This function is available since SDL 3.2.0. |
343 | * |
344 | * \sa SDL_CloseStorage |
345 | * \sa SDL_GetStorageFileSize |
346 | * \sa SDL_OpenUserStorage |
347 | * \sa SDL_ReadStorageFile |
348 | */ |
349 | extern SDL_DECLSPEC SDL_Storage * SDLCALL SDL_OpenTitleStorage(const char *override, SDL_PropertiesID props); |
350 | |
351 | /** |
352 | * Opens up a container for a user's unique read/write filesystem. |
353 | * |
354 | * While title storage can generally be kept open throughout runtime, user |
355 | * storage should only be opened when the client is ready to read/write files. |
356 | * This allows the backend to properly batch file operations and flush them |
357 | * when the container has been closed; ensuring safe and optimal save I/O. |
358 | * |
359 | * \param org the name of your organization. |
360 | * \param app the name of your application. |
361 | * \param props a property list that may contain backend-specific information. |
362 | * \returns a user storage container on success or NULL on failure; call |
363 | * SDL_GetError() for more information. |
364 | * |
365 | * \since This function is available since SDL 3.2.0. |
366 | * |
367 | * \sa SDL_CloseStorage |
368 | * \sa SDL_GetStorageFileSize |
369 | * \sa SDL_GetStorageSpaceRemaining |
370 | * \sa SDL_OpenTitleStorage |
371 | * \sa SDL_ReadStorageFile |
372 | * \sa SDL_StorageReady |
373 | * \sa SDL_WriteStorageFile |
374 | */ |
375 | extern SDL_DECLSPEC SDL_Storage * SDLCALL SDL_OpenUserStorage(const char *org, const char *app, SDL_PropertiesID props); |
376 | |
377 | /** |
378 | * Opens up a container for local filesystem storage. |
379 | * |
380 | * This is provided for development and tools. Portable applications should |
381 | * use SDL_OpenTitleStorage() for access to game data and |
382 | * SDL_OpenUserStorage() for access to user data. |
383 | * |
384 | * \param path the base path prepended to all storage paths, or NULL for no |
385 | * base path. |
386 | * \returns a filesystem storage container on success or NULL on failure; call |
387 | * SDL_GetError() for more information. |
388 | * |
389 | * \since This function is available since SDL 3.2.0. |
390 | * |
391 | * \sa SDL_CloseStorage |
392 | * \sa SDL_GetStorageFileSize |
393 | * \sa SDL_GetStorageSpaceRemaining |
394 | * \sa SDL_OpenTitleStorage |
395 | * \sa SDL_OpenUserStorage |
396 | * \sa SDL_ReadStorageFile |
397 | * \sa SDL_WriteStorageFile |
398 | */ |
399 | extern SDL_DECLSPEC SDL_Storage * SDLCALL SDL_OpenFileStorage(const char *path); |
400 | |
401 | /** |
402 | * Opens up a container using a client-provided storage interface. |
403 | * |
404 | * Applications do not need to use this function unless they are providing |
405 | * their own SDL_Storage implementation. If you just need an SDL_Storage, you |
406 | * should use the built-in implementations in SDL, like SDL_OpenTitleStorage() |
407 | * or SDL_OpenUserStorage(). |
408 | * |
409 | * This function makes a copy of `iface` and the caller does not need to keep |
410 | * it around after this call. |
411 | * |
412 | * \param iface the interface that implements this storage, initialized using |
413 | * SDL_INIT_INTERFACE(). |
414 | * \param userdata the pointer that will be passed to the interface functions. |
415 | * \returns a storage container on success or NULL on failure; call |
416 | * SDL_GetError() for more information. |
417 | * |
418 | * \since This function is available since SDL 3.2.0. |
419 | * |
420 | * \sa SDL_CloseStorage |
421 | * \sa SDL_GetStorageFileSize |
422 | * \sa SDL_GetStorageSpaceRemaining |
423 | * \sa SDL_INIT_INTERFACE |
424 | * \sa SDL_ReadStorageFile |
425 | * \sa SDL_StorageReady |
426 | * \sa SDL_WriteStorageFile |
427 | */ |
428 | extern SDL_DECLSPEC SDL_Storage * SDLCALL SDL_OpenStorage(const SDL_StorageInterface *iface, void *userdata); |
429 | |
430 | /** |
431 | * Closes and frees a storage container. |
432 | * |
433 | * \param storage a storage container to close. |
434 | * \returns true if the container was freed with no errors, false otherwise; |
435 | * call SDL_GetError() for more information. Even if the function |
436 | * returns an error, the container data will be freed; the error is |
437 | * only for informational purposes. |
438 | * |
439 | * \since This function is available since SDL 3.2.0. |
440 | * |
441 | * \sa SDL_OpenFileStorage |
442 | * \sa SDL_OpenStorage |
443 | * \sa SDL_OpenTitleStorage |
444 | * \sa SDL_OpenUserStorage |
445 | */ |
446 | extern SDL_DECLSPEC bool SDLCALL SDL_CloseStorage(SDL_Storage *storage); |
447 | |
448 | /** |
449 | * Checks if the storage container is ready to use. |
450 | * |
451 | * This function should be called in regular intervals until it returns true - |
452 | * however, it is not recommended to spinwait on this call, as the backend may |
453 | * depend on a synchronous message loop. You might instead poll this in your |
454 | * game's main loop while processing events and drawing a loading screen. |
455 | * |
456 | * \param storage a storage container to query. |
457 | * \returns true if the container is ready, false otherwise. |
458 | * |
459 | * \since This function is available since SDL 3.2.0. |
460 | */ |
461 | extern SDL_DECLSPEC bool SDLCALL SDL_StorageReady(SDL_Storage *storage); |
462 | |
463 | /** |
464 | * Query the size of a file within a storage container. |
465 | * |
466 | * \param storage a storage container to query. |
467 | * \param path the relative path of the file to query. |
468 | * \param length a pointer to be filled with the file's length. |
469 | * \returns true if the file could be queried or false on failure; call |
470 | * SDL_GetError() for more information. |
471 | * |
472 | * \since This function is available since SDL 3.2.0. |
473 | * |
474 | * \sa SDL_ReadStorageFile |
475 | * \sa SDL_StorageReady |
476 | */ |
477 | extern SDL_DECLSPEC bool SDLCALL SDL_GetStorageFileSize(SDL_Storage *storage, const char *path, Uint64 *length); |
478 | |
479 | /** |
480 | * Synchronously read a file from a storage container into a client-provided |
481 | * buffer. |
482 | * |
483 | * The value of `length` must match the length of the file exactly; call |
484 | * SDL_GetStorageFileSize() to get this value. This behavior may be relaxed in |
485 | * a future release. |
486 | * |
487 | * \param storage a storage container to read from. |
488 | * \param path the relative path of the file to read. |
489 | * \param destination a client-provided buffer to read the file into. |
490 | * \param length the length of the destination buffer. |
491 | * \returns true if the file was read or false on failure; call SDL_GetError() |
492 | * for more information. |
493 | * |
494 | * \since This function is available since SDL 3.2.0. |
495 | * |
496 | * \sa SDL_GetStorageFileSize |
497 | * \sa SDL_StorageReady |
498 | * \sa SDL_WriteStorageFile |
499 | */ |
500 | extern SDL_DECLSPEC bool SDLCALL SDL_ReadStorageFile(SDL_Storage *storage, const char *path, void *destination, Uint64 length); |
501 | |
502 | /** |
503 | * Synchronously write a file from client memory into a storage container. |
504 | * |
505 | * \param storage a storage container to write to. |
506 | * \param path the relative path of the file to write. |
507 | * \param source a client-provided buffer to write from. |
508 | * \param length the length of the source buffer. |
509 | * \returns true if the file was written or false on failure; call |
510 | * SDL_GetError() for more information. |
511 | * |
512 | * \since This function is available since SDL 3.2.0. |
513 | * |
514 | * \sa SDL_GetStorageSpaceRemaining |
515 | * \sa SDL_ReadStorageFile |
516 | * \sa SDL_StorageReady |
517 | */ |
518 | extern SDL_DECLSPEC bool SDLCALL SDL_WriteStorageFile(SDL_Storage *storage, const char *path, const void *source, Uint64 length); |
519 | |
520 | /** |
521 | * Create a directory in a writable storage container. |
522 | * |
523 | * \param storage a storage container. |
524 | * \param path the path of the directory to create. |
525 | * \returns true on success or false on failure; call SDL_GetError() for more |
526 | * information. |
527 | * |
528 | * \since This function is available since SDL 3.2.0. |
529 | * |
530 | * \sa SDL_StorageReady |
531 | */ |
532 | extern SDL_DECLSPEC bool SDLCALL SDL_CreateStorageDirectory(SDL_Storage *storage, const char *path); |
533 | |
534 | /** |
535 | * Enumerate a directory in a storage container through a callback function. |
536 | * |
537 | * This function provides every directory entry through an app-provided |
538 | * callback, called once for each directory entry, until all results have been |
539 | * provided or the callback returns either SDL_ENUM_SUCCESS or |
540 | * SDL_ENUM_FAILURE. |
541 | * |
542 | * This will return false if there was a system problem in general, or if a |
543 | * callback returns SDL_ENUM_FAILURE. A successful return means a callback |
544 | * returned SDL_ENUM_SUCCESS to halt enumeration, or all directory entries |
545 | * were enumerated. |
546 | * |
547 | * If `path` is NULL, this is treated as a request to enumerate the root of |
548 | * the storage container's tree. An empty string also works for this. |
549 | * |
550 | * \param storage a storage container. |
551 | * \param path the path of the directory to enumerate, or NULL for the root. |
552 | * \param callback a function that is called for each entry in the directory. |
553 | * \param userdata a pointer that is passed to `callback`. |
554 | * \returns true on success or false on failure; call SDL_GetError() for more |
555 | * information. |
556 | * |
557 | * \since This function is available since SDL 3.2.0. |
558 | * |
559 | * \sa SDL_StorageReady |
560 | */ |
561 | extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateStorageDirectory(SDL_Storage *storage, const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata); |
562 | |
563 | /** |
564 | * Remove a file or an empty directory in a writable storage container. |
565 | * |
566 | * \param storage a storage container. |
567 | * \param path the path of the directory to enumerate. |
568 | * \returns true on success or false on failure; call SDL_GetError() for more |
569 | * information. |
570 | * |
571 | * \since This function is available since SDL 3.2.0. |
572 | * |
573 | * \sa SDL_StorageReady |
574 | */ |
575 | extern SDL_DECLSPEC bool SDLCALL SDL_RemoveStoragePath(SDL_Storage *storage, const char *path); |
576 | |
577 | /** |
578 | * Rename a file or directory in a writable storage container. |
579 | * |
580 | * \param storage a storage container. |
581 | * \param oldpath the old path. |
582 | * \param newpath the new path. |
583 | * \returns true on success or false on failure; call SDL_GetError() for more |
584 | * information. |
585 | * |
586 | * \since This function is available since SDL 3.2.0. |
587 | * |
588 | * \sa SDL_StorageReady |
589 | */ |
590 | extern SDL_DECLSPEC bool SDLCALL SDL_RenameStoragePath(SDL_Storage *storage, const char *oldpath, const char *newpath); |
591 | |
592 | /** |
593 | * Copy a file in a writable storage container. |
594 | * |
595 | * \param storage a storage container. |
596 | * \param oldpath the old path. |
597 | * \param newpath the new path. |
598 | * \returns true on success or false on failure; call SDL_GetError() for more |
599 | * information. |
600 | * |
601 | * \since This function is available since SDL 3.2.0. |
602 | * |
603 | * \sa SDL_StorageReady |
604 | */ |
605 | extern SDL_DECLSPEC bool SDLCALL SDL_CopyStorageFile(SDL_Storage *storage, const char *oldpath, const char *newpath); |
606 | |
607 | /** |
608 | * Get information about a filesystem path in a storage container. |
609 | * |
610 | * \param storage a storage container. |
611 | * \param path the path to query. |
612 | * \param info a pointer filled in with information about the path, or NULL to |
613 | * check for the existence of a file. |
614 | * \returns true on success or false if the file doesn't exist, or another |
615 | * failure; call SDL_GetError() for more information. |
616 | * |
617 | * \since This function is available since SDL 3.2.0. |
618 | * |
619 | * \sa SDL_StorageReady |
620 | */ |
621 | extern SDL_DECLSPEC bool SDLCALL SDL_GetStoragePathInfo(SDL_Storage *storage, const char *path, SDL_PathInfo *info); |
622 | |
623 | /** |
624 | * Queries the remaining space in a storage container. |
625 | * |
626 | * \param storage a storage container to query. |
627 | * \returns the amount of remaining space, in bytes. |
628 | * |
629 | * \since This function is available since SDL 3.2.0. |
630 | * |
631 | * \sa SDL_StorageReady |
632 | * \sa SDL_WriteStorageFile |
633 | */ |
634 | extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetStorageSpaceRemaining(SDL_Storage *storage); |
635 | |
636 | /** |
637 | * Enumerate a directory tree, filtered by pattern, and return a list. |
638 | * |
639 | * Files are filtered out if they don't match the string in `pattern`, which |
640 | * may contain wildcard characters `*` (match everything) and `?` (match one |
641 | * character). If pattern is NULL, no filtering is done and all results are |
642 | * returned. Subdirectories are permitted, and are specified with a path |
643 | * separator of '/'. Wildcard characters `*` and `?` never match a path |
644 | * separator. |
645 | * |
646 | * `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching |
647 | * case-insensitive. |
648 | * |
649 | * The returned array is always NULL-terminated, for your iterating |
650 | * convenience, but if `count` is non-NULL, on return it will contain the |
651 | * number of items in the array, not counting the NULL terminator. |
652 | * |
653 | * If `path` is NULL, this is treated as a request to enumerate the root of |
654 | * the storage container's tree. An empty string also works for this. |
655 | * |
656 | * \param storage a storage container. |
657 | * \param path the path of the directory to enumerate, or NULL for the root. |
658 | * \param pattern the pattern that files in the directory must match. Can be |
659 | * NULL. |
660 | * \param flags `SDL_GLOB_*` bitflags that affect this search. |
661 | * \param count on return, will be set to the number of items in the returned |
662 | * array. Can be NULL. |
663 | * \returns an array of strings on success or NULL on failure; call |
664 | * SDL_GetError() for more information. The caller should pass the |
665 | * returned pointer to SDL_free when done with it. This is a single |
666 | * allocation that should be freed with SDL_free() when it is no |
667 | * longer needed. |
668 | * |
669 | * \threadsafety It is safe to call this function from any thread, assuming |
670 | * the `storage` object is thread-safe. |
671 | * |
672 | * \since This function is available since SDL 3.2.0. |
673 | */ |
674 | extern SDL_DECLSPEC char ** SDLCALL SDL_GlobStorageDirectory(SDL_Storage *storage, const char *path, const char *pattern, SDL_GlobFlags flags, int *count); |
675 | |
676 | /* Ends C function definitions when using C++ */ |
677 | #ifdef __cplusplus |
678 | } |
679 | #endif |
680 | #include <SDL3/SDL_close_code.h> |
681 | |
682 | #endif /* SDL_storage_h_ */ |
683 | |