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

// Copyright (c) 1997-1999 Microsoft Corporation
#include "precomp.h"
#include "shlwapi2.h"
#include <platform.h>
//---------------------------------------------------------
#ifdef UNICODE
//*** FAST_CharNext -- fast CharNext for path operations
// DESCRIPTION
// when we're just stepping thru chars in a path, a simple '++' is fine.
#define FAST_CharNext(p) (DBNotNULL(p) + 1)
#ifdef DEBUG
LPWSTR WINAPI DBNotNULL(LPCWSTR lpszCurrent)
{
ATLASSERT(*lpszCurrent);
return (LPWSTR) lpszCurrent;
}
#else
#define DBNotNULL(p) (p)
#endif
#else
#define FAST_CharNext(p) CharNext(p)
#endif
//---------------------------------------------------------
LPTSTR PathFindFileName(LPCTSTR pPath)
{
LPCTSTR pT = pPath;
if(pPath)
{
for( ; *pPath; pPath = FAST_CharNext(pPath))
{
if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':') || pPath[0] == TEXT('/'))
&& pPath[1] && pPath[1] != TEXT('\\') && pPath[1] != TEXT('/'))
pT = pPath + 1;
}
}
return (LPTSTR)pT; // const -> non const
}
//---------------------------------------------------------
#ifndef UNICODE
// light weight logic for charprev that is not painful for sbcs
BOOL IsTrailByte(LPCTSTR pszSt, LPCTSTR pszCur)
{
LPCTSTR psz = pszCur;
// if the given pointer is at the top of string, at least it's not a trail
// byte.
//
if (psz <= pszSt) return FALSE;
while (psz > pszSt)
{
psz--;
if (!IsDBCSLeadByte(*psz))
{
// This is either a trail byte of double byte char
// or a single byte character we've first seen.
// Thus, the next pointer must be at either of a leadbyte
// or pszCur itself.
psz++;
break;
}
}
// Now psz can point to:
// 1) a leadbyte of double byte character.
// 2) pszSt
// 3) pszCur
//
// if psz == pszSt, psz should point to a valid double byte char.
// because we didn't hit the above if statement.
//
// if psz == pszCur, the *(pszCur-1) was non lead byte so pszCur can't
// be a trail byte.
//
// Thus, we can see pszCur as trail byte pointer if the distance from
// psz is not DBCS boundary that is 2.
//
return (BOOL) ((pszCur-psz) & 1);
}
#endif
//----------------------------------------------------------------------
#define LEN_MID_ELLIPSES 4
#define LEN_END_ELLIPSES 3
#define MIN_CCHMAX LEN_MID_ELLIPSES + LEN_END_ELLIPSES
// PathCompactPathEx
// Output:
// "."
// ".."
// "..."
// "...\"
// "...\."
// "...\.."
// "...\..."
// "...\Truncated filename..."
// "...\whole filename"
// "Truncated path\...\whole filename"
// "Whole path\whole filename"
// The '/' might be used instead of a '\' if the original string used it
// If there is no path, but only a file name that does not fit, the output is:
// "truncated filename..."
BOOL PathCompactPathEx(LPTSTR pszOut,
LPCTSTR pszSrc,
UINT cchMax,
DWORD dwFlags)
{
if(pszSrc)
{
TCHAR * pszFileName, *pszWalk;
UINT uiFNLen = 0;
int cchToCopy = 0, n;
TCHAR chSlash = TEXT('0');
ZeroMemory(pszOut, cchMax * sizeof(TCHAR));
if((UINT)lstrlen(pszSrc)+1 < cchMax)
{
lstrcpy(pszOut, pszSrc);
ATLASSERT(pszOut[cchMax-1] == TEXT('\0'));
return TRUE;
}
// Determine what we use as a slash - a / or a \ (default \)
pszWalk = (TCHAR*)pszSrc;
chSlash = TEXT('\\');
// Scan the entire string as we want the path separator closest to the end
// eg. "file://\\Themesrv\desktop\desktop.htm"
while(*pszWalk)
{
if((*pszWalk == TEXT('/')) || (*pszWalk == TEXT('\\')))
chSlash = *pszWalk;
pszWalk = FAST_CharNext(pszWalk);
}
pszFileName = PathFindFileName(pszSrc);
uiFNLen = lstrlen(pszFileName);
// if the whole string is a file name
if(pszFileName == pszSrc && cchMax > LEN_END_ELLIPSES)
{
lstrcpyn(pszOut, pszSrc, cchMax - LEN_END_ELLIPSES);
#ifndef UNICODE
if(IsTrailByte(pszSrc, pszSrc+cchMax-LEN_END_ELLIPSES))
*(pszOut+cchMax-LEN_END_ELLIPSES-1) = TEXT('\0');
#endif
lstrcat(pszOut, TEXT("..."));
ATLASSERT(pszOut[cchMax-1] == TEXT('\0'));
return TRUE;
}
// Handle all the cases where we just use ellipses ie '.' to '.../...'
if((cchMax < MIN_CCHMAX))
{
for(n = 0; n < (int)cchMax-1; n++)
{
if((n+1) == LEN_MID_ELLIPSES)
pszOut[n] = chSlash;
else
pszOut[n] = TEXT('.');
}
ATLASSERT(0==cchMax || pszOut[cchMax-1] == TEXT('\0'));
return TRUE;
}
// Ok, how much of the path can we copy ? Buffer - (Lenght of MID_ELLIPSES + Len_Filename)
cchToCopy = cchMax - (LEN_MID_ELLIPSES + uiFNLen);
if (cchToCopy < 0)
cchToCopy = 0;
#ifndef UNICODE
if (cchToCopy > 0 && IsTrailByte(pszSrc, pszSrc+cchToCopy))
cchToCopy--;
#endif
lstrcpyn(pszOut, pszSrc, cchToCopy);
// Now throw in the ".../" or "...\"
lstrcat(pszOut, TEXT(".../"));
pszOut[lstrlen(pszOut) - 1] = chSlash;
//Finally the filename and ellipses if necessary
if(cchMax > (LEN_MID_ELLIPSES + uiFNLen))
{
lstrcat(pszOut, pszFileName);
}
else
{
cchToCopy = cchMax - LEN_MID_ELLIPSES - LEN_END_ELLIPSES;
#ifndef UNICODE
if(cchToCopy >0 && IsTrailByte(pszFileName, pszFileName+cchToCopy))
cchToCopy--;
#endif
lstrcpyn(pszOut + LEN_MID_ELLIPSES, pszFileName, cchToCopy);
lstrcat(pszOut, TEXT("..."));
}
ATLASSERT(pszOut[cchMax-1] == TEXT('\0'));
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------
// Returns TRUE if the given string is a UNC path.
//
// TRUE
// "\\foo\bar"
// "\\foo" <- careful
// "\\"
// FALSE
// "\foo"
// "foo"
// "c:\foo"
//
//
bool PathIsUNC(LPCTSTR pszPath)
{
if(pszPath)
{
return ((pszPath[0] == _T('\\')) && (pszPath[1] == _T('\\')));
}
return false;
}
// add a backslash to a qualified path
//
// in:
// lpszPath path (A:, C:\foo, etc)
//
// out:
// lpszPath A:\, C:\foo\ ;
//
// returns:
// pointer to the NULL that terminates the path
//
//----------------------------------------------------------------------
LPTSTR PathAddBackslash(LPTSTR lpszPath)
{
if(lpszPath)
{
LPTSTR lpszEnd;
// perf: avoid lstrlen call for guys who pass in ptr to end
// of buffer (or rather, EOB - 1).
// note that such callers need to check for overflow themselves.
int ichPath = (*lpszPath && !*(lpszPath + 1)) ? 1 : lstrlen(lpszPath);
// try to keep us from tromping over MAX_PATH in size.
// if we find these cases, return NULL. Note: We need to
// check those places that call us to handle their GP fault
// if they try to use the NULL!
if(ichPath >= (_MAX_PATH - 1))
{
return(NULL);
}
lpszEnd = lpszPath + ichPath;
// this is really an error, caller shouldn't pass
// an empty string
if(!*lpszPath)
return lpszEnd;
// Get the end of the source directory
switch(*CharPrev(lpszPath, lpszEnd))
{
case _T(FILENAME_SEPARATOR):
break;
default:
*lpszEnd++ = _T(FILENAME_SEPARATOR);
*lpszEnd = _T('\0');
}
return lpszEnd;
}
return NULL;
}