|
|
// 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; }
|