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.

376 lines
11 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxspath.h
  5. Abstract:
  6. popular cousin of "String.h" and "Wheel.h"
  7. Author:
  8. Jay Krell (a-JayK, JayKrell) April 2000
  9. Revision History:
  10. --*/
  11. #pragma once
  12. #include "fusionstring.h"
  13. /*
  14. See also
  15. If you find yourself scanning strings with for loops, stop, and
  16. learn to use:
  17. FusionString.h
  18. StringReverseSpan
  19. StringReverseComplementSpan
  20. <string.h> / <wchar.h>
  21. wcschr
  22. wcsrchr
  23. wcsspn
  24. wcscspn
  25. wcsstr
  26. StringBuffer.h
  27. Member functions with "Path" in their name.
  28. */
  29. /*-----------------------------------------------------------------------------
  30. Split a path into
  31. root, path, base, extension
  32. the full path is roughly root + "\\" + path + "\\" + base + "." + extension
  33. but path, base, and extension can be empty (but not all three) and root
  34. might end in a slash, so you shouldn't do that blindly.
  35. Forward and backward slashes are accepted.
  36. Runs of slashes are accepted and mean the same thing as individual slashes
  37. (a run is sort of special case at the start to indicate UNC, but other than
  38. the call out to ntdll.dll, that doesn't effect the logic here)
  39. This class has no path length limitations (ntdll.dll?)
  40. The output of this class is its public member data.
  41. -----------------------------------------------------------------------------*/
  42. template <typename PCWSTRorPWSTR = PCWSTR>
  43. class CFullPathSplitPointersTemplate
  44. {
  45. public:
  46. CFullPathSplitPointersTemplate();
  47. BOOL Initialize(PCWSTR full)
  48. {
  49. return GenericInitialize(full);
  50. }
  51. BOOL Initialize(PWSTR full)
  52. {
  53. return GenericInitialize(full);
  54. }
  55. protected:
  56. BOOL GenericInitialize(PCWSTRorPWSTR full);
  57. public:
  58. BOOL IsBaseEmpty() const;
  59. BOOL IsBaseEqual(const CFullPathSplitPointersTemplate&) const;
  60. //
  61. // This public data is the output of this class.
  62. // none of these have trailing slashes except possibly "c:\"
  63. // all "end" values are "one past the end", STL style
  64. // extension doesn't include the dot, but you can be paranoid
  65. // and check for that (it'll be NULL or point to nul if there's no extension)
  66. // path must be "well formed", full, Win32 drive letter or UNC,
  67. // and not end in a slash, otherwise Initialize will return false
  68. //
  69. // These are not in general nul terminated.
  70. // m_extensionEnd usually does point to a nul.
  71. //
  72. // Generally, you yourself put stick a nul over m_*end,
  73. // because generally none of the pieces overlap, but a
  74. // root of c:\ is a common exception. CSetupCopyQueuePathParameters
  75. // sticks in nuls, and allows for this exception.
  76. //
  77. // The length of any element is m_*end - m_*, as is the STL iterator way.
  78. //
  79. PCWSTRorPWSTR m_root; // never NULL or ""
  80. PCWSTRorPWSTR m_rootEnd; // never == m_root
  81. PCWSTRorPWSTR m_path; // NULL or "" in case of c:\foo.txt
  82. PCWSTRorPWSTR m_pathEnd; // == m_path in case of c:\foo.txt
  83. PCWSTRorPWSTR m_base; // NULL or "" in case of c:\.foo
  84. PCWSTRorPWSTR m_baseEnd; // == m_base in case of c:\.foo
  85. PCWSTRorPWSTR m_extension; // NULL or "" in case c:\foo
  86. PCWSTRorPWSTR m_extensionEnd; // == fullEnd if there is no extension
  87. // if the file has a base, this points to it
  88. // followed by dot and extension if it has one
  89. // if the file has no base, this points to the extension, including the dot
  90. // this is always nul terminated
  91. // this is never null, and shouldn't be empty either
  92. PCWSTRorPWSTR m_name;
  93. };
  94. typedef CFullPathSplitPointersTemplate<> CFullPathSplitPointers;
  95. typedef CFullPathSplitPointersTemplate<PWSTR> CMutableFullPathSplitPointers;
  96. /*-----------------------------------------------------------------------------
  97. Building on CFullPathSplitPointers, take two strings and split them up
  98. exactly as SetupCopyQueue wants them, into
  99. source root, root path, source name (base + extension)
  100. destination directory (root + path), destination name (base + extension)
  101. The output of this class is its public member data.
  102. -----------------------------------------------------------------------------*/
  103. class CSetupCopyQueuePathParameters
  104. {
  105. public:
  106. CSetupCopyQueuePathParameters();
  107. BOOL
  108. Initialize(
  109. PCWSTR pszSource,
  110. PCWSTR pszDestination
  111. );
  112. // rather than copy each substring into its own buffer, put nuls
  113. // in place, over the delimiting slashes (and dot), BUT watch out
  114. // for c:\foo, so if the root is three characters, copy it
  115. // into a seperate buffer.
  116. public:
  117. //
  118. // These are null terminated.
  119. //
  120. PCWSTR m_sourceRoot;
  121. PCWSTR m_sourcePath;
  122. PCWSTR m_sourceName; // base and extension
  123. PCWSTR m_destinationDirectory; // root and path
  124. PCWSTR m_destinationName; // base and extension
  125. protected:
  126. WCHAR m_sourceRootStorage[4];
  127. CStringBuffer m_sourceBuffer;
  128. CMutableFullPathSplitPointers m_sourceSplit;
  129. WCHAR m_destinationDirectoryStorage[4]; // root and path, if path is empty
  130. CStringBuffer m_destinationBuffer;
  131. CMutableFullPathSplitPointers m_destinationSplit;
  132. private:
  133. CSetupCopyQueuePathParameters(const CSetupCopyQueuePathParameters &);
  134. void operator =(const CSetupCopyQueuePathParameters &);
  135. };
  136. /*-----------------------------------------------------------------------------
  137. inline implementation of CFullPathSplitPointersTemplate,
  138. because it is a template
  139. -----------------------------------------------------------------------------*/
  140. template <typename T>
  141. inline CFullPathSplitPointersTemplate<T>::CFullPathSplitPointersTemplate()
  142. :
  143. m_root(NULL),
  144. m_rootEnd(NULL),
  145. m_path(NULL),
  146. m_pathEnd(NULL),
  147. m_base(NULL),
  148. m_baseEnd(NULL),
  149. m_extension(NULL),
  150. m_extensionEnd(NULL),
  151. m_name(L"")
  152. {
  153. }
  154. template <typename T>
  155. inline BOOL
  156. CFullPathSplitPointersTemplate<T>::GenericInitialize(T full)
  157. {
  158. BOOL fSuccess = FALSE;
  159. FN_TRACE_WIN32(fSuccess);
  160. RTL_PATH_TYPE pathType;
  161. pathType = ::SxspDetermineDosPathNameType(full);
  162. PARAMETER_CHECK(
  163. (pathType == RtlPathTypeUncAbsolute) ||
  164. (pathType == RtlPathTypeLocalDevice) ||
  165. (pathType == RtlPathTypeDriveAbsolute));
  166. T fullEnd;
  167. fullEnd = full + StringLength(full);
  168. m_root = full;
  169. if (m_root[1] == ':')
  170. {
  171. m_path = m_root + 3;
  172. m_rootEnd = m_path;
  173. m_path += wcsspn(m_path, CUnicodeCharTraits::PathSeparators()); // skip path separators
  174. }
  175. else
  176. {
  177. m_path = m_root;
  178. m_path += wcsspn(m_path, CUnicodeCharTraits::PathSeparators()); // skip "\\"
  179. m_path += wcscspn(m_path, CUnicodeCharTraits::PathSeparators()); // skip "\\computer"
  180. m_path += wcsspn(m_path, CUnicodeCharTraits::PathSeparators()); // skip "\\computer\"
  181. m_path += wcscspn(m_path, CUnicodeCharTraits::PathSeparators()); // skip "\\computer\share"
  182. m_rootEnd = m_path;
  183. m_path += wcsspn(m_path, CUnicodeCharTraits::PathSeparators()); // skip "\\computer\share\"
  184. }
  185. //
  186. // now work from the right
  187. // first find the last dot and last slash, and determine
  188. // where the base and extension are, if any
  189. //
  190. INT nameExtLength;
  191. INT extLength;
  192. nameExtLength = ::StringReverseComplementSpan(m_path, fullEnd, CUnicodeCharTraits::PathSeparators());
  193. extLength = ::StringReverseComplementSpan(m_path, fullEnd, L".");
  194. //
  195. // determine the extension
  196. //
  197. if (extLength > nameExtLength)
  198. {
  199. // no extension on leaf, but one on a parent, slightly unusual
  200. // c:\foo.bar\abc
  201. m_extension = NULL;
  202. m_extensionEnd = NULL;
  203. }
  204. else
  205. {
  206. // c:\foo\abc.txt or c:\foo.bar\abc.txt (or c:\foo\.txt or some others)
  207. m_extension = fullEnd - extLength;
  208. m_extensionEnd = fullEnd;
  209. }
  210. //
  211. // determine the base
  212. //
  213. if (extLength + 1 == nameExtLength)
  214. {
  215. // unusual case, extension but no base
  216. // c:\.foo or c:\abc\.foo
  217. m_base = NULL;
  218. m_baseEnd = NULL;
  219. }
  220. else
  221. {
  222. m_base = fullEnd - nameExtLength;
  223. if (m_extension != NULL)
  224. {
  225. // normal case, base.extension
  226. m_baseEnd = m_extension - 1;
  227. }
  228. else
  229. {
  230. // no extension
  231. m_baseEnd = fullEnd;
  232. }
  233. }
  234. //
  235. // determine the path
  236. //
  237. if (m_base != NULL)
  238. {
  239. if (m_path == m_base)
  240. {
  241. // no path c:\foo.txt
  242. m_path = NULL;
  243. m_pathEnd = NULL;
  244. }
  245. else
  246. {
  247. // normal case of path ends at base c:\abc\def.txt
  248. m_pathEnd = m_base - 1;
  249. }
  250. }
  251. else if (m_extension != NULL)
  252. {
  253. // no base, but an extension
  254. // c:\.txt or c:\abc\.txt
  255. if (m_path + 1 == m_extension)
  256. {
  257. // no path c:\.txt
  258. m_path = NULL;
  259. m_pathEnd = NULL;
  260. }
  261. else
  262. {
  263. // path ends at extension c:\abc\.txt
  264. m_pathEnd = m_extension - 2;
  265. }
  266. }
  267. else
  268. {
  269. // no path and no extension
  270. // this probably happens when we have a terminal slash
  271. // we've already filtered out empty strings
  272. m_pathEnd = fullEnd - ::StringReverseSpan(m_path, fullEnd, CUnicodeCharTraits::PathSeparators());
  273. }
  274. // there is always a root (paths are always full)
  275. ASSERT(m_root != NULL && m_rootEnd != NULL);
  276. // there is always a base or an extension (or both)
  277. ASSERT(m_base != NULL || m_extension != NULL);
  278. // if there's a start, there's an end
  279. ASSERT((m_base != NULL) == (m_baseEnd != NULL));
  280. ASSERT((m_extension != NULL) == (m_extensionEnd != NULL));
  281. m_name = (m_base != NULL) ? m_base : (m_extension - 1);
  282. fSuccess = TRUE;
  283. Exit:
  284. return fSuccess;
  285. }
  286. template <typename T>
  287. inline BOOL
  288. CFullPathSplitPointersTemplate<T>::IsBaseEmpty(
  289. ) const
  290. {
  291. return (m_base == m_baseEnd);
  292. }
  293. template <typename T>
  294. inline BOOL
  295. CFullPathSplitPointersTemplate<T>::IsBaseEqual(
  296. const CFullPathSplitPointersTemplate& other
  297. ) const
  298. {
  299. BOOL fEqual = FALSE;
  300. const INT length1 = static_cast<INT>(m_baseEnd - m_base);
  301. const INT length2 = static_cast<INT>(other.m_baseEnd - other.m_base);
  302. if (length1 != length2)
  303. goto Exit;
  304. fEqual = (::FusionpCompareStrings(m_base, length1, other.m_base, length1, true) == 0);
  305. Exit:
  306. return fEqual;
  307. }
  308. /*-----------------------------------------------------------------------------
  309. inline implementation of CSetupCopyQueuePathParameters
  310. -----------------------------------------------------------------------------*/
  311. inline CSetupCopyQueuePathParameters::CSetupCopyQueuePathParameters()
  312. :
  313. m_sourcePath(NULL),
  314. m_sourceName(NULL),
  315. m_destinationDirectory(NULL),
  316. m_destinationName(NULL)
  317. {
  318. m_sourceRootStorage[0] = 0;
  319. m_destinationDirectoryStorage[0] = 0;
  320. }