Skip to content

Commit aa6234e

Browse files
author
Argent77
committed
Merge remote-tracking branch 'origin/devel'
2 parents f9448ba + 878dda6 commit aa6234e

File tree

8 files changed

+373
-183
lines changed

8 files changed

+373
-183
lines changed

tileconv/fileio.cpp

Lines changed: 215 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,54 +20,250 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020
THE 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

2731
namespace 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

72268
File::File(const char *fileName, const char *mode) noexcept
73269
: m_file(0)

tileconv/fileio.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,44 @@ namespace tc {
3333
class File
3434
{
3535
public:
36+
/** Extracts the full path component of the given file name. */
37+
static std::string ExtractFilePath(const std::string &fileName) noexcept;
38+
/** Extracts the top-level path component of the given file name which can be filename or folder. */
39+
static std::string ExtractFileName(const std::string &fileName) noexcept;
40+
/** Extracts the top-level path component without extension. */
41+
static std::string ExtractFileBase(const std::string &fileName) noexcept;
42+
/** Extracts the file extension of the top-level path component. */
43+
static std::string ExtractFileExt(const std::string &fileName) noexcept;
44+
45+
/** Concatenates path and file and returns the result. */
46+
static std::string CreateFileName(const std::string &path, const std::string &file) noexcept;
47+
48+
/** Changes the file extension of the specified filename. */
49+
static std::string ChangeFileExt(const std::string &fileName, const std::string &fileExt) noexcept;
50+
51+
/** Returns true if the specified character is a path separator. */
52+
static bool IsPathSeparator(char ch) noexcept;
53+
3654
/** Returns true only if the given path is a directory. */
37-
static bool IsDirectory(const char *fileName) noexcept;
55+
static bool IsDirectory(const std::string &fileName) noexcept;
56+
57+
/**
58+
* Returns true only if the given path exists (can be regular file, folder
59+
* or any other kind of file type).
60+
*/
61+
static bool Exists(const std::string &path) noexcept;
3862

3963
/** Returns size of the given file in bytes. Returns -1 on error. */
40-
static long GetFileSize(const char *fileName) noexcept;
64+
static long GetFileSize(const std::string &fileName) noexcept;
4165

4266
/** Deletes the file identified by the given name. */
43-
static bool RemoveFile(const char *fileName) noexcept;
67+
static bool RemoveFile(const std::string &fileName) noexcept;
4468

4569
/** Changes the name of a file. */
46-
static bool RenameFile(const char *oldFileName, const char *newFileName) noexcept;
70+
static bool RenameFile(const std::string &oldFileName, const std::string &newFileName) noexcept;
71+
72+
/** Returns whether the two specified path strings are pointing to the same file. */
73+
static bool IsEqual(const std::string &path1, const std::string &path2) noexcept;
4774

4875
public:
4976
/** Opens a file in the specified mode. */
@@ -142,6 +169,8 @@ class File
142169
File& operator=(const File &) = delete;
143170

144171
private:
172+
static const char PATH_SEPARATOR; // OS-specific path separator character (either '\' or '/')
173+
145174
std::FILE *m_file; // current file handle
146175
std::string m_fileName; // filename
147176
std::string m_mode; // current file mode

0 commit comments

Comments
 (0)