Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
8.2 KiB

  1. // Copyright (c) 1997-1999 Microsoft Corporation
  2. #include "precomp.h"
  3. #include "shlwapi2.h"
  4. #include <platform.h>
  5. //---------------------------------------------------------
  6. #ifdef UNICODE
  7. //*** FAST_CharNext -- fast CharNext for path operations
  8. // DESCRIPTION
  9. // when we're just stepping thru chars in a path, a simple '++' is fine.
  10. #define FAST_CharNext(p) (DBNotNULL(p) + 1)
  11. #ifdef DEBUG
  12. LPWSTR WINAPI DBNotNULL(LPCWSTR lpszCurrent)
  13. {
  14. ATLASSERT(*lpszCurrent);
  15. return (LPWSTR) lpszCurrent;
  16. }
  17. #else
  18. #define DBNotNULL(p) (p)
  19. #endif
  20. #else
  21. #define FAST_CharNext(p) CharNext(p)
  22. #endif
  23. //---------------------------------------------------------
  24. LPTSTR PathFindFileName(LPCTSTR pPath)
  25. {
  26. LPCTSTR pT = pPath;
  27. if(pPath)
  28. {
  29. for( ; *pPath; pPath = FAST_CharNext(pPath))
  30. {
  31. if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':') || pPath[0] == TEXT('/'))
  32. && pPath[1] && pPath[1] != TEXT('\\') && pPath[1] != TEXT('/'))
  33. pT = pPath + 1;
  34. }
  35. }
  36. return (LPTSTR)pT; // const -> non const
  37. }
  38. //---------------------------------------------------------
  39. #ifndef UNICODE
  40. // light weight logic for charprev that is not painful for sbcs
  41. BOOL IsTrailByte(LPCTSTR pszSt, LPCTSTR pszCur)
  42. {
  43. LPCTSTR psz = pszCur;
  44. // if the given pointer is at the top of string, at least it's not a trail
  45. // byte.
  46. //
  47. if (psz <= pszSt) return FALSE;
  48. while (psz > pszSt)
  49. {
  50. psz--;
  51. if (!IsDBCSLeadByte(*psz))
  52. {
  53. // This is either a trail byte of double byte char
  54. // or a single byte character we've first seen.
  55. // Thus, the next pointer must be at either of a leadbyte
  56. // or pszCur itself.
  57. psz++;
  58. break;
  59. }
  60. }
  61. // Now psz can point to:
  62. // 1) a leadbyte of double byte character.
  63. // 2) pszSt
  64. // 3) pszCur
  65. //
  66. // if psz == pszSt, psz should point to a valid double byte char.
  67. // because we didn't hit the above if statement.
  68. //
  69. // if psz == pszCur, the *(pszCur-1) was non lead byte so pszCur can't
  70. // be a trail byte.
  71. //
  72. // Thus, we can see pszCur as trail byte pointer if the distance from
  73. // psz is not DBCS boundary that is 2.
  74. //
  75. return (BOOL) ((pszCur-psz) & 1);
  76. }
  77. #endif
  78. //----------------------------------------------------------------------
  79. #define LEN_MID_ELLIPSES 4
  80. #define LEN_END_ELLIPSES 3
  81. #define MIN_CCHMAX LEN_MID_ELLIPSES + LEN_END_ELLIPSES
  82. // PathCompactPathEx
  83. // Output:
  84. // "."
  85. // ".."
  86. // "..."
  87. // "...\"
  88. // "...\."
  89. // "...\.."
  90. // "...\..."
  91. // "...\Truncated filename..."
  92. // "...\whole filename"
  93. // "Truncated path\...\whole filename"
  94. // "Whole path\whole filename"
  95. // The '/' might be used instead of a '\' if the original string used it
  96. // If there is no path, but only a file name that does not fit, the output is:
  97. // "truncated filename..."
  98. BOOL PathCompactPathEx(LPTSTR pszOut,
  99. LPCTSTR pszSrc,
  100. UINT cchMax,
  101. DWORD dwFlags)
  102. {
  103. if(pszSrc)
  104. {
  105. TCHAR * pszFileName, *pszWalk;
  106. UINT uiFNLen = 0;
  107. int cchToCopy = 0, n;
  108. TCHAR chSlash = TEXT('0');
  109. ZeroMemory(pszOut, cchMax * sizeof(TCHAR));
  110. if((UINT)lstrlen(pszSrc)+1 < cchMax)
  111. {
  112. lstrcpy(pszOut, pszSrc);
  113. ATLASSERT(pszOut[cchMax-1] == TEXT('\0'));
  114. return TRUE;
  115. }
  116. // Determine what we use as a slash - a / or a \ (default \)
  117. pszWalk = (TCHAR*)pszSrc;
  118. chSlash = TEXT('\\');
  119. // Scan the entire string as we want the path separator closest to the end
  120. // eg. "file://\\Themesrv\desktop\desktop.htm"
  121. while(*pszWalk)
  122. {
  123. if((*pszWalk == TEXT('/')) || (*pszWalk == TEXT('\\')))
  124. chSlash = *pszWalk;
  125. pszWalk = FAST_CharNext(pszWalk);
  126. }
  127. pszFileName = PathFindFileName(pszSrc);
  128. uiFNLen = lstrlen(pszFileName);
  129. // if the whole string is a file name
  130. if(pszFileName == pszSrc && cchMax > LEN_END_ELLIPSES)
  131. {
  132. lstrcpyn(pszOut, pszSrc, cchMax - LEN_END_ELLIPSES);
  133. #ifndef UNICODE
  134. if(IsTrailByte(pszSrc, pszSrc+cchMax-LEN_END_ELLIPSES))
  135. *(pszOut+cchMax-LEN_END_ELLIPSES-1) = TEXT('\0');
  136. #endif
  137. lstrcat(pszOut, TEXT("..."));
  138. ATLASSERT(pszOut[cchMax-1] == TEXT('\0'));
  139. return TRUE;
  140. }
  141. // Handle all the cases where we just use ellipses ie '.' to '.../...'
  142. if((cchMax < MIN_CCHMAX))
  143. {
  144. for(n = 0; n < (int)cchMax-1; n++)
  145. {
  146. if((n+1) == LEN_MID_ELLIPSES)
  147. pszOut[n] = chSlash;
  148. else
  149. pszOut[n] = TEXT('.');
  150. }
  151. ATLASSERT(0==cchMax || pszOut[cchMax-1] == TEXT('\0'));
  152. return TRUE;
  153. }
  154. // Ok, how much of the path can we copy ? Buffer - (Lenght of MID_ELLIPSES + Len_Filename)
  155. cchToCopy = cchMax - (LEN_MID_ELLIPSES + uiFNLen);
  156. if (cchToCopy < 0)
  157. cchToCopy = 0;
  158. #ifndef UNICODE
  159. if (cchToCopy > 0 && IsTrailByte(pszSrc, pszSrc+cchToCopy))
  160. cchToCopy--;
  161. #endif
  162. lstrcpyn(pszOut, pszSrc, cchToCopy);
  163. // Now throw in the ".../" or "...\"
  164. lstrcat(pszOut, TEXT(".../"));
  165. pszOut[lstrlen(pszOut) - 1] = chSlash;
  166. //Finally the filename and ellipses if necessary
  167. if(cchMax > (LEN_MID_ELLIPSES + uiFNLen))
  168. {
  169. lstrcat(pszOut, pszFileName);
  170. }
  171. else
  172. {
  173. cchToCopy = cchMax - LEN_MID_ELLIPSES - LEN_END_ELLIPSES;
  174. #ifndef UNICODE
  175. if(cchToCopy >0 && IsTrailByte(pszFileName, pszFileName+cchToCopy))
  176. cchToCopy--;
  177. #endif
  178. lstrcpyn(pszOut + LEN_MID_ELLIPSES, pszFileName, cchToCopy);
  179. lstrcat(pszOut, TEXT("..."));
  180. }
  181. ATLASSERT(pszOut[cchMax-1] == TEXT('\0'));
  182. return TRUE;
  183. }
  184. return FALSE;
  185. }
  186. //----------------------------------------------------------------------
  187. // Returns TRUE if the given string is a UNC path.
  188. //
  189. // TRUE
  190. // "\\foo\bar"
  191. // "\\foo" <- careful
  192. // "\\"
  193. // FALSE
  194. // "\foo"
  195. // "foo"
  196. // "c:\foo"
  197. //
  198. //
  199. bool PathIsUNC(LPCTSTR pszPath)
  200. {
  201. if(pszPath)
  202. {
  203. return ((pszPath[0] == _T('\\')) && (pszPath[1] == _T('\\')));
  204. }
  205. return false;
  206. }
  207. // add a backslash to a qualified path
  208. //
  209. // in:
  210. // lpszPath path (A:, C:\foo, etc)
  211. //
  212. // out:
  213. // lpszPath A:\, C:\foo\ ;
  214. //
  215. // returns:
  216. // pointer to the NULL that terminates the path
  217. //
  218. //----------------------------------------------------------------------
  219. LPTSTR PathAddBackslash(LPTSTR lpszPath)
  220. {
  221. if(lpszPath)
  222. {
  223. LPTSTR lpszEnd;
  224. // perf: avoid lstrlen call for guys who pass in ptr to end
  225. // of buffer (or rather, EOB - 1).
  226. // note that such callers need to check for overflow themselves.
  227. int ichPath = (*lpszPath && !*(lpszPath + 1)) ? 1 : lstrlen(lpszPath);
  228. // try to keep us from tromping over MAX_PATH in size.
  229. // if we find these cases, return NULL. Note: We need to
  230. // check those places that call us to handle their GP fault
  231. // if they try to use the NULL!
  232. if(ichPath >= (_MAX_PATH - 1))
  233. {
  234. return(NULL);
  235. }
  236. lpszEnd = lpszPath + ichPath;
  237. // this is really an error, caller shouldn't pass
  238. // an empty string
  239. if(!*lpszPath)
  240. return lpszEnd;
  241. // Get the end of the source directory
  242. switch(*CharPrev(lpszPath, lpszEnd))
  243. {
  244. case _T(FILENAME_SEPARATOR):
  245. break;
  246. default:
  247. *lpszEnd++ = _T(FILENAME_SEPARATOR);
  248. *lpszEnd = _T('\0');
  249. }
  250. return lpszEnd;
  251. }
  252. return NULL;
  253. }