windows-nt/Source/XPSP1/NT/net/upnp/common/upbase/ncfile.cpp
2020-09-26 16:20:57 +08:00

194 lines
6.4 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: N C F I L E . C P P
//
// Contents: Really useful file functions that are implemented in shlwapi
// but which aren't exported.
//
// Notes: Stolen from shell32\path.c
//
// Using these functions likely requires linking with shlwapi.lib
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "ncfile.h"
#include "trace.h"
#include <shlobj.h>
#include <shlobjp.h> // PCS_ flags
#include <shlwapi.h>
// PathTruncateKeepExtension
//
// Attempts to truncate the filename pszSpec such that pszDir+pszSpec are less than MAX_PATH-5.
// The extension is protected so it won't get truncated or altered.
//
// in:
// pszDir the path to a directory. No trailing '\' is needed.
// pszSpec the filespec to be truncated. This should not include a path but can have an extension.
// This input buffer can be of any length.
// iTruncLimit The minimum length to truncate pszSpec. If addition truncation would be required we fail.
// out:
// pszSpec The truncated filespec with it's extension unaltered.
// return:
// TRUE if the filename was truncated, FALSE if we were unable to truncate because the directory name
// was too long, the extension was too long, or the iTruncLimit is too high. pszSpec is unaltered
// when this function returns FALSE.
//
STDAPI_(BOOL) PathTruncateKeepExtension( LPCTSTR pszDir, LPTSTR pszSpec, int iTruncLimit )
{
LPTSTR pszExt = PathFindExtension(pszSpec);
int cchExt = lstrlen(pszExt);
int cchSpec = (int)(pszExt - pszSpec + cchExt);
int cchKeep = MAX_PATH-lstrlen(pszDir)-5; // the -5 is just to provide extra padding
// IF...
// ...the filename is to long
// ...we are within the limit to which we can truncate
// ...the extension is short enough to allow the trunctation
if ( (cchSpec > cchKeep) && (cchKeep >= iTruncLimit) && (cchKeep > cchExt) )
{
// THEN... go ahead and truncate
StrCpy( pszSpec+cchKeep-cchExt, pszExt );
return TRUE;
}
return FALSE;
}
// notes: modified to only handle LFN drives
STDAPI_(int) PathCleanupSpec2(LPCTSTR pszDir, LPTSTR pszSpec)
{
LPTSTR pszNext, pszCur;
UINT uMatch = GCT_LFNCHAR;
int iRet = 0;
LPTSTR pszPrevDot = NULL;
for (pszCur = pszNext = pszSpec; *pszNext; pszNext = CharNext(pszNext))
{
if (PathGetCharType(*pszNext) & uMatch)
{
*pszCur = *pszNext;
#ifndef UNICODE
if (IsDBCSLeadByte(*pszNext))
*(pszCur + 1) = *(pszNext + 1);
#endif UNICODE
pszCur = CharNext(pszCur);
}
else
{
switch (*pszNext)
{
case TEXT('/'): // used often for things like add/remove
case TEXT(' '): // blank (only replaced for short name drives)
*pszCur = TEXT('-');
pszCur = CharNext(pszCur);
iRet |= PCS_REPLACEDCHAR;
break;
default:
iRet |= PCS_REMOVEDCHAR;
}
}
}
*pszCur = 0; // null terminate
if (pszDir && (lstrlen(pszDir) + lstrlen(pszSpec) > MAX_PATH - 1))
{
iRet |= PCS_PATHTOOLONG | PCS_FATAL;
}
return(iRet);
}
// PathCleanupSpecEx
//
// Just like PathCleanupSpec, PathCleanupSpecEx removes illegal characters from pszSpec
// and enforces 8.3 format on non-LFN drives. In addition, this function will attempt to
// truncate pszSpec if the combination of pszDir + pszSpec is greater than MAX_PATH.
//
// in:
// pszDir The directory in which the filespec pszSpec will reside
// pszSpec The filespec that is being cleaned up which includes any extension being used
// out:
// pszSpec The modified filespec with illegal characters removed, truncated to
// 8.3 if pszDir is on a non-LFN drive, and truncated to a shorter number
// of characters if pszDir is an LFN drive but pszDir + pszSpec is more
// than MAX_PATH characters.
// return:
// returns a bit mask indicating what happened. This mask can include the following cases:
// PCS_REPLACEDCHAR One or more illegal characters were replaced with legal characters
// PCS_REMOVEDCHAR One or more illegal characters were removed
// PCS_TRUNCATED Truncated to fit 8.3 format or because pszDir+pszSpec was too long
// PCS_PATHTOOLONG pszDir is so long that we cannot truncate pszSpec to form a legal filename
// PCS_FATAL The resultant pszDir+pszSpec is not a legal filename. Always used with PCS_PATHTOOLONG.
//
// note: this is the stolen implementation of PathCleanupSpecEx, which is
// defined in shlobjp.h but not exported by shell32.dll
//
STDAPI_(int) PathCleanupSpecEx2(LPCTSTR pszDir, LPTSTR pszSpec)
{
int iRet = 0;
iRet = PathCleanupSpec2(pszDir, pszSpec);
if ( iRet & (PCS_PATHTOOLONG|PCS_FATAL) )
{
// 30 is the shortest we want to truncate pszSpec to to satisfy the
// pszDir+pszSpec<MAX_PATH requirement. If this amount of truncation isn't enough
// then we go ahead and return PCS_PATHTOOLONG|PCS_FATAL without doing any further
// truncation of pszSpec
if ( PathTruncateKeepExtension(pszDir, pszSpec, 30 ) )
{
// We fixed the error returned by PathCleanupSpec so mask out the error.
iRet |= PCS_TRUNCATED;
iRet &= ~(PCS_PATHTOOLONG|PCS_FATAL);
}
}
else
{
// ensure that if both of these aren't set then neither is set.
Assert( !(iRet&PCS_PATHTOOLONG) && !(iRet&PCS_FATAL) );
}
return(iRet);
}
// if you already have a fully-qualified filename, just use PathFileExists
BOOL
fFileExistsAtPath(LPCTSTR pszFile, LPCTSTR pszPath)
{
Assert(pszFile);
Assert(pszPath);
Assert((_tcslen(pszFile) + _tcslen(pszPath)) < MAX_PATH);
TCHAR pszFullPath [ MAX_PATH + 1 ];
BOOL fExists;
BOOL fResult;
fExists = FALSE;
_tcscpy(pszFullPath, pszPath);
fResult = ::PathAppend(pszFullPath, pszFile);
if (fResult)
{
fExists = ::PathFileExists(pszFullPath);
}
else
{
TraceTag(ttidDefault, "fFileExistsAtPath: PathAppend failed");
}
return fExists;
}