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