···19051905#define SDL_HINT_SHUTDOWN_DBUS_ON_QUIT "SDL_SHUTDOWN_DBUS_ON_QUIT"
1906190619071907/**
19081908+ * A variable that specifies a backend to use for title storage.
19091909+ *
19101910+ * By default, SDL will try all available storage backends in a reasonable order until it finds one that can work, but this hint allows the app or user to force a specific target, such as "pc" if, say, you are on Steam but want to avoid SteamRemoteStorage for title data.
19111911+ *
19121912+ * This hint should be set before SDL is initialized.
19131913+ */
19141914+#define SDL_HINT_STORAGE_TITLE_DRIVER "SDL_STORAGE_TITLE_DRIVER"
19151915+19161916+/**
19171917+ * A variable that specifies a backend to use for user storage.
19181918+ *
19191919+ * By default, SDL will try all available storage backends in a reasonable order until it finds one that can work, but this hint allows the app or user to force a specific target, such as "pc" if, say, you are on Steam but want to avoid SteamRemoteStorage for user data.
19201920+ *
19211921+ * This hint should be set before SDL is initialized.
19221922+ */
19231923+#define SDL_HINT_STORAGE_USER_DRIVER "SDL_STORAGE_USER_DRIVER"
19241924+19251925+/**
19081926 * Specifies whether SDL_THREAD_PRIORITY_TIME_CRITICAL should be treated as realtime.
19091927 *
19101928 * On some platforms, like Linux, a realtime priority thread may be subject to restrictions that require special handling by the application. This hint exists to let SDL know that the app is prepared to handle said restrictions.
+276
include/SDL3/SDL_storage.h
···11+/*
22+ Simple DirectMedia Layer
33+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
44+55+ This software is provided 'as-is', without any express or implied
66+ warranty. In no event will the authors be held liable for any damages
77+ arising from the use of this software.
88+99+ Permission is granted to anyone to use this software for any purpose,
1010+ including commercial applications, and to alter it and redistribute it
1111+ freely, subject to the following restrictions:
1212+1313+ 1. The origin of this software must not be misrepresented; you must not
1414+ claim that you wrote the original software. If you use this software
1515+ in a product, an acknowledgment in the product documentation would be
1616+ appreciated but is not required.
1717+ 2. Altered source versions must be plainly marked as such, and must not be
1818+ misrepresented as being the original software.
1919+ 3. This notice may not be removed or altered from any source distribution.
2020+*/
2121+2222+/**
2323+ * \file SDL_storage.h
2424+ *
2525+ * Include file for storage container SDL API functions
2626+ */
2727+2828+#ifndef SDL_storage_h_
2929+#define SDL_storage_h_
3030+3131+#include <SDL3/SDL_stdinc.h>
3232+#include <SDL3/SDL_mutex.h>
3333+#include <SDL3/SDL_properties.h>
3434+3535+#include <SDL3/SDL_begin_code.h>
3636+3737+/* Set up for C function definitions, even when using C++ */
3838+#ifdef __cplusplus
3939+extern "C" {
4040+#endif
4141+4242+/* !!! FIXME: Don't let this ship without async R/W support!!! */
4343+4444+typedef struct SDL_StorageInterface
4545+{
4646+ int (SDLCALL *close)(void *userdata);
4747+4848+ SDL_bool (SDLCALL *ready)(void *userdata);
4949+5050+ int (SDLCALL *fileSize)(void *userdata, const char *path, Uint64 *length);
5151+5252+ int (SDLCALL *readFile)(void *userdata, const char *path, void *destination, Uint64 length);
5353+5454+ int (SDLCALL *writeFile)(void *userdata, const char *path, const void *source, Uint64 length);
5555+5656+ Uint64 (SDLCALL *spaceRemaining)(void *userdata);
5757+} SDL_StorageInterface;
5858+5959+typedef struct SDL_Storage SDL_Storage;
6060+6161+/**
6262+ * Opens up a read-only container for the application's filesystem.
6363+ *
6464+ * \param override a path to override the backend's default title root
6565+ * \param props a property list that may contain backend-specific information
6666+ * \returns a title storage container on success or NULL on failure; call
6767+ * SDL_GetError() for more information.
6868+ *
6969+ * \since This function is available since SDL 3.0.0.
7070+ *
7171+ * \sa SDL_OpenUserStorage
7272+ * \sa SDL_OpenStorage
7373+ * \sa SDL_TitleStorageReady
7474+ * \sa SDL_CloseStorage
7575+ * \sa SDL_StorageReady
7676+ * \sa SDL_StorageFileSize
7777+ * \sa SDL_StorageReadFile
7878+ * \sa SDL_StorageWriteFile
7979+ * \sa SDL_StorageSpaceRemaining
8080+ */
8181+extern DECLSPEC SDL_Storage *SDLCALL SDL_OpenTitleStorage(const char *override, SDL_PropertiesID props);
8282+8383+/**
8484+ * Opens up a container for a user's unique read/write filesystem.
8585+ *
8686+ * While title storage can generally be kept open throughout runtime, user
8787+ * storage should only be opened when the client is ready to read/write files.
8888+ * This allows the backend to properly batch R/W operations and flush them when
8989+ * the container has been closed; ensuring safe and optimal save I/O.
9090+ *
9191+ * \param org the name of your organization
9292+ * \param app the name of your application
9393+ * \param props a property list that may contain backend-specific information
9494+ * \returns a user storage container on success or NULL on failure; call
9595+ * SDL_GetError() for more information.
9696+ *
9797+ * \since This function is available since SDL 3.0.0.
9898+ *
9999+ * \sa SDL_OpenTitleStorage
100100+ * \sa SDL_OpenStorage
101101+ * \sa SDL_CloseStorage
102102+ * \sa SDL_StorageReady
103103+ * \sa SDL_StorageFileSize
104104+ * \sa SDL_StorageReadFile
105105+ * \sa SDL_StorageWriteFile
106106+ * \sa SDL_StorageSpaceRemaining
107107+ */
108108+extern DECLSPEC SDL_Storage *SDLCALL SDL_OpenUserStorage(const char *org, const char *app, SDL_PropertiesID props);
109109+110110+/**
111111+ * Opens up a container using a client-provided storage interface.
112112+ *
113113+ * Applications do not need to use this function unless they are providing
114114+ * their own SDL_Storage implementation. If you just need an
115115+ * SDL_Storage, you should use the built-in implementations in SDL,
116116+ * like SDL_OpenTitleStorage() or SDL_OpenUserStorage().
117117+ *
118118+ * \param iface the function table to be used by this container
119119+ * \param userdata the pointer that will be passed to the store interface
120120+ * \returns a storage container on success or NULL on failure; call
121121+ * SDL_GetError() for more information.
122122+ *
123123+ * \since This function is available since SDL 3.0.0.
124124+ *
125125+ * \sa SDL_OpenTitleStorage
126126+ * \sa SDL_OpenUserStorage
127127+ * \sa SDL_CloseStorage
128128+ * \sa SDL_StorageReady
129129+ * \sa SDL_StorageFileSize
130130+ * \sa SDL_StorageReadFile
131131+ * \sa SDL_StorageWriteFile
132132+ * \sa SDL_StorageSpaceRemaining
133133+ */
134134+extern DECLSPEC SDL_Storage *SDLCALL SDL_OpenStorage(const SDL_StorageInterface *iface, void *userdata);
135135+136136+/**
137137+ * Closes and frees a storage container.
138138+ *
139139+ * \param storage a storage container to close
140140+ * \returns 0 if the container was freed with no errors, a negative value
141141+ * otherwise; call SDL_GetError() for more information. Even if the
142142+ * function returns an error, the container data will be freed; the
143143+ * error is only for informational purposes.
144144+ *
145145+ * \since This function is available since SDL 3.0.0.
146146+ *
147147+ * \sa SDL_OpenTitleStorage
148148+ * \sa SDL_OpenUserStorage
149149+ * \sa SDL_OpenStorage
150150+ * \sa SDL_StorageReady
151151+ * \sa SDL_StorageFileSize
152152+ * \sa SDL_StorageReadFile
153153+ * \sa SDL_StorageWriteFile
154154+ * \sa SDL_StorageSpaceRemaining
155155+ */
156156+extern DECLSPEC int SDLCALL SDL_CloseStorage(SDL_Storage *storage);
157157+158158+/**
159159+ * Checks if the storage container is ready to use.
160160+ *
161161+ * This function should be called in regular intervals until it returns
162162+ * SDL_TRUE - however, it is not recommended to spinwait on this call, as
163163+ * the backend may depend on a synchronous message loop.
164164+ *
165165+ * \param storage a storage container to query
166166+ * \returns SDL_TRUE if the container is ready, SDL_FALSE otherwise
167167+ *
168168+ * \since This function is available since SDL 3.0.0.
169169+ *
170170+ * \sa SDL_OpenTitleStorage
171171+ * \sa SDL_OpenUserStorage
172172+ * \sa SDL_OpenStorage
173173+ * \sa SDL_CloseStorage
174174+ * \sa SDL_StorageFileSize
175175+ * \sa SDL_StorageReadFile
176176+ * \sa SDL_StorageWriteFile
177177+ * \sa SDL_StorageSpaceRemaining
178178+ */
179179+extern DECLSPEC SDL_bool SDLCALL SDL_StorageReady(SDL_Storage *storage);
180180+181181+/**
182182+ * Query the size of a file within a storage container.
183183+ *
184184+ * \param storage a storage container to query
185185+ * \param path the relative path of the file to query
186186+ * \param length a pointer to be filled with the file's length
187187+ * \returns 0 if the file could be queried, a negative value otherwise; call
188188+ * SDL_GetError() for more information.
189189+ *
190190+ * \since This function is available since SDL 3.0.0.
191191+ *
192192+ * \sa SDL_OpenTitleStorage
193193+ * \sa SDL_OpenUserStorage
194194+ * \sa SDL_OpenStorage
195195+ * \sa SDL_CloseStorage
196196+ * \sa SDL_StorageReady
197197+ * \sa SDL_StorageReadFile
198198+ * \sa SDL_StorageWriteFile
199199+ * \sa SDL_StorageSpaceRemaining
200200+ */
201201+extern DECLSPEC int SDLCALL SDL_StorageFileSize(SDL_Storage *storage, const char *path, Uint64 *length);
202202+203203+/**
204204+ * Synchronously read a file from a storage container into a client-provided buffer.
205205+ *
206206+ * \param storage a storage container to read from
207207+ * \param path the relative path of the file to read
208208+ * \param destination a client-provided buffer to read the file into
209209+ * \param length the length of the destination buffer
210210+ * \returns 0 if the file was read, a negative value otherwise; call
211211+ * SDL_GetError() for more information.
212212+ *
213213+ * \since This function is available since SDL 3.0.0.
214214+ *
215215+ * \sa SDL_OpenTitleStorage
216216+ * \sa SDL_OpenUserStorage
217217+ * \sa SDL_OpenStorage
218218+ * \sa SDL_CloseStorage
219219+ * \sa SDL_StorageReady
220220+ * \sa SDL_StorageFileSize
221221+ * \sa SDL_StorageWriteFile
222222+ * \sa SDL_StorageSpaceRemaining
223223+ */
224224+extern DECLSPEC int SDLCALL SDL_StorageReadFile(SDL_Storage *storage, const char *path, void *destination, Uint64 length);
225225+226226+/**
227227+ * Synchronously write a file from client memory into a storage container.
228228+ *
229229+ * \param storage a storage container to write to
230230+ * \param path the relative path of the file to write
231231+ * \param source a client-provided buffer to write from
232232+ * \param length the length of the source buffer
233233+ * \returns 0 if the file was written, a negative value otherwise; call
234234+ * SDL_GetError() for more information.
235235+ *
236236+ * \since This function is available since SDL 3.0.0.
237237+ *
238238+ * \sa SDL_OpenTitleStorage
239239+ * \sa SDL_OpenUserStorage
240240+ * \sa SDL_OpenStorage
241241+ * \sa SDL_CloseStorage
242242+ * \sa SDL_StorageReady
243243+ * \sa SDL_StorageFileSize
244244+ * \sa SDL_StorageReadFile
245245+ * \sa SDL_StorageSpaceRemaining
246246+ */
247247+extern DECLSPEC int SDL_StorageWriteFile(SDL_Storage *storage, const char *path, const void *source, Uint64 length);
248248+249249+/**
250250+ * Queries the remaining space in a storage container.
251251+ *
252252+ * \param storage a storage container to query
253253+ * \returns the amount of remaining space, in bytes
254254+ *
255255+ * \since This function is available since SDL 3.0.0.
256256+ *
257257+ * \sa SDL_OpenTitleStorage
258258+ * \sa SDL_OpenUserStorage
259259+ * \sa SDL_OpenStorage
260260+ * \sa SDL_CloseStorage
261261+ * \sa SDL_StorageReady
262262+ * \sa SDL_StorageFileSize
263263+ * \sa SDL_StorageReadFile
264264+ * \sa SDL_StorageReadFileAsync
265265+ * \sa SDL_StorageWriteFile
266266+ * \sa SDL_StorageWriteFileAsync
267267+ */
268268+extern DECLSPEC Uint64 SDLCALL SDL_StorageSpaceRemaining(SDL_Storage *storage);
269269+270270+/* Ends C function definitions when using C++ */
271271+#ifdef __cplusplus
272272+}
273273+#endif
274274+#include <SDL3/SDL_close_code.h>
275275+276276+#endif /* SDL_storage_h_ */
+4
include/build_config/SDL_build_config.h.cmake
···465465#cmakedefine SDL_FILESYSTEM_PS2 @SDL_FILESYSTEM_PS2@
466466#cmakedefine SDL_FILESYSTEM_N3DS @SDL_FILESYSTEM_N3DS@
467467468468+/* Enable system storage support */
469469+#cmakedefine SDL_STORAGE_GENERIC @SDL_STORAGE_GENERIC@
470470+#cmakedefine SDL_STORAGE_STEAM @SDL_STORAGE_STEAM@
471471+468472/* Enable camera subsystem */
469473#cmakedefine SDL_CAMERA_DRIVER_DUMMY @SDL_CAMERA_DRIVER_DUMMY@
470474/* !!! FIXME: for later cmakedefine SDL_CAMERA_DRIVER_DISK @SDL_CAMERA_DRIVER_DISK@ */
+8
src/dynapi/SDL_dynapi.sym
···979979 SDL_OpenIO;
980980 SDL_CloseIO;
981981 SDL_GetIOStatus;
982982+ SDL_OpenTitleStorage;
983983+ SDL_OpenUserStorage;
984984+ SDL_OpenStorage;
985985+ SDL_CloseStorage;
986986+ SDL_StorageReady;
987987+ SDL_StorageFileSize;
988988+ SDL_StorageReadFile;
989989+ SDL_StorageSpaceRemaining;
982990 # extra symbols go here (don't modify this line)
983991 local: *;
984992};
···11+/*
22+ Simple DirectMedia Layer
33+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
44+55+ This software is provided 'as-is', without any express or implied
66+ warranty. In no event will the authors be held liable for any damages
77+ arising from the use of this software.
88+99+ Permission is granted to anyone to use this software for any purpose,
1010+ including commercial applications, and to alter it and redistribute it
1111+ freely, subject to the following restrictions:
1212+1313+ 1. The origin of this software must not be misrepresented; you must not
1414+ claim that you wrote the original software. If you use this software
1515+ in a product, an acknowledgment in the product documentation would be
1616+ appreciated but is not required.
1717+ 2. Altered source versions must be plainly marked as such, and must not be
1818+ misrepresented as being the original software.
1919+ 3. This notice may not be removed or altered from any source distribution.
2020+*/
2121+2222+#include "SDL_internal.h"
2323+2424+#include "SDL_sysstorage.h"
2525+2626+/* Available title storage drivers */
2727+static TitleStorageBootStrap *titlebootstrap[] = {
2828+ &GENERIC_titlebootstrap,
2929+};
3030+3131+/* Available user storage drivers */
3232+static UserStorageBootStrap *userbootstrap[] = {
3333+#ifdef SDL_STORAGE_STEAM
3434+ &STEAM_userbootstrap,
3535+#endif
3636+ &GENERIC_userbootstrap,
3737+};
3838+3939+struct SDL_Storage
4040+{
4141+ SDL_StorageInterface iface;
4242+ void *userdata;
4343+};
4444+4545+#define CHECK_STORAGE_MAGIC() \
4646+ if (!storage) { \
4747+ return SDL_SetError("Invalid storage container"); \
4848+ }
4949+5050+#define CHECK_STORAGE_MAGIC_RET(retval) \
5151+ if (!storage) { \
5252+ SDL_SetError("Invalid storage container"); \
5353+ return retval; \
5454+ }
5555+5656+SDL_Storage *SDL_OpenTitleStorage(const char *override, SDL_PropertiesID props)
5757+{
5858+ SDL_Storage *storage = NULL;
5959+ int i = 0;
6060+6161+ /* Select the proper storage driver */
6262+ const char *driver_name = SDL_GetHint(SDL_HINT_STORAGE_TITLE_DRIVER);
6363+ if (driver_name && *driver_name != 0) {
6464+ const char *driver_attempt = driver_name;
6565+ while (driver_attempt && *driver_attempt != 0 && !storage) {
6666+ const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
6767+ size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt)
6868+ : SDL_strlen(driver_attempt);
6969+7070+ for (i = 0; titlebootstrap[i]; ++i) {
7171+ if ((driver_attempt_len == SDL_strlen(titlebootstrap[i]->name)) &&
7272+ (SDL_strncasecmp(titlebootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) {
7373+ storage = titlebootstrap[i]->create(override, props);
7474+ break;
7575+ }
7676+ }
7777+7878+ driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL;
7979+ }
8080+ } else {
8181+ for (i = 0; titlebootstrap[i]; ++i) {
8282+ storage = titlebootstrap[i]->create(override, props);
8383+ if (storage) {
8484+ break;
8585+ }
8686+ }
8787+ }
8888+ if (!storage) {
8989+ if (driver_name) {
9090+ SDL_SetError("%s not available", driver_name);
9191+ } else {
9292+ SDL_SetError("No available title storage driver");
9393+ }
9494+ }
9595+ return storage;
9696+}
9797+9898+SDL_Storage *SDL_OpenUserStorage(const char *org, const char *app, SDL_PropertiesID props)
9999+{
100100+ SDL_Storage *storage = NULL;
101101+ int i = 0;
102102+103103+ /* Select the proper storage driver */
104104+ const char *driver_name = SDL_GetHint(SDL_HINT_STORAGE_USER_DRIVER);
105105+ if (driver_name && *driver_name != 0) {
106106+ const char *driver_attempt = driver_name;
107107+ while (driver_attempt && *driver_attempt != 0 && !storage) {
108108+ const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
109109+ size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt)
110110+ : SDL_strlen(driver_attempt);
111111+112112+ for (i = 0; userbootstrap[i]; ++i) {
113113+ if ((driver_attempt_len == SDL_strlen(userbootstrap[i]->name)) &&
114114+ (SDL_strncasecmp(userbootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) {
115115+ storage = userbootstrap[i]->create(org, app, props);
116116+ break;
117117+ }
118118+ }
119119+120120+ driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL;
121121+ }
122122+ } else {
123123+ for (i = 0; userbootstrap[i]; ++i) {
124124+ storage = userbootstrap[i]->create(org, app, props);
125125+ if (storage) {
126126+ break;
127127+ }
128128+ }
129129+ }
130130+ if (!storage) {
131131+ if (driver_name) {
132132+ SDL_SetError("%s not available", driver_name);
133133+ } else {
134134+ SDL_SetError("No available user storage driver");
135135+ }
136136+ }
137137+ return storage;
138138+}
139139+140140+SDL_Storage *SDL_OpenStorage(const SDL_StorageInterface *iface, void *userdata)
141141+{
142142+ SDL_Storage *storage;
143143+144144+ if (iface->close == NULL || iface->ready == NULL || iface->fileSize == NULL) {
145145+ SDL_SetError("iface is missing required callbacks");
146146+ return NULL;
147147+ }
148148+149149+ if ((iface->writeFile != NULL) != (iface->spaceRemaining != NULL)) {
150150+ SDL_SetError("Writeable containers must have both writeFile and spaceRemaining");
151151+ return NULL;
152152+ }
153153+154154+ storage = (SDL_Storage*) SDL_malloc(sizeof(SDL_Storage));
155155+ if (storage == NULL) {
156156+ SDL_OutOfMemory();
157157+ return NULL;
158158+ }
159159+160160+ SDL_memcpy(&storage->iface, iface, sizeof(SDL_StorageInterface));
161161+ storage->userdata = userdata;
162162+ return storage;
163163+}
164164+165165+int SDL_CloseStorage(SDL_Storage *storage)
166166+{
167167+ int retval;
168168+169169+ CHECK_STORAGE_MAGIC()
170170+171171+ retval = storage->iface.close(storage->userdata);
172172+ SDL_free(storage);
173173+ return retval;
174174+}
175175+176176+SDL_bool SDL_StorageReady(SDL_Storage *storage)
177177+{
178178+ CHECK_STORAGE_MAGIC_RET(SDL_FALSE)
179179+180180+ return storage->iface.ready(storage->userdata);
181181+}
182182+183183+int SDL_StorageFileSize(SDL_Storage *storage, const char *path, Uint64 *length)
184184+{
185185+ CHECK_STORAGE_MAGIC()
186186+187187+ return storage->iface.fileSize(storage->userdata, path, length);
188188+}
189189+190190+int SDL_StorageReadFile(SDL_Storage *storage, const char *path, void *destination, Uint64 length)
191191+{
192192+ CHECK_STORAGE_MAGIC()
193193+194194+ if (storage->iface.readFile == NULL) {
195195+ return SDL_SetError("Storage container does not have read capability");
196196+ }
197197+198198+ return storage->iface.readFile(storage->userdata, path, destination, length);
199199+}
200200+201201+int SDL_StorageWriteFile(SDL_Storage *storage, const char *path, const void *source, Uint64 length)
202202+{
203203+ CHECK_STORAGE_MAGIC()
204204+205205+ if (storage->iface.writeFile == NULL) {
206206+ return SDL_SetError("Storage container does not have write capability");
207207+ }
208208+209209+ return storage->iface.writeFile(storage->userdata, path, source, length);
210210+}
211211+212212+Uint64 SDL_StorageSpaceRemaining(SDL_Storage *storage)
213213+{
214214+ CHECK_STORAGE_MAGIC_RET(0)
215215+216216+ if (storage->iface.spaceRemaining == NULL) {
217217+ SDL_SetError("Storage container does not have write capability");
218218+ return 0;
219219+ }
220220+221221+ return storage->iface.spaceRemaining(storage->userdata);
222222+}
+49
src/storage/SDL_sysstorage.h
···11+/*
22+ Simple DirectMedia Layer
33+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
44+55+ This software is provided 'as-is', without any express or implied
66+ warranty. In no event will the authors be held liable for any damages
77+ arising from the use of this software.
88+99+ Permission is granted to anyone to use this software for any purpose,
1010+ including commercial applications, and to alter it and redistribute it
1111+ freely, subject to the following restrictions:
1212+1313+ 1. The origin of this software must not be misrepresented; you must not
1414+ claim that you wrote the original software. If you use this software
1515+ in a product, an acknowledgment in the product documentation would be
1616+ appreciated but is not required.
1717+ 2. Altered source versions must be plainly marked as such, and must not be
1818+ misrepresented as being the original software.
1919+ 3. This notice may not be removed or altered from any source distribution.
2020+*/
2121+2222+#ifndef SDL_sysstorage_h_
2323+#define SDL_sysstorage_h_
2424+2525+#include "SDL_internal.h"
2626+2727+typedef struct TitleStorageBootStrap
2828+{
2929+ const char *name;
3030+ const char *desc;
3131+ SDL_Storage *(*create)(const char*, SDL_PropertiesID);
3232+} TitleStorageBootStrap;
3333+3434+typedef struct UserStorageBootStrap
3535+{
3636+ const char *name;
3737+ const char *desc;
3838+ SDL_Storage *(*create)(const char*, const char*, SDL_PropertiesID);
3939+} UserStorageBootStrap;
4040+4141+/* Not all of these are available in a given build. Use #ifdefs, etc. */
4242+4343+extern TitleStorageBootStrap GENERIC_titlebootstrap;
4444+/* Steam does not have title storage APIs */
4545+4646+extern UserStorageBootStrap GENERIC_userbootstrap;
4747+extern UserStorageBootStrap STEAM_userbootstrap;
4848+4949+#endif /* SDL_sysstorage_h_ */
+188
src/storage/generic/SDL_genericstorage.c
···11+/*
22+ Simple DirectMedia Layer
33+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
44+55+ This software is provided 'as-is', without any express or implied
66+ warranty. In no event will the authors be held liable for any damages
77+ arising from the use of this software.
88+99+ Permission is granted to anyone to use this software for any purpose,
1010+ including commercial applications, and to alter it and redistribute it
1111+ freely, subject to the following restrictions:
1212+1313+ 1. The origin of this software must not be misrepresented; you must not
1414+ claim that you wrote the original software. If you use this software
1515+ in a product, an acknowledgment in the product documentation would be
1616+ appreciated but is not required.
1717+ 2. Altered source versions must be plainly marked as such, and must not be
1818+ misrepresented as being the original software.
1919+ 3. This notice may not be removed or altered from any source distribution.
2020+*/
2121+2222+#include "SDL_internal.h"
2323+2424+#include "../SDL_sysstorage.h"
2525+2626+static char *GENERIC_INTERNAL_CreateFullPath(const char *base, const char *relative)
2727+{
2828+ size_t fulllen = SDL_strlen(base) + SDL_strlen(relative) + 1;
2929+ char *result = (char*) SDL_malloc(fulllen);
3030+ if (result != NULL) {
3131+ SDL_snprintf(result, fulllen, "%s%s", base, relative);
3232+ }
3333+ return result;
3434+}
3535+3636+static int GENERIC_StorageClose(void *userdata)
3737+{
3838+ SDL_free(userdata);
3939+ return 0;
4040+}
4141+4242+static SDL_bool GENERIC_StorageReady(void *userdata)
4343+{
4444+ return SDL_TRUE;
4545+}
4646+4747+static int GENERIC_StorageFileSize(void *userdata, const char *path, Uint64 *length)
4848+{
4949+ SDL_IOStream *stream;
5050+ Sint64 result;
5151+5252+ char *fullpath = GENERIC_INTERNAL_CreateFullPath((char*) userdata, path);
5353+ if (fullpath == NULL) {
5454+ return SDL_OutOfMemory();
5555+ }
5656+ stream = SDL_IOFromFile(fullpath, "rb");
5757+ SDL_free(fullpath);
5858+5959+ result = SDL_SizeIO(stream);
6060+ SDL_CloseIO(stream);
6161+ if (result < 0) {
6262+ return result;
6363+ }
6464+6565+ /* FIXME: Should SDL_SizeIO use u64 now...? */
6666+ *length = (Uint64) result;
6767+ return 0;
6868+}
6969+7070+static int GENERIC_StorageReadFile(void *userdata, const char *path, void *destination, Uint64 length)
7171+{
7272+ SDL_IOStream *stream;
7373+ char *fullpath;
7474+ int fullread;
7575+7676+ if (length > SDL_SIZE_MAX) {
7777+ return SDL_SetError("Read size exceeds SDL_SIZE_MAX");
7878+ }
7979+8080+ fullpath = GENERIC_INTERNAL_CreateFullPath((char*) userdata, path);
8181+ if (fullpath == NULL) {
8282+ return SDL_OutOfMemory();
8383+ }
8484+ stream = SDL_IOFromFile(fullpath, "rb");
8585+ SDL_free(fullpath);
8686+8787+ /* FIXME: Should SDL_ReadIO use u64 now...? */
8888+ fullread = (SDL_ReadIO(stream, destination, (size_t) length) == length);
8989+ SDL_CloseIO(stream);
9090+ return fullread - 1;
9191+}
9292+9393+static int GENERIC_StorageWriteFile(void *userdata, const char *path, const void *source, Uint64 length)
9494+{
9595+ /* TODO: Recursively create subdirectories with SDL_mkdir */
9696+ SDL_IOStream *stream;
9797+ char *fullpath;
9898+ int fullwrite;
9999+100100+ if (length > SDL_SIZE_MAX) {
101101+ return SDL_SetError("Write size exceeds SDL_SIZE_MAX");
102102+ }
103103+104104+ fullpath = GENERIC_INTERNAL_CreateFullPath((char*) userdata, path);
105105+ if (fullpath == NULL) {
106106+ return SDL_OutOfMemory();
107107+ }
108108+ stream = SDL_IOFromFile(fullpath, "wb");
109109+ SDL_free(fullpath);
110110+111111+ /* FIXME: Should SDL_WriteIO use u64 now...? */
112112+ fullwrite = (SDL_WriteIO(stream, source, (size_t) length) == length);
113113+ SDL_CloseIO(stream);
114114+ return fullwrite - 1;
115115+}
116116+117117+static Uint64 GENERIC_StorageSpaceRemaining(void *userdata)
118118+{
119119+ /* TODO: There's totally a way to query a folder root's quota... */
120120+ return SDL_MAX_UINT64;
121121+}
122122+123123+static const SDL_StorageInterface GENERIC_title_iface = {
124124+ GENERIC_StorageClose,
125125+ GENERIC_StorageReady,
126126+ GENERIC_StorageFileSize,
127127+ GENERIC_StorageReadFile,
128128+ NULL,
129129+ NULL
130130+};
131131+132132+static SDL_Storage *GENERIC_Title_Create(const char *override, SDL_PropertiesID props)
133133+{
134134+ SDL_Storage *result;
135135+136136+ char *basepath;
137137+ if (override != NULL) {
138138+ basepath = SDL_strdup(override);
139139+ } else {
140140+ basepath = SDL_GetBasePath();
141141+ }
142142+ if (basepath == NULL) {
143143+ return NULL;
144144+ }
145145+146146+ result = SDL_OpenStorage(&GENERIC_title_iface, basepath);
147147+ if (result == NULL) {
148148+ SDL_free(basepath);
149149+ }
150150+ return result;
151151+}
152152+153153+TitleStorageBootStrap GENERIC_titlebootstrap = {
154154+ "generic",
155155+ "SDL generic title storage driver",
156156+ GENERIC_Title_Create
157157+};
158158+159159+static const SDL_StorageInterface GENERIC_user_iface = {
160160+ GENERIC_StorageClose,
161161+ GENERIC_StorageReady,
162162+ GENERIC_StorageFileSize,
163163+ GENERIC_StorageReadFile,
164164+ GENERIC_StorageWriteFile,
165165+ GENERIC_StorageSpaceRemaining
166166+};
167167+168168+static SDL_Storage *GENERIC_User_Create(const char *org, const char *app, SDL_PropertiesID props)
169169+{
170170+ SDL_Storage *result;
171171+172172+ char *prefpath = SDL_GetPrefPath(org, app);
173173+ if (prefpath == NULL) {
174174+ return NULL;
175175+ }
176176+177177+ result = SDL_OpenStorage(&GENERIC_user_iface, prefpath);
178178+ if (result == NULL) {
179179+ SDL_free(prefpath);
180180+ }
181181+ return result;
182182+}
183183+184184+UserStorageBootStrap GENERIC_userbootstrap = {
185185+ "generic",
186186+ "SDL generic user storage driver",
187187+ GENERIC_User_Create
188188+};
+199
src/storage/steam/SDL_steamstorage.c
···11+/*
22+ Simple DirectMedia Layer
33+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
44+55+ This software is provided 'as-is', without any express or implied
66+ warranty. In no event will the authors be held liable for any damages
77+ arising from the use of this software.
88+99+ Permission is granted to anyone to use this software for any purpose,
1010+ including commercial applications, and to alter it and redistribute it
1111+ freely, subject to the following restrictions:
1212+1313+ 1. The origin of this software must not be misrepresented; you must not
1414+ claim that you wrote the original software. If you use this software
1515+ in a product, an acknowledgment in the product documentation would be
1616+ appreciated but is not required.
1717+ 2. Altered source versions must be plainly marked as such, and must not be
1818+ misrepresented as being the original software.
1919+ 3. This notice may not be removed or altered from any source distribution.
2020+*/
2121+2222+#include "SDL_internal.h"
2323+2424+#include "../SDL_sysstorage.h"
2525+2626+#include <stdbool.h> /* Needed by Steamworks */
2727+2828+// !!! FIXME: Async API can use SteamRemoteStorage_ReadFileAsync
2929+// !!! FIXME: Async API can use SteamRemoteStorage_WriteFileAsync
3030+3131+#define STEAM_PROC(ret, func, parms) \
3232+ typedef ret (*steamfntype_##func) parms;
3333+#include "SDL_steamstorage_proc.h"
3434+3535+typedef struct STEAM_RemoteStorage
3636+{
3737+ void *libsteam_api;
3838+ #define STEAM_PROC(ret, func, parms) \
3939+ steamfntype_##func func;
4040+ #include "SDL_steamstorage_proc.h"
4141+} STEAM_RemoteStorage;
4242+4343+static int STEAM_UserStorageClose(void *userdata)
4444+{
4545+ int result = 0;
4646+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage*) userdata;
4747+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
4848+ if (steamremotestorage == NULL) {
4949+ result = SDL_SetError("SteamRemoteStorage unavailable");
5050+ } else if (!steam->SteamAPI_ISteamRemoteStorage_EndFileWriteBatch(steamremotestorage)) {
5151+ result = SDL_SetError("SteamRemoteStorage()->EndFileWriteBatch() failed");
5252+ }
5353+ SDL_UnloadObject(steam->libsteam_api);
5454+ SDL_free(steam);
5555+ return result;
5656+}
5757+5858+static SDL_bool STEAM_UserStorageReady(void *userdata)
5959+{
6060+ return SDL_TRUE;
6161+}
6262+6363+static int STEAM_UserStorageFileSize(void *userdata, const char *path, Uint64 *length)
6464+{
6565+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage*) userdata;
6666+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
6767+ if (steamremotestorage == NULL) {
6868+ return SDL_SetError("SteamRemoteStorage unavailable");
6969+ }
7070+ *length = steam->SteamAPI_ISteamRemoteStorage_GetFileSize(steamremotestorage, path);
7171+ return 0;
7272+}
7373+7474+static int STEAM_UserStorageReadFile(void *userdata, const char *path, void *destination, Uint64 length)
7575+{
7676+ int retval;
7777+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage*) userdata;
7878+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
7979+ if (steamremotestorage == NULL) {
8080+ return SDL_SetError("SteamRemoteStorage unavailable");
8181+ }
8282+ if (length > SDL_MAX_SINT32) {
8383+ return SDL_SetError("SteamRemoteStorage only supports INT32_MAX read size");
8484+ }
8585+ retval = steam->SteamAPI_ISteamRemoteStorage_FileRead(steamremotestorage, path, destination, (Sint32) length) == length;
8686+ return retval - 1;
8787+}
8888+8989+static int STEAM_UserStorageWriteFile(void *userdata, const char *path, const void *source, Uint64 length)
9090+{
9191+ int retval;
9292+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage*) userdata;
9393+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
9494+ if (steamremotestorage == NULL) {
9595+ return SDL_SetError("SteamRemoteStorage unavailable");
9696+ }
9797+ if (length > SDL_MAX_SINT32) {
9898+ return SDL_SetError("SteamRemoteStorage only supports INT32_MAX write size");
9999+ }
100100+ retval = steam->SteamAPI_ISteamRemoteStorage_FileWrite(steamremotestorage, path, source, (Sint32) length) == length;
101101+ return retval - 1;
102102+}
103103+104104+static Uint64 STEAM_UserStorageSpaceRemaining(void *userdata)
105105+{
106106+ Uint64 total, remaining;
107107+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage*) userdata;
108108+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
109109+ if (steamremotestorage == NULL) {
110110+ SDL_SetError("SteamRemoteStorage unavailable");
111111+ return 0;
112112+ }
113113+ if (!steam->SteamAPI_ISteamRemoteStorage_GetQuota(steamremotestorage, &total, &remaining)) {
114114+ SDL_SetError("SteamRemoteStorage()->GetQuota failed");
115115+ return 0;
116116+ }
117117+ return remaining;
118118+}
119119+120120+static const SDL_StorageInterface STEAM_user_iface = {
121121+ STEAM_UserStorageClose,
122122+ STEAM_UserStorageReady,
123123+ STEAM_UserStorageFileSize,
124124+ STEAM_UserStorageReadFile,
125125+ STEAM_UserStorageWriteFile,
126126+ STEAM_UserStorageSpaceRemaining
127127+};
128128+129129+static SDL_Storage *STEAM_User_Create(const char *org, const char *app, SDL_PropertiesID props)
130130+{
131131+ SDL_Storage *result;
132132+ STEAM_RemoteStorage *steam;
133133+ void *steamremotestorage;
134134+135135+ steam = (STEAM_RemoteStorage*) SDL_malloc(sizeof(STEAM_RemoteStorage));
136136+ if (steam == NULL) {
137137+ SDL_OutOfMemory();
138138+ return NULL;
139139+ }
140140+141141+ steam->libsteam_api = SDL_LoadObject(
142142+#if defined(_WIN64)
143143+ "steam_api64.dll"
144144+#elif defined(_WIN32)
145145+ "steam_api.dll"
146146+#elif defined(__APPLE__)
147147+ "libsteam_api.dylib"
148148+#else
149149+ "libsteam_api.so"
150150+#endif
151151+ );
152152+ if (steam->libsteam_api == NULL) {
153153+ SDL_free(steam);
154154+ return NULL;
155155+ }
156156+157157+ #define STEAM_PROC(ret, func, parms) \
158158+ steam->func = (steamfntype_##func) SDL_LoadFunction(steam->libsteam_api, #func); \
159159+ if (steam->func == NULL) { \
160160+ SDL_SetError("Could not load function " #func); \
161161+ goto steamfail; \
162162+ }
163163+ #include "SDL_steamstorage_proc.h"
164164+165165+ steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
166166+ if (steamremotestorage == NULL) {
167167+ SDL_SetError("SteamRemoteStorage unavailable");
168168+ goto steamfail;
169169+ }
170170+ if (!steam->SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount(steamremotestorage)) {
171171+ SDL_SetError("Steam cloud is disabled for this user");
172172+ goto steamfail;
173173+ }
174174+ if (!steam->SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp(steamremotestorage)) {
175175+ SDL_SetError("Steam cloud is disabled for this application");
176176+ goto steamfail;
177177+ }
178178+ if (!steam->SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch(steamremotestorage)) {
179179+ SDL_SetError("SteamRemoteStorage()->BeginFileWriteBatch failed");
180180+ goto steamfail;
181181+ }
182182+183183+ result = SDL_OpenStorage(&STEAM_user_iface, steam);
184184+ if (result == NULL) {
185185+ goto steamfail;
186186+ }
187187+ return result;
188188+189189+steamfail:
190190+ SDL_UnloadObject(steam->libsteam_api);
191191+ SDL_free(steam);
192192+ return NULL;
193193+}
194194+195195+UserStorageBootStrap STEAM_userbootstrap = {
196196+ "steam",
197197+ "SDL Steam user storage driver",
198198+ STEAM_User_Create
199199+};