!I (1670409):
[CRYENGINE.git] / Code / CryEngine / CryCommon / CryString / CryPath.h
blob1728265f9855adb62a3402a5e8dc36e8700c6892
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #pragma once
5 #include <CryCore/Platform/CryWindows.h>
6 #include <CryString/CryString.h>
7 #include <CryString/CryFixedString.h>
8 #include <algorithm>
9 #include <type_traits>
11 #if CRY_PLATFORM_POSIX
12 #define CRY_NATIVE_PATH_SEPSTR "/"
13 #else
14 #define CRY_NATIVE_PATH_SEPSTR "\\"
15 #endif
17 namespace PathUtil
19 namespace detail
21 template<typename>
22 struct IsValidStringType : std::false_type {};
24 template<>
25 struct IsValidStringType<string> : std::true_type {};
27 template<>
28 struct IsValidStringType<wstring> : std::true_type {};
30 template<size_t Size>
31 struct IsValidStringType<CryStackStringT<char, Size>> : std::true_type {};
33 template<size_t Size>
34 struct IsValidStringType<CryStackStringT<wchar_t, Size>> : std::true_type {};
36 template<size_t Size>
37 struct IsValidStringType<CryFixedStringT<Size>> : std::true_type {};
39 template<size_t Size>
40 struct IsValidStringType<CryFixedWStringT<Size>> : std::true_type {};
42 template<typename>
43 struct SStringConstants
45 static constexpr const char* ForwardSlash = "/";
46 static constexpr const char* BackSlash = "\\";
49 template<>
50 struct SStringConstants<wstring>
52 static constexpr const wchar_t* ForwardSlash = L"/";
53 static constexpr const wchar_t* BackSlash = L"\\";
57 //! Convert a path to the uniform form.
58 template<typename TString>
59 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
60 inline /*TString*/ ToUnixPath(const TString& strPath)
62 if (strPath.find('\\') != TString::npos)
64 auto path = strPath;
65 #ifdef CRY_STRING
66 path.replace('\\', '/');
67 #else
68 std::replace(path.begin(), path.end(), '\\', '/');
69 #endif
70 return path;
72 return strPath;
75 inline string ToUnixPath(const char* szPath)
77 return ToUnixPath(string(szPath));
80 //! Convert a path to the DOS form.
81 template<typename TString>
82 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
83 inline /*TString*/ ToDosPath(const TString& strPath)
85 if (strPath.find('/') != TString::npos)
87 auto path = strPath;
88 #ifdef CRY_STRING
89 path.replace('/', '\\');
90 #else
91 std::replace(path.begin(), path.end(), '/', '\\');
92 #endif
93 return path;
95 return strPath;
98 inline string ToDosPath(const char* szPath)
100 return ToDosPath(string(szPath));
103 inline bool IsStrValid(const char* str)
105 return str && *str;
108 inline bool IsRelativePath(const char* p)
110 if (!IsStrValid(p))
112 return true;
114 return p[0] != '/' && p[0] != '\\' && !strchr(p, ':');
117 //! Split full file name to path and filename.
118 //! \param[in] filepath Full file name including path.
119 //! \param[out] path Extracted file path.
120 //! \param[out] filename Extracted file (without extension).
121 //! \param[out] extension Extracted file's extension (without .).
122 template<typename TString>
123 typename std::enable_if<detail::IsValidStringType<TString>::value>::type
124 inline /*void*/ Split(const TString& filepath, TString& path, TString& filename, TString& extension)
126 path = filename = extension = TString();
127 if (filepath.empty())
128 return;
129 const char* szFilepath = filepath.c_str();
130 const char* szExtension = szFilepath + filepath.length() - 1;
131 const char* p;
132 for (p = szExtension; p >= szFilepath; --p)
134 switch (*p)
136 case ':':
137 case '/':
138 case '\\':
139 path = TString(szFilepath, p + 1);
140 filename = TString(p + 1, szExtension);
141 return;
142 case '.':
143 // there's an extension in this file name
144 extension = filepath.substr(p - szFilepath + 1);
145 szExtension = p;
146 break;
149 filename = filepath.substr(p - szFilepath + 1, szExtension - p);
152 template<typename TString>
153 typename std::enable_if<detail::IsValidStringType<TString>::value>::type
154 inline /*void*/ Split(const char* szFilepath, TString& path, TString& filename, TString& extension)
156 return Split(TString(szFilepath), path, filename, extension);
159 //! Split full file name to path and filename.
160 //! \param[in] filepath Full file name including path.
161 //! \param[out] path Extracted file path.
162 //! \param[out] file Extracted file (with extension).
163 template<typename TString>
164 typename std::enable_if<detail::IsValidStringType<TString>::value>::type
165 inline /*void*/ Split(const TString& filepath, TString& path, TString& file)
167 TString extension;
168 Split(filepath, path, file, extension);
169 if (!extension.empty())
171 file += '.' + extension;
175 template<typename TString>
176 typename std::enable_if<detail::IsValidStringType<TString>::value>::type
177 inline /*void*/ Split(const char* szFilepath, TString& path, TString& file)
179 return Split(TString(szFilepath), path, file);
182 //! Extract extension from full specified file path.
183 //! \return Pointer to the extension (without .) or pointer to an empty 0-terminated string.
184 inline const char* GetExt(const char* filepath)
186 const char* szFilepath = filepath;
187 const size_t length = strlen(filepath);
188 for (const char* p = szFilepath + length - 1; p >= szFilepath; --p)
190 switch (*p)
192 case ':':
193 case '/':
194 case '\\':
195 // we've reached a path separator - it means there's no extension in this name
196 return "";
197 case '.':
198 // there's an extension in this file name
199 return p + 1;
202 return "";
205 //! Removes filename from path. Example: "some/directory/file.ext" => "some/directory/"
206 template<typename TString>
207 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
208 inline /*TString*/ GetPathWithoutFilename(const TString& filepath)
210 const char* szFilepath = filepath.c_str();
211 for (const char* p = szFilepath + filepath.length() - 1; p >= szFilepath; --p)
213 switch (*p)
215 case ':':
216 case '/':
217 case '\\':
218 return filepath.substr(0, p - szFilepath + 1);
221 return "";
224 //! Removes filename from path. Example: "some/directory/file.ext" => "some/directory/"
225 inline string GetPathWithoutFilename(const char* filepath)
227 return GetPathWithoutFilename(string(filepath));
230 //! Extract file name with extension from full specified file path.
231 template<typename TString>
232 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
233 inline /*TString*/ GetFile(const TString& filepath)
235 const char* szFilepath = filepath.c_str();
236 for (const char* p = szFilepath + filepath.length() - 1; p >= szFilepath; --p)
238 switch (*p)
240 case ':':
241 case '/':
242 case '\\':
243 return filepath.substr(p - szFilepath + 1);
246 return filepath;
249 inline const char* GetFile(const char* szFilepath)
251 const size_t len = strlen(szFilepath);
252 for (const char* p = szFilepath + len - 1; p >= szFilepath; --p)
254 switch (*p)
256 case ':':
257 case '/':
258 case '\\':
259 return p + 1;
262 return szFilepath;
265 //! Remove extension for given file.
266 template<typename TString>
267 typename std::enable_if<detail::IsValidStringType<TString>::value, void>::type
268 inline /*void*/ RemoveExtension(TString& filepath)
270 const char* szFilepath = filepath.c_str();
271 for (const char* p = szFilepath + filepath.length() - 1; p >= szFilepath; --p)
273 switch (*p)
275 case ':':
276 case '/':
277 case '\\':
278 // we've reached a path separator - it means there's no extension in this name
279 return;
280 case '.':
281 // there's an extension in this file name
282 filepath.erase(p - szFilepath);
283 return;
286 // it seems the file name is a pure name, without extension
289 //! Remove extension for given file.
290 inline void RemoveExtension(char* szFilePath)
292 for (char* p = szFilePath + strlen(szFilePath) - 1; p >= szFilePath; --p)
294 switch (*p)
296 case ':':
297 case '/':
298 case '\\':
299 // we've reached a path separator - it means there's no extension in this name
300 return;
301 case '.':
302 // there's an extension in this file name
303 *p = '\0';
304 return;
307 // it seems the file name is a pure name, without extension
310 template<typename TString>
311 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
312 inline /*TString*/ RemoveExtension(const TString& filepath)
314 auto result = filepath;
315 RemoveExtension(result);
316 return result;
319 inline string RemoveExtension(const char* szFilepath)
321 return RemoveExtension(string(szFilepath));
324 //! Extract file name without extension from full specified file path.
325 template<typename TString>
326 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
327 inline /*TString*/ GetFileName(const TString& filepath)
329 return GetFile(RemoveExtension(filepath));
332 inline string GetFileName(const char* szFilepath)
334 return GetFileName(string(szFilepath));
337 //! Removes the trailing slash or backslash from a given path.
338 template<typename TString>
339 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
340 inline /*TString*/ RemoveSlash(const TString& path)
342 if (path.empty() || (path[path.length() - 1] != '/' && path[path.length() - 1] != '\\'))
343 return path;
344 return path.substr(0, path.length() - 1);
347 inline string RemoveSlash(const char* szPath)
349 return RemoveSlash(string(szPath));
352 inline string GetEnginePath()
354 char szEngineRootDir[_MAX_PATH];
355 CryFindEngineRootFolder(CRY_ARRAY_COUNT(szEngineRootDir), szEngineRootDir);
356 return RemoveSlash(szEngineRootDir);
359 //! Add a slash if necessary.
360 template<typename TString>
361 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
362 inline /*TString*/ AddSlash(const TString& path)
364 if (path.empty() || path[path.length() - 1] == '/')
365 return path;
366 if (path[path.length() - 1] == '\\')
367 return path.substr(0, path.length() - 1) + detail::SStringConstants<TString>::ForwardSlash;
368 return path + detail::SStringConstants<TString>::ForwardSlash;
371 inline string AddSlash(const char* szPath)
373 return AddSlash(string(szPath));
376 //! Add a backslash if necessary.
377 template<typename TString>
378 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
379 inline /*TString*/ AddBackslash(const TString& path)
381 if (path.empty() || path[path.length() - 1] == '\\')
382 return path;
383 if (path[path.length() - 1] == '/')
384 return path.substr(0, path.length() - 1) + detail::SStringConstants<TString>::BackSlash;
385 return path + detail::SStringConstants<TString>::BackSlash;
388 inline string AddBackslash(const char* szPath)
390 return AddBackslash(string(szPath));
393 //! Replace extension for given file.
394 template<typename TString>
395 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
396 inline /*TString*/ ReplaceExtension(const TString& filepath, const TString& extension)
398 auto str = filepath;
399 RemoveExtension(str);
400 if (extension[0] != '\0' && extension[0] != '.')
402 str += ".";
404 str += extension;
405 return str;
408 inline string ReplaceExtension(const char* szFilepath, const char* szExtension)
410 return ReplaceExtension(string(szFilepath), string(szExtension));
413 //! Makes a fully specified file path from path and file name.
414 template<typename TString>
415 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
416 inline /*TString*/ Make(const TString& directory, const TString& filename)
418 return AddSlash(directory) + filename;
421 inline string Make(const char* szPath, const char* szFilename)
423 return Make(string(szPath), string(szFilename));
426 //! Makes a fully specified file path from path and file name.
427 template<typename TString>
428 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
429 inline /*TString*/ Make(const TString& directory, const TString& filename, const TString& extension)
431 return AddSlash(directory) + ReplaceExtension(filename, extension);
434 inline string Make(const char* szPath, const char* szFilename, const char* szExtension)
436 return Make(string(szPath), string(szFilename), string(szExtension));
439 template<typename TString>
440 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
441 inline /*TString*/ GetParentDirectory(const TString& filePath, int generation = 1)
443 for (const char* p = filePath.c_str() + filePath.length() - 2; // -2 is for the possible trailing slash: there always must be some trailing symbol which is the file/directory name for which we should get the parent
444 p >= filePath.c_str();
445 --p)
447 switch (*p)
449 case ':':
450 return TString(filePath.c_str(), p);
451 case '/':
452 case '\\':
453 // we've reached a path separator - return everything before it.
454 if (!--generation)
455 return TString(filePath.c_str(), p);
456 break;
460 // it seems the file name is a pure name, without path or extension
461 return TString();
464 inline string GetParentDirectory(const char* szFilePath, int generation = 1)
466 return GetParentDirectory(string(szFilePath), generation);
469 //! \return True if the string matches the wildcard.
470 inline bool MatchWildcard(const char* szString, const char* szWildcard)
472 const char* pString = szString, * pWildcard = szWildcard;
473 // skip the obviously the same starting substring
474 while (*pWildcard && *pWildcard != '*' && *pWildcard != '?')
476 if (*pString != *pWildcard)
477 return false; // must be exact match unless there's a wildcard character in the wildcard string
478 else
479 ++pString, ++pWildcard;
482 if (!*pString)
484 // this will only match if there are no non-wild characters in the wildcard
485 for (; *pWildcard; ++pWildcard)
487 if (*pWildcard != '*' && *pWildcard != '?')
488 return false;
490 return true;
493 switch (*pWildcard)
495 case '\0':
496 return false; // the only way to match them after the leading non-wildcard characters is !*pString, which was already checked
498 // we have a wildcard with wild character at the start.
499 case '*':
501 // merge consecutive ? and *, since they are equivalent to a single *
502 while (*pWildcard == '*' || *pWildcard == '?')
503 ++pWildcard;
505 if (!*pWildcard)
506 return true; // the rest of the string doesn't matter: the wildcard ends with *
508 for (; *pString; ++pString)
510 if (MatchWildcard(pString, pWildcard))
511 return true;
514 return false;
517 case '?':
518 return MatchWildcard(pString + 1, pWildcard + 1) || MatchWildcard(pString, pWildcard + 1);
520 default:
521 assert(false);
522 return false;
526 inline std::vector<string> GetDirectoryStructure(const string& path)
528 if (path.empty())
530 return std::vector<string>();
533 string currentDirectoryName;
534 const char* pchCurrentPosition = path.c_str();
535 const char* pchLastPosition = path.c_str();
537 // It removes as many slashes the path has in its start...
538 // MAYBE and just maybe we should consider paths starting with
539 // more than 2 slashes invalid paths...
540 while ((*pchLastPosition == '\\') || (*pchLastPosition == '/'))
542 ++pchLastPosition;
543 ++pchCurrentPosition;
546 std::vector<string> result;
549 pchCurrentPosition = strpbrk(pchLastPosition, "\\/");
550 if (pchCurrentPosition == nullptr)
552 break;
554 currentDirectoryName.assign(pchLastPosition, pchCurrentPosition);
555 pchLastPosition = pchCurrentPosition + 1;
556 // Again, here we are skipping as many consecutive slashes.
557 while ((*pchLastPosition == '\\') || (*pchLastPosition == '/'))
559 ++pchLastPosition;
561 result.push_back(currentDirectoryName);
563 while (true);
565 return result;
568 enum EPathStyle
570 //! Allows Posix paths:
571 //! - absolute path (/foo/bar)
572 //! - relative path (foo, ../bar) paths
573 //! Output slashes are '/'
574 ePathStyle_Posix,
576 //! Allows Posix paths as well as these Windows specific paths:
577 //! - UNC path (\\server\foo\bar)
578 //! - drive-absolute path (c:\foo\bar)
579 //! - drive-relative path (c:foo, c:..\bar)
580 //! Output slashes are '\'
581 ePathStyle_Windows,
583 #if CRY_PLATFORM_WINAPI
584 ePathStyle_Native = ePathStyle_Windows,
585 #elif CRY_PLATFORM_POSIX
586 ePathStyle_Native = ePathStyle_Posix,
587 #else
588 #error Native path style is not supported
589 #endif
592 //! Simplifies a given file path, such that . and .. are removed (if possible).
593 //! Slashes are unified according to the path style and redundant and trailing slashes are removed.
594 //! The path-style also determines what inputs are accepted by the function. See EPathStyle enumeration values for more information.
595 //! If an error occurs or if the buffer is too small, the buffer will contain an empty string and the function returns false.
596 //! \note The output will always be shorter or equal length to the input, so a buffer of the same size as the input will always work.
597 inline bool SimplifyFilePath(const char* const szInput, char* const szBuf, const size_t bufLength, const EPathStyle pathStyle)
599 #define CRY_SIMPLIFY_REJECT { *szBuf = 0; return false; }
600 #define CRY_SIMPLIFY_EMIT(expr) { if (--pOut < szBuf) { *szBuf = 0; return false; } *pOut = expr; }
602 if (szBuf == nullptr || bufLength == 0)
604 return false;
606 if (szInput == nullptr || (*szInput == 0))
608 CRY_SIMPLIFY_REJECT;
611 const bool bWinApi = pathStyle == ePathStyle_Windows;
612 const char kSlash = bWinApi ? '\\' : '/';
613 const char* pIn = szInput + strlen(szInput);
614 const char* pLast = pIn - 1;
615 const char* pLastSlash = pIn;
616 char* pOut = szBuf + bufLength;
617 size_t skipElements = 0;
618 bool bDots = true;
619 char driveRelative = 0;
621 CRY_SIMPLIFY_EMIT(0); // null-terminator
622 while (pIn != szInput)
624 assert(pIn >= szInput);
625 const char c = *--pIn;
626 switch (c)
628 case '\\':
629 case '/':
630 if ((pIn == szInput + 1) && ((szInput[0] == '\\') || (szInput[0] == '/'))) // UNC path
632 if (!bWinApi || bDots || skipElements != 0)
634 CRY_SIMPLIFY_REJECT;
636 CRY_SIMPLIFY_EMIT(kSlash);
637 CRY_SIMPLIFY_EMIT(kSlash);
638 pIn = szInput;
639 continue;
641 else if (bDots) // handle redundant slashes and . and .. elements
643 const size_t numDots = pLastSlash - pIn - 1;
644 if (numDots == 2)
646 ++skipElements;
648 else if ((numDots != 0) && (numDots != 1) && (pIn != pLast))
650 CRY_SIMPLIFY_REJECT;
653 else if (skipElements != 0) // mark eaten element
655 --skipElements;
657 if ((*pOut != kSlash) && (skipElements == 0))
659 if (*pOut != '\0') // don't emit trailing slashes
661 CRY_SIMPLIFY_EMIT(kSlash);
663 else if (pIn == szInput || (bWinApi && pIn[-1] == ':')) // exception for single slash input '/' and 'c:\'
665 CRY_SIMPLIFY_EMIT(kSlash);
668 pLastSlash = pIn;
669 bDots = true;
670 continue;
672 case '.':
673 if (bDots) // count dots
675 continue;
677 break;
679 case ':':
680 if (bWinApi) // ':' should belong to a drive, otherwise it is not an allowed char in win
682 if ((pIn != szInput + 1) || ((pLastSlash == szInput + 2) && (skipElements != 0)))
684 CRY_SIMPLIFY_REJECT;
686 else // handle drive identifier
688 const char driveLetter = pIn[-1];
689 if (!(driveLetter >= 'a' && driveLetter <= 'z') && !(driveLetter >= 'A' && driveLetter <= 'Z'))
691 CRY_SIMPLIFY_REJECT;
693 if (pLastSlash == szInput + 2)
695 if (skipElements != 0)
697 CRY_SIMPLIFY_REJECT;
700 else if (bDots)
702 const size_t numDots = pLastSlash - pIn - 1;
703 if (numDots == 2)
705 CRY_SIMPLIFY_EMIT('.');
706 CRY_SIMPLIFY_EMIT('.');
708 else if (numDots != 1)
710 CRY_SIMPLIFY_REJECT;
713 else if (skipElements != 0)
715 --skipElements;
717 driveRelative = driveLetter;
718 pIn = szInput;
719 bDots = false;
720 continue;
723 // fall-through
724 default:
725 if (bDots)
727 if (skipElements == 0)
729 const size_t numDots = pLastSlash - pIn - 1;
730 for (size_t i = 0; i < numDots; ++i)
732 CRY_SIMPLIFY_EMIT('.');
735 bDots = false;
737 break;
739 if (!skipElements)
741 CRY_SIMPLIFY_EMIT(c);
745 if (bDots) // record remaining dots
747 const size_t numDots = pLastSlash - szInput;
748 if (numDots == 2)
750 ++skipElements;
752 else if (numDots == 1)
754 if ((*pOut == kSlash) && (skipElements == 0))
756 ++pOut; // leading dot should eat a slash
758 else if (*pOut == 0)
760 CRY_SIMPLIFY_EMIT('.'); // special case, the input is only a dot, keep it
763 else if (skipElements != 0)
765 CRY_SIMPLIFY_REJECT;
768 else if (skipElements && !driveRelative) // if not bDots, then we read a relative element that needs to be discounted, e.g. a/..
770 --skipElements;
773 for (size_t i = 0; i < skipElements; ++i) // flush all pending dots
775 CRY_SIMPLIFY_EMIT('.');
776 CRY_SIMPLIFY_EMIT('.');
777 if (i != skipElements - 1)
779 CRY_SIMPLIFY_EMIT(kSlash);
783 if (driveRelative != 0) // Fix up non-absolute but drive-relative paths.
785 CRY_SIMPLIFY_EMIT(':');
786 CRY_SIMPLIFY_EMIT(driveRelative);
789 if (pOut != szBuf) // left-align in the buffer
791 const size_t resultLength = szBuf + bufLength - pOut;
792 assert(resultLength > 0);
793 memmove(szBuf, pOut, resultLength);
795 return true;
797 #undef CRY_SIMPLIFY_REJECT
798 #undef CRY_SIMPLIFY_EMIT
801 //! Converts \ to / and replaces ASCII characters to lower-case (A-Z only).
802 //! This function is ASCII-only and Unicode agnostic.
803 template<typename TString>
804 typename std::enable_if<detail::IsValidStringType<TString>::value>::type
805 inline /*void*/ UnifyFilePath(TString& path)
807 path.replace('\\', '/');
808 path.MakeLower();
812 #ifndef CRY_COMMON_HELPERS_ONLY
813 #include <CrySystem/File/ICryPak.h>
814 #include <CrySystem/ICmdLine.h>
816 namespace PathUtil
818 inline string GetGameFolder()
820 CRY_ASSERT(gEnv && gEnv->pCryPak);
821 return gEnv->pCryPak->GetGameFolder();
824 inline string GetProjectFolder()
826 static bool checkedForCmdLineProjectArg = false;
827 static string cmdLineProjectPath;
828 if (cmdLineProjectPath.IsEmpty() && !checkedForCmdLineProjectArg)
830 CRY_ASSERT_MESSAGE(gEnv && gEnv->pSystem && gEnv->pSystem->GetICmdLine(), "PathUtil::GetProjectFolder() was called before system was initialized");
831 const ICmdLineArg* project = gEnv->pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "project");
832 if (project)
834 cmdLineProjectPath = PathUtil::GetParentDirectory(project->GetValue());
836 checkedForCmdLineProjectArg = true;
838 return cmdLineProjectPath;
841 inline string GetLocalizationFolder()
843 CRY_ASSERT(gEnv && gEnv->pCryPak);
844 return gEnv->pCryPak->GetLocalizationFolder();
847 //! Make a game correct path out of any input path.
848 template<typename TString>
849 typename std::enable_if<detail::IsValidStringType<TString>::value, TString>::type
850 inline /*TString*/ MakeGamePath(const TString& path)
852 const auto fullpath = ToUnixPath(path);
853 const auto rootDataFolder = ToUnixPath(AddSlash(PathUtil::GetGameFolder()));
854 if (fullpath.length() > rootDataFolder.length() && strnicmp(fullpath.c_str(), rootDataFolder.c_str(), rootDataFolder.length()) == 0)
856 return fullpath.substr(rootDataFolder.length(), fullpath.length() - rootDataFolder.length());
858 return fullpath;
861 inline string MakeGamePath(const char* szPath)
863 return MakeGamePath(string(szPath));
866 #endif