libxcks  0.1.0.1
pathutil.cpp
Go to the documentation of this file.
1 /*
2  * libxcks
3  * Copyright (C) 2022 Julien Couot
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
25 //---------------------------------------------------------------------------
26 #if defined(_WIN32) || defined(_WIN64)
27 #include <windows.h>
28 #endif
29 
30 #include <utf8cpp/utf8.h>
31 #if 0 && __has_include(<utf8cpp/cpp17.h>) // don't needed here
32  #include <utf8cpp/cpp17.h>
33  #define LIBXCKS_UTF8CPP_HAS_STRING_VIEW
34 #endif
35 
36 #include <algorithm>
37 #include <iterator>
38 #include <cstdio>
39 
40 #include "pathutil.hpp"
41 #include "strutil.hpp"
42 //---------------------------------------------------------------------------
43 
44 
46 using namespace std;
47 
49 using namespace std::filesystem;
50 //---------------------------------------------------------------------------
51 
52 
53 namespace libxcks
54 {
55 //###########################################################################
56 // Directories functions
57 //###########################################################################
64 std::vector<std::filesystem::path> getDirectories(const std::filesystem::path& p)
65 {
66  vector<path> paths;
67  path pp = p.relative_path().parent_path();
68  copy(pp.begin(), pp.end(), back_inserter(paths));
69 
70  return paths;
71 }
72 //---------------------------------------------------------------------------
73 
74 
81 ArrayString getDirectoriesAsArrayString(const std::filesystem::path& p)
82 {
83  ArrayString paths;
84  path pp = p.relative_path().parent_path();
85  for (path d : pp)
86  paths.emplace_back(from_u8string(d.u8string()));
87 
88  return paths;
89 }
90 //---------------------------------------------------------------------------
91 
92 
93 
94 //###########################################################################
95 // Comparison functions
96 //###########################################################################
97 
108 int compareFileName(const std::string& fn1, const std::string& fn2)
109 {
110  int res;
111  #if defined(_WIN32) || defined(_WIN64)
112  wstring wfn1, wfn2;
113  utf8::utf8to16(fn1.begin(), fn1.end(), back_inserter(wfn1));
114  utf8::utf8to16(fn2.begin(), fn2.end(), back_inserter(wfn2));
115 
116  res = CompareStringEx(LOCALE_NAME_USER_DEFAULT, NORM_IGNORECASE, wfn1.c_str(), wfn1.size(), wfn2.c_str(), wfn2.size(), nullptr, nullptr, 0) - CSTR_EQUAL;
117  //res = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, wfn1.c_str(), -1, wfn2.c_str(), -1) - CSTR_EQUAL;
118  #else
119  res = fn1.compare(fn2);
120  #endif // _WIN32 || _WIN64
121 
122  return res;
123 }
124 //---------------------------------------------------------------------------
125 
126 
137 int compareFileName(const std::filesystem::path& p1, const std::filesystem::path& p2)
138 {
139  int res;
140 
141  #if defined(_WIN32) || defined(_WIN64)
142  wstring wfn1 = p1.filename().wstring();
143  wstring wfn2 = p2.filename().wstring();
144 
145  res = CompareStringEx(LOCALE_NAME_USER_DEFAULT, NORM_IGNORECASE, wfn1.c_str(), wfn1.size(), wfn2.c_str(), wfn2.size(), nullptr, nullptr, 0) - CSTR_EQUAL;
146  //res = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, wfn1.c_str(), -1, wfn2.c_str(), -1) - CSTR_EQUAL;
147  #else
148  u32string fn1 = p1.filename().u32string();
149  u32string fn2 = p2.filename().u32string();
150  res = fn1.compare(fn2);
151  #endif // _WIN32 || _WIN64
152 
153  return res;
154 }
155 //---------------------------------------------------------------------------
156 
157 
158 
159 //###########################################################################
160 // Construction functions
161 //###########################################################################
162 
170 std::filesystem::path constructPath(const ArrayString& dirs, const std::string& filename)
171 {
172  const char32_t sep = U'/';
173  u32string p;
174  for (const string& d : dirs)
175  {
176  if (!p.empty())
177  p += sep;
178  #if defined(_MSC_VER)
179  utf8::utf8to32(d.c_str(), d.c_str() + d.size(), back_inserter(p));
180  #else
181  p += utf8::utf8to32(d);
182  #endif
183  }
184  if (!filename.empty())
185  {
186  if (!p.empty())
187  p += sep;
188  #if defined(_MSC_VER)
189  utf8::utf8to32(filename.c_str(), filename.c_str() + filename.size(), back_inserter(p));
190  #else
191  p += utf8::utf8to32(filename);
192  #endif
193  }
194 
195  return path(p).make_preferred();
196 }
197 //---------------------------------------------------------------------------
198 
199 
209 std::filesystem::path ensureEndsWithPathSeparator(const std::filesystem::path& p)
210 {
211  u32string generic = p.generic_u32string();
212  if (generic.back() == U'/')
213  return path(p).make_preferred();
214  else
215  {
216  generic.push_back(U'/');
217  return path(generic).make_preferred();
218  }
219 }
220 //---------------------------------------------------------------------------
221 
222 
223 
224 //###########################################################################
225 // Check functions
226 //###########################################################################
227 
266 bool isFileNameValid(const std::string& filename)
267 {
268  if (filename.empty())
269  return false;
270 
271  #if defined(__unix__) || defined(__unix) || defined(_WIN32) || defined(_WIN64)
272  if ((filename == ".") || (filename == ".."))
273  return false;
274  #endif
275 
276  #if defined(__APPLE__) && !(defined(__unix__) || defined(__unix))
277  char invalidChars[] = { '/', ':', '\0' };
278  #elif defined(_WIN32) || defined(_WIN64)
279  char invalidChars[] = { '<', '>', ':', '"', '/', '\\', '|', '?', '*',
280  '\0',
281  '\x01', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
282  '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F',
283  '\x10', '\x11', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
284  '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F' };
285  #elif defined(__unix__) || defined(__unix)
286  #if defined(__APPLE__)
287  char invalidChars[] = { '/', ':', '\0' };
288  #else
289  char invalidChars[] = { '/', '\0' };
290  #endif
291  #else
292  #error Unknow OS. :-(
293  #endif
294 
295  bool valid = true;
296  size_t i = 0;
297  while (valid && (i < (sizeof(invalidChars) / sizeof(invalidChars[0]))))
298  {
299  valid = (filename.find(invalidChars[i]) == string::npos);
300  i++;
301  }
302 
303  #if defined(_WIN32) || defined(_WIN64)
304  if (valid)
305  {
306  const char& last = filename.back(); // string is not empty
307  if ((last == ' ') || (last == '.'))
308  valid = false;
309  else
310  {
311  ArrayString invalidNames;
312  invalidNames.emplace_back(string("CON"));
313  invalidNames.emplace_back(string("PRN"));
314  invalidNames.emplace_back(string("AUX"));
315  invalidNames.emplace_back(string("NUL"));
316  for (int i = 1; i <= 9; i++)
317  {
318  char buf[5];
319  snprintf(buf, 5, "COM%d", i);
320  invalidNames.emplace_back(string(buf));
321  snprintf(buf, 5, "LPT%d", i);
322  invalidNames.emplace_back(string(buf));
323  }
324 
325  i = 0;
326  while (valid && (i < invalidNames.size()))
327  {
328  valid = (compareFileName(filename, invalidNames[i]) != 0);
329  i++;
330  }
331  }
332  }
333  #endif
334 
335  return valid;
336 }
337 //---------------------------------------------------------------------------
338 
339 } // namespace libxcks
340 //---------------------------------------------------------------------------
bool isFileNameValid(const std::string &filename)
Checks if the name of the file is valid.
Definition: pathutil.cpp:266
std::vector< std::filesystem::path > getDirectories(const std::filesystem::path &p)
Gets directories of a path.
Definition: pathutil.cpp:64
int compareFileName(const std::string &fn1, const std::string &fn2)
Compares two file names.
Definition: pathutil.cpp:108
std::filesystem::path constructPath(const ArrayString &dirs, const std::string &filename)
Constructs a path from an array of directories and an optional filename.
Definition: pathutil.cpp:170
ArrayString getDirectoriesAsArrayString(const std::filesystem::path &p)
Gets directories of a path.
Definition: pathutil.cpp:81
std::filesystem::path ensureEndsWithPathSeparator(const std::filesystem::path &p)
Ensures the path ends with a path separator.
Definition: pathutil.cpp:209
Path utilities.
std::string from_u8string(const std::string &s)
Returns an UTF-8 encoded string in an object of type std::string (C++17).
Definition: strutil.cpp:217
String utilities.
std::vector< std::string > ArrayString
Array of strings.
Definition: types.hpp:44