1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 #include <vtkm/io/FileUtils.h>
11
12 #include <vtkm/cont/ErrorBadValue.h>
13
14 #include <algorithm>
15 // TODO (nadavi): Once we get c++17 installed uncomment this
16 // #include <filesystem>
17 #include <errno.h>
18 #include <sys/stat.h>
19
20 #ifdef _MSC_VER
21 #include <direct.h>
22 #endif
23
24
25 namespace vtkm
26 {
27 namespace io
28 {
29
EndsWith(const std::string & value,const std::string & ending)30 bool EndsWith(const std::string& value, const std::string& ending)
31 {
32 if (ending.size() > value.size())
33 {
34 return false;
35 }
36 return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
37 }
38
Filename(const std::string & filePath)39 std::string Filename(const std::string& filePath)
40 {
41 // TODO (nadavi): Once we get c++17 installed uncomment this
42 // std::filesystem::path path(filePath);
43 // return path.filename();
44
45 #ifdef _MSC_VER
46 auto lastSlashPos = filePath.rfind(GetWindowsPathSeperator(filePath));
47 #else
48 auto lastSlashPos = filePath.rfind('/');
49 #endif
50 if (lastSlashPos != std::string::npos)
51 {
52 return filePath.substr(lastSlashPos + 1);
53 }
54 return filePath;
55 }
56
ParentPath(const std::string & filePath)57 std::string ParentPath(const std::string& filePath)
58 {
59 // TODO (nadavi): Once we get c++17 installed uncomment this
60 // std::filesystem::path path(filePath);
61 // return path.parent_path();
62
63 #ifdef _MSC_VER
64 auto lastSlashPos = filePath.rfind(GetWindowsPathSeperator(filePath));
65 #else
66 auto lastSlashPos = filePath.rfind('/');
67 #endif
68 if (lastSlashPos != std::string::npos)
69 {
70 return filePath.substr(0, lastSlashPos);
71 }
72 return "";
73 }
74
CreateDirectoriesFromFilePath(const std::string & filePath)75 bool CreateDirectoriesFromFilePath(const std::string& filePath)
76 {
77 // TODO (nadavi): Once we get c++17 installed uncomment this
78 // auto dir = ParentPath(filePath);
79 // if (dir.empty())
80 // {
81 // return false;
82 // }
83 // return std::filesystem::create_directories(dir);
84
85 auto dir = ParentPath(filePath);
86 if (dir.empty())
87 {
88 return false;
89 }
90
91 #ifdef _MSC_VER
92 auto ret = _mkdir(dir.c_str());
93 #else
94 mode_t mode = 0755;
95 auto ret = mkdir(dir.c_str(), mode);
96 #endif
97
98 if (ret == 0)
99 {
100 return true;
101 }
102
103 switch (errno)
104 {
105 case ENOENT:
106 {
107 if (!CreateDirectoriesFromFilePath(dir))
108 {
109 return false;
110 }
111 return CreateDirectoriesFromFilePath(filePath);
112 }
113 case EEXIST:
114 return false;
115 default:
116 return false;
117 }
118 }
119
MergePaths(const std::string & filePathPrefix,const std::string & filePathSuffix)120 std::string MergePaths(const std::string& filePathPrefix, const std::string& filePathSuffix)
121 {
122 // TODO (nadavi): Once we get c++17 installed uncomment this
123 // NOTE: This function may not directly mimic the c++ filesystem '/' behavior
124 // the edge case tests will probably need to be updated when switching.
125 // std::filesystem::path prefix(filePathPrefix);
126 // std::filesystem::path suffix(filePathSuffix);
127 // std::filesystem::path fullPath = prefix / suffix;
128 // return fullPath.string();
129
130 auto prefix = filePathPrefix;
131 auto suffix = filePathSuffix;
132 char prefixPathSeperator = '/';
133 char suffixPathSeperator = '/';
134
135 if (prefix.empty() && suffix.empty())
136 {
137 return "";
138 }
139 else if (prefix.empty())
140 {
141 return suffix;
142 }
143 else if (suffix.empty())
144 {
145 return prefix;
146 }
147
148 #ifdef _MSC_VER
149 prefixPathSeperator = GetWindowsPathSeperator(prefix);
150 suffixPathSeperator = suffix[0] == '/' || suffix[0] == '\\' ? suffix[0] : prefixPathSeperator;
151 #endif
152
153 if (prefix[prefix.length() - 1] == prefixPathSeperator)
154 {
155 prefix = prefix.substr(0, prefix.length() - 1);
156 }
157 if (suffix[0] == suffixPathSeperator)
158 {
159 suffix = suffix.substr(1, suffix.length());
160 }
161 return prefix + prefixPathSeperator + suffix;
162 }
163
PrefixStringToFilename(const std::string & filePath,const std::string & prefix)164 std::string PrefixStringToFilename(const std::string& filePath, const std::string& prefix)
165 {
166 auto parentPath = ParentPath(filePath);
167 auto filename = Filename(filePath);
168 filename = prefix + filename;
169 return MergePaths(parentPath, filename);
170 }
171
GetWindowsPathSeperator(const std::string & filePath)172 char GetWindowsPathSeperator(const std::string& filePath)
173 {
174 auto slashType = filePath.rfind('/');
175 if (slashType == std::string::npos)
176 {
177 return '\\';
178 }
179 return '/';
180 }
181
182 } // namespace vtkm::io
183 } // namespace vtkm
184