annotate foosdk/sdk/pfc/pathUtils.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #include "pfc-lite.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2 #include "pathUtils.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4 static_assert(L'Ö' == 0xD6, "Compile as Unicode!!!");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6 namespace pfc { namespace io { namespace path {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 #ifdef _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 #define KPathSeparators "\\/|"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 #define KPathSeparators "/"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 string getFileName(string path) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 t_size split = path.lastIndexOfAnyChar(KPathSeparators);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 if (split == SIZE_MAX) return path;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 else return path.subString(split+1);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 string getFileNameWithoutExtension(string path) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 string fn = getFileName(path);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 t_size split = fn.lastIndexOf('.');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 if (split == SIZE_MAX) return fn;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 else return fn.subString(0,split);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 string getFileExtension(string path) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 string fn = getFileName(path);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 t_size split = fn.lastIndexOf('.');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28 if (split == SIZE_MAX) return "";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 else return fn.subString(split);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 string getDirectory(string filePath) {return getParent(filePath);}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 string getParent(string filePath) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 t_size split = filePath.lastIndexOfAnyChar(KPathSeparators);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 if (split == SIZE_MAX) return "";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 #ifdef _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 if (split > 0 && getIllegalNameChars().contains(filePath[split-1])) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38 if (split + 1 < filePath.length()) return filePath.subString(0,split+1);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 else return "";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 return filePath.subString(0,split);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 string combine(string basePath,string fileName) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45 if (basePath.length() > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46 if (!isSeparator(basePath.lastChar())) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 basePath.add_byte( getDefaultSeparator() );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 return basePath + fileName;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 //todo?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 return fileName;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 bool isSeparator(char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 return strchr(KPathSeparators, c) != nullptr;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 string getSeparators() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 return KPathSeparators;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 const char * charReplaceDefault(char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 switch (c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 case '*':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 return "x";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 case '\"':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 return "\'\'";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 case ':':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 case '/':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 case '\\':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 return "-";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 case '?':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 return "";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 default:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 return "_";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 const char * charReplaceModern(char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 switch (c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 case '*':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 return reinterpret_cast<const char*>( u8"∗" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 case '\"':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 return reinterpret_cast<const char*>( u8"''" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 case ':':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 return reinterpret_cast<const char*>( u8"∶" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 case '/':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 return reinterpret_cast<const char*>( u8"\u2215" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90 case '\\':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 return reinterpret_cast<const char*>( u8"⧵" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 case '?':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 return reinterpret_cast<const char*>( u8"?" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 case '<':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 return reinterpret_cast<const char*>( u8"˂" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 case '>':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 return reinterpret_cast<const char*>( u8"˃" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 case '|':
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 return reinterpret_cast<const char*>( u8"∣" );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 default:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 return "_";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 string replaceIllegalPathChars(string fn, charReplace_t replaceIllegalChar) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 string illegal = getIllegalNameChars();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
107 string separators = getSeparators();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
108 string_formatter output;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
109 for(t_size walk = 0; walk < fn.length(); ++walk) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
110 const char c = fn[walk];
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
111 if (separators.contains(c)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
112 output.add_byte(getDefaultSeparator());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
113 } else if (string::isNonTextChar(c) || illegal.contains(c)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
114 string replacement = replaceIllegalChar(c);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
115 if (replacement.containsAnyChar(illegal)) /*per-OS weirdness security*/ replacement = "_";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
116 output << replacement.ptr();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
117 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
118 output.add_byte(c);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
119 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
120 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
121 return output.toString();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
122 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
123
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
124 string replaceIllegalNameChars(string fn, bool allowWC, charReplace_t replaceIllegalChar) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
125 const string illegal = getIllegalNameChars(allowWC);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
126 string_formatter output;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
127 for(t_size walk = 0; walk < fn.length(); ++walk) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
128 const char c = fn[walk];
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
129 if (string::isNonTextChar(c) || illegal.contains(c)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
130 string replacement = replaceIllegalChar(c);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
131 if (replacement.containsAnyChar(illegal)) /*per-OS weirdness security*/ replacement = "_";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
132 output << replacement.ptr();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
133 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
134 output.add_byte(c);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
135 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
136 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
137 return output.toString();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
138 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
139
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
140 bool isInsideDirectory(pfc::string directory, pfc::string inside) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
141 //not very efficient
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
142 string walk = inside;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
143 for(;;) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
144 walk = getParent(walk);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
145 if (walk == "") return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
146 if (equals(directory,walk)) return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
147 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
148 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
149 bool isDirectoryRoot(string path) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
150 return getParent(path).isEmpty();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
151 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
152 //OS-dependant part starts here
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
153
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
154
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
155 char getDefaultSeparator() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
156 #ifdef _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
157 return '\\';
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
158 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
159 return '/';
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
160 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
161 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
162
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
163 #ifdef _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
164 #define KIllegalNameCharsEx ":<>\""
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
165 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
166 // Mac OS allows : in filenames but does funny things presenting them in Finder, so don't use it
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
167 #define KIllegalNameCharsEx ":"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
168 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
169
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
170 #define KWildcardChars "*?"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
171
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
172 #define KIllegalNameChars KPathSeparators KIllegalNameCharsEx KWildcardChars
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
173 #define KIllegalNameChars_noWC KPathSeparators KIllegalNameCharsEx
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
174
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
175 static string g_illegalNameChars ( KIllegalNameChars );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
176 static string g_illegalNameChars_noWC ( KIllegalNameChars_noWC );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
177
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
178 string getIllegalNameChars(bool allowWC) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
179 return allowWC ? g_illegalNameChars_noWC : g_illegalNameChars;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
180 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
181
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
182 #ifdef _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
183 static const char * const specialIllegalNames[] = {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
184 "con", "aux", "lst", "prn", "nul", "eof", "inp", "out"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
185 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
186 #endif // _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
187
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
188 #ifdef _WIN32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
189 static constexpr unsigned maxPathComponent = 255;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
190 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
191 static constexpr unsigned maxPathComponent = NAME_MAX;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
192 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
193
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
194 static size_t safeTruncat( const char * str, size_t maxLen ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
195 size_t i = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
196 size_t ret = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
197 for( ; i < maxLen; ++ i ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
198 auto d = pfc::utf8_char_len( str + ret );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
199 if ( d == 0 ) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
200 ret += d;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
201 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
202 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
203 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
204
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
205 static size_t utf8_length( const char * str ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
206 size_t ret = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
207 for (; ++ret;) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
208 size_t d = pfc::utf8_char_len( str );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
209 if ( d == 0 ) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
210 str += d;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
211 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
212 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
213 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
214 static string truncatePathComponent( string name, bool preserveExt ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
215
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
216 if (name.length() <= maxPathComponent) return name;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
217 if (preserveExt) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
218 auto dot = name.lastIndexOf('.');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
219 if (dot != pfc_infinite) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
220 const auto ext = name.subString(dot);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
221 const auto extLen = utf8_length( ext.c_str() );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
222 if (extLen < maxPathComponent) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
223 auto lim = maxPathComponent - extLen;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
224 lim = safeTruncat( name.c_str(), lim );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
225 if (lim < dot) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
226 return name.subString(0, lim) + ext;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
227 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
228 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
229 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
230 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
231
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
232 size_t truncat = safeTruncat( name.c_str(), maxPathComponent );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
233 return name.subString(0, truncat);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
234 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
235
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
236 static string trailingSanity(string name, bool preserveExt, const char * lstIllegal) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
237
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
238 const auto isIllegalTrailingChar = [lstIllegal](char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
239 return strchr(lstIllegal, c) != nullptr;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
240 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
241
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
242 t_size end = name.length();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
243 if (preserveExt) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
244 size_t offset = pfc::string_find_last(name.c_str(), '.');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
245 if (offset < end) end = offset;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
246 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
247 const size_t endEx = end;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
248 while (end > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
249 if (!isIllegalTrailingChar(name[end - 1])) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
250 --end;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
251 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
252 t_size begin = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
253 while (begin < end) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
254 if (!isIllegalTrailingChar(name[begin])) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
255 ++begin;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
256 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
257 if (end < endEx || begin > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
258 name = name.subString(begin, end - begin) + name.subString(endEx);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
259 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
260 return name;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
261 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
262 string validateFileName(string name, bool allowWC, bool preserveExt, charReplace_t replaceIllegalChar) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
263 if (!allowWC) { // special fix for filenames that consist only of question marks
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
264 size_t end = name.length();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
265 if (preserveExt) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
266 size_t offset = pfc::string_find_last(name.c_str(), '.');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
267 if (offset < end) end = offset;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
268 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
269 bool unnamed = true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
270 for (size_t walk = 0; walk < end; ++walk) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
271 if (name[walk] != '?') unnamed = false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
272 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
273 if (unnamed) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
274 name = string("[unnamed]") + name.subString(end);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
275 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
276 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
277
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
278 // Trailing sanity AFTER replaceIllegalNameChars
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
279 // replaceIllegalNameChars may remove chars exposing illegal prefix/suffix chars
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
280 name = replaceIllegalNameChars(name, allowWC, replaceIllegalChar);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
281 if (name.length() > 0 && !allowWC) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
282 const char* lstIllegal = preserveExt ? "" : " .";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
283 name = trailingSanity(name, preserveExt, lstIllegal);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
284 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
285
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
286 name = truncatePathComponent(name, preserveExt);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
287
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
288 #ifdef _WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
289 for( auto p : specialIllegalNames ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
290 if (pfc::stringEqualsI_ascii( name.c_str(), p ) ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
291 name += "-";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
292 break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
293 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
294 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
295 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
296
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
297 if (name.isEmpty()) name = "_";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
298 return name;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
299 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
300
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
301 }}} // namespaces