Atlas - SDL_steamstorage.c

Home / ext / SDL / src / storage / steam Lines: 1 | Size: 10764 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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#include "SDL_internal.h" 23 24#include "../SDL_sysstorage.h" 25 26#if defined(_WIN64) 27#define SDL_DRIVER_STEAMAPI_DYNAMIC "steam_api64.dll" 28#elif defined(_WIN32) 29#define SDL_DRIVER_STEAMAPI_DYNAMIC "steam_api.dll" 30#elif defined(__APPLE__) 31#define SDL_DRIVER_STEAMAPI_DYNAMIC "libsteam_api.dylib" 32#else 33#define SDL_DRIVER_STEAMAPI_DYNAMIC "libsteam_api.so" 34#endif 35 36SDL_ELF_NOTE_DLOPEN( 37 "storage-steam", 38 "Support for Steam user storage", 39 SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, 40 SDL_DRIVER_STEAMAPI_DYNAMIC 41) 42 43// !!! FIXME: Async API can use SteamRemoteStorage_ReadFileAsync 44// !!! FIXME: Async API can use SteamRemoteStorage_WriteFileAsync 45 46#define STEAM_PROC(ret, func, parms) \ 47 typedef ret (*steamfntype_##func) parms; 48#include "SDL_steamstorage_proc.h" 49 50typedef struct STEAM_RemoteStorage 51{ 52 SDL_SharedObject *libsteam_api; 53 #define STEAM_PROC(ret, func, parms) \ 54 steamfntype_##func func; 55 #include "SDL_steamstorage_proc.h" 56} STEAM_RemoteStorage; 57 58static SDL_AtomicInt SDL_steam_storage_refcount; 59 60static bool STEAM_CloseStorage(void *userdata) 61{ 62 bool result = true; 63 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 64 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 65 bool end_batch = SDL_AtomicDecRef(&SDL_steam_storage_refcount); 66 if (steamremotestorage == NULL) { 67 result = SDL_SetError("SteamRemoteStorage unavailable"); 68 } else if (end_batch) { 69 if (!steam->SteamAPI_ISteamRemoteStorage_EndFileWriteBatch(steamremotestorage)) { 70 result = SDL_SetError("SteamRemoteStorage()->EndFileWriteBatch() failed"); 71 } 72 } 73 SDL_UnloadObject(steam->libsteam_api); 74 SDL_free(steam); 75 return result; 76} 77 78static bool STEAM_StorageReady(void *userdata) 79{ 80 return true; 81} 82 83static char *GetNormalizedStoragePath(const char *path, bool add_separator) 84{ 85 if (SDL_strcmp(path, ".") == 0) { 86 path = ""; 87 } else { 88 while (*path == '/') { 89 ++path; 90 } 91 } 92 93 size_t pathlen = SDL_strlen(path); 94 while (pathlen > 0 && path[pathlen - 1] == '/') { 95 --pathlen; 96 } 97 98 char *normalized = (char *)SDL_malloc(pathlen + add_separator + 1); 99 if (normalized) { 100 SDL_memcpy(normalized, path, pathlen); 101 if (add_separator) { 102 normalized[pathlen++] = '/'; 103 } 104 normalized[pathlen] = '\0'; 105 } 106 return normalized; 107} 108 109static bool STEAM_EnumerateStorageDirectory(void *userdata, const char *path, SDL_EnumerateDirectoryCallback callback, void *callback_userdata) 110{ 111 bool result = true; 112 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 113 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 114 if (steamremotestorage == NULL) { 115 return SDL_SetError("SteamRemoteStorage unavailable"); 116 } 117 118 char *dirname = GetNormalizedStoragePath(path, true); 119 if (!dirname) { 120 return false; 121 } 122 size_t dirlen = SDL_strlen(dirname); 123 124 bool done = false; 125 Sint32 count = steam->SteamAPI_ISteamRemoteStorage_GetFileCount(steamremotestorage); 126 for (Sint32 i = count; i-- && !done; ) { 127 const char *file = steam->SteamAPI_ISteamRemoteStorage_GetFileNameAndSize(steamremotestorage, i, NULL); 128 if (!file) { 129 continue; 130 } 131 132 const char *fname; 133 if (dirlen > 1) { 134 // Make sure the directory matches 135 if (SDL_strncmp(dirname, file, dirlen) != 0) { 136 continue; 137 } 138 fname = file + dirlen; 139 } else { 140 fname = file; 141 } 142 143 // Make sure this is a file in the current directory 144 if (SDL_strchr(fname, '/') != NULL) { 145 continue; 146 } 147 148 switch (callback(callback_userdata, dirname, fname)) { 149 case SDL_ENUM_SUCCESS: 150 done = true; 151 break; 152 case SDL_ENUM_FAILURE: 153 result = false; 154 done = true; 155 break; 156 default: 157 break; 158 } 159 } 160 SDL_free(dirname); 161 162 return result; 163} 164 165static bool STEAM_GetStoragePathInfo(void *userdata, const char *path, SDL_PathInfo *info) 166{ 167 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 168 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 169 if (steamremotestorage == NULL) { 170 return SDL_SetError("SteamRemoteStorage unavailable"); 171 } 172 173 if (!steam->SteamAPI_ISteamRemoteStorage_FileExists(steamremotestorage, path)) { 174 return SDL_SetError("Can't stat"); 175 } 176 177 if (info) { 178 SDL_zerop(info); 179 info->type = SDL_PATHTYPE_FILE; 180 info->size = steam->SteamAPI_ISteamRemoteStorage_GetFileSize(steamremotestorage, path); 181 Sint64 mtime = steam->SteamAPI_ISteamRemoteStorage_GetFileTimestamp(steamremotestorage, path); 182 info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(mtime); 183 } 184 return true; 185} 186 187static bool STEAM_ReadStorageFile(void *userdata, const char *path, void *destination, Uint64 length) 188{ 189 bool result = false; 190 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 191 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 192 if (steamremotestorage == NULL) { 193 return SDL_SetError("SteamRemoteStorage unavailable"); 194 } 195 if (length > SDL_MAX_SINT32) { 196 return SDL_SetError("SteamRemoteStorage only supports INT32_MAX read size"); 197 } 198 if (steam->SteamAPI_ISteamRemoteStorage_FileRead(steamremotestorage, path, destination, (Sint32) length) == length) { 199 result = true; 200 } else { 201 SDL_SetError("SteamRemoteStorage()->FileRead() failed"); 202 } 203 return result; 204} 205 206static bool STEAM_WriteStorageFile(void *userdata, const char *path, const void *source, Uint64 length) 207{ 208 bool result = false; 209 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 210 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 211 if (steamremotestorage == NULL) { 212 return SDL_SetError("SteamRemoteStorage unavailable"); 213 } 214 if (length > SDL_MAX_SINT32) { 215 return SDL_SetError("SteamRemoteStorage only supports INT32_MAX write size"); 216 } 217 if (steam->SteamAPI_ISteamRemoteStorage_FileWrite(steamremotestorage, path, source, (Sint32)length)) { 218 result = true; 219 } else { 220 SDL_SetError("SteamRemoteStorage()->FileWrite() failed"); 221 } 222 return result; 223} 224 225static bool STEAM_RemoveStoragePath(void *userdata, const char *path) 226{ 227 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 228 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 229 if (steamremotestorage == NULL) { 230 return SDL_SetError("SteamRemoteStorage unavailable"); 231 } 232 if (!steam->SteamAPI_ISteamRemoteStorage_FileDelete(steamremotestorage, path)) { 233 return SDL_SetError("SteamRemoteStorage()->FileDelete() failed"); 234 } 235 return true; 236} 237 238static Uint64 STEAM_GetStorageSpaceRemaining(void *userdata) 239{ 240 Uint64 total, remaining; 241 STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata; 242 void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 243 if (steamremotestorage == NULL) { 244 SDL_SetError("SteamRemoteStorage unavailable"); 245 return 0; 246 } 247 if (!steam->SteamAPI_ISteamRemoteStorage_GetQuota(steamremotestorage, &total, &remaining)) { 248 SDL_SetError("SteamRemoteStorage()->GetQuota() failed"); 249 return 0; 250 } 251 return remaining; 252} 253 254static const SDL_StorageInterface STEAM_user_iface = { 255 sizeof(SDL_StorageInterface), 256 STEAM_CloseStorage, 257 STEAM_StorageReady, 258 STEAM_EnumerateStorageDirectory, 259 STEAM_GetStoragePathInfo, 260 STEAM_ReadStorageFile, 261 STEAM_WriteStorageFile, 262 NULL, // mkdir 263 STEAM_RemoveStoragePath, 264 NULL, // rename 265 NULL, // copy 266 STEAM_GetStorageSpaceRemaining 267}; 268 269static SDL_Storage *STEAM_User_Create(const char *org, const char *app, SDL_PropertiesID props) 270{ 271 SDL_Storage *result; 272 STEAM_RemoteStorage *steam; 273 void *steamremotestorage; 274 275 steam = (STEAM_RemoteStorage *)SDL_malloc(sizeof(STEAM_RemoteStorage)); 276 if (steam == NULL) { 277 return NULL; 278 } 279 280 steam->libsteam_api = SDL_LoadObject(SDL_DRIVER_STEAMAPI_DYNAMIC); 281 if (steam->libsteam_api == NULL) { 282 SDL_free(steam); 283 return NULL; 284 } 285 286 #define STEAM_PROC(ret, func, parms) \ 287 steam->func = (steamfntype_##func) SDL_LoadFunction(steam->libsteam_api, #func); \ 288 if (steam->func == NULL) { \ 289 SDL_SetError("Could not load function " #func); \ 290 goto steamfail; \ 291 } 292 #include "SDL_steamstorage_proc.h" 293 294 steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016(); 295 if (steamremotestorage == NULL) { 296 SDL_SetError("SteamRemoteStorage unavailable"); 297 goto steamfail; 298 } 299 if (!steam->SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount(steamremotestorage)) { 300 SDL_SetError("Steam cloud is disabled for this user"); 301 goto steamfail; 302 } 303 if (!steam->SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp(steamremotestorage)) { 304 SDL_SetError("Steam cloud is disabled for this application"); 305 goto steamfail; 306 } 307 308 result = SDL_OpenStorage(&STEAM_user_iface, steam); 309 if (!result) { 310 goto steamfail; 311 } 312 313 if (SDL_AtomicIncRef(&SDL_steam_storage_refcount) == 0) { 314 if (!steam->SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch(steamremotestorage)) { 315 // We probably already have a batch in progress (maybe we crashed earlier?) 316 } 317 } 318 return result; 319 320steamfail: 321 SDL_UnloadObject(steam->libsteam_api); 322 SDL_free(steam); 323 return NULL; 324} 325 326UserStorageBootStrap STEAM_userbootstrap = { 327 "steam", 328 "SDL Steam user storage driver", 329 STEAM_User_Create 330}; 331
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.