/src/poco/Foundation/src/Path.cpp
Line | Count | Source |
1 | | // |
2 | | // Path.cpp |
3 | | // |
4 | | // Library: Foundation |
5 | | // Package: Filesystem |
6 | | // Module: Path |
7 | | // |
8 | | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | | // and Contributors. |
10 | | // |
11 | | // SPDX-License-Identifier: BSL-1.0 |
12 | | // |
13 | | |
14 | | |
15 | | #include "Poco/Path.h" |
16 | | #include "Poco/File.h" |
17 | | #include "Poco/Exception.h" |
18 | | #include "Poco/StringTokenizer.h" |
19 | | #if defined(_WIN32) |
20 | | #include "Poco/UnicodeConverter.h" |
21 | | #include "Poco/Buffer.h" |
22 | | #endif |
23 | | #include <algorithm> |
24 | | |
25 | | |
26 | | #if defined(POCO_OS_FAMILY_UNIX) |
27 | | #include "Path_UNIX.cpp" |
28 | | #elif defined(POCO_OS_FAMILY_WINDOWS) |
29 | | #include "Path_WIN32U.cpp" |
30 | | #endif |
31 | | |
32 | | |
33 | | namespace Poco { |
34 | | |
35 | | |
36 | 178k | Path::Path(): _absolute(false) |
37 | 178k | { |
38 | 178k | } |
39 | | |
40 | | |
41 | 0 | Path::Path(bool absolute): _absolute(absolute) |
42 | 0 | { |
43 | 0 | } |
44 | | |
45 | | |
46 | | Path::Path(const std::string& path) |
47 | 10.3k | { |
48 | 10.3k | assign(path); |
49 | 10.3k | } |
50 | | |
51 | | |
52 | | Path::Path(const std::string& path, Style style) |
53 | 35.6k | { |
54 | 35.6k | assign(path, style); |
55 | 35.6k | } |
56 | | |
57 | | |
58 | | Path::Path(const char* path) |
59 | 0 | { |
60 | 0 | poco_check_ptr(path); |
61 | 0 | assign(path); |
62 | 0 | } |
63 | | |
64 | | |
65 | | Path::Path(const char* path, Style style) |
66 | 0 | { |
67 | 0 | poco_check_ptr(path); |
68 | 0 | assign(path, style); |
69 | 0 | } |
70 | | |
71 | | |
72 | | Path::Path(const Path& path): |
73 | 5.56k | _node(path._node), |
74 | 5.56k | _device(path._device), |
75 | 5.56k | _name(path._name), |
76 | 5.56k | _version(path._version), |
77 | 5.56k | _dirs(path._dirs), |
78 | 5.56k | _absolute(path._absolute) |
79 | 5.56k | { |
80 | 5.56k | } |
81 | | |
82 | | |
83 | | Path::Path(Path&& path) noexcept: |
84 | 0 | _node(std::move(path._node)), |
85 | 0 | _device(std::move(path._device)), |
86 | 0 | _name(std::move(path._name)), |
87 | 0 | _version(std::move(path._version)), |
88 | 0 | _dirs(std::move(path._dirs)), |
89 | 0 | _absolute(std::move(path._absolute)) |
90 | 0 | { |
91 | 0 | } |
92 | | |
93 | | |
94 | | Path::Path(const Path& parent, const std::string& fileName): |
95 | 0 | _node(parent._node), |
96 | 0 | _device(parent._device), |
97 | 0 | _name(parent._name), |
98 | 0 | _version(parent._version), |
99 | 0 | _dirs(parent._dirs), |
100 | 0 | _absolute(parent._absolute) |
101 | 0 | { |
102 | 0 | makeDirectory(); |
103 | 0 | _name = fileName; |
104 | 0 | } |
105 | | |
106 | | |
107 | | Path::Path(const Path& parent, const char* fileName): |
108 | 0 | _node(parent._node), |
109 | 0 | _device(parent._device), |
110 | 0 | _name(parent._name), |
111 | 0 | _version(parent._version), |
112 | 0 | _dirs(parent._dirs), |
113 | 0 | _absolute(parent._absolute) |
114 | 0 | { |
115 | 0 | makeDirectory(); |
116 | 0 | _name = fileName; |
117 | 0 | } |
118 | | |
119 | | |
120 | | Path::Path(const Path& parent, const Path& relative): |
121 | 2.90k | _node(parent._node), |
122 | 2.90k | _device(parent._device), |
123 | 2.90k | _name(parent._name), |
124 | 2.90k | _version(parent._version), |
125 | 2.90k | _dirs(parent._dirs), |
126 | 2.90k | _absolute(parent._absolute) |
127 | 2.90k | { |
128 | 2.90k | resolve(relative); |
129 | 2.90k | } |
130 | | |
131 | | |
132 | | Path::~Path() |
133 | 232k | { |
134 | 232k | } |
135 | | |
136 | | |
137 | | Path& Path::operator = (const Path& path) |
138 | 0 | { |
139 | 0 | return assign(path); |
140 | 0 | } |
141 | | |
142 | | |
143 | | Path& Path::operator = (Path&& path) noexcept |
144 | 0 | { |
145 | 0 | _node = std::move(path._node); |
146 | 0 | _device = std::move(path._device); |
147 | 0 | _name = std::move(path._name); |
148 | 0 | _version = std::move(path._version); |
149 | 0 | _dirs = std::move(path._dirs); |
150 | 0 | _absolute = std::move(path._absolute); |
151 | 0 | return *this; |
152 | 0 | } |
153 | | |
154 | | |
155 | | Path& Path::operator = (const std::string& path) |
156 | 0 | { |
157 | 0 | return assign(path); |
158 | 0 | } |
159 | | |
160 | | |
161 | | Path& Path::operator = (const char* path) |
162 | 0 | { |
163 | 0 | poco_check_ptr(path); |
164 | 0 | return assign(path); |
165 | 0 | } |
166 | | |
167 | | |
168 | | void Path::swap(Path& path) noexcept |
169 | 0 | { |
170 | 0 | std::swap(_node, path._node); |
171 | 0 | std::swap(_device, path._device); |
172 | 0 | std::swap(_name, path._name); |
173 | 0 | std::swap(_version, path._version); |
174 | 0 | std::swap(_dirs, path._dirs); |
175 | 0 | std::swap(_absolute, path._absolute); |
176 | 0 | } |
177 | | |
178 | | |
179 | | Path& Path::assign(const Path& path) |
180 | 88.8k | { |
181 | 88.8k | if (&path != this) |
182 | 88.8k | { |
183 | 88.8k | _node = path._node; |
184 | 88.8k | _device = path._device; |
185 | 88.8k | _name = path._name; |
186 | 88.8k | _version = path._version; |
187 | 88.8k | _dirs = path._dirs; |
188 | 88.8k | _absolute = path._absolute; |
189 | 88.8k | } |
190 | 88.8k | return *this; |
191 | 88.8k | } |
192 | | |
193 | | |
194 | | Path& Path::assign(const std::string& path) |
195 | 13.2k | { |
196 | | #if defined(POCO_OS_FAMILY_WINDOWS) |
197 | | parseWindows(path); |
198 | | #else |
199 | 13.2k | parseUnix(path); |
200 | 13.2k | #endif |
201 | 13.2k | return *this; |
202 | 13.2k | } |
203 | | |
204 | | |
205 | | Path& Path::assign(const std::string& path, Style style) |
206 | 124k | { |
207 | 124k | switch (style) |
208 | 124k | { |
209 | 37.2k | case PATH_UNIX: |
210 | 37.2k | parseUnix(path); |
211 | 37.2k | break; |
212 | 204 | case PATH_WINDOWS: |
213 | 204 | parseWindows(path); |
214 | 204 | break; |
215 | 615 | case PATH_VMS: |
216 | 615 | parseVMS(path); |
217 | 615 | break; |
218 | 57 | case PATH_NATIVE: |
219 | 57 | assign(path); |
220 | 57 | break; |
221 | 86.7k | case PATH_GUESS: |
222 | 86.7k | parseGuess(path); |
223 | 86.7k | break; |
224 | 0 | default: |
225 | 0 | poco_bugcheck(); |
226 | 124k | } |
227 | 123k | return *this; |
228 | 124k | } |
229 | | |
230 | | |
231 | | Path& Path::assign(const char* path) |
232 | 0 | { |
233 | 0 | return assign(std::string(path)); |
234 | 0 | } |
235 | | |
236 | | |
237 | | std::string Path::toString() const |
238 | 243k | { |
239 | | #if defined(POCO_OS_FAMILY_WINDOWS) |
240 | | return buildWindows(); |
241 | | #else |
242 | 243k | return buildUnix(); |
243 | 243k | #endif |
244 | 243k | } |
245 | | |
246 | | |
247 | | std::string Path::toString(Style style) const |
248 | 2.90k | { |
249 | 2.90k | switch (style) |
250 | 2.90k | { |
251 | 1.27k | case PATH_UNIX: |
252 | 1.27k | return buildUnix(); |
253 | 489 | case PATH_WINDOWS: |
254 | 489 | return buildWindows(); |
255 | 837 | case PATH_VMS: |
256 | 837 | return buildVMS(); |
257 | 207 | case PATH_NATIVE: |
258 | 301 | case PATH_GUESS: |
259 | 301 | return toString(); |
260 | 0 | default: |
261 | 0 | poco_bugcheck(); |
262 | 2.90k | } |
263 | 0 | return std::string(); |
264 | 2.90k | } |
265 | | |
266 | | |
267 | | bool Path::tryParse(const std::string& path) |
268 | 2.90k | { |
269 | 2.90k | try |
270 | 2.90k | { |
271 | 2.90k | Path p; |
272 | 2.90k | p.parse(path); |
273 | 2.90k | assign(p); |
274 | 2.90k | return true; |
275 | 2.90k | } |
276 | 2.90k | catch (...) |
277 | 2.90k | { |
278 | 0 | return false; |
279 | 0 | } |
280 | 2.90k | } |
281 | | |
282 | | |
283 | | bool Path::tryParse(const std::string& path, Style style) |
284 | 86.3k | { |
285 | 86.3k | try |
286 | 86.3k | { |
287 | 86.3k | Path p; |
288 | 86.3k | p.parse(path, style); |
289 | 86.3k | assign(p); |
290 | 86.3k | return true; |
291 | 86.3k | } |
292 | 86.3k | catch (...) |
293 | 86.3k | { |
294 | 564 | return false; |
295 | 564 | } |
296 | 86.3k | } |
297 | | |
298 | | |
299 | | Path& Path::parseDirectory(const std::string& path) |
300 | 0 | { |
301 | 0 | assign(addDirectorySeparator(path)); |
302 | 0 | return makeDirectory(); |
303 | 0 | } |
304 | | |
305 | | |
306 | | Path& Path::parseDirectory(const std::string& path, Style style) |
307 | 0 | { |
308 | 0 | assign(addDirectorySeparator(path, style), style); |
309 | 0 | return makeDirectory(); |
310 | 0 | } |
311 | | |
312 | | |
313 | | Path& Path::makeDirectory() |
314 | 2.68k | { |
315 | 2.68k | pushDirectory(_name); |
316 | 2.68k | _name.clear(); |
317 | 2.68k | _version.clear(); |
318 | 2.68k | return *this; |
319 | 2.68k | } |
320 | | |
321 | | |
322 | | Path& Path::makeFile() |
323 | 0 | { |
324 | 0 | if (!_dirs.empty() && _name.empty()) |
325 | 0 | { |
326 | 0 | _name = _dirs.back(); |
327 | 0 | _dirs.pop_back(); |
328 | 0 | } |
329 | 0 | return *this; |
330 | 0 | } |
331 | | |
332 | | |
333 | | Path& Path::makeAbsolute() |
334 | 2.66k | { |
335 | 2.66k | return makeAbsolute(current()); |
336 | 2.66k | } |
337 | | |
338 | | |
339 | | Path& Path::makeAbsolute(const Path& base) |
340 | 2.66k | { |
341 | 2.66k | if (!_absolute) |
342 | 2.66k | { |
343 | 2.66k | Path tmp = base; |
344 | 2.66k | tmp.makeDirectory(); |
345 | 2.66k | for (const auto& d: _dirs) |
346 | 2.82M | { |
347 | 2.82M | tmp.pushDirectory(d); |
348 | 2.82M | } |
349 | 2.66k | _node = tmp._node; |
350 | 2.66k | _device = tmp._device; |
351 | 2.66k | _dirs = tmp._dirs; |
352 | 2.66k | _absolute = base._absolute; |
353 | 2.66k | } |
354 | 2.66k | return *this; |
355 | 2.66k | } |
356 | | |
357 | | |
358 | | Path Path::absolute() const |
359 | 2.90k | { |
360 | 2.90k | Path result(*this); |
361 | 2.90k | if (!result._absolute) |
362 | 2.66k | { |
363 | 2.66k | result.makeAbsolute(); |
364 | 2.66k | } |
365 | 2.90k | return result; |
366 | 2.90k | } |
367 | | |
368 | | |
369 | | Path Path::absolute(const Path& base) const |
370 | 0 | { |
371 | 0 | Path result(*this); |
372 | 0 | if (!result._absolute) |
373 | 0 | { |
374 | 0 | result.makeAbsolute(base); |
375 | 0 | } |
376 | 0 | return result; |
377 | 0 | } |
378 | | |
379 | | |
380 | | Path Path::parent() const |
381 | 0 | { |
382 | 0 | Path p(*this); |
383 | 0 | return p.makeParent(); |
384 | 0 | } |
385 | | |
386 | | |
387 | | Path& Path::makeParent() |
388 | 0 | { |
389 | 0 | if (_name.empty()) |
390 | 0 | { |
391 | 0 | if (_dirs.empty()) |
392 | 0 | { |
393 | 0 | if (!_absolute) |
394 | 0 | _dirs.push_back(".."); |
395 | 0 | } |
396 | 0 | else |
397 | 0 | { |
398 | 0 | if (_dirs.back() == "..") |
399 | 0 | _dirs.push_back(".."); |
400 | 0 | else |
401 | 0 | _dirs.pop_back(); |
402 | 0 | } |
403 | 0 | } |
404 | 0 | else |
405 | 0 | { |
406 | 0 | _name.clear(); |
407 | 0 | _version.clear(); |
408 | 0 | } |
409 | 0 | return *this; |
410 | 0 | } |
411 | | |
412 | | |
413 | | Path& Path::append(const Path& path) |
414 | 0 | { |
415 | 0 | makeDirectory(); |
416 | 0 | _dirs.insert(_dirs.end(), path._dirs.begin(), path._dirs.end()); |
417 | 0 | _name = path._name; |
418 | 0 | _version = path._version; |
419 | 0 | return *this; |
420 | 0 | } |
421 | | |
422 | | |
423 | | Path& Path::resolve(const Path& path) |
424 | 2.90k | { |
425 | 2.90k | if (path.isAbsolute()) |
426 | 153 | { |
427 | 153 | assign(path); |
428 | 153 | } |
429 | 2.74k | else |
430 | 2.74k | { |
431 | 539k | for (int i = 0; i < path.depth(); ++i) |
432 | 536k | pushDirectory(path[i]); |
433 | 2.74k | _name = path._name; |
434 | 2.74k | } |
435 | 2.90k | return *this; |
436 | 2.90k | } |
437 | | |
438 | | |
439 | | Path& Path::setNode(const std::string& node) |
440 | 35.6k | { |
441 | 35.6k | _node = node; |
442 | 35.6k | _absolute = _absolute || !node.empty(); |
443 | 35.6k | return *this; |
444 | 35.6k | } |
445 | | |
446 | | |
447 | | Path& Path::setDevice(const std::string& device) |
448 | 0 | { |
449 | 0 | _device = device; |
450 | 0 | _absolute = _absolute || !device.empty(); |
451 | 0 | return *this; |
452 | 0 | } |
453 | | |
454 | | |
455 | | const std::string& Path::directory(int n) const |
456 | 0 | { |
457 | 0 | poco_assert (0 <= n && static_cast<std::size_t>(n) <= _dirs.size()); |
458 | |
|
459 | 0 | if (static_cast<std::size_t>(n) < _dirs.size()) |
460 | 0 | return _dirs[n]; |
461 | 0 | else |
462 | 0 | return _name; |
463 | 0 | } |
464 | | |
465 | | |
466 | | const std::string& Path::operator [] (int n) const |
467 | 536k | { |
468 | 536k | poco_assert (0 <= n && static_cast<std::size_t>(n) <= _dirs.size()); |
469 | | |
470 | 536k | if (static_cast<std::size_t>(n) < _dirs.size()) |
471 | 536k | return _dirs[n]; |
472 | 0 | else |
473 | 0 | return _name; |
474 | 536k | } |
475 | | |
476 | | |
477 | | Path& Path::pushDirectory(const std::string& dir) |
478 | 348M | { |
479 | 348M | if (!dir.empty() && dir != ".") |
480 | 348M | { |
481 | 348M | if (dir == "..") |
482 | 857k | { |
483 | 857k | if (!_dirs.empty() && _dirs.back() != "..") |
484 | 21.5k | _dirs.pop_back(); |
485 | 835k | else if (!_absolute) |
486 | 643k | _dirs.push_back(dir); |
487 | 857k | } |
488 | 347M | else _dirs.push_back(dir); |
489 | 348M | } |
490 | 348M | return *this; |
491 | 348M | } |
492 | | |
493 | | |
494 | | Path& Path::popDirectory() |
495 | 0 | { |
496 | 0 | poco_assert (!_dirs.empty()); |
497 | |
|
498 | 0 | _dirs.pop_back(); |
499 | 0 | return *this; |
500 | 0 | } |
501 | | |
502 | | |
503 | | Path& Path::popFrontDirectory() |
504 | 0 | { |
505 | 0 | poco_assert (!_dirs.empty()); |
506 | |
|
507 | 0 | StringVec::iterator it = _dirs.begin(); |
508 | 0 | _dirs.erase(it); |
509 | 0 | return *this; |
510 | 0 | } |
511 | | |
512 | | |
513 | | Path& Path::setFileName(const std::string& name) |
514 | 0 | { |
515 | 0 | _name = name; |
516 | 0 | return *this; |
517 | 0 | } |
518 | | |
519 | | |
520 | | Path& Path::setBaseName(const std::string& name) |
521 | 0 | { |
522 | 0 | std::string ext = getExtension(); |
523 | 0 | _name = name; |
524 | 0 | if (!ext.empty()) |
525 | 0 | { |
526 | 0 | _name.append("."); |
527 | 0 | _name.append(ext); |
528 | 0 | } |
529 | 0 | return *this; |
530 | 0 | } |
531 | | |
532 | | |
533 | | std::string Path::getBaseName() const |
534 | 0 | { |
535 | 0 | std::string::size_type pos = _name.rfind('.'); |
536 | 0 | if (pos != std::string::npos && pos != 0) |
537 | 0 | return _name.substr(0, pos); |
538 | 0 | else |
539 | 0 | return _name; |
540 | 0 | } |
541 | | |
542 | | |
543 | | Path& Path::setExtension(const std::string& extension) |
544 | 0 | { |
545 | 0 | _name = getBaseName(); |
546 | 0 | if (!extension.empty()) |
547 | 0 | { |
548 | 0 | _name.append("."); |
549 | 0 | _name.append(extension); |
550 | 0 | } |
551 | 0 | return *this; |
552 | 0 | } |
553 | | |
554 | | |
555 | | std::string Path::getExtension() const |
556 | 0 | { |
557 | 0 | std::string::size_type pos = _name.rfind('.'); |
558 | 0 | if (pos != std::string::npos && pos != 0) |
559 | 0 | return _name.substr(pos + 1); |
560 | 0 | else |
561 | 0 | return std::string(); |
562 | 0 | } |
563 | | |
564 | | |
565 | | Path& Path::clear() |
566 | 138k | { |
567 | 138k | _node.clear(); |
568 | 138k | _device.clear(); |
569 | 138k | _name.clear(); |
570 | 138k | _dirs.clear(); |
571 | 138k | _version.clear(); |
572 | 138k | _absolute = false; |
573 | 138k | return *this; |
574 | 138k | } |
575 | | |
576 | | |
577 | | std::string Path::addDirectorySeparator(const std::string& path) |
578 | 0 | { |
579 | 0 | poco_assert(!path.empty()); |
580 | |
|
581 | 0 | if (path.back() != separator()) |
582 | 0 | { |
583 | 0 | return path + separator(); |
584 | 0 | } |
585 | 0 | return path; |
586 | 0 | } |
587 | | |
588 | | |
589 | | std::string Path::addDirectorySeparator(const std::string& path, Style style) |
590 | 0 | { |
591 | 0 | poco_assert(!path.empty()); |
592 | |
|
593 | 0 | char ch = '\0'; |
594 | 0 | switch (style) |
595 | 0 | { |
596 | 0 | case PATH_UNIX: |
597 | 0 | ch = '/'; |
598 | 0 | break; |
599 | 0 | case PATH_WINDOWS: |
600 | 0 | ch = '\\'; |
601 | 0 | break; |
602 | 0 | case PATH_VMS: |
603 | 0 | ch = '.'; |
604 | 0 | break; |
605 | 0 | case PATH_NATIVE: |
606 | 0 | ch = separator(); |
607 | 0 | break; |
608 | 0 | default: |
609 | 0 | poco_bugcheck(); |
610 | 0 | } |
611 | | |
612 | 0 | if (path.back() != ch) |
613 | 0 | { |
614 | 0 | return path + ch; |
615 | 0 | } |
616 | 0 | return path; |
617 | 0 | } |
618 | | |
619 | | |
620 | | std::string Path::self() |
621 | 0 | { |
622 | 0 | return PathImpl::selfImpl(); |
623 | 0 | } |
624 | | |
625 | | |
626 | | std::string Path::current() |
627 | 2.66k | { |
628 | 2.66k | return PathImpl::currentImpl(); |
629 | 2.66k | } |
630 | | |
631 | | |
632 | | std::string Path::home() |
633 | 1.86k | { |
634 | 1.86k | return PathImpl::homeImpl(); |
635 | 1.86k | } |
636 | | |
637 | | |
638 | | std::string Path::configHome() |
639 | 0 | { |
640 | 0 | #if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS) |
641 | 0 | return PathImpl::configHomeImpl(); |
642 | | #else |
643 | | return PathImpl::homeImpl(); |
644 | | #endif |
645 | 0 | } |
646 | | |
647 | | |
648 | | std::string Path::dataHome() |
649 | 0 | { |
650 | 0 | #if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS) |
651 | 0 | return PathImpl::dataHomeImpl(); |
652 | | #else |
653 | | return PathImpl::homeImpl(); |
654 | | #endif |
655 | 0 | } |
656 | | |
657 | | |
658 | | std::string Path::tempHome() |
659 | 0 | { |
660 | 0 | #if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS) |
661 | 0 | return PathImpl::tempHomeImpl(); |
662 | | #else |
663 | | return PathImpl::tempImpl(); |
664 | | #endif |
665 | 0 | } |
666 | | |
667 | | |
668 | | std::string Path::cacheHome() |
669 | 0 | { |
670 | 0 | #if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS) |
671 | 0 | return PathImpl::cacheHomeImpl(); |
672 | | #else |
673 | | return PathImpl::homeImpl(); |
674 | | #endif |
675 | 0 | } |
676 | | |
677 | | |
678 | | std::string Path::temp() |
679 | 0 | { |
680 | 0 | return PathImpl::tempImpl(); |
681 | 0 | } |
682 | | |
683 | | |
684 | | std::string Path::config() |
685 | 0 | { |
686 | 0 | #if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS) |
687 | 0 | return PathImpl::configImpl(); |
688 | | #else |
689 | | return PathImpl::currentImpl(); |
690 | | #endif |
691 | 0 | } |
692 | | |
693 | | |
694 | | std::string Path::null() |
695 | 0 | { |
696 | 0 | return PathImpl::nullImpl(); |
697 | 0 | } |
698 | | |
699 | | |
700 | | std::string Path::expand(const std::string& path) |
701 | 2.90k | { |
702 | 2.90k | return PathImpl::expandImpl(path); |
703 | 2.90k | } |
704 | | |
705 | | |
706 | | void Path::listRoots(std::vector<std::string>& roots) |
707 | 0 | { |
708 | 0 | PathImpl::listRootsImpl(roots); |
709 | 0 | } |
710 | | |
711 | | |
712 | | bool Path::find(StringVec::const_iterator it, StringVec::const_iterator end, const std::string& name, Path& path) |
713 | 0 | { |
714 | 0 | while (it != end) |
715 | 0 | { |
716 | | #if defined(WIN32) |
717 | | std::string cleanPath(*it); |
718 | | if (cleanPath.size() > 1 && cleanPath[0] == '"' && cleanPath[cleanPath.size() - 1] == '"') |
719 | | { |
720 | | cleanPath = cleanPath.substr(1, cleanPath.size() - 2); |
721 | | } |
722 | | Path p(cleanPath); |
723 | | #else |
724 | 0 | Path p(*it); |
725 | 0 | #endif |
726 | 0 | p.makeDirectory(); |
727 | 0 | p.resolve(Path(name)); |
728 | 0 | File f(p); |
729 | 0 | if (f.exists()) |
730 | 0 | { |
731 | 0 | path = p; |
732 | 0 | return true; |
733 | 0 | } |
734 | 0 | ++it; |
735 | 0 | } |
736 | 0 | return false; |
737 | 0 | } |
738 | | |
739 | | |
740 | | bool Path::find(const std::string& pathList, const std::string& name, Path& path) |
741 | 0 | { |
742 | 0 | StringTokenizer st(pathList, std::string(1, pathSeparator()), StringTokenizer::TOK_IGNORE_EMPTY + StringTokenizer::TOK_TRIM); |
743 | 0 | return find(st.begin(), st.end(), name, path); |
744 | 0 | } |
745 | | |
746 | | |
747 | | void Path::parseUnix(const std::string& path) |
748 | 82.4k | { |
749 | 82.4k | clear(); |
750 | | |
751 | 82.4k | std::string::const_iterator it = path.begin(); |
752 | 82.4k | std::string::const_iterator end = path.end(); |
753 | | |
754 | 82.4k | if (it != end) |
755 | 65.1k | { |
756 | 65.1k | if (*it == '/') |
757 | 44.2k | { |
758 | 44.2k | _absolute = true; ++it; |
759 | 44.2k | } |
760 | 20.9k | else if (*it == '~') |
761 | 2.26k | { |
762 | 2.26k | ++it; |
763 | 2.26k | if (it == end || *it == '/') |
764 | 1.86k | { |
765 | 1.86k | Path cwd(home()); |
766 | 1.86k | _dirs = cwd._dirs; |
767 | 1.86k | _absolute = true; |
768 | 1.86k | } |
769 | 405 | else --it; |
770 | 2.26k | } |
771 | | |
772 | 324M | while (it != end) |
773 | 324M | { |
774 | 324M | std::string name; |
775 | 2.54G | while (it != end && *it != '/') name += *it++; |
776 | 324M | if (it != end) |
777 | 324M | { |
778 | 324M | if (_dirs.empty()) |
779 | 167k | { |
780 | 167k | if (!name.empty() && *(name.rbegin()) == ':') |
781 | 40.8k | { |
782 | 40.8k | _absolute = true; |
783 | 40.8k | _device.assign(name, 0, name.length() - 1); |
784 | 40.8k | } |
785 | 126k | else |
786 | 126k | { |
787 | 126k | pushDirectory(name); |
788 | 126k | } |
789 | 167k | } |
790 | 323M | else pushDirectory(name); |
791 | 324M | } |
792 | 26.6k | else _name = name; |
793 | 324M | if (it != end) ++it; |
794 | 324M | } |
795 | 65.1k | } |
796 | 82.4k | } |
797 | | |
798 | | |
799 | | void Path::parseWindows(const std::string& path) |
800 | 6.08k | { |
801 | 6.08k | clear(); |
802 | | |
803 | 6.08k | std::string::const_iterator it = path.begin(); |
804 | 6.08k | std::string::const_iterator end = path.end(); |
805 | | |
806 | 6.08k | if (it != end) |
807 | 6.07k | { |
808 | 6.07k | if (*it == '\\' || *it == '/') { _absolute = true; ++it; } |
809 | 6.07k | if (_absolute && it != end && (*it == '\\' || *it == '/')) // UNC |
810 | 2.10k | { |
811 | 2.10k | ++it; |
812 | 135k | while (it != end && *it != '\\' && *it != '/') _node += *it++; |
813 | 2.10k | if (it != end) ++it; |
814 | 2.10k | } |
815 | 3.96k | else if (it != end) |
816 | 3.96k | { |
817 | 3.96k | char d = *it++; |
818 | 3.96k | if (it != end && *it == ':') // drive letter |
819 | 171 | { |
820 | 171 | if (_absolute || !((d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z'))) throw PathSyntaxException(path); |
821 | 100 | _absolute = true; |
822 | 100 | _device += d; |
823 | 100 | ++it; |
824 | 100 | if (it != end) |
825 | 96 | { |
826 | 96 | if ((*it != '\\' && *it != '/')) |
827 | 16 | { |
828 | 16 | throw PathSyntaxException(path); |
829 | 16 | } |
830 | 80 | ++it; |
831 | 80 | } |
832 | 100 | } |
833 | 3.79k | else --it; |
834 | 3.96k | } |
835 | 21.0M | while (it != end) |
836 | 21.0M | { |
837 | 21.0M | std::string name; |
838 | 511M | while (it != end && *it != '\\' && *it != '/') name += *it++; |
839 | 21.0M | if (it != end) |
840 | 21.0M | pushDirectory(name); |
841 | 2.94k | else |
842 | 2.94k | _name = name; |
843 | 21.0M | if (it != end) ++it; |
844 | 21.0M | } |
845 | 5.99k | } |
846 | 5.99k | if (!_node.empty() && _dirs.empty() && !_name.empty()) |
847 | 23 | makeDirectory(); |
848 | 5.99k | } |
849 | | |
850 | | |
851 | | void Path::parseVMS(const std::string& path) |
852 | 49.5k | { |
853 | 49.5k | clear(); |
854 | | |
855 | 49.5k | std::string::const_iterator it = path.begin(); |
856 | 49.5k | std::string::const_iterator end = path.end(); |
857 | | |
858 | 49.5k | if (it != end) |
859 | 49.5k | { |
860 | 49.5k | std::string name; |
861 | 90.3M | while (it != end && *it != ':' && *it != '[' && *it != ';') name += *it++; |
862 | 49.5k | if (it != end) |
863 | 49.4k | { |
864 | 49.4k | if (*it == ':') |
865 | 12.7k | { |
866 | 12.7k | ++it; |
867 | 12.7k | if (it != end && *it == ':') |
868 | 12.1k | { |
869 | 12.1k | _node = name; |
870 | 12.1k | ++it; |
871 | 12.1k | } |
872 | 662 | else _device = name; |
873 | 12.7k | _absolute = true; |
874 | 12.7k | name.clear(); |
875 | 12.7k | } |
876 | 49.4k | if (it != end) |
877 | 49.4k | { |
878 | 49.4k | if (_device.empty() && *it != '[') |
879 | 44.9k | { |
880 | 13.2M | while (it != end && *it != ':' && *it != ';') name += *it++; |
881 | 44.9k | if (it != end) |
882 | 44.8k | { |
883 | 44.8k | if (*it == ':') |
884 | 905 | { |
885 | 905 | _device = name; |
886 | 905 | _absolute = true; |
887 | 905 | name.clear(); |
888 | 905 | ++it; |
889 | 905 | } |
890 | 44.8k | } |
891 | 44.9k | } |
892 | 49.4k | } |
893 | 49.4k | if (name.empty()) |
894 | 5.47k | { |
895 | 5.47k | if (it != end && *it == '[') |
896 | 4.81k | { |
897 | 4.81k | ++it; |
898 | 4.81k | if (it != end) |
899 | 4.37k | { |
900 | 4.37k | _absolute = true; |
901 | 4.37k | if (*it == '.') |
902 | 381 | { _absolute = false; ++it; } |
903 | 3.99k | else if (*it == ']' || *it == '-') |
904 | 1.13k | _absolute = false; |
905 | 11.6M | while (it != end && *it != ']') |
906 | 11.6M | { |
907 | 11.6M | name.clear(); |
908 | 11.6M | if (*it == '-') |
909 | 9.12M | name = "-"; |
910 | 2.56M | else |
911 | 216M | while (it != end && *it != '.' && *it != ']') name += *it++; |
912 | 11.6M | if (!name.empty()) |
913 | 11.5M | { |
914 | 11.5M | if (name == "-") |
915 | 9.12M | { |
916 | 9.12M | if (_dirs.empty() || _dirs.back() == "..") |
917 | 9.00M | _dirs.push_back(".."); |
918 | 120k | else |
919 | 120k | _dirs.pop_back(); |
920 | 9.12M | } |
921 | 2.44M | else _dirs.push_back(name); |
922 | 11.5M | } |
923 | 11.6M | if (it != end && *it != ']') ++it; |
924 | 11.6M | } |
925 | 4.37k | if (it == end) throw PathSyntaxException(path); |
926 | 3.88k | ++it; |
927 | 3.88k | if (it != end && *it == '[') |
928 | 1.54k | { |
929 | 1.54k | if (!_absolute) throw PathSyntaxException(path); |
930 | 1.50k | ++it; |
931 | 1.50k | if (it != end && *it == '.') throw PathSyntaxException(path); |
932 | 1.48k | auto d = _dirs.size(); |
933 | 46.1M | while (it != end && *it != ']') |
934 | 46.1M | { |
935 | 46.1M | name.clear(); |
936 | 46.1M | if (*it == '-') |
937 | 5.72k | name = "-"; |
938 | 46.1M | else |
939 | 424M | while (it != end && *it != '.' && *it != ']') name += *it++; |
940 | 46.1M | if (!name.empty()) |
941 | 46.1M | { |
942 | 46.1M | if (name == "-") |
943 | 5.72k | { |
944 | 5.72k | if (_dirs.size() > d) |
945 | 2.20k | _dirs.pop_back(); |
946 | 5.72k | } |
947 | 46.0M | else _dirs.push_back(name); |
948 | 46.1M | } |
949 | 46.1M | if (it != end && *it != ']') ++it; |
950 | 46.1M | } |
951 | 1.48k | if (it == end) throw PathSyntaxException(path); |
952 | 1.12k | ++it; |
953 | 1.12k | } |
954 | 3.88k | } |
955 | 3.91k | _name.clear(); |
956 | 3.91k | } |
957 | 9.06M | while (it != end && *it != ';') _name += *it++; |
958 | 4.56k | } |
959 | 43.9k | else _name = name; |
960 | 48.5k | if (it != end && *it == ';') |
961 | 45.3k | { |
962 | 45.3k | ++it; |
963 | 5.68M | while (it != end) _version += *it++; |
964 | 45.3k | } |
965 | 48.5k | } |
966 | 70 | else _name = name; |
967 | 49.5k | } |
968 | 49.5k | } |
969 | | |
970 | | |
971 | | void Path::parseGuess(const std::string& path) |
972 | 86.7k | { |
973 | 86.7k | bool hasBackslash = false; |
974 | 86.7k | bool hasSlash = false; |
975 | 86.7k | bool hasOpenBracket = false; |
976 | 86.7k | bool hasClosBracket = false; |
977 | 86.7k | bool isWindows = path.length() > 2 && path[1] == ':' && (path[2] == '/' || path[2] == '\\'); |
978 | 86.7k | std::string::const_iterator end = path.end(); |
979 | 86.7k | std::string::const_iterator semiIt = end; |
980 | 86.7k | if (!isWindows) |
981 | 86.3k | { |
982 | 970M | for (std::string::const_iterator it = path.begin(); it != end; ++it) |
983 | 970M | { |
984 | 970M | switch (*it) |
985 | 970M | { |
986 | 17.2M | case '\\': hasBackslash = true; break; |
987 | 6.75M | case '/': hasSlash = true; break; |
988 | 29.1k | case '[': hasOpenBracket = true; |
989 | 29.1k | [[fallthrough]]; |
990 | 59.3k | case ']': hasClosBracket = hasOpenBracket; |
991 | 59.3k | [[fallthrough]]; |
992 | 213k | case ';': semiIt = it; break; |
993 | 970M | } |
994 | 970M | } |
995 | 86.3k | } |
996 | 86.7k | if (hasBackslash || isWindows) |
997 | 5.87k | { |
998 | 5.87k | parseWindows(path); |
999 | 5.87k | } |
1000 | 80.8k | else if (hasSlash) |
1001 | 29.8k | { |
1002 | 29.8k | parseUnix(path); |
1003 | 29.8k | } |
1004 | 51.0k | else |
1005 | 51.0k | { |
1006 | 51.0k | bool isVMS = hasClosBracket; |
1007 | 51.0k | if (!isVMS && semiIt != end) |
1008 | 36.9k | { |
1009 | 36.9k | isVMS = true; |
1010 | 36.9k | ++semiIt; |
1011 | 66.6k | while (semiIt != end) |
1012 | 29.7k | { |
1013 | 29.7k | if (*semiIt < '0' || *semiIt > '9') |
1014 | 43 | { |
1015 | 43 | isVMS = false; break; |
1016 | 43 | } |
1017 | 29.7k | ++semiIt; |
1018 | 29.7k | } |
1019 | 36.9k | } |
1020 | 51.0k | if (isVMS) |
1021 | 48.9k | parseVMS(path); |
1022 | 2.14k | else |
1023 | 2.14k | parseUnix(path); |
1024 | 51.0k | } |
1025 | 86.7k | } |
1026 | | |
1027 | | |
1028 | | std::string Path::buildUnix() const |
1029 | 244k | { |
1030 | 244k | std::string result; |
1031 | 244k | if (!_device.empty()) |
1032 | 2.46k | { |
1033 | 2.46k | result.append("/"); |
1034 | 2.46k | result.append(_device); |
1035 | 2.46k | result.append(":/"); |
1036 | 2.46k | } |
1037 | 241k | else if (_absolute) |
1038 | 157k | { |
1039 | 157k | result.append("/"); |
1040 | 157k | } |
1041 | 244k | for (const auto& d: _dirs) |
1042 | 66.2M | { |
1043 | 66.2M | result.append(d); |
1044 | 66.2M | result.append("/"); |
1045 | 66.2M | } |
1046 | 244k | result.append(_name); |
1047 | 244k | return result; |
1048 | 244k | } |
1049 | | |
1050 | | |
1051 | | std::string Path::buildWindows() const |
1052 | 489 | { |
1053 | 489 | std::string result; |
1054 | 489 | if (!_node.empty()) |
1055 | 0 | { |
1056 | 0 | result.append("\\\\"); |
1057 | 0 | result.append(_node); |
1058 | 0 | result.append("\\"); |
1059 | 0 | } |
1060 | 489 | else if (!_device.empty()) |
1061 | 52 | { |
1062 | 52 | result.append(_device); |
1063 | 52 | result.append(":\\"); |
1064 | 52 | } |
1065 | 437 | else if (_absolute) |
1066 | 74 | { |
1067 | 74 | result.append("\\"); |
1068 | 74 | } |
1069 | 489 | for (const auto& d: _dirs) |
1070 | 108M | { |
1071 | 108M | result.append(d); |
1072 | 108M | result.append("\\"); |
1073 | 108M | } |
1074 | 489 | result.append(_name); |
1075 | 489 | return result; |
1076 | 489 | } |
1077 | | |
1078 | | |
1079 | | std::string Path::buildVMS() const |
1080 | 837 | { |
1081 | 837 | std::string result; |
1082 | 837 | if (!_node.empty()) |
1083 | 0 | { |
1084 | 0 | result.append(_node); |
1085 | 0 | result.append("::"); |
1086 | 0 | } |
1087 | 837 | if (!_device.empty()) |
1088 | 120 | { |
1089 | 120 | result.append(_device); |
1090 | 120 | result.append(":"); |
1091 | 120 | } |
1092 | 837 | if (!_dirs.empty()) |
1093 | 734 | { |
1094 | 734 | result.append("["); |
1095 | 734 | if (!_absolute && _dirs[0] != "..") |
1096 | 356 | result.append("."); |
1097 | 133M | for (StringVec::const_iterator it = _dirs.begin(); it != _dirs.end(); ++it) |
1098 | 133M | { |
1099 | 133M | if (it != _dirs.begin() && *it != "..") |
1100 | 133M | result.append("."); |
1101 | 133M | if (*it == "..") |
1102 | 488k | result.append("-"); |
1103 | 133M | else |
1104 | 133M | result.append(*it); |
1105 | 133M | } |
1106 | 734 | result.append("]"); |
1107 | 734 | } |
1108 | 837 | result.append(_name); |
1109 | 837 | if (!_version.empty()) |
1110 | 0 | { |
1111 | 0 | result.append(";"); |
1112 | 0 | result.append(_version); |
1113 | 0 | } |
1114 | 837 | return result; |
1115 | 837 | } |
1116 | | |
1117 | | |
1118 | | std::string Path::transcode(const std::string& path) |
1119 | 0 | { |
1120 | | #if defined(_WIN32) |
1121 | | std::wstring uniPath; |
1122 | | UnicodeConverter::toUTF16(path, uniPath); |
1123 | | DWORD len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, uniPath.c_str(), static_cast<int>(uniPath.length()), nullptr, 0, nullptr, nullptr); |
1124 | | if (len > 0) |
1125 | | { |
1126 | | Buffer<char> buffer(len); |
1127 | | DWORD rc = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, uniPath.c_str(), static_cast<int>(uniPath.length()), buffer.begin(), static_cast<int>(buffer.size()), nullptr, nullptr); |
1128 | | if (rc) |
1129 | | { |
1130 | | return std::string(buffer.begin(), buffer.size()); |
1131 | | } |
1132 | | } |
1133 | | #endif |
1134 | 0 | return path; |
1135 | 0 | } |
1136 | | |
1137 | | |
1138 | | } // namespace Poco |