foobar2000 SDK  2015-08-03
pathUtils.cpp
Go to the documentation of this file.
1 #include "pfc.h"
2 
3 namespace pfc { namespace io { namespace path {
4 
5 #ifdef _WINDOWS
6 static const string g_pathSeparators ("\\/|");
7 #else
8 static const string g_pathSeparators ("/");
9 #endif
10 
11 string getFileName(string path) {
12  t_size split = path.lastIndexOfAnyChar(g_pathSeparators);
13  if (split == ~0) return path;
14  else return path.subString(split+1);
15 }
16 string getFileNameWithoutExtension(string path) {
17  string fn = getFileName(path);
18  t_size split = fn.lastIndexOf('.');
19  if (split == ~0) return fn;
20  else return fn.subString(0,split);
21 }
22 string getFileExtension(string path) {
23  string fn = getFileName(path);
24  t_size split = fn.lastIndexOf('.');
25  if (split == ~0) return "";
26  else return fn.subString(split);
27 }
28 string getDirectory(string filePath) {return getParent(filePath);}
29 
30 string getParent(string filePath) {
31  t_size split = filePath.lastIndexOfAnyChar(g_pathSeparators);
32  if (split == ~0) return "";
33 #ifdef _WINDOWS
34  if (split > 0 && getIllegalNameChars().contains(filePath[split-1])) {
35  if (split + 1 < filePath.length()) return filePath.subString(0,split+1);
36  else return "";
37  }
38 #endif
39  return filePath.subString(0,split);
40 }
41 string combine(string basePath,string fileName) {
42  if (basePath.length() > 0) {
43  if (!isSeparator(basePath.lastChar())) {
44  basePath += getDefaultSeparator();
45  }
46  return basePath + fileName;
47  } else {
48  //todo?
49  return fileName;
50  }
51 }
52 
53 bool isSeparator(char c) {
54  return g_pathSeparators.indexOf(c) != ~0;
55 }
56 string getSeparators() {
57  return g_pathSeparators;
58 }
59 
60 static string replaceIllegalChar(char c) {
61  switch(c) {
62  case '*':
63  return "x";
64  case '\"':
65  return "\'\'";
66  case ':':
67  case '/':
68  case '\\':
69  return "-";
70  default:
71  return "_";
72  }
73 }
74 string replaceIllegalPathChars(string fn) {
75  string illegal = getIllegalNameChars();
76  string separators = getSeparators();
78  for(t_size walk = 0; walk < fn.length(); ++walk) {
79  const char c = fn[walk];
80  if (separators.contains(c)) {
81  output.add_byte(getDefaultSeparator());
82  } else if (string::isNonTextChar(c) || illegal.contains(c)) {
83  string replacement = replaceIllegalChar(c);
84  if (replacement.containsAnyChar(illegal)) /*per-OS weirdness security*/ replacement = "_";
85  output << replacement.ptr();
86  } else {
87  output.add_byte(c);
88  }
89  }
90  return output.toString();
91 }
92 
93 string replaceIllegalNameChars(string fn, bool allowWC) {
94  const string illegal = getIllegalNameChars(allowWC);
96  for(t_size walk = 0; walk < fn.length(); ++walk) {
97  const char c = fn[walk];
98  if (string::isNonTextChar(c) || illegal.contains(c)) {
99  string replacement = replaceIllegalChar(c);
100  if (replacement.containsAnyChar(illegal)) /*per-OS weirdness security*/ replacement = "_";
101  output << replacement.ptr();
102  } else {
103  output.add_byte(c);
104  }
105  }
106  return output.toString();
107 }
108 
109 bool isInsideDirectory(pfc::string directory, pfc::string inside) {
110  //not very efficient
111  string walk = inside;
112  for(;;) {
113  walk = getParent(walk);
114  if (walk == "") return false;
115  if (equals(directory,walk)) return true;
116  }
117 }
118 bool isDirectoryRoot(string path) {
119  return getParent(path).isEmpty();
120 }
121 //OS-dependant part starts here
122 
123 
125 #ifdef _WINDOWS
126  return '\\';
127 #else
128  return '/';
129 #endif
130 }
131 
132 static const string g_illegalNameChars(g_pathSeparators
133 #ifdef _WINDOWS
134  + ":<>*?\""
135 #else
136  + "*?"
137 #endif
138  );
139 
140 static const string g_illegalNameChars_noWC(g_pathSeparators
141 #ifdef _WINDOWS
142  + ":<>?\""
143 #endif
144  );
145 string getIllegalNameChars(bool allowWC) {
146  return allowWC ? g_illegalNameChars_noWC : g_illegalNameChars;
147 }
148 
149 #ifdef _WINDOWS
150 static bool isIllegalTrailingChar(char c) {
151  return c == ' ' || c == '.';
152 }
153 #endif
154 
155 string validateFileName(string name, bool allowWC) {
156  for(t_size walk = 0; name[walk];) {
157  if (name[walk] == '?') {
158  t_size end = walk;
159  do { ++end; } while(name[end] == '?');
160  name = name.subString(0, walk) + name.subString(end);
161  } else {
162  ++walk;
163  }
164  }
165 #ifdef _WINDOWS
166  name = replaceIllegalNameChars(name, allowWC);
167  if (name.length() > 0) {
168  t_size end = name.length();
169  while(end > 0) {
170  if (!isIllegalTrailingChar(name[end-1])) break;
171  --end;
172  }
173  t_size begin = 0;
174  while(begin < end) {
175  if (!isIllegalTrailingChar(name[begin])) break;
176  ++begin;
177  }
178  if (end < name.length() || begin > 0) name = name.subString(begin,end - begin);
179  }
180  if (name.isEmpty()) name = "_";
181  return name;
182 #else
183  return replaceIllegalNameChars(name);
184 #endif
185 }
186 
187 }}}
t_size length() const
Definition: stringNew.h:127
static bool isIllegalTrailingChar(char c)
Definition: pathUtils.cpp:150
static const string g_illegalNameChars(g_pathSeparators#ifdef _WINDOWS+":<>*?\""#else+"*?"#endif)
string getDirectory(string filePath)
Definition: pathUtils.cpp:28
char lastChar() const
Definition: stringNew.cpp:61
string combine(string basePath, string fileName)
Definition: pathUtils.cpp:41
string getFileName(string path)
Definition: pathUtils.cpp:11
string subString(t_size base) const
Definition: stringNew.h:67
string getSeparators()
Definition: pathUtils.cpp:56
string validateFileName(string name, bool allowWC)
Definition: pathUtils.cpp:155
t_size lastIndexOfAnyChar(stringp s, t_size base=~0) const
Definition: stringNew.cpp:26
const char * ptr() const
Definition: stringNew.h:124
string getFileNameWithoutExtension(string path)
Definition: pathUtils.cpp:16
bool isSeparator(char c)
Definition: pathUtils.cpp:53
bool isDirectoryRoot(string path)
Definition: pathUtils.cpp:118
static string replaceIllegalChar(char c)
Definition: pathUtils.cpp:60
static bool isNonTextChar(char c)
Definition: stringNew.h:134
bool containsAnyChar(stringp s) const
Definition: stringNew.cpp:81
size_t t_size
Definition: int_types.h:48
string8_fastalloc string_formatter
Definition: string_base.h:615
static const string g_pathSeparators("\\/|")
string getParent(string filePath)
Definition: pathUtils.cpp:30
t_size lastIndexOf(char c, t_size base=~0) const
Definition: stringNew.cpp:8
bool isInsideDirectory(pfc::string directory, pfc::string inside)
Definition: pathUtils.cpp:109
string getIllegalNameChars(bool allowWC)
Definition: pathUtils.cpp:145
string getFileExtension(string path)
Definition: pathUtils.cpp:22
string replaceIllegalNameChars(string fn, bool allowWC)
Definition: pathUtils.cpp:93
string replaceIllegalPathChars(string fn)
Definition: pathUtils.cpp:74
char getDefaultSeparator()
Definition: pathUtils.cpp:124
bool contains(char c) const
Definition: stringNew.cpp:79
bool isEmpty() const
Definition: stringNew.h:140
New EXPERIMENTAL string class, allowing efficient copies and returning from functions. Does not implement the string_base interface so you still need string8 in many cases. Safe to pass between DLLs, but since a reference is used, objects possibly created by other DLLs must be released before owning DLLs are unloaded.
Definition: stringNew.h:19
t_size indexOf(char c, t_size base=0) const
Definition: stringNew.cpp:5
static const string g_illegalNameChars_noWC(g_pathSeparators#ifdef _WINDOWS+":<>?\""#endif)
Definition: output.h:95
bool equals(const t1 &v1, const t2 &v2)
Definition: pathUtils.h:27