1 /*
2 Copyright (c) 2016-2021 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 module dlib.filesystem.stdwindowsdir;
30 
31 import std..string;
32 import std.conv;
33 import std.range;
34 import core.stdc..string;
35 import core.stdc.wchar_;
36 
37 version(Windows)
38 {
39     import core.sys.windows.windows;
40 }
41 
42 import dlib.core.memory;
43 import dlib.filesystem.filesystem;
44 import dlib.text.utf16;
45 
46 version(Windows):
47 
48 string unmanagedStrFromCStrW(wchar* cstr)
49 {
50     return cast(string)convertUTF16ztoUTF8(cstr);
51 }
52 
53 class StdWindowsDirEntryRange: InputRange!(DirEntry)
54 {
55     HANDLE hFind = INVALID_HANDLE_VALUE;
56     WIN32_FIND_DATAW findData;
57     DirEntry frontEntry;
58     bool _empty = false;
59     wchar* path;
60     bool initialized = false;
61 
62     this(wchar* cwstr)
63     {
64         this.path = cwstr;
65     }
66 
67     ~this()
68     {
69         if (frontEntry.name.length)
70             Delete(frontEntry.name);
71 
72         close();
73     }
74 
75     import std.stdio;
76 
77     bool advance()
78     {
79         bool success = false;
80 
81         if (frontEntry.name.length)
82             Delete(frontEntry.name);
83 
84         if (!initialized)
85         {
86             hFind = FindFirstFileW(path, &findData);
87             initialized = true;
88             if (hFind != INVALID_HANDLE_VALUE)
89                 success = true;
90 
91             string name = unmanagedStrFromCStrW(findData.cFileName.ptr);
92             if (name == "." || name == "..")
93             {
94                 success = false;
95                 Delete(name);
96             }
97             else
98             {
99                 bool isDir = cast(bool)(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
100                 bool isFile = !isDir;
101                 frontEntry = DirEntry(name, isFile, isDir);
102             }
103         }
104 
105         if (!success && hFind != INVALID_HANDLE_VALUE)
106         {
107             string name;
108             while(!success)
109             {
110                 auto r = FindNextFileW(hFind, &findData);
111                 if (!r)
112                     break;
113 
114                 name = unmanagedStrFromCStrW(findData.cFileName.ptr);
115                 if (name != "." && name != "..")
116                     success = true;
117                 else
118                     Delete(name);
119             }
120 
121             if (success)
122             {
123                 bool isDir = cast(bool)(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
124                 bool isFile = !isDir;
125                 frontEntry = DirEntry(name, isFile, isDir);
126             }
127         }
128 
129         if (!success)
130         {
131             FindClose(hFind);
132             hFind = INVALID_HANDLE_VALUE;
133         }
134 
135         return success;
136     }
137 
138     override DirEntry front()
139     {
140         return frontEntry;
141     }
142 
143     override void popFront()
144     {
145         _empty = !advance();
146     }
147 
148     override DirEntry moveFront()
149     {
150         _empty = !advance();
151         return frontEntry;
152     }
153 
154     override bool empty()
155     {
156         return _empty;
157     }
158 
159     int opApply(scope int delegate(DirEntry) dg)
160     {
161         int result = 0;
162 
163         for (size_t i = 0; !empty; i++)
164         {
165             popFront();
166             if (!empty())
167                 result = dg(frontEntry);
168 
169             if (result != 0)
170                 break;
171         }
172 
173         return result;
174     }
175 
176     int opApply(scope int delegate(size_t, DirEntry) dg)
177     {
178         int result = 0;
179 
180         for (size_t i = 0; !empty; i++)
181         {
182             popFront();
183             if (!empty())
184                 result = dg(i, frontEntry);
185 
186             if (result != 0)
187                 break;
188         }
189 
190         return result;
191     }
192 
193     void reset()
194     {
195         close();
196     }
197 
198     void close()
199     {
200         if (hFind != INVALID_HANDLE_VALUE)
201         {
202             FindClose(hFind);
203             hFind = INVALID_HANDLE_VALUE;
204         }
205         initialized = false;
206         _empty = false;
207     }
208 }
209 
210 class StdWindowsDirectory: Directory
211 {
212     StdWindowsDirEntryRange drange;
213     wchar* path;
214 
215     this(wchar* cwstr)
216     {
217         path = cwstr;
218         drange = New!StdWindowsDirEntryRange(path);
219     }
220 
221     void close()
222     {
223         drange.close();
224     }
225 
226     StdWindowsDirEntryRange contents()
227     {
228         if (drange)
229             drange.reset();
230         return drange;
231     }
232 
233     ~this()
234     {
235         Delete(drange);
236         drange = null;
237         Delete(path);
238     }
239 }