YSTest: FileSystem.cpp 源文件

YSTest PreAlpha_b500_20140530 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

全部 类 命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义 组 页
YCLib/FileSystem.cpp
浏览该文件的文档.
1 /*
2 © 2012-2014 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "YCLib/YModules.h"
29 #include "CHRLib/YModules.h"
30 #include YFM_YCLib_FileSystem
31 #include YFM_YCLib_NativeAPI
32 #include YFM_CHRLib_CharacterProcessing
33 #include <cstring> // for std::strcpy, std::strchr;
34 #if YCL_DS
35 # include <fcntl.h>
36
38 extern "C" int _EXFUN(fileno, (FILE *));
39 #elif YCL_Win32
40 # if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
41 // At least one headers of <stdlib.h>, <stdio.h>, <windows.h>, <windef.h>
42 // (and probably more) should have been included to make the MinGW-W64 macro
43 // available if it is really being used.
45
46 extern "C" _CRTIMP int __cdecl __MINGW_NOTHROW
47 _fileno(::FILE*);
48
49 extern "C" _CRTIMP ::FILE* __cdecl __MINGW_NOTHROW
50 _wfopen(const wchar_t*, const wchar_t*);
52 # endif
53 # include <Shlwapi.h> // for ::PathIsRelativeW;
54 #elif YCL_Android
55 # include <fcntl.h>
56 # include <dirent.h>
57 # include <sys/stat.h>
58 #endif
59
61 using namespace CHRLib;
62
63 namespace platform
64 {
65
66 static_assert(std::is_same<CHRLib::ucs2_t, char16_t>::value,
67 "Wrong character type found.");
68 static_assert(std::is_same<CHRLib::ucs4_t, char32_t>::value,
69 "Wrong character type found.");
70 #if YCL_Win32
71 static_assert(sizeof(wchar_t) == sizeof(CHRLib::ucs2_t),
72 "Wrong character type found.");
73 static_assert(yalignof(wchar_t) == yalignof(CHRLib::ucs2_t),
74 "Inconsistent alignment between character types found.");
75 #endif
76
77 namespace
78 {
79
80 #if YCL_DS || YCL_Android
81 #elif YCL_MinGW32
82 std::wstring
83 u_to_w(const char* str)
84 {
85 return std::wstring(reinterpret_cast<const wchar_t*>(ucsdup(str).c_str()));
86 }
87
88
90
91 class DirEnv
92 {
93 public:
94 std::wstring d_name;
95 WIN32_FIND_DATAW& find_data;
96
97 DirEnv(std::wstring&, ::WIN32_FIND_DATAW&);
98
99 DefGetter(const ynothrow, ::DWORD, Attributes, find_data.dwFileAttributes)
100 };
101
102 DirEnv::DirEnv(std::wstring& dir_name, ::WIN32_FIND_DATAW& win32_fdata)
103 : d_name(), find_data(win32_fdata)
104 {
105 yconstraint(!dir_name.empty() && dir_name.back() != '\\');
106
107 const auto r(::GetFileAttributesW(dir_name.c_str()));
108
109 if(r != INVALID_FILE_ATTRIBUTES && r & FILE_ATTRIBUTE_DIRECTORY)
110 dir_name += L"\\*";
111 else
112 throw FileOperationFailure("Opening directory failed.");
113 }
114
115
116 class DirectoryData : private ystdex::noncopyable
117 {
118 private:
119 std::wstring dir_name;
120 ::WIN32_FIND_DATAW find_data;
121 ::HANDLE h_node;
122 DirEnv posix_dir;
123
124 public:
125 DirectoryData(const char*);
126 ~DirectoryData();
127
128 DefGetterMem(const ynothrow, ::DWORD, Attributes, posix_dir)
129
130 private:
131 void
132 Close() ynothrow;
133
134 public:
135 DirEnv*
136 Read();
137
138 void
139 Rewind() ynothrow;
140 };
141
142 DirectoryData::DirectoryData(const char* name)
143 : dir_name(ystdex::rtrim(u_to_w(name), L"/\\")),
144 find_data(), h_node(), posix_dir(dir_name, find_data)
145 {}
146 DirectoryData::~DirectoryData()
147 {
148 if(h_node)
149 Close();
150 }
151
152 void
153 DirectoryData::Close() ynothrow
154 {
155 const auto res(::FindClose(h_node));
156
157 YAssert(res, "No valid directory found.");
158 yunused(res);
159 }
160
161 DirEnv*
162 DirectoryData::Read()
163 {
164 if(!h_node)
165 {
166 // NOTE: See MSDN "FindFirstFile function" for details.
167 yassume(!dir_name.empty());
168 yassume(dir_name.back() != L'\\');
169 if((h_node = ::FindFirstFileW(dir_name.c_str(), &find_data))
170 == INVALID_HANDLE_VALUE)
171 h_node = {};
172 }
173 else if(!::FindNextFileW(h_node, &find_data))
174 {
175 Close();
176 h_node = {};
177 }
178 if(h_node && h_node != INVALID_HANDLE_VALUE)
179 {
180 yassume(find_data.cFileName);
181 posix_dir.d_name = find_data.cFileName;
182 }
183 return !h_node ? nullptr : &posix_dir;
184 }
185
186 void
187 DirectoryData::Rewind() ynothrow
188 {
189 if(h_node)
190 {
191 Close();
192 h_node = {};
193 }
194 }
196 #else
197 # error "Unsupported platform found."
198 #endif
199
200 } // unnamed namespace;
201
202
203 int
204 uopen(const char* filename, int oflag) ynothrow
205 {
206 yconstraint(filename);
207 #if !YCL_Win32
208 return ::open(filename, oflag);
209 #else
210 try
211 {
212 return ::_wopen(u_to_w(filename).c_str(), oflag);
213 }
214 catch(...)
215 {}
216 return -1;
217 #endif
218 }
219 int
220 uopen(const char* filename, int oflag, int pmode) ynothrow
221 {
222 yconstraint(filename);
223 #if !YCL_Win32
224 return ::open(filename, oflag, pmode);
225 #else
226 try
227 {
228 return ::_wopen(u_to_w(filename).c_str(), oflag, pmode);
229 }
230 catch(...)
231 {}
232 return -1;
233 #endif
234 }
235 int
236 uopen(const char16_t* filename, int oflag) ynothrow
237 {
238 yconstraint(filename);
239 #if !YCL_Win32
240 try
241 {
242 return ::open(strdup(filename).c_str(), oflag);
243 }
244 catch(...)
245 {}
246 return -1;
247 #else
248 return ::_wopen(reinterpret_cast<const wchar_t*>(filename), oflag);
249 #endif
250 }
251 int
252 uopen(const char16_t* filename, int oflag, int pmode) ynothrow
253 {
254 yconstraint(filename);
255 #if !YCL_Win32
256 try
257 {
258 return ::open(strdup(filename).c_str(), oflag, pmode);
259 }
260 catch(...)
261 {}
262 return -1;
263 #else
264 return ::_wopen(reinterpret_cast<const wchar_t*>(filename), oflag, pmode);
265 #endif
266 }
267
268 std::FILE*
269 ufopen(const char* filename, const char* mode) ynothrow
270 {
271 yconstraint(filename),
272 yconstraint(mode);
273 yconstraint(*mode != char());
274 #if !YCL_Win32
275 return std::fopen(filename, mode);
276 #else
277 try
278 {
279 return ::_wfopen(u_to_w(filename).c_str(), u_to_w(mode).c_str());
280 }
281 catch(...)
282 {}
283 return nullptr;
284 #endif
285 }
286 std::FILE*
287 ufopen(const char16_t* filename, const char16_t* mode) ynothrow
288 {
289 yconstraint(filename),
290 yconstraint(mode);
291 yconstraint(*mode != char());
292 #if !YCL_Win32
293 try
294 {
295 return std::fopen(strdup(filename).c_str(), strdup(mode).c_str());
296 }
297 catch(...)
298 {}
299 return nullptr;
300 #else
301 return ::_wfopen(reinterpret_cast<const wchar_t*>(filename),
302 reinterpret_cast<const wchar_t*>(mode));
303 #endif
304 }
305
306 bool
307 ufexists(const char* filename) ynothrow
308 {
309 #if !YCL_Win32
310 return ystdex::fexists(filename);
311 #else
312 yconstraint(filename);
313 if(const auto file = ufopen(filename, "rb"))
314 {
315 std::fclose(file);
316 return true;
317 }
318 return false;
319 #endif
320 }
321 bool
322 ufexists(const char16_t* filename) ynothrow
323 {
324 yconstraint(filename);
325
326 if(const auto file = ufopen(filename, u"rb"))
327 {
328 std::fclose(file);
329 return true;
330 }
331 return false;
332 }
333
334 char16_t*
335 u16getcwd_n(char16_t* buf, std::size_t size) ynothrow
336 {
337 if(size == 0)
338 // last_err = EINVAL;
339 ;
340 else
341 {
342 using namespace std;
343 using namespace CHRLib;
344
345 if(YB_LIKELY(buf))
346 #if !YCL_Win32
347 {
348 const auto p(static_cast<ucs2_t*>(malloc((size + 1)
349 * sizeof(ucs2_t))));
350
351 if(YB_LIKELY(p))
352 {
353 auto len(MBCSToUCS2(p,
354 ::getcwd(reinterpret_cast<char*>(buf), size)));
355
356 if(size < len + 1)
357 {
358 // last_err = ERANGE;
359 return nullptr;
360 }
361 memcpy(buf, p, ++len * sizeof(ucs2_t));
362 return buf;
363 }
364 // else
365 // last_err = ENOMEM;
366 }
367 #else
368 return reinterpret_cast< ucs2_t*>(
369 ::_wgetcwd(reinterpret_cast<wchar_t*>(buf), size));
370 #endif
371 }
372 return nullptr;
373 }
374
376 #define YCL_FileSystem_ufunc_impl1(_n) \
377 bool \
378 _n(const char* path) ynothrow \
379 { \
380 yconstraint(path); \
381
382 #if !YCL_Win32
383 # define YCL_FileSystem_ufunc_impl2(_fn, _wfn) \
385 return _fn(path) == 0; \
386 }
387 #else
388 # define YCL_FileSystem_ufunc_impl2(_fn, _wfn) \
390 try \
391 { \
392 return _wfn(u_to_w(path).c_str()) == 0; \
393 } \
394 catch(...) \
395 {} \
396 return false; \
397 }
398 #endif
399
401 #define YCL_FileSystem_ufunc_impl(_n, _fn, _wfn) \
402 YCL_FileSystem_ufunc_impl1(_n) \
403 YCL_FileSystem_ufunc_impl2(_fn, _wfn)
404
405 YCL_FileSystem_ufunc_impl(uchdir, ::chdir, ::_wchdir)
406
407 YCL_FileSystem_ufunc_impl1(umkdir)
408 #if !YCL_Win32
409 return ::mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == 0;
410 }
411 #else
412 YCL_FileSystem_ufunc_impl2(_unused_, ::_wmkdir)
413 #endif
414
415 YCL_FileSystem_ufunc_impl(urmdir, ::rmdir, ::_wrmdir)
416
417 YCL_FileSystem_ufunc_impl(uunlink, ::unlink, ::_wunlink)
418
419 YCL_FileSystem_ufunc_impl(uremove, std::remove, ::_wremove)
420
421 #undef YCL_FileSystem_ufunc_impl1
422 #undef YCL_FileSystem_ufunc_impl2
423 #undef YCL_FileSystem_ufunc_impl
424
425 bool
426 truncate(std::FILE* fp, std::size_t size) ynothrow
427 {
428 #if !YCL_Win32
429 return ::ftruncate(fileno(fp), ::off_t(size)) == 0;
430 #else
431 return ::_chsize(::_fileno(fp), long(size)) == 0;
432 #endif
433 }
434
435
436 std::uint64_t
437 GetFileSizeOf(int fd)
438 {
439 #if !YCL_Win32
440 struct ::stat st;
441
442 if(::fstat(fd, &st) == 0)
443 return st.st_size;
444 #else
445 ::LARGE_INTEGER sz;
446
447 // XXX: Error handling for indirect calls.
448 if(::GetFileSizeEx(::HANDLE(::_get_osfhandle(fd)), &sz) != 0
449 && YB_LIKELY(sz.QuadPart >= 0))
450 return sz.QuadPart;
451 #endif
452 throw FileOperationFailure("Failed getting file size.");
453 }
454 std::uint64_t
455 GetFileSizeOf(std::FILE* fp)
456 {
457 yconstraint(fp);
458 #ifdef YCL_API_FILESYSTEM_POSIX
459 return GetFileSizeOf(fileno(fp));
460 #else
461 return GetFileSizeOf(::_fileno(fp));
462 #endif
463 }
464
465
466 DirectorySession::DirectorySession(const char* path)
467 : dir(
468 #if !YCL_Win32
469 ::opendir
470 #else
471 new DirectoryData
472 #endif
473 (path && *path != '\0' ? path : ".")
474 )
475 {
476 if(!dir)
477 throw FileOperationFailure("Opening directory failed.");
478 }
479 DirectorySession::~DirectorySession()
480 {
481 #if !YCL_Win32
482 const auto res(::closedir(dir));
483
484 YAssert(res == 0, "No valid directory found.");
485 yunused(res);
486 #else
487 delete static_cast<DirectoryData*>(dir);
488 #endif
489 }
490
491 void
492 DirectorySession::Rewind() ynothrow
493 {
494 YAssert(dir, "Invalid native handle found.");
495 #if !YCL_Win32
496 ::rewinddir(dir);
497 #else
498 static_cast<DirectoryData*>(dir)->Rewind();
499 #endif
500 }
501
502
503 HDirectory&
504 HDirectory::operator++()
505 {
506 #if !YCL_Win32
507 p_dirent = ::readdir(GetNativeHandle());
508 #else
509 p_dirent = static_cast<DirectoryData*>(GetNativeHandle())->Read();
510 #endif
511 return *this;
512 }
513
514 NodeCategory
515 HDirectory::GetNodeCategory() const ynothrow
516 {
517 if(p_dirent)
518 {
519 #if !YCL_Win32
520 return p_dirent->d_type & DT_DIR ? NodeCategory::Directory
521 : NodeCategory::Regular;
522 #else
523 return static_cast<DirectoryData*>(GetNativeHandle())->GetAttributes()
524 & FILE_ATTRIBUTE_DIRECTORY ? NodeCategory::Directory
525 : NodeCategory::Regular;
526 #endif
527 }
528 return NodeCategory::Empty;
529 }
530
531 const char*
532 HDirectory::GetName() const ynothrow
533 {
534 if(p_dirent)
535 {
536 #if !YCL_Win32
537 return p_dirent->d_name;
538 #else
539 try
540 {
541 utf8_name = strdup(reinterpret_cast<const char16_t*>(
542 (static_cast<DirEnv*>(p_dirent))->d_name.c_str()));
543 return &utf8_name[0];
544 }
545 catch(...)
546 {}
547 #endif
548 }
549 return ".";
550 }
551
552
553 bool
554 IsAbsolute(const char* path)
555 {
556 #if !YCL_Win32
557 if(path)
558 {
559 if(*path == '/')
560 return true;
561
562 const auto p(std::strstr(path, ":/"));
563
564 return p && p != path && !std::strstr(p, ":/");
565 }
566 return false;
567 #else
568 return !::PathIsRelativeW(u_to_w(path).c_str());
569 #endif
570 }
571
572 std::size_t
573 GetRootNameLength(const char* path)
574 {
575 const char* p(std::strchr(path, ':'));
576
577 return !p ? 0 : p - path + 1;
578 }
579
580 }
581
582 namespace platform_ex
583 {
584
585 #if !YCL_Win32
586 char16_t
587 FS_IsRoot(const char16_t* str)
588 {
589 const std::u16string ustr(str);
590 #if YCL_DS
591 return ustr == u"/" || ustr == u"fat:/" || ustr == u"sd:/";
592 #else
593 return ustr == u"/";
594 #endif
595 }
596 #endif
597
598 }
599
platform::u16getcwd_n
char16_t * u16getcwd_n(char16_t *buf, std::size_t size) ynothrow
Definition: YCLib/FileSystem.cpp:335
CHRLib::fp
std::FILE ConversionState fp
Definition: chrproc.h:88
platform::NodeCategory::Regular
platform::IsAbsolute
YF_API bool IsAbsolute(const char *)
判断指定路径字符串是否表示一个绝对路径。
Definition: YCLib/FileSystem.cpp:554
CHRLib::strdup
YF_API std::string strdup(const ucs2_t *, Encoding=CS_Default)
复制 UCS-2 字符串为多字节字符串。
Definition: chrproc.cpp:162
platform::truncate
YF_API bool truncate(std::FILE *, std::size_t) ynothrow
截断文件至指定长度。
Definition: YCLib/FileSystem.cpp:426
platform::GetRootNameLength
YF_API std::size_t GetRootNameLength(const char *)
取指定路径的文件系统根节点名称的长度。
Definition: YCLib/FileSystem.cpp:573
platform::DirectorySession::DirectorySession
DirectorySession(const char *path={})
构造：打开目录路径。
Definition: YCLib/FileSystem.cpp:466
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:697
platform::HDirectory::GetName
GetName()) const char *GetName() const ynothrow
间接操作：取节点名称。
Definition: YCLib/FileSystem.cpp:532
CHRLib::MBCSToUCS2
YF_API size_t MBCSToUCS2(ucs2_t *, const char *, Encoding=CS_Default)
按指定编码转换 MBCS 字符串为 UCS-2 字符串，返回转换的串长。
Definition: chrproc.cpp:112
YModules.h
YCL_FileSystem_ufunc_impl
#define YCL_FileSystem_ufunc_impl(_n, _fn, _wfn)
Definition: YCLib/FileSystem.cpp:401
platform::ufexists
YF_API bool ufexists(const char *) ynothrow
判断指定 UTF-8 文件名的文件是否存在。
Definition: YCLib/FileSystem.cpp:307
DefGetter
#define DefGetter(_q, _t, _n,...)
Definition: YBaseMacro.h:180
platform::PathCategory::Empty
CHRLib::ucsdup
YF_API std::basic_string< ucs2_t > ucsdup(const char *, Encoding=CS_Default)
复制多字节字符串为 UCS-2 字符串。
Definition: chrproc.cpp:174
platform::ynothrow
std::size_t size ynothrow
Definition: YCLib/FileSystem.h:256
YSLib::Drawing::size_t
size_t
Definition: ygdi.h:352
platform::uchdir
YF_API bool uchdir(const char *) ynothrow
切换当前工作路径至指定的 UTF-8 字符串。
Definition: YCLib/FileSystem.cpp:405
platform::urmdir
YF_API bool urmdir(const char *) ynothrow
按 UTF-8 路径删除一个空目录。
Definition: YCLib/FileSystem.cpp:415
ystdex::noncopyable
不可复制对象：禁止派生类调用默认原型的复制构造函数和复制赋值操作符。
Definition: utility.hpp:75
yassume
#define yassume
假定：环境语义。
Definition: cassert.h:58
platform::DirectorySession::~DirectorySession
~DirectorySession()
析构：关闭目录路径。
Definition: YCLib/FileSystem.cpp:479
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:514
YSLib::UI::name
yconstfn const string & name
Definition: Loader.h:110
platform::fd
fd
Definition: MemoryMapping.cpp:82
yalignof
#define yalignof(_type)
指定特定类型的对齐。
Definition: ydef.h:442
platform::HDirectory::p_dirent
::dirent * p_dirent
节点信息。
Definition: YCLib/FileSystem.h:460
platform::ufopen
YF_API std::FILE * ufopen(const char *filename, const char *mode) ynothrow
以 UTF-8 文件名打开文件。
Definition: YCLib/FileSystem.cpp:269
yconstraint
#define yconstraint
约束：接口语义。
Definition: cassert.h:47
YCL_FileSystem_ufunc_impl2
#define YCL_FileSystem_ufunc_impl2(_fn, _wfn)
Definition: YCLib/FileSystem.cpp:384
platform::HDirectory::GetNodeCategory
NodeCategory GetNodeCategory() const ynothrow
取节点状态信息确定的文件系统节点类别。
Definition: YCLib/FileSystem.cpp:515
YSLib::Drawing::if
if(YB_LIKELY(!error)) if(YB_LIKELY(!(error
platform::uunlink
YF_API bool uunlink(const char *) ynothrow
按 UTF-8 路径删除一个非目录文件。
Definition: YCLib/FileSystem.cpp:417
platform::NodeCategory::Directory
platform::uremove
YF_API bool uremove(const char *) ynothrow
按 UTF-8 路径删除一个文件。
Definition: YCLib/FileSystem.cpp:419
platform::umkdir
YF_API bool umkdir(const char *) ynothrow
按 UTF-8 路径以默认权限新建一个目录。
Definition: YCLib/FileSystem.cpp:407
platform::HDirectory::operator++
const ynothrow ImplRet this HDirectory & operator++()
迭代：向后遍历。
Definition: YCLib/FileSystem.cpp:504
platform_ex::FS_IsRoot
char16_t FS_IsRoot(const char16_t *)
Definition: YCLib/FileSystem.cpp:587
YCL_FileSystem_ufunc_impl1
#define YCL_FileSystem_ufunc_impl1(_n)
Definition: YCLib/FileSystem.cpp:376
CHRLib::ucs2_t
char16_t ucs2_t
UCS-2 字符类型。
Definition: chrdef.h:44
YSLib::Drawing::r
bounds & r
Definition: ydraw.h:220
platform::FileOperationFailure
表示文件操作失败的异常。
Definition: YCLib/FileSystem.h:390
DefGetterMem
#define DefGetterMem(_q, _t, _n, _m)
Definition: YBaseMacro.h:185
platform::GetFileSizeOf
YF_API std::uint64_t GetFileSizeOf(int)
取文件的大小。
Definition: YCLib/FileSystem.cpp:437
platform::DirectorySession::dir
NativeHandle dir
Definition: YCLib/FileSystem.h:415
YB_LIKELY
#define YB_LIKELY(expr)
Definition: ydef.h:297
ystdex::fexists
bool fexists(const char *)
判断指定路径的文件是否存在。
Definition: cstdio.cpp:36
platform::uopen
YF_API int uopen(const char *filename, int oflag) ynothrow
以 UTF-8 文件名无缓冲打开文件。
Definition: YCLib/FileSystem.cpp:204
platform::NodeCategory
NodeCategory
文件系统节点类别。
Definition: YCLib/FileSystem.h:343
YSLib::UI::Close
void Close(IWidget &wgt)
Definition: ywidget.cpp:95
YModules.h
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:73
ystdex::rtrim
_tString && rtrim(_tString &&str, typename string_traits< _tString >::const_pointer t=&to_array< typename string_traits< _tString >::value_type >("\n\r\t\v ")[0])
删除字符串中指定的连续后缀字符。
Definition: string.hpp:231