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