comparison foosdk/sdk/foobar2000/SDK/filesystem.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #pragma once
2
3 #include "file.h"
4 #include "fsitem.h"
5 #include <functional>
6
7 #ifndef _WIN32
8 struct stat;
9 #endif
10
11 //! Contains various I/O related structures and interfaces.
12 namespace foobar2000_io
13 {
14
15 //! Disk space info struct
16 struct drivespace_t {
17 //! Free space, in bytes
18 t_filesize m_free = filesize_invalid;
19 //! Total size, in bytes
20 t_filesize m_total = filesize_invalid;
21 //! Free space available to caller, in bytes \n
22 //! If not specifically supported by filesystem, same as m_free.
23 t_filesize m_avail = filesize_invalid;
24 };
25
26
27
28 class filesystem;
29
30 class NOVTABLE directory_callback {
31 public:
32 //! @returns true to continue enumeration, false to abort.
33 virtual bool on_entry(filesystem * p_owner,abort_callback & p_abort,const char * p_url,bool p_is_subdirectory,const t_filestats & p_stats)=0;
34 };
35
36 class NOVTABLE directory_callback_v3 {
37 public:
38 virtual bool on_entry(filesystem* owner, const char* URL, t_filestats2 const& stats, abort_callback& abort) = 0;
39 };
40
41 //! Entrypoint service for all filesystem operations.\n
42 //! Implementation: standard implementations for local filesystem etc are provided by core.\n
43 //! Instantiation: use static helper functions rather than calling filesystem interface methods directly, e.g. filesystem::g_open() to open a file.
44 class NOVTABLE filesystem : public service_base {
45 FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(filesystem);
46 public:
47 //! Enumeration specifying how to open a file. See: filesystem::open(), filesystem::g_open().
48 typedef uint32_t t_open_mode;
49 enum {
50 //! Opens an existing file for reading; if the file does not exist, the operation will fail.
51 open_mode_read,
52 //! Opens an existing file for writing; if the file does not exist, the operation will fail.
53 open_mode_write_existing,
54 //! Opens a new file for writing; if the file exists, its contents will be wiped.
55 open_mode_write_new,
56
57 open_mode_mask = 0xFF,
58 open_shareable = 0x100,
59 };
60
61 virtual bool get_canonical_path(const char * p_path,pfc::string_base & p_out)=0;
62 virtual bool is_our_path(const char * p_path)=0;
63 virtual bool get_display_path(const char * p_path,pfc::string_base & p_out)=0;
64
65 virtual void open(service_ptr_t<file> & p_out,const char * p_path, t_open_mode p_mode,abort_callback & p_abort)=0;
66 virtual void remove(const char * p_path,abort_callback & p_abort)=0;
67 //! Moves/renames a file. Will fail if the destination file already exists. \n
68 //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
69 virtual void move(const char * p_src,const char * p_dst,abort_callback & p_abort)=0;
70 //! Queries whether a file at specified path belonging to this filesystem is a remote object or not.
71 virtual bool is_remote(const char * p_src) = 0;
72
73 //! Retrieves stats of a file at specified path.
74 virtual void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort) = 0;
75 //! Helper
76 t_filestats get_stats( const char * path, abort_callback & abort );
77
78 virtual bool relative_path_create(const char* file_path, const char* playlist_path, pfc::string_base& out) { (void)file_path; (void)playlist_path; (void)out; return false; }
79 virtual bool relative_path_parse(const char* relative_path, const char* playlist_path, pfc::string_base& out) { (void)relative_path; (void)playlist_path; (void)out; return false; }
80
81 //! Creates a directory.
82 virtual void create_directory(const char * p_path,abort_callback & p_abort) = 0;
83
84 virtual void list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort)=0;
85
86 //! Hint; returns whether this filesystem supports mime types. \n
87 //! When this returns false, all file::get_content_type() calls on files opened thru this filesystem implementation will return false; otherwise, file::get_content_type() calls may return true depending on the file.
88 virtual bool supports_content_types() = 0;
89
90 static void g_get_canonical_path(const char * path,pfc::string_base & out);
91 static void g_get_display_path(const char * path,pfc::string_base & out);
92 static void g_get_display_path(const char* path, pfc::string_base& out, filesystem::ptr & reuseMe);
93 //! Retrieves a shortened display name for this file. By default this is implemented by returning filename.ext portion of the path.
94 static bool g_get_display_name_short( const char * path, pfc::string_base & out );
95 //! Extracts the native filesystem path, sets out to the input path if native path cannot be extracted so the output is always set.
96 //! @returns True if native path was extracted successfully, false otherwise (but output is set anyway).
97 static bool g_get_native_path( const char * path, pfc::string_base & out, abort_callback & a = fb2k::noAbort);
98 static pfc::string8 g_get_native_path( const char * path, abort_callback & a = fb2k::noAbort );
99
100 static bool g_get_interface(service_ptr_t<filesystem> & p_out,const char * path);//path is AFTER get_canonical_path
101 static filesystem::ptr g_get_interface(const char * path);// throws exception_io_no_handler_for_path on failure
102 static filesystem::ptr get( const char * path ) { return g_get_interface(path); } // shortened; never returns null, throws on failure
103 static filesystem::ptr getLocalFS(); // returns local filesystem object
104 static filesystem::ptr tryGet(const char* path); // returns null if not found instead of throwing
105 static bool g_is_remote(const char * p_path);//path is AFTER get_canonical_path
106 static bool g_is_recognized_and_remote(const char * p_path);//path is AFTER get_canonical_path
107 static bool g_is_remote_safe(const char * p_path) {return g_is_recognized_and_remote(p_path);}
108 static bool g_is_remote_or_unrecognized(const char * p_path);
109 static bool g_is_recognized_path(const char * p_path);
110
111 //! Opens file at specified path, with specified access privileges.
112 static void g_open(service_ptr_t<file> & p_out,const char * p_path,t_open_mode p_mode,abort_callback & p_abort);
113 //! Attempts to open file at specified path; if the operation fails with sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time.
114 static void g_open_timeout(service_ptr_t<file> & p_out,const char * p_path,t_open_mode p_mode,double p_timeout,abort_callback & p_abort);
115 static void g_open_write_new(service_ptr_t<file> & p_out,const char * p_path,abort_callback & p_abort);
116 static void g_open_read(service_ptr_t<file> & p_out,const char * path,abort_callback & p_abort) {return g_open(p_out,path,open_mode_read,p_abort);}
117 static void g_open_precache(service_ptr_t<file> & p_out,const char * path,abort_callback & p_abort);//open only for precaching data (eg. will fail on http etc)
118 static bool g_exists(const char * p_path,abort_callback & p_abort);
119 static bool g_exists_writeable(const char * p_path,abort_callback & p_abort);
120 //! Removes file at specified path.
121 static void g_remove(const char * p_path,abort_callback & p_abort);
122 //! Attempts to remove file at specified path; if the operation fails with a sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time.
123 static void g_remove_timeout(const char * p_path,double p_timeout,abort_callback & p_abort);
124 //! Moves file from one path to another.
125 //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
126 static void g_move(const char * p_src,const char * p_dst,abort_callback & p_abort);
127 //! Attempts to move file from one path to another; if the operation fails with a sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time.
128 static void g_move_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort);
129
130 static void g_link(const char * p_src,const char * p_dst,abort_callback & p_abort);
131 static void g_link_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort);
132
133 static void g_copy(const char * p_src,const char * p_dst,abort_callback & p_abort);//needs canonical path
134 static void g_copy_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort);//needs canonical path
135 static void g_copy_directory(const char * p_src,const char * p_dst,abort_callback & p_abort);//needs canonical path
136 static void g_get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort);
137 static bool g_relative_path_create(const char * p_file_path,const char * p_playlist_path,pfc::string_base & out);
138 static bool g_relative_path_parse(const char * p_relative_path,const char * p_playlist_path,pfc::string_base & out);
139
140 static void g_create_directory(const char * p_path,abort_callback & p_abort);
141
142 static void g_open_temp(service_ptr_t<file> & p_out,abort_callback & p_abort);
143 static void g_open_tempmem(service_ptr_t<file> & p_out,abort_callback & p_abort);
144 static file::ptr g_open_tempmem();
145
146 static void g_list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort);// path must be canonical
147
148 static bool g_is_valid_directory(const char * path,abort_callback & p_abort);
149 static bool g_is_empty_directory(const char * path,abort_callback & p_abort);
150
151 void remove_object_recur(const char * path, abort_callback & abort);
152 void remove_directory_content(const char * path, abort_callback & abort);
153 static void g_remove_object_recur(const char * path, abort_callback & abort);
154 static void g_remove_object_recur_timeout(const char * path, double timeout, abort_callback & abort);
155
156 // Presumes both source and destination belong to this filesystem.
157 void copy_directory(const char * p_src, const char * p_dst, abort_callback & p_abort);
158 void copy_directory_contents(const char* p_src, const char* p_dst, abort_callback& p_abort);
159
160 //! Moves/renames a file, overwriting the destination atomically if exists. \n
161 //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
162 void move_overwrite( const char * src, const char * dst, abort_callback & abort);
163 //! Moves/renames a file, overwriting the destination atomically if exists. \n
164 //! Meant to retain destination attributes if feasible. Otherwise identical to move_overwrite(). \n
165 //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
166 void replace_file(const char * src, const char * dst, abort_callback & abort);
167 //! Create a directory, without throwing an exception if it already exists.
168 //! @param didCreate bool flag indicating whether a new directory was created or not. \n
169 //! This should be a retval, but because it's messy to obtain this information with certain APIs, the caller can opt out of receiving this information,.
170 void make_directory( const char * path, abort_callback & abort, bool * didCreate = nullptr );
171 //! Bool retval version of make_directory().
172 bool make_directory_check( const char * path, abort_callback & abort );
173
174 //! Returns whether a directory exists at path, false if doesn't exist or not a directory.
175 bool directory_exists(const char * path, abort_callback & abort);
176 //! Returns whether a file exists at path, false if doesn't exist or not a file.
177 bool file_exists( const char * path, abort_callback & abort );
178 //! Returns whether either a file or a directory exists at path. Effectively directory_exists() || file_exists(), but somewhat more efficient.
179 bool exists(const char* path, abort_callback& a);
180
181 char pathSeparator();
182 //! Extracts the filename.ext portion of the path. \n
183 //! The filename is ready to be presented to the user - URL decoding and such (similar to get_display_path()) is applied.
184 void extract_filename_ext(const char * path, pfc::string_base & outFN);
185 pfc::string8 extract_filename_ext(const char* path);
186 pfc::string8 get_extension(const char* path);
187 static pfc::string8 g_get_extension(const char* path);
188 //! Retrieves the parent path.
189 bool get_parent_path(const char * path, pfc::string_base & out);
190 //! Retrieves the parent path, alternate version.
191 fb2k::stringRef parentPath(const char* path);
192
193 file::ptr openWriteNew( const char * path, abort_callback & abort, double timeout );
194 file::ptr openWriteExisting(const char * path, abort_callback & abort, double timeout);
195 file::ptr openRead( const char * path, abort_callback & abort, double timeout);
196 file::ptr openEx( const char * path, t_open_mode mode, abort_callback & abort, double timeout);
197 void remove_(const char* path, abort_callback& a, double timeout);
198
199 //! Read whole file into a mem_block_container
200 void read_whole_file(const char * path, mem_block_container & out, pfc::string_base & outContentType, size_t maxBytes, abort_callback & abort );
201 //! Alternate read whole file, fb2k mobile style
202 fb2k::memBlockRef readWholeFile(const char* path, size_t maxBytes, abort_callback& abort);
203 static fb2k::memBlockRef g_readWholeFile(const char * path, size_t sizeSanity, abort_callback & aborter);
204
205 bool is_transacted();
206 bool commit_if_transacted(abort_callback &abort);
207
208 //! Full file rewrite helper that automatically does the right thing to ensure atomic update. \n
209 //! If this is a transacted filesystem, a simple in-place rewrite is performed. \n
210 //! If this is not a transacted filesystem, your content first goes to a temporary file, which then replaces the original. \n
211 //! See also: filesystem_transacted. \n
212 //! In order to perform transacted operations, you must obtain a transacted filesystem explicitly, or get one passed down from a higher level context (example: in config_io_callback_v3).
213 void rewrite_file( const char * path, abort_callback & abort, double opTimeout, std::function<void (file::ptr) > worker );
214 void rewrite_file(const char* path, abort_callback& abort, double opTimeout, const void* payload, size_t bytes);
215 //! Full directory rewrite helper that automatically does the right thing to ensure atomic update. \n
216 //! If this is a transacted filesystem, a simple in-place rewrite is performed. \n
217 //! If this is not a transacted filesystem, your content first goes to a temporary folder, which then replaces the original. \n
218 //! It is encouraged to perform flushFileBuffers on all files accessed from within. \n
219 //! See also: filesystem_transacted. \n
220 //! In order to perform transacted operations, you must obtain a transacted filesystem explicitly, or get one passed down from a higher level context (example: in config_io_callback_v3).
221 void rewrite_directory(const char * path, abort_callback & abort, double opTimeout, std::function<void(const char *) > worker);
222
223 t_filestats2 get_stats2_(const char* p_path, uint32_t s2flags, abort_callback& p_abort);
224 static t_filestats2 g_get_stats2(const char* p_path, uint32_t s2flags, abort_callback& p_abort);
225
226 bool get_display_name_short_(const char* path, pfc::string_base& out);
227
228 fsItemFolder::ptr makeItemFolderStd(const char* pathCanonical, t_filestats2 const& stats = filestats2_invalid );
229 fsItemFile::ptr makeItemFileStd(const char* pathCanonical, t_filestats2 const& stats = filestats2_invalid );
230 fsItemBase::ptr findItem_(const char* path, abort_callback& p_abort);
231 fsItemFile::ptr findItemFile_(const char* path, abort_callback& p_abort);
232 fsItemFolder::ptr findItemFolder_(const char* path, abort_callback& p_abort);
233
234
235 typedef std::function<void(const char*, t_filestats2 const&) > list_callback_t;
236 void list_directory_(const char* path, list_callback_t cb, unsigned listMode,abort_callback& a);
237
238 //! Compares two paths determining if one is a subpath of another,
239 //! Returns false if the paths are unrelated.
240 //! Returns true if the paths are related, and then: result is set 0 if they are equal, 1 if p2 is a subpath of p1, -1 if p1 is a subpath of p2
241 static bool g_compare_paths(const char* p1, const char* p2, int& result);
242
243 //! Batch file stats read. Some filesystems provide an optimized implementation of this.
244 static void g_readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort);
245
246 //! See filesystem_v3::fileNameSanity(). Throws pfc::exception_not_implemented() if not available.
247 fb2k::stringRef fileNameSanity_(const char* fn);
248
249 //! See filesystem_v3::getDriveSpace(). Throws pfc::exception_not_implemented() if not available.
250 drivespace_t getDriveSpace_(const char* pathAt, abort_callback& abort);
251
252 protected:
253 static bool get_parent_helper(const char * path, char separator, pfc::string_base & out);
254 void read_whole_file_fallback( const char * path, mem_block_container & out, pfc::string_base & outContentType, size_t maxBytes, abort_callback & abort );
255 };
256
257 class filesystem_v2 : public filesystem {
258 FB2K_MAKE_SERVICE_INTERFACE( filesystem_v2, filesystem )
259 public:
260 //! Moves/renames a file, overwriting the destination atomically if exists. \n
261 //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
262 virtual void move_overwrite(const char * src, const char * dst, abort_callback & abort) = 0;
263 //! Moves/renames a file, overwriting the destination atomically if exists. \n
264 //! Meant to retain destination attributes if feasible. Otherwise identical to move_overwrite(). \n
265 //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios.
266 virtual void replace_file(const char * src, const char * dst, abort_callback & abort);
267 //! Create a directory, without throwing an exception if it already exists.
268 //! @param didCreate bool flag indicating whether a new directory was created or not. \n
269 //! This should be a retval, but because it's messy to obtain this information with certain APIs, the caller can opt out of receiving this information,.
270 virtual void make_directory(const char * path, abort_callback & abort, bool * didCreate = nullptr) = 0;
271 virtual bool directory_exists(const char * path, abort_callback & abort) = 0;
272 virtual bool file_exists(const char * path, abort_callback & abort) = 0;
273 virtual char pathSeparator() = 0;
274 virtual void extract_filename_ext(const char * path, pfc::string_base & outFN);
275 virtual bool get_parent_path( const char * path, pfc::string_base & out);
276 virtual void list_directory_ex(const char * p_path, directory_callback & p_out, unsigned listMode, abort_callback & p_abort) = 0;
277 virtual void read_whole_file(const char * path, mem_block_container & out, pfc::string_base & outContentType, size_t maxBytes, abort_callback & abort);
278
279 //! Wrapper to list_directory_ex
280 void list_directory( const char * p_path, directory_callback & p_out, abort_callback & p_abort );
281
282 bool make_directory_check(const char * path, abort_callback & abort);
283 };
284
285 //! \since 2.0
286 class filesystem_v3 : public filesystem_v2 {
287 FB2K_MAKE_SERVICE_INTERFACE(filesystem_v3, filesystem_v2);
288 public:
289 //! Retrieves free space on the volume at the specified path.
290 //! Optional functionality, throws pfc::exception_not_implemented if n/a.
291 virtual drivespace_t getDriveSpace(const char* pathAt, abort_callback& abort);
292
293 //! Retrieves stats of a file at specified path.
294 virtual t_filestats2 get_stats2(const char* p_path, uint32_t s2flags, abort_callback& p_abort) = 0;
295
296 virtual bool get_display_name_short(const char* in, pfc::string_base& out);
297
298 virtual void list_directory_v3(const char* path, directory_callback_v3& callback, unsigned listMode, abort_callback& p_abort) = 0;
299
300 virtual fsItemBase::ptr findItem(const char* path, abort_callback& p_abort);
301 virtual fsItemFile::ptr findItemFile(const char* path, abort_callback& p_abort);
302 virtual fsItemFolder::ptr findItemFolder(const char* path, abort_callback& p_abort);
303 virtual fsItemFolder::ptr findParentFolder(const char* path, abort_callback& p_abort);
304 virtual fb2k::stringRef fileNameSanity(const char* fn);
305 virtual void readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort);
306
307 //! Optional method to return a native filesystem path to this item, null if N/A.
308 //! Aborter provided for corner cases, normally not needed.
309 virtual fb2k::stringRef getNativePath(const char* in, abort_callback& a) { (void)in; (void)a; return nullptr; }
310
311 // Old method wrapped to get_stats2()
312 void get_stats(const char* p_path, t_filestats& p_stats, bool& p_is_writeable, abort_callback& p_abort) override;
313 // Old method wrapped to list_directory_v3()
314 void list_directory_ex(const char* p_path, directory_callback& p_out, unsigned listMode, abort_callback& p_abort) override;
315
316 // Old method wrapped to get_stats2()
317 bool directory_exists(const char* path, abort_callback& abort) override;
318 // Old method wrapped to get_stats2()
319 bool file_exists(const char* path, abort_callback& abort) override;
320 };
321
322 class directory_callback_impl : public directory_callback
323 {
324 struct t_entry
325 {
326 pfc::string_simple m_path;
327 t_filestats m_stats;
328 t_entry(const char * p_path, const t_filestats & p_stats) : m_path(p_path), m_stats(p_stats) {}
329 };
330
331
332 pfc::list_t<pfc::rcptr_t<t_entry> > m_data;
333 bool m_recur;
334
335 static int sortfunc(const pfc::rcptr_t<const t_entry> & p1, const pfc::rcptr_t<const t_entry> & p2) {return pfc::io::path::compare(p1->m_path,p2->m_path);}
336 public:
337 bool on_entry(filesystem * owner,abort_callback & p_abort,const char * url,bool is_subdirectory,const t_filestats & p_stats);
338
339 directory_callback_impl(bool p_recur) : m_recur(p_recur) {}
340 t_size get_count() {return m_data.get_count();}
341 const char * operator[](t_size n) const {return m_data[n]->m_path;}
342 const char * get_item(t_size n) const {return m_data[n]->m_path;}
343 const t_filestats & get_item_stats(t_size n) const {return m_data[n]->m_stats;}
344 void sort() {m_data.sort_t(sortfunc);}
345 };
346
347
348 t_filetimestamp filetimestamp_from_system_timer();
349
350 #ifdef _WIN32
351 inline t_filetimestamp import_filetimestamp(FILETIME ft) {
352 return *reinterpret_cast<t_filetimestamp*>(&ft);
353 }
354 #endif
355
356 void generate_temp_location_for_file(pfc::string_base & p_out, const char * p_origpath,const char * p_extension,const char * p_magic);
357
358
359 inline file_ptr fileOpen(const char * p_path,filesystem::t_open_mode p_mode,abort_callback & p_abort,double p_timeout) {
360 file_ptr temp; filesystem::g_open_timeout(temp,p_path,p_mode,p_timeout,p_abort); PFC_ASSERT(temp.is_valid()); return temp;
361 }
362
363 inline file_ptr fileOpenReadExisting(const char * p_path,abort_callback & p_abort,double p_timeout = 0) {
364 return fileOpen(p_path,filesystem::open_mode_read,p_abort,p_timeout);
365 }
366 inline file_ptr fileOpenWriteExisting(const char * p_path,abort_callback & p_abort,double p_timeout = 0) {
367 return fileOpen(p_path,filesystem::open_mode_write_existing,p_abort,p_timeout);
368 }
369 inline file_ptr fileOpenWriteNew(const char * p_path,abort_callback & p_abort,double p_timeout = 0) {
370 return fileOpen(p_path,filesystem::open_mode_write_new,p_abort,p_timeout);
371 }
372
373 template<typename t_list>
374 class directory_callback_retrieveList : public directory_callback {
375 public:
376 directory_callback_retrieveList(t_list & p_list,bool p_getFiles,bool p_getSubDirectories) : m_list(p_list), m_getFiles(p_getFiles), m_getSubDirectories(p_getSubDirectories) {}
377 bool on_entry(filesystem * p_owner,abort_callback & p_abort,const char * p_url,bool p_is_subdirectory,const t_filestats & p_stats) {
378 p_abort.check();
379 if (p_is_subdirectory ? m_getSubDirectories : m_getFiles) {
380 m_list.add_item(p_url);
381 }
382 return true;
383 }
384 private:
385 const bool m_getSubDirectories;
386 const bool m_getFiles;
387 t_list & m_list;
388 };
389 template<typename t_list>
390 class directory_callback_retrieveListEx : public directory_callback {
391 public:
392 directory_callback_retrieveListEx(t_list & p_files, t_list & p_directories) : m_files(p_files), m_directories(p_directories) {}
393 bool on_entry(filesystem * p_owner,abort_callback & p_abort,const char * p_url,bool p_is_subdirectory,const t_filestats & p_stats) {
394 p_abort.check();
395 if (p_is_subdirectory) m_directories += p_url;
396 else m_files += p_url;
397 return true;
398 }
399 private:
400 t_list & m_files;
401 t_list & m_directories;
402 };
403 template<typename t_list> class directory_callback_retrieveListRecur : public directory_callback {
404 public:
405 directory_callback_retrieveListRecur(t_list & p_list) : m_list(p_list) {}
406 bool on_entry(filesystem * owner,abort_callback & p_abort,const char * path, bool isSubdir, const t_filestats&) {
407 if (isSubdir) {
408 try { owner->list_directory(path,*this,p_abort); } catch(exception_io const &) {}
409 } else {
410 m_list.add_item(path);
411 }
412 return true;
413 }
414 private:
415 t_list & m_list;
416 };
417
418 template<typename t_list>
419 static void listFiles(const char * p_path,t_list & p_out,abort_callback & p_abort) {
420 directory_callback_retrieveList<t_list> callback(p_out,true,false);
421 filesystem::g_list_directory(p_path,callback,p_abort);
422 }
423 template<typename t_list>
424 static void listDirectories(const char * p_path,t_list & p_out,abort_callback & p_abort) {
425 directory_callback_retrieveList<t_list> callback(p_out,false,true);
426 filesystem::g_list_directory(p_path,callback,p_abort);
427 }
428 template<typename t_list>
429 static void listFilesAndDirectories(const char * p_path,t_list & p_files,t_list & p_directories,abort_callback & p_abort) {
430 directory_callback_retrieveListEx<t_list> callback(p_files,p_directories);
431 filesystem::g_list_directory(p_path,callback,p_abort);
432 }
433 template<typename t_list>
434 static void listFilesRecur(const char * p_path,t_list & p_out,abort_callback & p_abort) {
435 directory_callback_retrieveListRecur<t_list> callback(p_out);
436 filesystem::g_list_directory(p_path,callback,p_abort);
437 }
438
439 bool extract_native_path(const char * p_fspath,pfc::string_base & p_native);
440 bool _extract_native_path_ptr(const char * & p_fspath);
441 bool is_native_filesystem( const char * p_fspath );
442 bool extract_native_path_ex(const char * p_fspath, pfc::string_base & p_native);//prepends \\?\ where needed
443
444 bool extract_native_path_archive_aware( const char * fspatch, pfc::string_base & out );
445 bool extract_native_path_archive_aware_ex( const char * fspatch, pfc::string_base & out, abort_callback & a );
446
447 template<typename T>
448 pfc::string getPathDisplay(const T& source) {
449 const char * c = pfc::stringToPtr(source);
450 if ( *c == 0 ) return c;
451 pfc::string_formatter temp;
452 filesystem::g_get_display_path(c,temp);
453 return temp.toString();
454 }
455 template<typename T>
456 pfc::string getPathCanonical(const T& source) {
457 const char * c = pfc::stringToPtr(source);
458 if ( *c == 0 ) return c;
459 pfc::string_formatter temp;
460 filesystem::g_get_canonical_path(c,temp);
461 return temp.toString();
462 }
463
464
465 bool matchContentType(const char * fullString, const char * ourType);
466 bool matchProtocol(const char * fullString, const char * protocolName);
467 bool testIfHasProtocol( const char * fullString );
468 const char * afterProtocol( const char * fullString );
469 pfc::string8 getProtocol(const char* fullString);
470 void substituteProtocol(pfc::string_base & out, const char * fullString, const char * protocolName);
471
472 bool matchContentType_MP3( const char * fullString);
473 bool matchContentType_MP4audio( const char * fullString);
474 bool matchContentType_MP4( const char * fullString);
475 bool matchContentType_Ogg( const char * fullString);
476 bool matchContentType_Opus( const char * fullString);
477 bool matchContentType_FLAC( const char * fullString);
478 bool matchContentType_WavPack( const char * fullString);
479 bool matchContentType_WAV( const char * fullString);
480 bool matchContentType_Musepack( const char * fullString);
481 const char * extensionFromContentType( const char * contentType );
482 const char * contentTypeFromExtension( const char * ext );
483
484 void purgeOldFiles(const char * directory, t_filetimestamp period, abort_callback & abort);
485
486 #ifndef _WIN32
487 // Struct stat to fb2k filestats converter
488 t_filestats nixMakeFileStats(const struct stat & st);
489 t_filestats2 nixMakeFileStats2(const struct stat & st);
490 bool nixQueryReadonly( const struct stat & st );
491 bool nixQueryDirectory( const struct stat & st );
492 bool compactHomeDir(pfc::string_base & str);
493 bool expandHomeDir(pfc::string_base & str);
494
495
496 #endif
497
498 //! \since 1.6
499 class read_ahead_tools : public service_base {
500 FB2K_MAKE_SERVICE_COREAPI(read_ahead_tools);
501 public:
502 //! Turn any file object into asynchronous read-ahead-buffered file.
503 //! @param f File object to wrap. Do not call this object's method after a successful call to add_read_ahead; new file object takes over the ownership of it.
504 //! @param size Requested read-ahead bytes. Pass 0 to use user settings for local/remote playback.
505 virtual file::ptr add_read_ahead(file::ptr f, size_t size, abort_callback & aborter) = 0;
506
507 //! A helper method to use prior to opening decoders. \n
508 //! May open the file if needed or leave it blank for the decoder to open.
509 //! @param f File object to open if needed (buffering mandated by user settings). May be valid or null prior to call. May be valid or null (no buffering) after call.
510 //! @param path Path to open. May be null if f is not null. At least one of f and path must be valid prior to call.
511 virtual void open_file_helper(file::ptr & f, const char * path, abort_callback & aborter) = 0;
512 };
513
514 }
515
516 using namespace foobar2000_io;
517
518 #include "filesystem_helper.h"