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