OSDN Git Service

Fixed Issue #135: Taskbar text says "TortoiseSVN"
[tortoisegit/TortoiseGitJp.git] / src / Utils / PathUtils.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseSVN\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "StdAfx.h"\r
20 #include "PathUtils.h"\r
21 \r
22 BOOL CPathUtils::MakeSureDirectoryPathExists(LPCTSTR path)\r
23 {\r
24         size_t len = _tcslen(path);\r
25         TCHAR * buf = new TCHAR[len+10];\r
26         TCHAR * internalpathbuf = new TCHAR[len+10];\r
27         TCHAR * pPath = internalpathbuf;\r
28         SECURITY_ATTRIBUTES attribs;\r
29 \r
30         SecureZeroMemory(&attribs, sizeof(SECURITY_ATTRIBUTES));\r
31 \r
32         attribs.nLength = sizeof(SECURITY_ATTRIBUTES);\r
33         attribs.bInheritHandle = FALSE;\r
34 \r
35         ConvertToBackslash(internalpathbuf, path, len+10);\r
36         do\r
37         {\r
38                 SecureZeroMemory(buf, (len+10)*sizeof(TCHAR));\r
39                 TCHAR * slashpos = _tcschr(pPath, '\\');\r
40                 if (slashpos)\r
41                         _tcsncpy_s(buf, len+10, internalpathbuf, slashpos - internalpathbuf);\r
42                 else\r
43                         _tcsncpy_s(buf, len+10, internalpathbuf, len+10);\r
44                 CreateDirectory(buf, &attribs);\r
45                 pPath = _tcschr(pPath, '\\');\r
46         } while ((pPath++)&&(_tcschr(pPath, '\\')));\r
47         \r
48         BOOL bRet = CreateDirectory(internalpathbuf, &attribs);\r
49         delete[] buf;\r
50         delete[] internalpathbuf;\r
51         return bRet;\r
52 }\r
53 \r
54 void CPathUtils::Unescape(char * psz)\r
55 {\r
56         char * pszSource = psz;\r
57         char * pszDest = psz;\r
58 \r
59         static const char szHex[] = "0123456789ABCDEF";\r
60 \r
61         // Unescape special characters. The number of characters\r
62         // in the *pszDest is assumed to be <= the number of characters\r
63         // in pszSource (they are both the same string anyway)\r
64 \r
65         while (*pszSource != '\0' && *pszDest != '\0')\r
66         {\r
67                 if (*pszSource == '%')\r
68                 {\r
69                         // The next two chars following '%' should be digits\r
70                         if ( *(pszSource + 1) == '\0' ||\r
71                                 *(pszSource + 2) == '\0' )\r
72                         {\r
73                                 // nothing left to do\r
74                                 break;\r
75                         }\r
76 \r
77                         char nValue = '?';\r
78                         const char * pszLow = NULL;\r
79                         const char * pszHigh = NULL;\r
80                         pszSource++;\r
81 \r
82                         *pszSource = (char) toupper(*pszSource);\r
83                         pszHigh = strchr(szHex, *pszSource);\r
84 \r
85                         if (pszHigh != NULL)\r
86                         {\r
87                                 pszSource++;\r
88                                 *pszSource = (char) toupper(*pszSource);\r
89                                 pszLow = strchr(szHex, *pszSource);\r
90 \r
91                                 if (pszLow != NULL)\r
92                                 {\r
93                                         nValue = (char) (((pszHigh - szHex) << 4) +\r
94                                                 (pszLow - szHex));\r
95                                 }\r
96                         }\r
97                         else\r
98                         {\r
99                                 pszSource--;\r
100                                 nValue = *pszSource;\r
101                         }\r
102                         *pszDest++ = nValue;\r
103                 } \r
104                 else\r
105                         *pszDest++ = *pszSource;\r
106 \r
107                 pszSource++;\r
108         }\r
109 \r
110         *pszDest = '\0';\r
111 }\r
112 \r
113 static const char iri_escape_chars[256] = {\r
114         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
115         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
116         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
117         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
118         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
119         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
120         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
121         1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,\r
122 \r
123         /* 128 */\r
124         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
125         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
126         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
127         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
128         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
129         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
130         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,\r
131         0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0\r
132 };\r
133 \r
134 const char uri_autoescape_chars[256] = {\r
135         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
136         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
137         0, 1, 0, 0, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,\r
138         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 1, 0, 0,\r
139 \r
140         /* 64 */\r
141         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,\r
142         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,\r
143         0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,\r
144         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,\r
145 \r
146         /* 128 */\r
147         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
148         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
149         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
150         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
151 \r
152         /* 192 */\r
153         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
154         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
155         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
156         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
157 };\r
158 \r
159 static const char uri_char_validity[256] = {\r
160         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
161         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
162         0, 1, 0, 0, 1, 0, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,\r
163         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 1, 0, 0,\r
164 \r
165         /* 64 */\r
166         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,\r
167         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,\r
168         0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,\r
169         1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,\r
170 \r
171         /* 128 */\r
172         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
173         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
174         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
175         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
176 \r
177         /* 192 */\r
178         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
179         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
180         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
181         0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,\r
182 };\r
183 \r
184 \r
185 void CPathUtils::ConvertToBackslash(LPTSTR dest, LPCTSTR src, size_t len)\r
186 {\r
187         _tcscpy_s(dest, len, src);\r
188         TCHAR * p = dest;\r
189         for (; *p != '\0'; ++p)\r
190                 if (*p == '/')\r
191                         *p = '\\';\r
192 }\r
193 \r
194 CStringA CPathUtils::PathEscape(const CStringA& path)\r
195 {\r
196         CStringA ret2;\r
197         int c;\r
198         int i;\r
199         for (i=0; path[i]; ++i)\r
200         {\r
201                 c = (unsigned char)path[i];\r
202                 if (iri_escape_chars[c])\r
203                 {\r
204                         // no escaping needed for that char\r
205                         ret2 += (unsigned char)path[i];\r
206                 }\r
207                 else\r
208                 {\r
209                         // char needs escaping\r
210                         CStringA temp;\r
211                         temp.Format("%%%02X", (unsigned char)c);\r
212                         ret2 += temp;\r
213                 }\r
214         }\r
215         CStringA ret;\r
216         for (i=0; ret2[i]; ++i)\r
217         {\r
218                 c = (unsigned char)ret2[i];\r
219                 if (uri_autoescape_chars[c])\r
220                 {\r
221                         // no escaping needed for that char\r
222                         ret += (unsigned char)ret2[i];\r
223                 }\r
224                 else\r
225                 {\r
226                         // char needs escaping\r
227                         CStringA temp;\r
228                         temp.Format("%%%02X", (unsigned char)c);\r
229                         ret += temp;\r
230                 }\r
231         }\r
232 \r
233         if ((ret.Left(11).Compare("file:///%5C") == 0) && (ret.Find('%', 12) < 0))\r
234                 ret.Replace(("file:///%5C"), ("file://"));\r
235         ret.Replace(("file:////%5C"), ("file://"));\r
236 \r
237         return ret;\r
238 }\r
239 \r
240 #ifdef _MFC_VER\r
241 CString CPathUtils::GetFileNameFromPath(CString sPath)\r
242 {\r
243         CString ret;\r
244         sPath.Replace(_T("/"), _T("\\"));\r
245         ret = sPath.Mid(sPath.ReverseFind('\\') + 1);\r
246         return ret;\r
247 }\r
248 \r
249 CString CPathUtils::GetFileExtFromPath(const CString& sPath)\r
250 {\r
251         int dotPos = sPath.ReverseFind('.');\r
252         int slashPos = sPath.ReverseFind('\\');\r
253         if (slashPos < 0)\r
254                 slashPos = sPath.ReverseFind('/');\r
255         if (dotPos > slashPos)\r
256                 return sPath.Mid(dotPos);\r
257         return CString();\r
258 }\r
259 \r
260 CString CPathUtils::GetLongPathname(const CString& path)\r
261 {\r
262         if (path.IsEmpty())\r
263                 return path;\r
264         TCHAR pathbufcanonicalized[MAX_PATH]; // MAX_PATH ok.\r
265         DWORD ret = 0;\r
266         CString sRet;\r
267         if (!PathIsURL(path) && PathIsRelative(path))\r
268         {\r
269                 ret = GetFullPathName(path, 0, NULL, NULL);\r
270                 if (ret)\r
271                 {\r
272                         TCHAR * pathbuf = new TCHAR[ret+1];\r
273                         if ((ret = GetFullPathName(path, ret, pathbuf, NULL))!=0)\r
274                         {\r
275                                 sRet = CString(pathbuf, ret);\r
276                         }\r
277                         delete [] pathbuf;\r
278                 }\r
279         }\r
280         else if (PathCanonicalize(pathbufcanonicalized, path))\r
281         {\r
282                 ret = ::GetLongPathName(pathbufcanonicalized, NULL, 0);\r
283                 TCHAR * pathbuf = new TCHAR[ret+2];     \r
284                 ret = ::GetLongPathName(pathbufcanonicalized, pathbuf, ret+1);\r
285                 sRet = CString(pathbuf, ret);\r
286                 delete[] pathbuf;\r
287         }\r
288         else\r
289         {\r
290                 ret = ::GetLongPathName(path, NULL, 0);\r
291                 TCHAR * pathbuf = new TCHAR[ret+2];\r
292                 ret = ::GetLongPathName(path, pathbuf, ret+1);\r
293                 sRet = CString(pathbuf, ret);\r
294                 delete[] pathbuf;\r
295         }\r
296         if (ret == 0)\r
297                 return path;\r
298         return sRet;\r
299 }\r
300 \r
301 BOOL CPathUtils::FileCopy(CString srcPath, CString destPath, BOOL force)\r
302 {\r
303         srcPath.Replace('/', '\\');\r
304         destPath.Replace('/', '\\');\r
305         CString destFolder = destPath.Left(destPath.ReverseFind('\\'));\r
306         MakeSureDirectoryPathExists(destFolder);\r
307         return (CopyFile(srcPath, destPath, !force));\r
308 }\r
309 \r
310 CString CPathUtils::ParsePathInString(const CString& Str)\r
311 {\r
312         CString sToken;\r
313         int curPos = 0;\r
314         sToken = Str.Tokenize(_T("'\t\r\n"), curPos);\r
315         while (!sToken.IsEmpty())\r
316         {\r
317                 if ((sToken.Find('/')>=0)||(sToken.Find('\\')>=0))\r
318                 {\r
319                         sToken.Trim(_T("'\""));\r
320                         return sToken;\r
321                 }\r
322                 sToken = Str.Tokenize(_T("'\t\r\n"), curPos);\r
323         }\r
324         sToken.Empty();\r
325         return sToken;\r
326 }\r
327 \r
328 CString CPathUtils::GetAppDirectory()\r
329 {\r
330         CString path;\r
331         DWORD len = 0;\r
332         DWORD bufferlen = MAX_PATH;             // MAX_PATH is not the limit here!\r
333         path.GetBuffer(bufferlen);\r
334         do \r
335         {\r
336                 bufferlen += MAX_PATH;          // MAX_PATH is not the limit here!\r
337                 path.ReleaseBuffer(0);\r
338                 len = GetModuleFileName(NULL, path.GetBuffer(bufferlen+1), bufferlen);                          \r
339         } while(len == bufferlen);\r
340         path.ReleaseBuffer();\r
341         path = path.Left(path.ReverseFind('\\')+1);\r
342         return path;\r
343 }\r
344 \r
345 CString CPathUtils::GetAppParentDirectory()\r
346 {\r
347         CString path = GetAppDirectory();\r
348         path = path.Left(path.ReverseFind('\\'));\r
349         path = path.Left(path.ReverseFind('\\')+1);\r
350         return path;\r
351 }\r
352 \r
353 CString CPathUtils::GetAppDataDirectory()\r
354 {\r
355         TCHAR path[MAX_PATH];           //MAX_PATH ok here.\r
356         if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path)!=S_OK)\r
357                 return CString();\r
358 \r
359         _tcscat_s(path, MAX_PATH, _T("\\TortoiseGit"));\r
360         if (!PathIsDirectory(path))\r
361                 CreateDirectory(path, NULL);\r
362 \r
363         return CString (path) + _T('\\');\r
364 }\r
365 \r
366 \r
367 CStringA CPathUtils::PathUnescape(const CStringA& path)\r
368 {\r
369         std::auto_ptr<char> urlabuf (new char[path.GetLength()+1]);\r
370 \r
371         strcpy_s(urlabuf.get(), path.GetLength()+1, path);\r
372         Unescape(urlabuf.get());\r
373 \r
374         return urlabuf.get();\r
375 }\r
376 \r
377 CStringW CPathUtils::PathUnescape(const CStringW& path)\r
378 {\r
379         char * buf;\r
380         CStringA patha;\r
381         int len = path.GetLength();\r
382         if (len==0)\r
383                 return CStringW();\r
384         buf = patha.GetBuffer(len*4 + 1);\r
385         int lengthIncTerminator = WideCharToMultiByte(CP_UTF8, 0, path, -1, buf, len*4, NULL, NULL);\r
386         patha.ReleaseBuffer(lengthIncTerminator-1);\r
387 \r
388         patha = PathUnescape(patha);\r
389 \r
390         WCHAR * bufw;\r
391         len = patha.GetLength();\r
392         bufw = new WCHAR[len*4 + 1];\r
393         SecureZeroMemory(bufw, (len*4 + 1)*sizeof(WCHAR));\r
394         MultiByteToWideChar(CP_UTF8, 0, patha, -1, bufw, len*4);\r
395         CStringW ret = CStringW(bufw);\r
396         delete [] bufw;\r
397         return ret;\r
398 }\r
399 \r
400 CString CPathUtils::GetVersionFromFile(const CString & p_strDateiname)\r
401 {\r
402         struct TRANSARRAY\r
403         {\r
404                 WORD wLanguageID;\r
405                 WORD wCharacterSet;\r
406         };\r
407 \r
408         CString strReturn;\r
409         DWORD dwReserved,dwBufferSize;\r
410         dwBufferSize = GetFileVersionInfoSize((LPTSTR)(LPCTSTR)p_strDateiname,&dwReserved);\r
411 \r
412         if (dwBufferSize > 0)\r
413         {\r
414                 LPVOID pBuffer = (void*) malloc(dwBufferSize);\r
415 \r
416                 if (pBuffer != (void*) NULL)\r
417                 {\r
418                         UINT        nInfoSize = 0,\r
419                                 nFixedLength = 0;\r
420                         LPSTR       lpVersion = NULL;\r
421                         VOID*       lpFixedPointer;\r
422                         TRANSARRAY* lpTransArray;\r
423                         CString     strLangProduktVersion;\r
424 \r
425                         GetFileVersionInfo((LPTSTR)(LPCTSTR)p_strDateiname,\r
426                                 dwReserved,\r
427                                 dwBufferSize,\r
428                                 pBuffer);\r
429 \r
430                         // Check the current language\r
431                         VerQueryValue(  pBuffer,\r
432                                 _T("\\VarFileInfo\\Translation"),\r
433                                 &lpFixedPointer,\r
434                                 &nFixedLength);\r
435                         lpTransArray = (TRANSARRAY*) lpFixedPointer;\r
436 \r
437                         strLangProduktVersion.Format(_T("\\StringFileInfo\\%04x%04x\\ProductVersion"),\r
438                                 lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);\r
439 \r
440                         VerQueryValue(pBuffer,\r
441                                 (LPTSTR)(LPCTSTR)strLangProduktVersion,\r
442                                 (LPVOID *)&lpVersion,\r
443                                 &nInfoSize);\r
444                         strReturn = (LPCTSTR)lpVersion;\r
445                         free(pBuffer);\r
446                 }\r
447         } \r
448 \r
449         return strReturn;\r
450 }\r
451 \r
452 CString CPathUtils::PathPatternEscape(const CString& path)\r
453 {\r
454         CString result = path;\r
455         // first remove already escaped patterns to avoid having those\r
456         // escaped twice\r
457         result.Replace(_T("\\["), _T("["));\r
458         result.Replace(_T("\\]"), _T("]"));\r
459         // now escape the patterns (again)\r
460         result.Replace(_T("["), _T("\\["));\r
461         result.Replace(_T("]"), _T("\\]"));\r
462         return result;\r
463 }\r
464 \r
465 CString CPathUtils::PathPatternUnEscape(const CString& path)\r
466 {\r
467         CString result = path;\r
468         result.Replace(_T("\\["), _T("["));\r
469         result.Replace(_T("\\]"), _T("]"));\r
470         return result;\r
471 }\r
472 \r
473 #endif\r
474 \r
475 #if defined(_DEBUG) && defined(_MFC_VER)\r
476 // Some test cases for these classes\r
477 static class CPathTests\r
478 {\r
479 public:\r
480         CPathTests()\r
481         {\r
482                 UnescapeTest();\r
483                 ExtTest();\r
484                 ParseTests();\r
485         }\r
486 \r
487 private:\r
488         void UnescapeTest()\r
489         {\r
490                 CString test(_T("file:///d:/REpos1/uCOS-100/Trunk/name%20with%20spaces/NewTest%20%%20NewTest"));\r
491                 CString test2 = CPathUtils::PathUnescape(test);\r
492                 ATLASSERT(test2.Compare(_T("file:///d:/REpos1/uCOS-100/Trunk/name with spaces/NewTest % NewTest")) == 0);\r
493                 CStringA test3 = CPathUtils::PathEscape("file:///d:/REpos1/uCOS-100/Trunk/name with spaces/NewTest % NewTest");\r
494                 ATLASSERT(test3.Compare("file:///d:/REpos1/uCOS-100/Trunk/name%20with%20spaces/NewTest%20%%20NewTest") == 0);\r
495         }\r
496         void ExtTest()\r
497         {\r
498                 CString test(_T("d:\\test\filename.ext"));\r
499                 ATLASSERT(CPathUtils::GetFileExtFromPath(test).Compare(_T(".ext")) == 0);\r
500                 test = _T("filename.ext");\r
501                 ATLASSERT(CPathUtils::GetFileExtFromPath(test).Compare(_T(".ext")) == 0);\r
502                 test = _T("d:\\test\filename");\r
503                 ATLASSERT(CPathUtils::GetFileExtFromPath(test).IsEmpty());\r
504                 test = _T("filename");\r
505                 ATLASSERT(CPathUtils::GetFileExtFromPath(test).IsEmpty());\r
506         }\r
507         void ParseTests()\r
508         {\r
509                 CString test(_T("test 'd:\\testpath with spaces' test"));\r
510                 ATLASSERT(CPathUtils::ParsePathInString(test).Compare(_T("d:\\testpath with spaces")) == 0);\r
511                 test = _T("d:\\testpath with spaces");\r
512                 ATLASSERT(CPathUtils::ParsePathInString(test).Compare(_T("d:\\testpath with spaces")) == 0);\r
513         }\r
514 \r
515 } CPathTests;\r
516 #endif\r
517 \r