1 /*
2     DSDL
3     Copyright (C) 2025 Inochi2D Project <luna@foxgirls.gay>
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     Simple DirectMedia Layer
24     Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
25 
26     This software is provided 'as-is', without any express or implied
27     warranty.  In no event will the authors be held liable for any damages
28     arising from the use of this software.
29 
30     Permission is granted to anyone to use this software for any purpose,
31     including commercial applications, and to alter it and redistribute it
32     freely, subject to the following restrictions:
33 
34     1. The origin of this software must not be misrepresented; you must not
35         claim that you wrote the original software. If you use this software
36         in a product, an acknowledgment in the product documentation would be
37         appreciated but is not required.
38     2. Altered source versions must be plainly marked as such, and must not be
39         misrepresented as being the original software.
40     3. This notice may not be removed or altered from any source distribution.
41 */
42 
43 /**
44     SDL FileSystem
45 
46     See_Also:
47         $(LINK2 https://wiki.libsdl.org/SDL3/CategoryFileSystem, SDL3 MessageBox Documentation)
48     
49     Copyright: © 2025 Inochi2D Project, © 1997-2025 Sam Lantinga
50     License: Subject to the terms of the Zlib License, as written in the LICENSE file.
51     Authors: 
52         Luna Nielsen
53 */
54 module sdl.filesystem;
55 import sdl.stdc;
56 
57 extern (C) nothrow @nogc:
58 
59 /**
60     Get the directory where the application was run from.
61 
62     SDL caches the result of this call internally, but the first call to this
63     function is not necessarily fast, so plan accordingly.
64 
65     **macOS and iOS Specific Functionality**: If the application is in a ".app"
66     bundle, this function returns the Resource directory (e.g.
67     MyApp.app/Contents/Resources/). This behaviour can be overridden by adding
68     a property to the Info.plist file. Adding a string key with the name
69     SDL_FILESYSTEM_BASE_DIR_TYPE with a supported value will change the
70     behaviour.
71 
72     Supported values for the SDL_FILESYSTEM_BASE_DIR_TYPE property (Given an
73     application in /Applications/SDLApp/MyApp.app):
74 
75     -   `resource`: bundle resource directory (the default). For example:
76         `/Applications/SDLApp/MyApp.app/Contents/Resources`
77     -   `bundle`: the Bundle directory. For example:
78         `/Applications/SDLApp/MyApp.app/`
79     -   `parent`: the containing directory of the bundle. For example:
80         `/Applications/SDLApp/`
81 
82     **Nintendo 3DS Specific Functionality**: This function returns "romfs"
83     directory of the application as it is uncommon to store resources outside
84     the executable. As such it is not a writable directory.
85 
86     The returned path is guaranteed to end with a path separator ('\\' on
87     Windows, '/' on most other platforms).
88 
89     Returns:
90         An absolute path in UTF-8 encoding to the application data
91         directory. NULL will be returned on error or when the platform
92         doesn't implement this functionality, call SDL_GetError() for more
93         information.
94 
95     See_Also:
96         $(D SDL_GetPrefPath)
97 */
98 extern const(char)* SDL_GetBasePath();
99 
100 /**
101     Get the user-and-app-specific path where files can be written.
102 
103     Get the "pref dir". This is meant to be where users can write personal
104     files (preferences and save games, etc) that are specific to your
105     application. This directory is unique per user, per application.
106 
107     This function will decide the appropriate location in the native
108     filesystem, create the directory if necessary, and return a string of the
109     absolute path to the directory in UTF-8 encoding.
110 
111     On Windows, the string might look like:
112 
113     `C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name\\`
114 
115     On Linux, the string might look like:
116 
117     `/home/bob/.local/share/My Program Name/`
118 
119     On macOS, the string might look like:
120 
121     `/Users/bob/Library/Application Support/My Program Name/`
122 
123     You should assume the path returned by this function is the only safe place
124     to write files (and that SDL_GetBasePath(), while it might be writable, or
125     even the parent of the returned path, isn't where you should be writing
126     things).
127 
128     Both the org and app strings may become part of a directory name, so please
129     follow these rules:
130 
131     -   Try to use the same org string (_including case-sensitivity_) for all
132         your applications that use this function.
133     -   Always use a unique app string for each one, and make sure it never
134         changes for an app once you've decided on it.
135     -   Unicode characters are legal, as long as they are UTF-8 encoded, but...
136     -   ...only use letters, numbers, and spaces. Avoid punctuation like "Game
137         Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
138 
139     The returned path is guaranteed to end with a path separator ('\\' on
140     Windows, '/' on most other platforms).
141 
142     Params:
143         org =   the name of your organization.
144         app =   the name of your application.
145     
146     Returns:
147         A UTF-8 string of the user directory in platform-dependent
148         notation. NULL if there's a problem (creating directory failed,
149         etc.). This should be freed with SDL_free() when it is no longer
150         needed.
151 
152     See_Also:
153         $(D SDL_GetBasePath)
154 */
155 extern char* SDL_GetPrefPath(const(char)* org, const(char)* app);
156 
157 /**
158     The type of the OS-provided default folder for a specific purpose.
159 
160     Note that the Trash folder isn't included here, because trashing files
161     usually involves extra OS-specific functionality to remember the file's
162     original location.
163 
164     The folders supported per platform are:
165 
166     |             | Windows | macOS/iOS | tvOS | Unix (XDG) | Haiku | Emscripten |
167     | ----------- | ------- | --------- | ---- | ---------- | ----- | ---------- |
168     | HOME        | X       | X         |      | X          | X     | X          |
169     | DESKTOP     | X       | X         |      | X          | X     |            |
170     | DOCUMENTS   | X       | X         |      | X          |       |            |
171     | DOWNLOADS   | Vista+  | X         |      | X          |       |            |
172     | MUSIC       | X       | X         |      | X          |       |            |
173     | PICTURES    | X       | X         |      | X          |       |            |
174     | PUBLICSHARE |         | X         |      | X          |       |            |
175     | SAVEDGAMES  | Vista+  |           |      |            |       |            |
176     | SCREENSHOTS | Vista+  |           |      |            |       |            |
177     | TEMPLATES   | X       | X         |      | X          |       |            |
178     | VIDEOS      | X       | X*        |      | X          |       |            |
179 
180     Notes:
181         On macOS/iOS, the Videos folder is called "Movies".
182 
183     See_Also:
184         $(D SDL_GetUserFolder)
185 */
186 enum SDL_Folder {
187 
188     /**
189         The folder which contains all of the current user's data, preferences, and documents.
190         It usually contains most of the other folders.
191         If a requested folder does not exist, the home folder can be considered a safe fallback to store a user's documents.
192     */
193     SDL_FOLDER_HOME,
194 
195     /**
196         The folder of files that are displayed on the desktop.
197         Note that the existence of a desktop folder does not guarantee that the system does show icons on its desktop; 
198         certain GNU/Linux distros with a graphical environment may not have desktop icons.
199     */
200     SDL_FOLDER_DESKTOP,
201 
202     /**
203         User document files, possibly application-specific.
204         This is a good place to save a user's projects.
205     */
206     SDL_FOLDER_DOCUMENTS,
207 
208     /**
209         Standard folder for user files downloaded from the internet.
210     */
211     SDL_FOLDER_DOWNLOADS,
212 
213     /**
214         Music files that can be played using a standard music player (mp3, ogg...).
215     */
216     SDL_FOLDER_MUSIC,
217 
218     /**
219         Image files that can be displayed using a standard viewer (png, jpg...).
220     */
221     SDL_FOLDER_PICTURES,
222 
223     /**
224         Files that are meant to be shared with other users on the same computer.
225     */
226     SDL_FOLDER_PUBLICSHARE,
227 
228     /**
229         Save files for games.
230     */
231     SDL_FOLDER_SAVEDGAMES,
232 
233     /**
234         Application screenshots.
235     */
236     SDL_FOLDER_SCREENSHOTS,
237 
238     /**
239         Template files to be used when the user requests the desktop environment to create a new file in a certain folder, 
240         such as "New Text File.txt".
241         
242         Any file in the Templates folder can be used as a starting point for a new file.
243     */
244     SDL_FOLDER_TEMPLATES,
245 
246     /**
247         Video files that can be played using a standard video player (mp4, webm...).
248     */
249     SDL_FOLDER_VIDEOS,
250 
251     /**
252         Total number of types in this enum, not a folder type by itself.
253     */
254     SDL_FOLDER_COUNT
255 }
256 
257 /**
258     Finds the most suitable user folder for a specific purpose.
259 
260     Many OSes provide certain standard folders for certain purposes, such as
261     storing pictures, music or videos for a certain user. This function gives
262     the path for many of those special locations.
263 
264     This function is specifically for _user_ folders, which are meant for the
265     user to access and manage. For application-specific folders, meant to hold
266     data for the application to manage, see SDL_GetBasePath() and
267     SDL_GetPrefPath().
268 
269     The returned path is guaranteed to end with a path separator ('\\' on
270     Windows, '/' on most other platforms).
271 
272     If NULL is returned, the error may be obtained with SDL_GetError().
273 
274     Params:
275         folder = the type of folder to find.
276     
277     Returns:
278         either a null-terminated C string containing the full path to the
279         folder, or NULL if an error happened.
280 */
281 extern const(char)* SDL_GetUserFolder(SDL_Folder folder);
282 
283 /**
284     Types of filesystem entries.
285 
286     Note that there may be other sorts of items on a filesystem: devices,
287     symlinks, named pipes, etc. They are currently reported as
288     SDL_PATHTYPE_OTHER.
289 
290     See_Also:
291         $(D SDL_PathInfo)
292 */
293 enum SDL_PathType {
294 
295     /**
296         Path does not exist
297     */
298     SDL_PATHTYPE_NONE,
299 
300     /**
301         A normal file
302     */
303     SDL_PATHTYPE_FILE,
304 
305     /**
306         A directory
307     */
308     SDL_PATHTYPE_DIRECTORY,
309 
310     /**
311         Something completely different like a device node (not a symlink, those are always followed)
312     */
313     SDL_PATHTYPE_OTHER
314 }
315 
316 /**
317     Information about a path on the filesystem.
318 
319     See_Also:
320         $(D SDL_GetPathInfo)
321         $(D SDL_GetStoragePathInfo)
322 */
323 struct SDL_PathInfo {
324 
325     /**
326         The path type
327     */
328     SDL_PathType type;
329 
330     /**
331         The file size in bytes
332     */
333     Uint64 size;
334 
335     /**
336         The time when the path was created
337     */
338     SDL_Time create_time;
339 
340     /**
341         The last time the path was modified
342     */
343     SDL_Time modify_time;
344 
345     /**
346         The last time the path was read
347     */
348     SDL_Time access_time;
349 }
350 
351 /**
352     Flags for path matching.
353 
354     See_Also:
355         $(D SDL_GlobDirectory)
356         $(D SDL_GlobStorageDirectory)
357 */
358 enum SDL_GlobFlags : Uint32 {
359     SDL_GLOB_CASEINSENSITIVE = (1u << 0),
360 }
361 
362 /**
363     Create a directory, and any missing parent directories.
364 
365     This reports success if `path` already exists as a directory.
366 
367     If parent directories are missing, it will also create them. Note that if
368     this fails, it will not remove any parent directories it already made.
369 
370     Params:
371         path = the path of the directory to create.
372     
373     Returns:
374         true on success or false on failure; call SDL_GetError() for more
375         information.
376 */
377 extern bool SDL_CreateDirectory(const(char)* path);
378 
379 /**
380     Possible results from an enumeration callback.
381 
382     See_Also:
383         $(D SDL_EnumerateDirectoryCallback)
384 */
385 enum SDL_EnumerationResult {
386 
387     /**
388         Value that requests that enumeration continue.
389     */
390     SDL_ENUM_CONTINUE,
391 
392     /**
393         Value that requests that enumeration stop, successfully.
394     */
395     SDL_ENUM_SUCCESS,
396 
397     /**
398         Value that requests that enumeration stop, as a failure.
399     */
400     SDL_ENUM_FAILURE
401 }
402 
403 /**
404     Callback for directory enumeration.
405 
406     Enumeration of directory entries will continue until either all entries
407     have been provided to the callback, or the callback has requested a stop
408     through its return value.
409 
410     Returning SDL_ENUM_CONTINUE will let enumeration proceed, calling the
411     callback with further entries. SDL_ENUM_SUCCESS and SDL_ENUM_FAILURE will
412     terminate the enumeration early, and dictate the return value of the
413     enumeration function itself.
414 
415     `dirname` is guaranteed to end with a path separator ('\\' on Windows, '/'
416     on most other platforms).
417 
418     Params:
419         userdata =  an app-controlled pointer that is passed to the callback.
420         dirname =   the directory that is being enumerated.
421         fname =     the next entry in the enumeration.
422     
423     Returns:
424         how the enumeration should proceed.
425 
426     See_Also:
427         $(D SDL_EnumerateDirectory)
428 */
429 alias SDL_EnumerateDirectoryCallback = SDL_EnumerationResult function(
430     void* userdata, const(char)* dirname, const(char)* fname);
431 
432 /**
433     Enumerate a directory through a callback function.
434 
435     This function provides every directory entry through an app-provided
436     callback, called once for each directory entry, until all results have been
437     provided or the callback returns either SDL_ENUM_SUCCESS or
438     SDL_ENUM_FAILURE.
439 
440     This will return false if there was a system problem in general, or if a
441     callback returns SDL_ENUM_FAILURE. A successful return means a callback
442     returned SDL_ENUM_SUCCESS to halt enumeration, or all directory entries
443     were enumerated.
444 
445     Params:
446         path =      the path of the directory to enumerate.
447         callback =  a function that is called for each entry in the directory.
448         userdata =  a pointer that is passed to `callback`.
449     
450     Returns:
451         true on success or false on failure; call SDL_GetError() for more
452         information.
453 */
454 extern bool SDL_EnumerateDirectory(const(char)* path, SDL_EnumerateDirectoryCallback callback, void* userdata);
455 
456 /**
457     Remove a file or an empty directory.
458 
459     Directories that are not empty will fail; this function will not recursely
460     delete directory trees.
461 
462     Params:
463         path = the path to remove from the filesystem.
464     
465     Returns:
466         true on success or false on failure; call SDL_GetError() for more
467         information.
468 */
469 extern bool SDL_RemovePath(const(char)* path);
470 
471 /**
472     Rename a file or directory.
473 
474     If the file at `newpath` already exists, it will replaced.
475 
476     Note that this will not copy files across filesystems/drives/volumes, as
477     that is a much more complicated (and possibly time-consuming) operation.
478 
479     Which is to say, if this function fails, SDL_CopyFile() to a temporary file
480     in the same directory as `newpath`, then SDL_RenamePath() from the
481     temporary file to `newpath` and SDL_RemovePath() on `oldpath` might work
482     for files. Renaming a non-empty directory across filesystems is
483     dramatically more complex, however.
484 
485     Params:
486         oldpath =   the old path.
487         newpath =   the new path.
488     
489     Returns:
490         true on success or false on failure; call SDL_GetError() for more
491         information.
492 */
493 extern bool SDL_RenamePath(const(char)* oldpath, const(char)* newpath);
494 
495 /**
496     Copy a file.
497 
498     If the file at `newpath` already exists, it will be overwritten with the
499     contents of the file at `oldpath`.
500 
501     This function will block until the copy is complete, which might be a
502     significant time for large files on slow disks. On some platforms, the copy
503     can be handed off to the OS itself, but on others SDL might just open both
504     paths, and read from one and write to the other.
505 
506     Note that this is not an atomic operation! If something tries to read from
507     `newpath` while the copy is in progress, it will see an incomplete copy of
508     the data, and if the calling thread terminates (or the power goes out)
509     during the copy, `newpath`'s previous contents will be gone, replaced with
510     an incomplete copy of the data. To avoid this risk, it is recommended that
511     the app copy to a temporary file in the same directory as `newpath`, and if
512     the copy is successful, use SDL_RenamePath() to replace `newpath` with the
513     temporary file. This will ensure that reads of `newpath` will either see a
514     complete copy of the data, or it will see the pre-copy state of `newpath`.
515 
516     This function attempts to synchronize the newly-copied data to disk before
517     returning, if the platform allows it, so that the renaming trick will not
518     have a problem in a system crash or power failure, where the file could be
519     renamed but the contents never made it from the system file cache to the
520     physical disk.
521 
522     If the copy fails for any reason, the state of `newpath` is undefined. It
523     might be half a copy, it might be the untouched data of what was already
524     there, or it might be a zero-byte file, etc.
525 
526     Params:
527         oldpath =   the old path.
528         newpath =   the new path.
529     
530     Returns:
531         true on success or false on failure; call SDL_GetError() for more
532         information.
533 */
534 extern bool SDL_CopyFile(const(char)* oldpath, const(char)* newpath);
535 
536 /**
537     Get information about a filesystem path.
538 
539     Params:
540         path =  the path to query.
541         info =  a pointer filled in with information about the path, or NULL to
542                 check for the existence of a file.
543     
544     Returns:
545         true on success or false if the file doesn't exist, or another
546         failure; call SDL_GetError() for more information.
547 */
548 extern bool SDL_GetPathInfo(const(char)* path, SDL_PathInfo* info);
549 
550 /**
551     Enumerate a directory tree, filtered by pattern, and return a list.
552 
553     Files are filtered out if they don't match the string in `pattern`, which
554     may contain wildcard characters '\*' (match everything) and '?' (match one
555     character). If pattern is NULL, no filtering is done and all results are
556     returned. Subdirectories are permitted, and are specified with a path
557     separator of '/'. Wildcard characters '\*' and '?' never match a path
558     separator.
559 
560     `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching
561     case-insensitive.
562 
563     The returned array is always NULL-terminated, for your iterating
564     convenience, but if `count` is non-NULL, on return it will contain the
565     number of items in the array, not counting the NULL terminator.
566 
567     Params:
568         path =      the path of the directory to enumerate.
569         pattern =   the pattern that files in the directory must match. Can be
570                     NULL.
571         flags =     `SDL_GLOB_*` bitflags that affect this search.
572         count =     on return, will be set to the number of items in the returned
573                     array. Can be NULL.
574     
575     Returns:
576         an array of strings on success or NULL on failure; call
577         SDL_GetError() for more information. This is a single allocation
578         that should be freed with SDL_free() when it is no longer needed.
579 
580     Threadsafety:
581         It is safe to call this function from any thread.
582 */
583 extern char** SDL_GlobDirectory(const(char)* path, const(char)* pattern, SDL_GlobFlags flags, int* count);
584 
585 /**
586     Get what the system believes is the "current working directory."
587 
588     For systems without a concept of a current working directory, this will
589     still attempt to provide something reasonable.
590 
591     SDL does not provide a means to _change_ the current working directory; for
592     platforms without this concept, this would cause surprises with file access
593     outside of SDL.
594 
595     The returned path is guaranteed to end with a path separator ('\\' on
596     Windows, '/' on most other platforms).
597 
598     Returns:
599         A UTF-8 string of the current working directory in
600         platform-dependent notation. NULL if there's a problem. This
601         should be freed with SDL_free() when it is no longer needed.
602 */
603 extern char* SDL_GetCurrentDirectory();