Source code of Windows XP (NT5)
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.

193 lines
6.4 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N C F I L E . C P P
  7. //
  8. // Contents: Really useful file functions that are implemented in shlwapi
  9. // but which aren't exported.
  10. //
  11. // Notes: Stolen from shell32\path.c
  12. //
  13. // Using these functions likely requires linking with shlwapi.lib
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include "ncfile.h"
  19. #include "trace.h"
  20. #include <shlobj.h>
  21. #include <shlobjp.h> // PCS_ flags
  22. #include <shlwapi.h>
  23. // PathTruncateKeepExtension
  24. //
  25. // Attempts to truncate the filename pszSpec such that pszDir+pszSpec are less than MAX_PATH-5.
  26. // The extension is protected so it won't get truncated or altered.
  27. //
  28. // in:
  29. // pszDir the path to a directory. No trailing '\' is needed.
  30. // pszSpec the filespec to be truncated. This should not include a path but can have an extension.
  31. // This input buffer can be of any length.
  32. // iTruncLimit The minimum length to truncate pszSpec. If addition truncation would be required we fail.
  33. // out:
  34. // pszSpec The truncated filespec with it's extension unaltered.
  35. // return:
  36. // TRUE if the filename was truncated, FALSE if we were unable to truncate because the directory name
  37. // was too long, the extension was too long, or the iTruncLimit is too high. pszSpec is unaltered
  38. // when this function returns FALSE.
  39. //
  40. STDAPI_(BOOL) PathTruncateKeepExtension( LPCTSTR pszDir, LPTSTR pszSpec, int iTruncLimit )
  41. {
  42. LPTSTR pszExt = PathFindExtension(pszSpec);
  43. int cchExt = lstrlen(pszExt);
  44. int cchSpec = (int)(pszExt - pszSpec + cchExt);
  45. int cchKeep = MAX_PATH-lstrlen(pszDir)-5; // the -5 is just to provide extra padding
  46. // IF...
  47. // ...the filename is to long
  48. // ...we are within the limit to which we can truncate
  49. // ...the extension is short enough to allow the trunctation
  50. if ( (cchSpec > cchKeep) && (cchKeep >= iTruncLimit) && (cchKeep > cchExt) )
  51. {
  52. // THEN... go ahead and truncate
  53. StrCpy( pszSpec+cchKeep-cchExt, pszExt );
  54. return TRUE;
  55. }
  56. return FALSE;
  57. }
  58. // notes: modified to only handle LFN drives
  59. STDAPI_(int) PathCleanupSpec2(LPCTSTR pszDir, LPTSTR pszSpec)
  60. {
  61. LPTSTR pszNext, pszCur;
  62. UINT uMatch = GCT_LFNCHAR;
  63. int iRet = 0;
  64. LPTSTR pszPrevDot = NULL;
  65. for (pszCur = pszNext = pszSpec; *pszNext; pszNext = CharNext(pszNext))
  66. {
  67. if (PathGetCharType(*pszNext) & uMatch)
  68. {
  69. *pszCur = *pszNext;
  70. #ifndef UNICODE
  71. if (IsDBCSLeadByte(*pszNext))
  72. *(pszCur + 1) = *(pszNext + 1);
  73. #endif UNICODE
  74. pszCur = CharNext(pszCur);
  75. }
  76. else
  77. {
  78. switch (*pszNext)
  79. {
  80. case TEXT('/'): // used often for things like add/remove
  81. case TEXT(' '): // blank (only replaced for short name drives)
  82. *pszCur = TEXT('-');
  83. pszCur = CharNext(pszCur);
  84. iRet |= PCS_REPLACEDCHAR;
  85. break;
  86. default:
  87. iRet |= PCS_REMOVEDCHAR;
  88. }
  89. }
  90. }
  91. *pszCur = 0; // null terminate
  92. if (pszDir && (lstrlen(pszDir) + lstrlen(pszSpec) > MAX_PATH - 1))
  93. {
  94. iRet |= PCS_PATHTOOLONG | PCS_FATAL;
  95. }
  96. return(iRet);
  97. }
  98. // PathCleanupSpecEx
  99. //
  100. // Just like PathCleanupSpec, PathCleanupSpecEx removes illegal characters from pszSpec
  101. // and enforces 8.3 format on non-LFN drives. In addition, this function will attempt to
  102. // truncate pszSpec if the combination of pszDir + pszSpec is greater than MAX_PATH.
  103. //
  104. // in:
  105. // pszDir The directory in which the filespec pszSpec will reside
  106. // pszSpec The filespec that is being cleaned up which includes any extension being used
  107. // out:
  108. // pszSpec The modified filespec with illegal characters removed, truncated to
  109. // 8.3 if pszDir is on a non-LFN drive, and truncated to a shorter number
  110. // of characters if pszDir is an LFN drive but pszDir + pszSpec is more
  111. // than MAX_PATH characters.
  112. // return:
  113. // returns a bit mask indicating what happened. This mask can include the following cases:
  114. // PCS_REPLACEDCHAR One or more illegal characters were replaced with legal characters
  115. // PCS_REMOVEDCHAR One or more illegal characters were removed
  116. // PCS_TRUNCATED Truncated to fit 8.3 format or because pszDir+pszSpec was too long
  117. // PCS_PATHTOOLONG pszDir is so long that we cannot truncate pszSpec to form a legal filename
  118. // PCS_FATAL The resultant pszDir+pszSpec is not a legal filename. Always used with PCS_PATHTOOLONG.
  119. //
  120. // note: this is the stolen implementation of PathCleanupSpecEx, which is
  121. // defined in shlobjp.h but not exported by shell32.dll
  122. //
  123. STDAPI_(int) PathCleanupSpecEx2(LPCTSTR pszDir, LPTSTR pszSpec)
  124. {
  125. int iRet = 0;
  126. iRet = PathCleanupSpec2(pszDir, pszSpec);
  127. if ( iRet & (PCS_PATHTOOLONG|PCS_FATAL) )
  128. {
  129. // 30 is the shortest we want to truncate pszSpec to to satisfy the
  130. // pszDir+pszSpec<MAX_PATH requirement. If this amount of truncation isn't enough
  131. // then we go ahead and return PCS_PATHTOOLONG|PCS_FATAL without doing any further
  132. // truncation of pszSpec
  133. if ( PathTruncateKeepExtension(pszDir, pszSpec, 30 ) )
  134. {
  135. // We fixed the error returned by PathCleanupSpec so mask out the error.
  136. iRet |= PCS_TRUNCATED;
  137. iRet &= ~(PCS_PATHTOOLONG|PCS_FATAL);
  138. }
  139. }
  140. else
  141. {
  142. // ensure that if both of these aren't set then neither is set.
  143. Assert( !(iRet&PCS_PATHTOOLONG) && !(iRet&PCS_FATAL) );
  144. }
  145. return(iRet);
  146. }
  147. // if you already have a fully-qualified filename, just use PathFileExists
  148. BOOL
  149. fFileExistsAtPath(LPCTSTR pszFile, LPCTSTR pszPath)
  150. {
  151. Assert(pszFile);
  152. Assert(pszPath);
  153. Assert((_tcslen(pszFile) + _tcslen(pszPath)) < MAX_PATH);
  154. TCHAR pszFullPath [ MAX_PATH + 1 ];
  155. BOOL fExists;
  156. BOOL fResult;
  157. fExists = FALSE;
  158. _tcscpy(pszFullPath, pszPath);
  159. fResult = ::PathAppend(pszFullPath, pszFile);
  160. if (fResult)
  161. {
  162. fExists = ::PathFileExists(pszFullPath);
  163. }
  164. else
  165. {
  166. TraceTag(ttidDefault, "fFileExistsAtPath: PathAppend failed");
  167. }
  168. return fExists;
  169. }