comparison deps/Platinum/ThirdParty/Neptune/Source/System/Win32/NptWin32File.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3425707ddbf6
1 /*****************************************************************
2 |
3 | Neptune - File :: Win32 Implementation
4 |
5 | (c) 2001-2008 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
7 |
8 ****************************************************************/
9
10 /*----------------------------------------------------------------------
11 | includes
12 +---------------------------------------------------------------------*/
13 #include "NptLogging.h"
14 #include "NptFile.h"
15 #include "NptUtils.h"
16
17 #if defined(_XBOX)
18 #include <xtl.h>
19 #else
20 #include <windows.h>
21 #include <malloc.h>
22 #include <limits.h>
23 #endif
24 #include <assert.h>
25
26
27 /*----------------------------------------------------------------------
28 | logging
29 +---------------------------------------------------------------------*/
30 //NPT_SET_LOCAL_LOGGER("neptune.win32.file")
31
32 /*----------------------------------------------------------------------
33 | fix windows macros
34 +---------------------------------------------------------------------*/
35 #if !defined(_WIN32_WCE)
36 #if defined(CreateDirectory)
37 #undef CreateDirectory
38 #endif
39
40 #if defined(DeleteFile)
41 #undef DeleteFile
42 #endif
43 #endif
44
45 /*----------------------------------------------------------------------
46 | A2WHelper
47 +---------------------------------------------------------------------*/
48 static LPWSTR A2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
49 {
50 int ret;
51
52 assert(lpa != NULL);
53 assert(lpw != NULL);
54 if (lpw == NULL || lpa == NULL) return NULL;
55
56 lpw[0] = '\0';
57 ret = MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
58 if (ret == 0) {
59 assert(0);
60 return NULL;
61 }
62 return lpw;
63 }
64
65 /*----------------------------------------------------------------------
66 | W2AHelper
67 +---------------------------------------------------------------------*/
68 static LPSTR W2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp)
69 {
70 int ret;
71
72 assert(lpw != NULL);
73 assert(lpa != NULL);
74 if (lpa == NULL || lpw == NULL) return NULL;
75
76 lpa[0] = '\0';
77 ret = WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
78 if (ret == 0) {
79 assert(0);
80 return NULL;
81 }
82 return lpa;
83 }
84
85 /*----------------------------------------------------------------------
86 | macros
87 +---------------------------------------------------------------------*/
88 /* UNICODE support */
89 #if !defined(_XBOX)
90 #define NPT_WIN32_USE_CHAR_CONVERSION int _convert = 0; LPCWSTR _lpw = NULL; LPCSTR _lpa = NULL
91
92 #define NPT_WIN32_A2W(lpa) (\
93 ((_lpa = lpa) == NULL) ? NULL : (\
94 _convert = (int)(strlen(_lpa)+1),\
95 (INT_MAX/2<_convert)? NULL : \
96 A2WHelper((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, CP_UTF8)))
97
98 #define NPT_WIN32_W2A(lpw) (\
99 ((_lpw = lpw) == NULL) ? NULL : (\
100 (_convert = (lstrlenW(_lpw)+1), \
101 (_convert>INT_MAX/2) ? NULL : \
102 W2AHelper((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, _convert*sizeof(WCHAR), CP_UTF8))))
103
104 #else
105 #define NPT_WIN32_USE_CHAR_CONVERSION
106 #define NPT_WIN32_W2A(_s) (_s)
107 #define NPT_WIN32_A2W(_s) (_s)
108 #define GetFileAttributesW GetFileAttributes
109 #define FindFirstFileW FindFirstFile
110 #define FindNextFileW FindNextFile
111 #define FindCloseW FindClose
112 #define CreateDirectoryW CreateDirectoryA
113 #define RemoveDirectoryW RemoveDirectoryA
114 #define DeleteFileW DeleteFileA
115 #define MoveFileW MoveFileA
116 #define WIN32_FIND_DATAW WIN32_FIND_DATA
117 #endif
118
119 /*----------------------------------------------------------------------
120 | MapError
121 +---------------------------------------------------------------------*/
122 static NPT_Result
123 MapError(DWORD err) {
124 switch (err) {
125 case ERROR_ALREADY_EXISTS: return NPT_ERROR_FILE_ALREADY_EXISTS;
126 case ERROR_PATH_NOT_FOUND:
127 case ERROR_FILE_NOT_FOUND:
128 case ERROR_INVALID_DRIVE:
129 case ERROR_BAD_PATHNAME:
130 case ERROR_BAD_NET_NAME:
131 case ERROR_FILENAME_EXCED_RANGE:
132 case ERROR_NO_MORE_FILES:
133 case ERROR_BAD_NETPATH: return NPT_ERROR_NO_SUCH_FILE;
134 case ERROR_LOCK_VIOLATION:
135 case ERROR_SEEK_ON_DEVICE:
136 case ERROR_CURRENT_DIRECTORY:
137 case ERROR_CANNOT_MAKE:
138 case ERROR_FAIL_I24:
139 case ERROR_NETWORK_ACCESS_DENIED:
140 case ERROR_DRIVE_LOCKED:
141 case ERROR_ACCESS_DENIED: return NPT_ERROR_PERMISSION_DENIED;
142 case ERROR_NOT_LOCKED:
143 case ERROR_LOCK_FAILED:
144 case ERROR_SHARING_VIOLATION: return NPT_ERROR_FILE_BUSY;
145 case ERROR_INVALID_FUNCTION: return NPT_ERROR_INTERNAL;
146 case ERROR_NOT_ENOUGH_QUOTA: return NPT_ERROR_OUT_OF_MEMORY;
147 case ERROR_ARENA_TRASHED:
148 case ERROR_NOT_ENOUGH_MEMORY:
149 case ERROR_INVALID_BLOCK: return NPT_ERROR_OUT_OF_MEMORY;
150 case ERROR_DISK_FULL: return NPT_ERROR_FILE_NOT_ENOUGH_SPACE;
151 case ERROR_TOO_MANY_OPEN_FILES: return NPT_ERROR_OUT_OF_RESOURCES;
152 case ERROR_INVALID_HANDLE:
153 case ERROR_INVALID_ACCESS:
154 case ERROR_INVALID_DATA: return NPT_ERROR_INVALID_PARAMETERS;
155 case ERROR_DIR_NOT_EMPTY: return NPT_ERROR_DIRECTORY_NOT_EMPTY;
156 case ERROR_NEGATIVE_SEEK: return NPT_ERROR_OUT_OF_RANGE;
157 default: return NPT_FAILURE;
158 }
159 }
160
161 #if defined(_WIN32_WCE)
162 /*----------------------------------------------------------------------
163 | NPT_stat_utf8
164 +---------------------------------------------------------------------*/
165 int
166 NPT_stat_utf8(const char* path, struct __stat64* info)
167 {
168 return -1;
169 }
170
171 /*----------------------------------------------------------------------
172 | NPT_getcwd_utf8
173 +---------------------------------------------------------------------*/
174 char*
175 NPT_getcwd_utf8(char* dir, int max_size)
176 {
177 return NULL;
178 }
179
180 /*----------------------------------------------------------------------
181 | NPT_fopen_utf8
182 +---------------------------------------------------------------------*/
183 FILE*
184 NPT_fopen_utf8(const char* path, const char* mode)
185 {
186 NPT_WIN32_USE_CHAR_CONVERSION;
187 return _wfopen(NPT_WIN32_A2W(path), NPT_WIN32_A2W(mode));
188 }
189 #elif defined(_XBOX)
190 #include <sys/stat.h>
191 /*----------------------------------------------------------------------
192 | NPT_stat_utf8
193 +---------------------------------------------------------------------*/
194 int
195 NPT_stat_utf8(const char* path, struct __stat64* info)
196 {
197 return _stat64(path, info);
198 }
199
200 /*----------------------------------------------------------------------
201 | NPT_getcwd_utf8
202 +---------------------------------------------------------------------*/
203 char*
204 NPT_getcwd_utf8(char* dir, unsigned int max_size)
205 {
206 return NULL;
207 }
208
209 /*----------------------------------------------------------------------
210 | NPT_fsopen_utf8
211 +---------------------------------------------------------------------*/
212 FILE*
213 NPT_fsopen_utf8(const char* path, const char* mode, int sh_flags)
214 {
215 NPT_WIN32_USE_CHAR_CONVERSION;
216 return _fsopen(path, mode, sh_flags);
217 }
218 #else
219 #include <sys/stat.h>
220 #include <direct.h>
221
222 /*----------------------------------------------------------------------
223 | NPT_stat_utf8
224 +---------------------------------------------------------------------*/
225 int
226 NPT_stat_utf8(const char* path, struct __stat64* info)
227 {
228 NPT_WIN32_USE_CHAR_CONVERSION;
229 return _wstat64(NPT_WIN32_A2W(path), info);
230 }
231
232 /*----------------------------------------------------------------------
233 | NPT_getcwd_utf8
234 +---------------------------------------------------------------------*/
235 char*
236 NPT_getcwd_utf8(char* dir, unsigned int max_size)
237 {
238 NPT_WIN32_USE_CHAR_CONVERSION;
239 WCHAR* wdir = (WCHAR*)alloca(2*(max_size+1));
240 WCHAR* result = _wgetcwd(wdir, max_size);
241 if (result == NULL) return NULL;
242 char* converted = NPT_WIN32_W2A(result);
243 NPT_CopyString(dir, converted);
244 return dir;
245 }
246
247 /*----------------------------------------------------------------------
248 | NPT_fsopen_utf8
249 +---------------------------------------------------------------------*/
250 FILE*
251 NPT_fsopen_utf8(const char* path, const char* mode, int sh_flags)
252 {
253 NPT_WIN32_USE_CHAR_CONVERSION;
254 return _wfsopen(NPT_WIN32_A2W(path), NPT_WIN32_A2W(mode + NPT_String(", ccs=UNICODE")), sh_flags);
255 }
256 #endif
257
258 /*----------------------------------------------------------------------
259 | NPT_FilePath::Separator
260 +---------------------------------------------------------------------*/
261 const NPT_String NPT_FilePath::Separator("\\");
262
263 /*----------------------------------------------------------------------
264 | NPT_File::GetRoots
265 +---------------------------------------------------------------------*/
266 NPT_Result
267 NPT_File::GetRoots(NPT_List<NPT_String>& roots)
268 {
269 roots.Clear();
270 #if defined(_WIN32_WCE) || defined(_XBOX)
271 return NPT_ERROR_NOT_IMPLEMENTED;
272 #else
273 DWORD drives = GetLogicalDrives();
274 for (unsigned int i=0; i<26; i++) {
275 if (drives & (1<<i)) {
276 char drive_name[4] = {'A'+i, ':', '\\', 0};
277 roots.Add(drive_name);
278 }
279 }
280 return NPT_SUCCESS;
281 #endif
282 }
283
284 #if defined(_WIN32_WCE)
285 /*----------------------------------------------------------------------
286 | NPT_File::GetWorkingDirectory
287 +---------------------------------------------------------------------*/
288 NPT_Result
289 NPT_File::GetWorkingDirectory(NPT_String& path)
290 {
291 path.SetLength(0);
292 return NPT_ERROR_NOT_IMPLEMENTED;
293 }
294
295 /*----------------------------------------------------------------------
296 | NPT_File::GetInfo
297 +---------------------------------------------------------------------*/
298 NPT_Result
299 NPT_File::GetInfo(const char* path, NPT_FileInfo* info)
300 {
301 return NPT_ERROR_NOT_IMPLEMENTED;
302 }
303 #endif
304
305 /*----------------------------------------------------------------------
306 | NPT_File::CreateDirectory
307 +---------------------------------------------------------------------*/
308 NPT_Result
309 NPT_File::CreateDirectory(const char* path)
310 {
311 NPT_WIN32_USE_CHAR_CONVERSION;
312 BOOL result = ::CreateDirectoryW(NPT_WIN32_A2W(path), NULL);
313 if (result == 0) {
314 return MapError(GetLastError());
315 }
316 return NPT_SUCCESS;
317 }
318
319 /*----------------------------------------------------------------------
320 | NPT_File::DeleteFile
321 +---------------------------------------------------------------------*/
322 NPT_Result
323 NPT_File::DeleteFile(const char* path)
324 {
325 NPT_WIN32_USE_CHAR_CONVERSION;
326 BOOL result = ::DeleteFileW(NPT_WIN32_A2W(path));
327 if (result == 0) {
328 return MapError(GetLastError());
329 }
330 return NPT_SUCCESS;
331 }
332
333 /*----------------------------------------------------------------------
334 | NPT_File::DeleteDirectory
335 +---------------------------------------------------------------------*/
336 NPT_Result
337 NPT_File::DeleteDirectory(const char* path)
338 {
339 NPT_WIN32_USE_CHAR_CONVERSION;
340 BOOL result = RemoveDirectoryW(NPT_WIN32_A2W(path));
341 if (result == 0) {
342 return MapError(GetLastError());
343 }
344 return NPT_SUCCESS;
345 }
346
347 /*----------------------------------------------------------------------
348 | NPT_File::Rename
349 +---------------------------------------------------------------------*/
350 NPT_Result
351 NPT_File::Rename(const char* from_path, const char* to_path)
352 {
353 NPT_WIN32_USE_CHAR_CONVERSION;
354 BOOL result = MoveFileW(NPT_WIN32_A2W(from_path), NPT_WIN32_A2W(to_path));
355 if (result == 0) {
356 return MapError(GetLastError());
357 }
358 return NPT_SUCCESS;
359 }
360
361 /*----------------------------------------------------------------------
362 | NPT_File_ProcessFindData
363 +---------------------------------------------------------------------*/
364 static bool
365 NPT_File_ProcessFindData(WIN32_FIND_DATAW* find_data)
366 {
367 NPT_WIN32_USE_CHAR_CONVERSION;
368
369 // discard system specific files/shortcuts
370 if (NPT_StringsEqual(NPT_WIN32_W2A(find_data->cFileName), ".") ||
371 NPT_StringsEqual(NPT_WIN32_W2A(find_data->cFileName), "..")) {
372 return false;
373 }
374
375 return true;
376 }
377
378 /*----------------------------------------------------------------------
379 | NPT_File::ListDirectory
380 +---------------------------------------------------------------------*/
381 NPT_Result
382 NPT_File::ListDirectory(const char* path,
383 NPT_List<NPT_String>& entries,
384 NPT_Ordinal start /* = 0 */,
385 NPT_Cardinal max /* = 0 */)
386 {
387 NPT_WIN32_USE_CHAR_CONVERSION;
388
389 // default return value
390 entries.Clear();
391
392 // check the arguments
393 if (path == NULL || path[0] == '\0') return NPT_ERROR_INVALID_PARAMETERS;
394
395 // construct a path name with a \* wildcard at the end
396 NPT_String path_pattern = path;
397 if (path_pattern.EndsWith("\\") || path_pattern.EndsWith("/")) {
398 path_pattern += "*";
399 } else {
400 path_pattern += "\\*";
401 }
402
403 // list the entries
404 WIN32_FIND_DATAW find_data;
405 HANDLE find_handle = FindFirstFileW(NPT_WIN32_A2W(path_pattern.GetChars()), &find_data);
406 if (find_handle == INVALID_HANDLE_VALUE) return MapError(GetLastError());
407 NPT_Cardinal count = 0;
408 do {
409 if (NPT_File_ProcessFindData(&find_data)) {
410 // continue if not yet first item requested
411 if (start > 0) {
412 --start;
413 continue;
414 }
415 entries.Add(NPT_WIN32_W2A(find_data.cFileName));
416
417 // stop when reaching maximum requested
418 if (max && ++count == max) return NPT_SUCCESS;
419 }
420 } while (FindNextFileW(find_handle, &find_data));
421 DWORD last_error = GetLastError();
422 FindClose(find_handle);
423 if (last_error != ERROR_NO_MORE_FILES) return MapError(last_error);
424
425 return NPT_SUCCESS;
426 }