LMMS
Loading...
Searching...
No Matches
dirscan.h
Go to the documentation of this file.
1/*
2 WDL - dirscan.h
3 Copyright (C) 2005 and later Cockos Incorporated
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/*
24
25 This file provides the interface and implementation for WDL_DirScan, a simple
26 (and somewhat portable) directory reading class. On non-Win32 systems it wraps
27 opendir()/readdir()/etc. On Win32, it uses FindFirst*, and supports wildcards as
28 well.
29
30
31*/
32
33
34#ifndef _WDL_DIRSCAN_H_
35#define _WDL_DIRSCAN_H_
36
37#include "wdlstring.h"
38
39#ifndef _WIN32
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <dirent.h>
43extern struct stat wdl_stat_chk;
44// if this fails on linux, use CFLAGS += -D_FILE_OFFSET_BITS=64
45typedef char wdl_dirscan_assert_failed_stat_not_64[sizeof(wdl_stat_chk.st_size)!=8 ? -1 : 1];
46#endif
47
49{
50 public:
52#ifdef _WIN32
53 m_h(INVALID_HANDLE_VALUE)
54 #ifndef WDL_NO_SUPPORT_UTF8
55 , m_wcmode(false)
56 #endif
57#else
59#endif
60 {
61 }
62
64 {
65 Close();
66 }
67
68 int First(const char *dirname
69#ifdef _WIN32
70 , int isExactSpec=0
71#endif
72 ) // returns 0 if success
73 {
74 WDL_FastString scanstr(dirname);
75 const int l = scanstr.GetLength();
76 if (l < 1) return -1;
77
78#ifdef _WIN32
79 if (!isExactSpec)
80 {
81 if (dirname[l-1] == '\\' || dirname[l-1] == '/') scanstr.SetLen(l-1);
82 m_leading_path = scanstr;
83 scanstr.Append("\\*");
84 }
85 else
86 {
87 m_leading_path = scanstr;
88
89 // remove trailing wildcards and directory separator from m_leading_path
90 const char *sp = m_leading_path.Get();
91 int idx = m_leading_path.GetLength() - 1;
92 while (idx > 0 && sp[idx] != '/' && sp[idx] != '\\') idx--;
93 if (idx > 0) m_leading_path.SetLen(idx);
94 }
95#else
96 if (dirname[l-1] == '\\' || dirname[l-1] == '/') scanstr.SetLen(l-1);
97 m_leading_path = scanstr;
98 if (!scanstr.GetLength()) scanstr.Set("/"); // fix for scanning /
99#endif
100
101 Close();
102#ifdef _WIN32
103 #ifndef WDL_NO_SUPPORT_UTF8
104 m_h=INVALID_HANDLE_VALUE;
105 #ifdef WDL_SUPPORT_WIN9X
106 m_wcmode = GetVersion()< 0x80000000;
107 #else
108 m_wcmode = true;
109 #endif
110
111 if (m_wcmode)
112 {
113 int reqbuf = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,scanstr.Get(),-1,NULL,0);
114 if (reqbuf > 1000)
115 {
117 tmp.Resize(reqbuf+20);
118 if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,scanstr.Get(),-1,tmp.Get(),tmp.GetSize()-10))
119 {
120 correctlongpath(tmp.Get());
121 m_h=FindFirstFileW(tmp.Get(),&m_fd);
122 }
123 }
124 else
125 {
126 WCHAR wfilename[1024];
127 if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,scanstr.Get(),-1,wfilename,1024-10))
128 {
129 correctlongpath(wfilename);
130 m_h=FindFirstFileW(wfilename,&m_fd);
131 }
132 }
133 }
134
135 if (m_h==INVALID_HANDLE_VALUE) m_wcmode=false;
136
137 if (m_h==INVALID_HANDLE_VALUE)
138 #endif
139 m_h=FindFirstFile(scanstr.Get(),(WIN32_FIND_DATA*)&m_fd);
140 return (m_h == INVALID_HANDLE_VALUE);
141#else
142 m_ent=0;
143 m_h=opendir(scanstr.Get());
144 return !m_h || Next();
145#endif
146 }
147 int Next() // returns 0 on success
148 {
149#ifdef _WIN32
150 if (m_h == INVALID_HANDLE_VALUE) return -1;
151 #ifndef WDL_NO_SUPPORT_UTF8
152 if (m_wcmode) return !FindNextFileW(m_h,&m_fd);
153 #endif
154 return !FindNextFile(m_h,(WIN32_FIND_DATA*)&m_fd);
155#else
156 if (!m_h) return -1;
157 return !(m_ent=readdir(m_h));
158#endif
159 }
160 void Close()
161 {
162#ifdef _WIN32
163 if (m_h != INVALID_HANDLE_VALUE) FindClose(m_h);
164 m_h=INVALID_HANDLE_VALUE;
165#else
166 if (m_h) closedir(m_h);
167 m_h=0; m_ent=0;
168#endif
169 }
170
171#ifdef _WIN32
172 const char *GetCurrentFN()
173 {
174#ifndef WDL_NO_SUPPORT_UTF8
175 if (m_wcmode)
176 {
177 if (!WideCharToMultiByte(CP_UTF8,0,m_fd.cFileName,-1,m_tmpbuf,sizeof(m_tmpbuf),NULL,NULL))
178 m_tmpbuf[0]=0;
179 return m_tmpbuf;
180 }
181#endif
182 return ((WIN32_FIND_DATA *)&m_fd)->cFileName;
183 }
184#else
185 const char *GetCurrentFN() const { return m_ent?m_ent->d_name : ""; }
186#endif
187 template<class T> void GetCurrentFullFN(T *str)
188 {
189 str->Set(m_leading_path.Get());
190#ifdef _WIN32
191 str->Append("\\");
192#else
193 str->Append("/");
194#endif
195 str->Append(GetCurrentFN());
196 }
197 int GetCurrentIsDirectory() const // returns 1 if dir, 2 if symlink to dir, 4 if possibly-recursive symlink to dir
198 {
199#ifdef _WIN32
200 return !!(m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
201#else
202 char tmp[2048];
203 if (m_ent) switch (m_ent->d_type)
204 {
205 case DT_DIR: return 1;
206 case DT_LNK:
207 {
208 snprintf(tmp,sizeof(tmp),"%s/%s",m_leading_path.Get(),m_ent->d_name);
209 char *rp = realpath(tmp,NULL);
210 if (!rp) return 0;
211
212 struct stat sb;
213 int ret = (!stat(rp,&sb) && (sb.st_mode & S_IFMT) == S_IFDIR) ? 2 : 0;
214 if (ret)
215 {
216 // treat symlinks of /path/to/foo -> /path from being resolved (avoiding obvious feedback loops)
217 const int rpl = (int) strlen(rp);
218 if (
219#ifdef __APPLE__
220 !strnicmp(rp,m_leading_path.Get(),rpl)
221#else
222 !strncmp(rp,m_leading_path.Get(),rpl)
223#endif
224 && (m_leading_path.Get()[rpl] == '/' || m_leading_path.Get()[rpl] == 0)
225 ) ret = 4;
226 }
227 free(rp);
228 return ret;
229 }
230 case DT_UNKNOWN:
231 {
232 snprintf(tmp,sizeof(tmp),"%s/%s",m_leading_path.Get(),m_ent->d_name);
233 DIR *d = opendir(tmp);
234 if (d) { closedir(d); return 1; }
235 return 0;
236 }
237 }
238 return 0;
239#endif
240 }
241
242 // these are somewhat windows specific calls, eh
243#ifdef _WIN32
244 DWORD GetCurrentFileSize(DWORD *HighWord=NULL) const { if (HighWord) *HighWord = m_fd.nFileSizeHigh; return m_fd.nFileSizeLow; }
245 void GetCurrentLastWriteTime(FILETIME *ft) const { *ft = m_fd.ftLastWriteTime; }
246 void GetCurrentLastAccessTime(FILETIME *ft) const { *ft = m_fd.ftLastAccessTime; }
247 void GetCurrentCreationTime(FILETIME *ft) const { *ft = m_fd.ftCreationTime; }
248 DWORD GetFileAttributes() const { return m_fd.dwFileAttributes; }
249#elif defined(_WDL_SWELL_H_)
250
251 void GetCurrentCreationTime(FILETIME *ft)
252 {
253 char tmp[2048];
254 snprintf(tmp,sizeof(tmp),"%s/%s",m_leading_path.Get(),GetCurrentFN());
255 struct stat st={0,};
256 stat(tmp,&st);
257 unsigned long long a=(unsigned long long)st.st_ctime; // seconds since january 1st, 1970
258 a+=11644473600ull; // 1601->1970
259 a*=10000000; // seconds to 1/10th microseconds (100 nanoseconds)
260 ft->dwLowDateTime=a & 0xffffffff;
261 ft->dwHighDateTime=a>>32;
262 }
263
264 void GetCurrentLastWriteTime(FILETIME *ft)
265 {
266 char tmp[2048];
267 snprintf(tmp,sizeof(tmp),"%s/%s",m_leading_path.Get(),GetCurrentFN());
268 struct stat st={0,};
269 stat(tmp,&st);
270 unsigned long long a=(unsigned long long)st.st_mtime; // seconds since january 1st, 1970
271 a+=11644473600ull; // 1601->1970
272 a*=10000000; // seconds to 1/10th microseconds (100 nanoseconds)
273 ft->dwLowDateTime=a & 0xffffffff;
274 ft->dwHighDateTime=a>>32;
275 }
276 DWORD GetCurrentFileSize(DWORD *HighWord=NULL)
277 {
278 char tmp[2048];
279 snprintf(tmp,sizeof(tmp),"%s/%s",m_leading_path.Get(),GetCurrentFN());
280 struct stat st={0,};
281 stat(tmp,&st);
282
283 if (HighWord) *HighWord = (DWORD)(st.st_size>>32);
284 return (DWORD)(st.st_size&0xffffffff);
285 }
286
287#endif
288
289 private:
290#ifdef _WIN32
291
292#ifndef WDL_NO_SUPPORT_UTF8
293 bool m_wcmode;
294 WIN32_FIND_DATAW m_fd;
295 char m_tmpbuf[MAX_PATH*5]; // even if each byte gets encoded as 4 utf-8 bytes this should be plenty ;)
296#else
297 WIN32_FIND_DATA m_fd;
298#endif
299 HANDLE m_h;
300#else
301 DIR *m_h;
302 struct dirent *m_ent;
303#endif
304 WDL_FastString m_leading_path;
305
306#ifdef _WIN32
307 static void correctlongpath(WCHAR *buf) // this also exists as wdl_utf8_correctlongpath
308 {
309 const WCHAR *insert;
310 WCHAR *wr;
311 int skip = 0;
312 if (!buf || !buf[0] || wcslen(buf) < 256) return;
313 if (buf[1] == ':') insert=L"\\\\?\\";
314 else if (buf[0] == '\\' && buf[1] == '\\') { insert = L"\\\\?\\UNC\\"; skip=2; }
315 else return;
316
317 wr = buf + wcslen(insert);
318 memmove(wr, buf + skip, (wcslen(buf+skip)+1)*2);
319 memmove(buf,insert,wcslen(insert)*2);
320 while (*wr)
321 {
322 if (*wr == '/') *wr = '\\';
323 wr++;
324 }
325 }
326#endif
328
329#endif
#define NULL
Definition CarlaBridgeFormat.cpp:30
uint8_t a
Definition Spc_Cpu.h:141
uint8_t sp
Definition Spc_Cpu.h:145
int First(const char *dirname)
Definition dirscan.h:68
DIR * m_h
Definition dirscan.h:301
int Next()
Definition dirscan.h:147
void Close()
Definition dirscan.h:160
int GetCurrentIsDirectory() const
Definition dirscan.h:197
const char * GetCurrentFN() const
Definition dirscan.h:185
WDL_FastString m_leading_path
Definition dirscan.h:304
struct dirent * m_ent
Definition dirscan.h:302
WDL_DirScan()
Definition dirscan.h:51
~WDL_DirScan()
Definition dirscan.h:63
void GetCurrentFullFN(T *str)
Definition dirscan.h:187
Definition heapbuf.h:259
PTRTYPE * Resize(int newsize, bool resizedown=true)
Definition heapbuf.h:265
int GetSize() const
Definition heapbuf.h:263
PTRTYPE * Get() const
Definition heapbuf.h:261
int * l
Definition inflate.c:1579
unsigned d
Definition inflate.c:940
char wdl_dirscan_assert_failed_stat_not_64[sizeof(wdl_stat_chk.st_size)!=8 ? -1 :1]
Definition dirscan.h:45
struct stat wdl_stat_chk
#define false
Definition ordinals.h:83
DWORD dwHighDateTime
Definition swell-types.h:244
DWORD dwLowDateTime
Definition swell-types.h:243
#define MAX_PATH
unsigned int DWORD
Definition swell-types.h:164
#define strnicmp(x, y, z)
Definition swell-types.h:71
void * HANDLE
Definition swell-types.h:212
else
Definition fileio.c:764
#define dirent
Definition unix.c:70
closedir((DIR *) G.wild_dir)
typedef int(UZ_EXP MsgFn)()
#define WDL_FIXALIGN
Definition wdltypes.h:85
#define const
Definition zconf.h:137