819 lines
21 KiB
C++
819 lines
21 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1998 - 2000.
|
||
|
//
|
||
|
// File: FunyPath.hxx
|
||
|
//
|
||
|
// Contents: Implementation of ``Funny'' Path for long pathnames
|
||
|
//
|
||
|
// Classes: CFunnyPath
|
||
|
// CLowerFunnyPath
|
||
|
// CLowerFunnyStack
|
||
|
//
|
||
|
// Notes: This class takes in a fully qualified path. The path can be in
|
||
|
// two forms - C:\dir\... or \\machine\share\...
|
||
|
// EXCEPTION: To accomodate for scope restrictions, this class
|
||
|
// will also allow paths of \dir... format
|
||
|
// This path is converted to the "funny" form. The normal path
|
||
|
// takes the form of \\?\C:\dir\... and remote path takes the form
|
||
|
// of \\?\UNC\machine\share\... These funny paths can used by in
|
||
|
// functions like CreateFile to open paths > MAX_PATH
|
||
|
//
|
||
|
// History: 08-May-98 vikasman Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "lcase.hxx"
|
||
|
|
||
|
const WCHAR _FUNNY_PATH[] = L"\\\\?\\";
|
||
|
const WCHAR _UNC_FUNNY_PATH[] = L"\\\\?\\UN";
|
||
|
|
||
|
const _FUNNY_PATH_LENGTH = ( ( sizeof( _FUNNY_PATH ) / sizeof( WCHAR ) ) - 1 );
|
||
|
const _UNC_FUNNY_PATH_LENGTH = ( ( sizeof( _UNC_FUNNY_PATH ) / sizeof( WCHAR ) ) - 1 );
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CFunnyPath
|
||
|
//
|
||
|
// Purpose: A path name preceeded by "\\?\" to allow file operations
|
||
|
// when the length of the path is > MAX_PATH.
|
||
|
//
|
||
|
// History: 08-May-98 vikasman Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CFunnyPath
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// used by SetState function to set the state to funny/actual
|
||
|
enum PathState
|
||
|
{
|
||
|
FUNNY_PATH_STATE,
|
||
|
ACTUAL_PATH_STATE
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Constructors, Destructors, Operators...
|
||
|
//
|
||
|
|
||
|
CFunnyPath( BOOL fRemote = FALSE ) :
|
||
|
_fRemote( fRemote ),
|
||
|
_ccActualBuf( 0 )
|
||
|
{
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
_xBuf.SetSize( _UNC_FUNNY_PATH_LENGTH + 1 );
|
||
|
_xBuf[_UNC_FUNNY_PATH_LENGTH] = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_xBuf.SetSize( _FUNNY_PATH_LENGTH + 1 );
|
||
|
_xBuf[_FUNNY_PATH_LENGTH] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CFunnyPath( const WCHAR * wcsPath, unsigned cc = 0 ) :
|
||
|
_fRemote( FALSE ),
|
||
|
_ccActualBuf( 0 )
|
||
|
{
|
||
|
SetPath( wcsPath, cc );
|
||
|
}
|
||
|
|
||
|
CFunnyPath( CFunnyPath const & src )
|
||
|
{
|
||
|
*this = src;
|
||
|
}
|
||
|
|
||
|
CFunnyPath & operator =( CFunnyPath const & src )
|
||
|
{
|
||
|
_xBuf = src._xBuf;
|
||
|
_fRemote = src._fRemote;
|
||
|
_ccActualBuf = src._ccActualBuf;
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Sets the path "wcsPath"
|
||
|
//
|
||
|
virtual void SetPath( const WCHAR * wcsPath, unsigned cc = 0 )
|
||
|
{
|
||
|
Win4Assert( wcsPath );
|
||
|
|
||
|
_ccActualBuf = ( 0 == cc ? wcslen( wcsPath ) : cc ) ;
|
||
|
|
||
|
if ( 0 == _ccActualBuf )
|
||
|
{
|
||
|
InitBlank();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Win4Assert( _ccActualBuf > 1 ); // at least 2 characters
|
||
|
|
||
|
WCHAR * pwcActualPath;
|
||
|
BOOL fInvalidPath = FALSE;
|
||
|
|
||
|
if ( L'\\' != wcsPath[0] && L':' != wcsPath[1] )
|
||
|
// Looks like we don't have a valid path, but still
|
||
|
// we will continue. It's not CFunnyPath's problem
|
||
|
// We will treat it as a normal path
|
||
|
{
|
||
|
|
||
|
ciDebugOut(( DEB_ITRACE, "CFunnyPath::SetPath - The path (%ws) is not valid.\n", wcsPath ));
|
||
|
fInvalidPath = TRUE;
|
||
|
}
|
||
|
|
||
|
if ( L':' == wcsPath[1] || fInvalidPath )
|
||
|
{
|
||
|
// normal or invalid path
|
||
|
_fRemote = FALSE;
|
||
|
_xBuf.SetSize( _ccActualBuf + _FUNNY_PATH_LENGTH + 1 );
|
||
|
_xBuf.SetBuf( _FUNNY_PATH, _FUNNY_PATH_LENGTH );
|
||
|
pwcActualPath = &_xBuf[_FUNNY_PATH_LENGTH];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// remote path
|
||
|
_fRemote = TRUE;
|
||
|
_xBuf.SetSize( _ccActualBuf + _UNC_FUNNY_PATH_LENGTH + 1 );
|
||
|
_xBuf.SetBuf( _UNC_FUNNY_PATH, _UNC_FUNNY_PATH_LENGTH );
|
||
|
pwcActualPath = &_xBuf[_UNC_FUNNY_PATH_LENGTH];
|
||
|
}
|
||
|
RtlCopyMemory( pwcActualPath, wcsPath, _ccActualBuf * sizeof( WCHAR ) );
|
||
|
pwcActualPath[_ccActualBuf] = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Appends the path "wcsPath"
|
||
|
//
|
||
|
virtual void AppendPath( const WCHAR * wcsPath, unsigned cc = 0 )
|
||
|
{
|
||
|
AssertValid();
|
||
|
Win4Assert( wcsPath );
|
||
|
|
||
|
if ( 0 == cc )
|
||
|
{
|
||
|
cc = wcslen( wcsPath );
|
||
|
}
|
||
|
|
||
|
unsigned ccTotalSizeNeeded = cc + _ccActualBuf + 1;
|
||
|
WCHAR * pwcAppendAt;
|
||
|
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
_xBuf.SetSize( ccTotalSizeNeeded + _UNC_FUNNY_PATH_LENGTH );
|
||
|
pwcAppendAt = &_xBuf[_UNC_FUNNY_PATH_LENGTH + _ccActualBuf];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_xBuf.SetSize( ccTotalSizeNeeded + _FUNNY_PATH_LENGTH );
|
||
|
pwcAppendAt = &_xBuf[_FUNNY_PATH_LENGTH + _ccActualBuf];
|
||
|
}
|
||
|
RtlCopyMemory( pwcAppendAt, wcsPath, cc * sizeof( WCHAR ) );
|
||
|
pwcAppendAt[cc] = 0;
|
||
|
_ccActualBuf += cc;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns the path either as funny or unc_funny which can be used in
|
||
|
// functions like CreateFile. Do not keep and use the pointer from
|
||
|
// GetPath after calling GetActualPath.
|
||
|
// Reason: Both these functions(even though they are const) may
|
||
|
// modify the internal buffer before returning data
|
||
|
//
|
||
|
const WCHAR * GetPath() const
|
||
|
{
|
||
|
AssertValid();
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
// need to replace \ with C
|
||
|
((CFunnyPath*)this)->_xBuf[_UNC_FUNNY_PATH_LENGTH] = L'C';
|
||
|
}
|
||
|
return _xBuf.Get();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns the "actual path". Do not keep and use the pointer from
|
||
|
// GetActualPath after calling GetPath. Reason: Both these functions
|
||
|
// (even though they are const) may modify the internal buffer before
|
||
|
// returning data
|
||
|
//
|
||
|
const WCHAR * GetActualPath() const
|
||
|
{
|
||
|
return _GetActualPath();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Sets the state of the path to actual/funny
|
||
|
//
|
||
|
void SetState( const PathState state )
|
||
|
{
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
_xBuf[_UNC_FUNNY_PATH_LENGTH] =
|
||
|
( FUNNY_PATH_STATE == state ? L'C' : L'\\' );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns the actual length of characters
|
||
|
//
|
||
|
unsigned GetActualLength() const
|
||
|
{
|
||
|
return _ccActualBuf;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Returns the total length
|
||
|
//
|
||
|
unsigned GetLength() const
|
||
|
{
|
||
|
return ( _ccActualBuf +
|
||
|
(_fRemote ? _UNC_FUNNY_PATH_LENGTH : _FUNNY_PATH_LENGTH) );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Appends back slash
|
||
|
//
|
||
|
BOOL AppendBackSlash()
|
||
|
{
|
||
|
WCHAR * pwcsActualPath = _GetActualPath();
|
||
|
|
||
|
if ( 0 == _ccActualBuf || L'\\' == pwcsActualPath[_ccActualBuf - 1] )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
AppendPath( L"\\", 1 );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Removes back slash
|
||
|
//
|
||
|
BOOL RemoveBackSlash()
|
||
|
{
|
||
|
WCHAR * pwcsActualPath = _GetActualPath();
|
||
|
|
||
|
if ( 0 == _ccActualBuf || L'\\' != pwcsActualPath[_ccActualBuf - 1] )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pwcsActualPath[--_ccActualBuf] = 0;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Truncates the buf to ccNewLength (this is the "actual char.", excluding
|
||
|
// funny path prefix, length)
|
||
|
//
|
||
|
void Truncate( unsigned ccNewLength )
|
||
|
{
|
||
|
if ( ccNewLength < _ccActualBuf )
|
||
|
{
|
||
|
WCHAR * pwcActualPath = _GetActualPath();
|
||
|
pwcActualPath[ _ccActualBuf = ccNewLength ] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL IsRemote () const
|
||
|
{
|
||
|
return _fRemote;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// returns TRUE if any component in the path looks like the short version
|
||
|
// of a long file name.
|
||
|
//
|
||
|
BOOL IsShortPath () const;
|
||
|
static BOOL IsShortName( WCHAR const * const pwszName );
|
||
|
|
||
|
//
|
||
|
// Returns the count of all the characters in xBuf
|
||
|
//
|
||
|
unsigned Count() const
|
||
|
{
|
||
|
return _xBuf.Count();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the size of _xBuf
|
||
|
//
|
||
|
void SetSize( unsigned cc )
|
||
|
{
|
||
|
_xBuf.SetSize( cc );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the internal buffer
|
||
|
//
|
||
|
const WCHAR * GetBuffer() const
|
||
|
{
|
||
|
return _xBuf.Get();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This is a dangerous function as it exposes the internal buffer
|
||
|
//
|
||
|
WCHAR * GetBuffer()
|
||
|
{
|
||
|
return _xBuf.Get();
|
||
|
}
|
||
|
|
||
|
// This path initializes the internal buffer with empty actual path
|
||
|
void InitBlank( BOOL fRemote = FALSE )
|
||
|
{
|
||
|
_fRemote = fRemote;
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
_xBuf.SetBuf( _UNC_FUNNY_PATH, _UNC_FUNNY_PATH_LENGTH + 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_xBuf.SetBuf( _FUNNY_PATH, _FUNNY_PATH_LENGTH + 1 );
|
||
|
}
|
||
|
_ccActualBuf = 0;
|
||
|
}
|
||
|
|
||
|
#if CIDBG==1
|
||
|
//
|
||
|
// Asserts that we are in good state
|
||
|
//
|
||
|
void AssertValid() const
|
||
|
{
|
||
|
const WCHAR * pwcsFunny = _xBuf.Get();
|
||
|
Win4Assert( pwcsFunny &&
|
||
|
L'\\' == pwcsFunny[0] && L'\\' == pwcsFunny[1] &&
|
||
|
L'?' == pwcsFunny[2] && L'\\' == pwcsFunny[3] );
|
||
|
|
||
|
Win4Assert( L':' == pwcsFunny[5] || L'N' == pwcsFunny[5] ||
|
||
|
L'n' == pwcsFunny[5] );
|
||
|
|
||
|
}
|
||
|
#else
|
||
|
|
||
|
void AssertValid() const {}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Some static utility functions
|
||
|
//
|
||
|
enum FunnyUNC
|
||
|
{
|
||
|
NOT_FUNNY, // not funny
|
||
|
FUNNY_ONLY, // of type \\?\c:\dir\...
|
||
|
FUNNY_UNC // of type \\?\unc\...
|
||
|
};
|
||
|
|
||
|
static inline BOOL IsFunnyPath( WCHAR const * pwcsPath )
|
||
|
{
|
||
|
return ( pwcsPath &&
|
||
|
L'\\' == pwcsPath[0] &&
|
||
|
L'\\' == pwcsPath[1] &&
|
||
|
L'?' == pwcsPath[2] &&
|
||
|
L'\\' == pwcsPath[3] );
|
||
|
}
|
||
|
|
||
|
static inline FunnyUNC IsFunnyUNCPath( WCHAR const * pwcsPath )
|
||
|
{
|
||
|
// The 6th char here can also be as '\\' (instead of being c/C) as
|
||
|
// this class modifies that charatcter to be a '\\'.
|
||
|
return ( FALSE == IsFunnyPath( pwcsPath ) ?
|
||
|
NOT_FUNNY :
|
||
|
( ( (L'U' == pwcsPath[4] || L'u' == pwcsPath[4]) &&
|
||
|
(L'N' == pwcsPath[5] || L'n' == pwcsPath[5]) &&
|
||
|
(L'C' == pwcsPath[6] || L'c' == pwcsPath[6] || L'\\' == pwcsPath[6]) &&
|
||
|
(L'\\' == pwcsPath[7] ) ) ?
|
||
|
FUNNY_UNC :
|
||
|
FUNNY_ONLY ) );
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
|
||
|
WCHAR * _GetActualPath() const
|
||
|
{
|
||
|
WCHAR * pwcsActualPath;
|
||
|
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
pwcsActualPath = &(((CFunnyPath*)this)->_xBuf[_UNC_FUNNY_PATH_LENGTH]);
|
||
|
|
||
|
// need to replace C with "\"
|
||
|
*pwcsActualPath = L'\\';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pwcsActualPath = &(((CFunnyPath*)this)->_xBuf[_FUNNY_PATH_LENGTH]);
|
||
|
}
|
||
|
return pwcsActualPath;
|
||
|
}
|
||
|
|
||
|
BOOL _fRemote; // Is the path remote ?
|
||
|
unsigned _ccActualBuf; // number of actual characters in _xBuf
|
||
|
// (excluding _FUNNY_PATH/_UNC_FUNNY_PATH)
|
||
|
XGrowable<WCHAR> _xBuf;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFunnyPath::IsShortName, static public
|
||
|
//
|
||
|
// Arguments: [pwszName] -- name to be checked (only a single path component
|
||
|
// is checked at a time)
|
||
|
//
|
||
|
// Returns: TRUE if file is potentially a short (8.3) name for
|
||
|
// a file with a long name.
|
||
|
//
|
||
|
// History: 01-Sep-1998 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline BOOL CFunnyPath::IsShortName( WCHAR const * const pwszName )
|
||
|
{
|
||
|
//
|
||
|
// First, see if this is possibly a short name (has ~ in file name part).
|
||
|
//
|
||
|
|
||
|
BOOL fTwiddle = FALSE;
|
||
|
unsigned cDot = 0;
|
||
|
|
||
|
for ( unsigned cchFN = 0; cchFN < 13; cchFN++ )
|
||
|
{
|
||
|
if ( pwszName[cchFN] == L'~' && cchFN >= 1 )
|
||
|
fTwiddle = TRUE;
|
||
|
else if ( pwszName[cchFN] == L'.' )
|
||
|
{
|
||
|
if (cchFN == 0 || cchFN > 8)
|
||
|
return FALSE; // short names can't have '.' at beginning
|
||
|
cDot++;
|
||
|
}
|
||
|
else if ( pwszName[cchFN] == L'\0' || pwszName[cchFN] == L'\\' )
|
||
|
break;
|
||
|
|
||
|
cchFN++;
|
||
|
}
|
||
|
|
||
|
if (fTwiddle)
|
||
|
{
|
||
|
// short names can't have more than 1 '.'
|
||
|
// max filename size if no extension is 8
|
||
|
if (cDot >= 2 || cDot == 0 && cchFN > 8)
|
||
|
return FALSE;
|
||
|
|
||
|
// check for min (e.g., EXT~1 for .ext) and max lengths
|
||
|
if (cchFN >= 5 && cchFN <= 12)
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFunnyPath::IsShortPath, public
|
||
|
//
|
||
|
// Arguments: - none -
|
||
|
//
|
||
|
// Returns: TRUE if the path name potentially contains a short (8.3) name
|
||
|
// for a file with a long name.
|
||
|
//
|
||
|
// History: 15-Sep-1998 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline BOOL CFunnyPath::IsShortPath() const
|
||
|
{
|
||
|
//
|
||
|
// Check to see if the input path name contains an 8.3 short name
|
||
|
//
|
||
|
WCHAR * pwszTilde = wcschr( GetActualPath(), L'~' );
|
||
|
|
||
|
if (pwszTilde)
|
||
|
{
|
||
|
WCHAR * pwszComponent;
|
||
|
for ( pwszComponent = wcschr( GetActualPath(), L'\\' );
|
||
|
pwszComponent;
|
||
|
pwszComponent = wcschr( pwszComponent, L'\\' ) )
|
||
|
{
|
||
|
pwszComponent++;
|
||
|
pwszTilde = wcschr( pwszComponent, L'~' );
|
||
|
if ( 0 == pwszTilde || pwszTilde - pwszComponent > 13)
|
||
|
continue;
|
||
|
if (IsShortName( pwszComponent ))
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CFunnyPath
|
||
|
//
|
||
|
// Purpose: A path name preceeded by "\\?\" to allow file operations when
|
||
|
// the length of the path is > MAX_PATH. Keeps the FunnyPath in
|
||
|
// lower case.
|
||
|
//
|
||
|
// History: 08-May-98 vikasman Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CLowerFunnyPath : public CFunnyPath
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CLowerFunnyPath( BOOL fRemote = FALSE ) :
|
||
|
CFunnyPath( fRemote )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CLowerFunnyPath( const CLowerFunnyPath & src )
|
||
|
{
|
||
|
*this = src;
|
||
|
}
|
||
|
|
||
|
CLowerFunnyPath( const WCHAR * wcsPath,
|
||
|
unsigned cc = 0,
|
||
|
BOOL fNoConvert = FALSE ) :
|
||
|
CFunnyPath()
|
||
|
{
|
||
|
SetPath( wcsPath, cc, fNoConvert );
|
||
|
}
|
||
|
|
||
|
CLowerFunnyPath & operator =( CLowerFunnyPath const & src )
|
||
|
{
|
||
|
CFunnyPath::operator=( (CFunnyPath&)src );
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
virtual void SetPath( const WCHAR * wcsPath,
|
||
|
unsigned cc = 0,
|
||
|
BOOL fNoConvert = FALSE );
|
||
|
|
||
|
virtual void AppendPath( const WCHAR * wcsPath,
|
||
|
unsigned cc = 0,
|
||
|
BOOL fNoConvert = FALSE );
|
||
|
|
||
|
BOOL ConvertToLongName();
|
||
|
|
||
|
private:
|
||
|
|
||
|
//
|
||
|
// Converts to wcsPath of length cc to lower case and puts it in
|
||
|
// _xBuf starting from ccStart index (actual)
|
||
|
//
|
||
|
void ToLower( const WCHAR * wcsPath, unsigned cc, unsigned ccStart = 0 );
|
||
|
|
||
|
};
|
||
|
|
||
|
inline void CLowerFunnyPath::SetPath(
|
||
|
const WCHAR * wcsPath,
|
||
|
unsigned cc,
|
||
|
BOOL fNoConvert )
|
||
|
{
|
||
|
if ( fNoConvert )
|
||
|
{
|
||
|
// already lower case
|
||
|
CFunnyPath::SetPath( wcsPath, cc );
|
||
|
AssertLowerCase( GetActualPath(), GetActualLength() );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Win4Assert( wcsPath );
|
||
|
|
||
|
cc = ( 0 == cc ? wcslen( wcsPath ) : cc ) ;
|
||
|
|
||
|
if ( 0 == cc )
|
||
|
{
|
||
|
InitBlank();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
BOOL fInvalidPath = FALSE;
|
||
|
if ( L'\\' != wcsPath[0] && L':' != wcsPath[1] )
|
||
|
{
|
||
|
// Looks like we don't have a valid path, but still
|
||
|
// we will continue. It's not CFunnyPath's problem
|
||
|
// We will treat it as a normal path
|
||
|
|
||
|
ciDebugOut(( DEB_ITRACE,
|
||
|
"CLowerFunnyPath::SetPath - path (%ws) is not valid.\n",
|
||
|
wcsPath ));
|
||
|
fInvalidPath = TRUE;
|
||
|
}
|
||
|
|
||
|
if ( L':' == wcsPath[1] || fInvalidPath )
|
||
|
{
|
||
|
// normal or invalid path
|
||
|
_fRemote = FALSE;
|
||
|
_xBuf.SetBuf( _FUNNY_PATH, _FUNNY_PATH_LENGTH + 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// remote path
|
||
|
_fRemote = TRUE;
|
||
|
_xBuf.SetBuf( _UNC_FUNNY_PATH, _UNC_FUNNY_PATH_LENGTH + 1 );
|
||
|
}
|
||
|
ToLower( wcsPath, cc );
|
||
|
}
|
||
|
|
||
|
inline void CLowerFunnyPath::AppendPath(
|
||
|
const WCHAR * wcsPath,
|
||
|
unsigned cc,
|
||
|
BOOL fNoConvert )
|
||
|
{
|
||
|
if ( fNoConvert )
|
||
|
{
|
||
|
// already lower case
|
||
|
CFunnyPath::AppendPath( wcsPath, cc );
|
||
|
AssertLowerCase( GetActualPath(), GetActualLength() );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
AssertValid();
|
||
|
Win4Assert( wcsPath );
|
||
|
|
||
|
if ( 0 == cc )
|
||
|
{
|
||
|
cc = wcslen( wcsPath );
|
||
|
}
|
||
|
|
||
|
ToLower( wcsPath, cc, _ccActualBuf );
|
||
|
}
|
||
|
|
||
|
inline void CLowerFunnyPath::ToLower(
|
||
|
const WCHAR * wcsPath,
|
||
|
unsigned cc,
|
||
|
unsigned ccStart )
|
||
|
{
|
||
|
WCHAR * pwcDestActualPath;
|
||
|
unsigned ccDestActualCount;
|
||
|
|
||
|
Win4Assert( wcsPath );
|
||
|
if ( !cc )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if CIDBG == 1
|
||
|
// Variable to try lowercasing again due to some random
|
||
|
// failures with LCMapStringW
|
||
|
BOOL fTryAgain = TRUE;
|
||
|
#endif
|
||
|
while ( TRUE )
|
||
|
{
|
||
|
if ( _fRemote )
|
||
|
{
|
||
|
pwcDestActualPath = &_xBuf[_UNC_FUNNY_PATH_LENGTH] + ccStart;
|
||
|
ccDestActualCount = _xBuf.Count() - (_UNC_FUNNY_PATH_LENGTH + ccStart);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pwcDestActualPath = &_xBuf[_FUNNY_PATH_LENGTH] + ccStart;
|
||
|
ccDestActualCount = _xBuf.Count() - (_FUNNY_PATH_LENGTH + ccStart);
|
||
|
}
|
||
|
|
||
|
if ( ccDestActualCount < 2 )
|
||
|
{
|
||
|
// Need to allocate more memory
|
||
|
_xBuf.SetSize( _xBuf.Count() * 2 );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
unsigned cchLen = LCMapStringW ( LOCALE_NEUTRAL,
|
||
|
LCMAP_LOWERCASE,
|
||
|
wcsPath,
|
||
|
cc,
|
||
|
pwcDestActualPath,
|
||
|
ccDestActualCount - 1 );
|
||
|
|
||
|
if ( 0 == cchLen )
|
||
|
{
|
||
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
||
|
{
|
||
|
_xBuf.SetSize( _xBuf.Count() * 2 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ciDebugOut(( DEB_ERROR, "Error 0x%x lowercasing path\n", GetLastError() ));
|
||
|
#if CIDBG == 1
|
||
|
if ( fTryAgain )
|
||
|
{
|
||
|
fTryAgain = FALSE;
|
||
|
Win4Assert(( !"neutral lowercase failed. Trying again..." ));
|
||
|
continue;
|
||
|
}
|
||
|
#endif
|
||
|
Win4Assert(( !"neutral lowercase failed" ));
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Win4Assert( cchLen < ccDestActualCount );
|
||
|
pwcDestActualPath[ cchLen ] = 0;
|
||
|
_ccActualBuf = ccStart + cchLen;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CLowerFunnyPath::ConvertToLongName, public
|
||
|
//
|
||
|
// Synopsis: Converts file path name components to long names.
|
||
|
//
|
||
|
// Returns: TRUE if conversion was successful.
|
||
|
//
|
||
|
// Notes: GetLongPathNameW will fail with remote funny paths because
|
||
|
// it will try to call FindFirstFileW on the machine name and
|
||
|
// share name.
|
||
|
//
|
||
|
// History: 06-Jan-98 KyleP Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline BOOL CLowerFunnyPath::ConvertToLongName()
|
||
|
{
|
||
|
XGrowable<WCHAR> wcsTemp;
|
||
|
|
||
|
WCHAR * pwcsShortName;
|
||
|
unsigned ccFunnyChars;
|
||
|
|
||
|
if (IsRemote())
|
||
|
{
|
||
|
pwcsShortName = _GetActualPath();
|
||
|
ccFunnyChars = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pwcsShortName = (WCHAR *)GetPath();
|
||
|
ccFunnyChars = _FUNNY_PATH_LENGTH;
|
||
|
}
|
||
|
|
||
|
DWORD ccOut = GetLongPathNameW( pwcsShortName, // Short name
|
||
|
wcsTemp.Get(), // Long name
|
||
|
wcsTemp.Count() - 1 );
|
||
|
|
||
|
if ( ccOut > wcsTemp.Count() - 1 )
|
||
|
{
|
||
|
// Need to grow the buffer
|
||
|
wcsTemp.SetSize( ccOut + 1 );
|
||
|
ccOut = GetLongPathNameW( pwcsShortName, // Short name
|
||
|
wcsTemp.Get(), // Long name
|
||
|
wcsTemp.Count() - 1 );
|
||
|
Win4Assert( ccOut <= wcsTemp.Count() - 1 );
|
||
|
}
|
||
|
|
||
|
if ( 0 == ccOut )
|
||
|
{
|
||
|
ciDebugOut(( DEB_WARN, "GetLongPathName( %ws ) returned %d\n",
|
||
|
pwcsShortName, GetLastError() ));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
SetPath( wcsTemp.Get() + ccFunnyChars, ccOut - ccFunnyChars );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Stack class for FunnyPath
|
||
|
//
|
||
|
|
||
|
DECL_DYNSTACK( _CLowerFunnyStack, CLowerFunnyPath )
|
||
|
|
||
|
class CLowerFunnyStack : protected _CLowerFunnyStack
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
BOOL Pop( XPtr<CLowerFunnyPath> & xLowerFunnyPath )
|
||
|
{
|
||
|
if (Count() == 0)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
xLowerFunnyPath.Set( _CLowerFunnyStack::Pop() );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void Push( const CLowerFunnyPath & funnyElem )
|
||
|
{
|
||
|
XPtr<CLowerFunnyPath> xLowerFunnyPath( new CLowerFunnyPath(funnyElem) );
|
||
|
_CLowerFunnyStack::Push( xLowerFunnyPath.GetPointer() );
|
||
|
xLowerFunnyPath.Acquire();
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|