@@ -20,54 +20,250 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020THE SOFTWARE.
2121*/
2222#include " fileio.h"
23- #include < sys/types.h>
24- #include < sys/stat.h>
25- #include < unistd.h>
23+ #ifdef _WIN32
24+ # include < windows.h>
25+ #else
26+ # include < sys/types.h>
27+ # include < sys/stat.h>
28+ # include < unistd.h>
29+ #endif
2630
2731namespace tc {
2832
29- bool File::IsDirectory (const char *fileName) noexcept
33+ #ifdef _WIN32
34+ const char File::PATH_SEPARATOR = ' \\ ' ;
35+ #else
36+ const char File::PATH_SEPARATOR = ' /' ;
37+ #endif
38+
39+
40+ std::string File::ExtractFilePath (const std::string &fileName) noexcept
41+ {
42+ std::string retVal;
43+ if (!fileName.empty ()) {
44+ if (IsPathSeparator (fileName.at (fileName.size () - 1 ))) {
45+ retVal = fileName;
46+ } else {
47+ std::string::size_type pos = fileName.find_last_of (PATH_SEPARATOR);
48+ if (pos == std::string::npos) {
49+ pos = fileName.find_last_of (' /' );
50+ }
51+ if (pos != std::string::npos) {
52+ retVal = fileName.substr (0 , pos);
53+ }
54+ }
55+ }
56+ return retVal;
57+ }
58+
59+ std::string File::ExtractFileName (const std::string &fileName) noexcept
60+ {
61+ std::string retVal;
62+ if (!fileName.empty () && !IsPathSeparator (fileName.at (fileName.size () - 1 ))) {
63+ std::string::size_type pos = fileName.find_last_of (PATH_SEPARATOR);
64+ if (pos == std::string::npos) {
65+ pos = fileName.find_last_of (' /' );
66+ }
67+ if (pos != std::string::npos) {
68+ retVal = fileName.substr (pos+1 );
69+ } else {
70+ retVal = fileName;
71+ }
72+ }
73+ return retVal;
74+ }
75+
76+ std::string File::ExtractFileBase (const std::string &fileName) noexcept
77+ {
78+ std::string retVal = ExtractFileName (fileName);
79+ if (!retVal.empty ()) {
80+ std::string::size_type pos = retVal.find_last_of (' .' );
81+ if (pos != std::string::npos) {
82+ retVal = retVal.substr (0 , pos);
83+ }
84+ }
85+ return retVal;
86+ }
87+
88+ std::string File::ExtractFileExt (const std::string &fileName) noexcept
89+ {
90+ std::string retVal = ExtractFileName (fileName);
91+ std::string::size_type pos = retVal.find_last_of (' .' );
92+ if (pos != std::string::npos) {
93+ retVal = retVal.substr (pos);
94+ } else {
95+ retVal.clear ();
96+ }
97+ return retVal;
98+ }
99+
100+ std::string File::CreateFileName (const std::string &path, const std::string &file) noexcept
30101{
31- if (fileName != nullptr ) {
102+ std::string retVal;
103+ if (!path.empty ()) {
104+ retVal += path;
105+ if (!IsPathSeparator (path.at (path.size () - 1 ))) {
106+ retVal += PATH_SEPARATOR;
107+ }
108+ }
109+ if (!file.empty ()) {
110+ retVal += file;
111+ }
112+ return retVal;
113+ }
114+
115+ std::string File::ChangeFileExt (const std::string &fileName, const std::string &fileExt) noexcept
116+ {
117+ std::string retVal;
118+ if (!fileName.empty ()) {
119+ std::string path = ExtractFilePath (fileName);
120+ std::string name = ExtractFileBase (fileName);
121+ if (!name.empty ()) {
122+ if (!fileExt.empty () && fileExt.at (0 ) != ' .' ) {
123+ name += ' .' ;
124+ }
125+ name += fileExt;
126+ retVal = CreateFileName (path, name);
127+ } else {
128+ retVal = fileName;
129+ }
130+ }
131+ return retVal;
132+ }
133+
134+ bool File::IsPathSeparator (char ch) noexcept
135+ {
136+ // Note: '/' is always valid
137+ return (ch == PATH_SEPARATOR || ch == ' /' );
138+ }
139+
140+ bool File::IsDirectory (const std::string &fileName) noexcept
141+ {
142+ bool retVal = false ;
143+ if (!fileName.empty ()) {
144+ #ifdef _WIN32
145+ DWORD flags = ::GetFileAttributes (fileName.c_str ());
146+ if (flags != INVALID_FILE_ATTRIBUTES) {
147+ retVal = (flags & FILE_ATTRIBUTE_DIRECTORY) != 0 ;
148+ }
149+ #else
32150 struct stat s;
33- if (stat (fileName, &s) != -1 ) {
151+ if (:: stat (fileName. c_str () , &s) != -1 ) {
34152 return S_ISDIR (s.st_mode );
35153 }
154+ #endif
36155 }
37- return false ;
156+ return retVal ;
38157}
39158
159+ bool File::Exists (const std::string &path) noexcept
160+ {
161+ bool retVal = false ;
162+ if (!path.empty ()) {
163+ #ifdef _WIN32
164+ retVal = (::GetFileAttributes (path.c_str ()) != INVALID_FILE_ATTRIBUTES);
165+ #else
166+ struct stat s;
167+ retVal = (::stat (path.c_str (), &s) == 0 );
168+ #endif
169+ }
170+ return retVal;
171+ }
40172
41- long File::GetFileSize (const char * fileName) noexcept
173+ long File::GetFileSize (const std::string & fileName) noexcept
42174{
43- if (fileName != nullptr ) {
175+ if (!fileName.empty ()) {
176+ #ifdef _WIN32
177+ HANDLE h = ::CreateFile (fileName.c_str (), 0 , FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
178+ 0 , OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
179+ if (h != INVALID_HANDLE_VALUE) {
180+ DWORD size = ::GetFileSize (h, NULL );
181+ ::CloseHandle (h);
182+ if (size != INVALID_FILE_SIZE) {
183+ return size;
184+ }
185+ }
186+ #else
44187 struct stat s;
45- if (stat (fileName, &s) != -1 ) {
188+ if (:: stat (fileName. c_str () , &s) != -1 ) {
46189 return s.st_size ;
47190 }
191+ #endif
48192 }
49193 return -1L ;
50194}
51195
52-
53- bool File::RemoveFile (const char *fileName) noexcept
196+ bool File::RemoveFile (const std::string &fileName) noexcept
54197{
55- if (fileName != nullptr ) {
56- return (std::remove (fileName) == 0 );
198+ if (!fileName. empty () ) {
199+ return (std::remove (fileName. c_str () ) == 0 );
57200 }
58201 return false ;
59202}
60203
61-
62- bool File::RenameFile (const char *oldFileName, const char *newFileName) noexcept
204+ bool File::RenameFile (const std::string &oldFileName, const std::string &newFileName) noexcept
63205{
64- if (oldFileName != nullptr && *oldFileName != 0 &&
65- newFileName != nullptr && *newFileName != 0 ) {
66- return (std::rename (oldFileName, newFileName) == 0 );
206+ if (!oldFileName.empty () && !newFileName.empty ()) {
207+ return (std::rename (oldFileName.c_str (), newFileName.c_str ()) == 0 );
67208 }
68209 return false ;
69210}
70211
212+ bool File::IsEqual (const std::string &path1, const std::string &path2) noexcept
213+ {
214+ bool retVal = false ;
215+
216+ if (!path1.empty () && !path2.empty ()) {
217+ #ifdef _WIN32
218+ HANDLE h2 = ::CreateFile (path2.c_str (), 0 , FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
219+ 0 , OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
220+ HANDLE h1 = ::CreateFile (path1.c_str (), 0 , FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
221+ 0 , OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
222+ if (h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE) {
223+ if (h2 != INVALID_HANDLE_VALUE) {
224+ ::CloseHandle (h2);
225+ }
226+ if (h1 != INVALID_HANDLE_VALUE) {
227+ ::CloseHandle (h1);
228+ }
229+ return retVal;
230+ }
231+
232+ BY_HANDLE_FILE_INFORMATION info1, info2;
233+ bool b1 = ::GetFileInformationByHandle (h1, &info1);
234+ bool b2 = ::GetFileInformationByHandle (h2, &info2);
235+ if (!b1 || !b2) {
236+ ::CloseHandle (h2);
237+ ::CloseHandle (h1);
238+ return retVal;
239+ }
240+
241+ retVal = (info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber ) &&
242+ (info1.nFileIndexHigh == info2.nFileIndexHigh ) &&
243+ (info1.nFileIndexLow == info2.nFileIndexLow ) &&
244+ (info1.nFileSizeHigh == info2.nFileSizeHigh ) &&
245+ (info1.nFileSizeLow == info2.nFileSizeLow ) &&
246+ (info1.ftLastWriteTime .dwLowDateTime == info2.ftLastWriteTime .dwLowDateTime ) &&
247+ (info1.ftLastWriteTime .dwHighDateTime == info2.ftLastWriteTime .dwHighDateTime );
248+
249+ ::CloseHandle (h2);
250+ ::CloseHandle (h1);
251+
252+ #else
253+ struct stat s1, s2;
254+ int e2 = ::stat (path2.c_str (), &s2);
255+ int e1 = ::stat (path1.c_str (), &s1);
256+ if (e1 == 0 && e2 == 0 ) {
257+ retVal = (s1.st_dev == s2.st_dev ) &&
258+ (s1.st_ino == s2.st_ino ) &&
259+ (s1.st_size == s2.st_size ) &&
260+ (s1.st_mtime == s2.st_mtime );
261+ }
262+
263+ #endif
264+ }
265+ return retVal;
266+ }
71267
72268File::File (const char *fileName, const char *mode) noexcept
73269: m_file(0 )
0 commit comments