2025-11-27 16:46:48 +09:00

1212 lines
30 KiB
C++

// ==========================================================================
// Class Implementation : COXUNC
// ==========================================================================
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "OXUNC.h"
#include "OXUNCStandardActor.h"
#include "UTBStrOp.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Definition of static members
// All string constants will use normal slashes (no back slashes)
// and lowercase characters
const TCHAR COXUNC::m_cNull = _T('\0');
const TCHAR COXUNC::m_cSlash = _T('/');
const TCHAR COXUNC::m_cBackslash = _T('\\');
const TCHAR COXUNC::m_cColon = _T(':');
const TCHAR COXUNC::m_cDot = _T('.');
static const TCHAR szSlashes[] = _T("/\\");
static const TCHAR szInvalidChars[] = _T("<>|\"");
static const TCHAR szSpecialChars[] = _T(":/\\");
const LPCTSTR COXUNC::m_pszSlashes = szSlashes;
const LPCTSTR COXUNC::m_pszInvalidChars = szInvalidChars;
const LPCTSTR COXUNC::m_pszSpecialChars = szSpecialChars;
// Data members -------------------------------------------------------------
// protected:
// CString m_sUNC;
// --- The full UNC specification
// This must be the first data member of this object, so that a dumb cast
// of a UNC object to a LPCTSTR will work.
// (The first data member of a CString is the LPCTSTR)
// This is important when working with a variable number of paramaters
// for a function call (e.g. printf, TRACE etc)
// BOOL m_bMainBuilt;
// --- Whether the main part has been built
// When this is FALSE the value of m_sUNC should not be used
// CString m_sServer;
// --- The server or drive specification
// CString m_sShare;
// --- The share specification
// CString m_sDirectory;
// --- The directory specification
// CString m_sFile;
// --- The file specification
// BOOL m_bPartsBuilt;
// --- Whether the parts have been built
// When this is FALSE the values of m_sServer, m_sShare, m_sDirectory and
// m_sFile should not be used
// BOOL m_bURLPart;
// --- Whether this is part of a URL
// HRESULT m_nLastError;
// --- The last error that occurred
// COXUNCStandardActor* m_pActor;
// --- The actor used by this UNC
// private:
// Member functions ---------------------------------------------------------
// public:
COXUNC::COXUNC(LPCTSTR pszUNC /* = NULL */, BOOL bURLPart /* = FALSE */)
{
m_sUNC = pszUNC;
m_bURLPart = bURLPart;
m_nLastError = ERROR_SUCCESS;
// ... Use the one and only standard actor
m_pActor = &COXUNCStandardActor::m_theOneAndOnly;
ASSERT_VALID(m_pActor);
SetMainBuilt();
DestroyParts();
}
COXUNC::COXUNC(LPCTSTR pszServer, LPCTSTR pszShare, LPCTSTR pszDirectory,
LPCTSTR pszFile, BOOL bURLPart /* = FALSE */)
{
m_sServer = pszServer;
m_sShare = pszShare;
m_sDirectory = pszDirectory;
m_sFile = pszFile;
m_bURLPart = bURLPart;
m_nLastError = ERROR_SUCCESS;
// ... Use the one and only standard actor
m_pActor = &COXUNCStandardActor::m_theOneAndOnly;
ASSERT_VALID(m_pActor);
SetPartsBuilt();
DestroyMain();
}
COXUNC::COXUNC(const COXUNC& UNC)
{
m_sUNC = UNC.m_sUNC;
m_bMainBuilt = UNC.m_bMainBuilt;
m_sServer = UNC.m_sServer;
m_sShare = UNC.m_sShare;
m_sDirectory = UNC.m_sDirectory;
m_sFile = UNC.m_sFile;
m_bPartsBuilt = UNC.m_bPartsBuilt;
m_bURLPart = UNC.m_bURLPart;
m_nLastError = UNC.m_nLastError;
// ... Use the one and only standard actor
m_pActor = &COXUNCStandardActor::m_theOneAndOnly;
ASSERT_VALID(m_pActor);
}
COXUNC& COXUNC::operator=(const COXUNC& UNC)
{
if(this==&UNC)
return *this;
m_sUNC = UNC.m_sUNC;
m_bMainBuilt = UNC.m_bMainBuilt;
m_sServer = UNC.m_sServer;
m_sShare = UNC.m_sShare;
m_sDirectory = UNC.m_sDirectory;
m_sFile = UNC.m_sFile;
m_bPartsBuilt = UNC.m_bPartsBuilt;
m_bURLPart = UNC.m_bURLPart;
m_nLastError = UNC.m_nLastError;
// ... Use our current actor
// m_pActor
return *this;
}
COXUNC& COXUNC::operator=(LPCTSTR pszUNC)
{
operator=(COXUNC(pszUNC, m_bURLPart));
return *this;
}
const CString COXUNC::Full() const
{
COXUNC copyThis(*this);
return (LPCTSTR)copyThis;
}
const CString COXUNC::Server() const
{
COXUNC copyThis(*this);
return copyThis.Server();
}
const CString COXUNC::Share() const
{
COXUNC copyThis(*this);
return copyThis.Share();
}
const CString COXUNC::Directory() const
{
COXUNC copyThis(*this);
return copyThis.Directory();
}
const CString COXUNC::File() const
{
COXUNC copyThis(*this);
return copyThis.File();
}
const CString COXUNC::Base() const
{
CString sFile = File();
int nDotPos = sFile.ReverseFind(m_cDot);
if (0 <= nDotPos)
return sFile.Left(nDotPos);
else
return sFile;
}
const CString COXUNC::Extension(BOOL bIncludeDot /* = TRUE */) const
{
CString sFile = File();
int nDotPos = sFile.ReverseFind(m_cDot);
if (0 <= nDotPos)
{
if (bIncludeDot)
// ... Include the leading dot
return sFile.Mid(nDotPos);
else
// ... Exclude the leading dot
return sFile.Mid(nDotPos + 1);
}
else
return _T("");
}
const BOOL COXUNC::URLPart() const
{
return m_bURLPart;
}
const HRESULT COXUNC::LastError() const
{
return m_nLastError;
}
CString& COXUNC::Full()
{
BuildMain();
// ... We pass a reference so the user may change the string
DestroyParts();
return m_sUNC;
}
COXUNC::operator LPCTSTR()
{
BuildMain();
return m_sUNC;
}
CString& COXUNC::Server()
{
BuildParts();
// ... We pass a reference so the user may change the string
DestroyMain();
return m_sServer;
}
CString& COXUNC::Share()
{
BuildParts();
// ... We pass a reference so the user may change the string
DestroyMain();
return m_sShare;
}
CString& COXUNC::Directory()
{
BuildParts();
// ... We pass a reference so the user may change the string
DestroyMain();
return m_sDirectory;
}
CString& COXUNC::File()
{
BuildParts();
// ... We pass a reference so the user may change the string
DestroyMain();
return m_sFile;
}
BOOL& COXUNC::URLPart()
{
return m_bURLPart;
}
HRESULT& COXUNC::LastError()
{
return m_nLastError;
}
TCHAR COXUNC::PreferedSlash() const
{
if (m_bURLPart)
return COXUNC::m_cSlash;
else
return COXUNC::m_cBackslash;
}
CString COXUNC::StandardForm(BOOL bMakeLower /* = TRUE */) const
{
CString sStandardUNC = Full();
if (PreferedSlash() == m_cBackslash)
ConvertSlashToBackslash(sStandardUNC);
else
ConvertBackslashToSlash(sStandardUNC);
if (bMakeLower)
sStandardUNC.MakeLower();
return sStandardUNC;
}
CString COXUNC::FileForm() const
{
CString sDir = Directory();
CString sFile = File();
if (sFile.IsEmpty() && (1 < sDir.GetLength()))
{
// ... Last character must be a slash
ASSERT(_tcschr(m_pszSlashes, sDir[sDir.GetLength() - 1]) != NULL);
// ... Remove it
sDir = sDir.Left(sDir.GetLength() - 1);
}
CString sFileForm = Server() + Share() + sDir + sFile;
return sFileForm;
}
BOOL COXUNC::IsEmpty() const
{
return Full().IsEmpty();
}
void COXUNC::Empty()
{
m_sUNC.Empty();
m_bMainBuilt = FALSE;
m_sServer.Empty();
m_sShare.Empty();
m_sDirectory.Empty();
m_sFile.Empty();
m_bPartsBuilt = FALSE;
// ... Keep the present actor
}
BOOL COXUNC::MakeAbsolute()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->MakeAbsolute(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::Exists()
{
ASSERT_VALID(m_pActor);
BOOL bExists = FALSE;
m_nLastError = m_pActor->Exists(*this, bExists);
return bExists;
}
BOOL COXUNC::Create()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->Create(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::CreateTemporaryFile(LPCTSTR pszPrefix /* = NULL */)
{
ASSERT_VALID(m_pActor);
COXUNC tempDir;
if (!tempDir.GetTemporaryDirectory())
{
ASSERT(FAILED(m_nLastError));
return FALSE;
}
m_nLastError = m_pActor->CreateTemporaryFile(tempDir, pszPrefix, *this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::Copy(COXUNC destinationUNC, BOOL bReplaceExisting /* = FALSE */)
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->Copy(*this, destinationUNC, bReplaceExisting);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::Move(COXUNC destinationUNC, BOOL bReplaceExisting /* = FALSE */,
BOOL bCopyAllowed /* = TRUE */)
{
ASSERT_VALID(m_pActor);
DWORD dwFlags = (bReplaceExisting ? MOVEFILE_REPLACE_EXISTING : 0) | (bCopyAllowed ? MOVEFILE_COPY_ALLOWED : 0);
m_nLastError = m_pActor->MoveRename(*this, destinationUNC, dwFlags);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::Rename(COXUNC destinationUNC, BOOL bReplaceExisting /* = FALSE */)
{
ASSERT_VALID(m_pActor);
DWORD dwFlags = (bReplaceExisting ? MOVEFILE_REPLACE_EXISTING : 0);
m_nLastError = m_pActor->MoveRename(*this, destinationUNC, dwFlags);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::Delete(BOOL bRemoveReadOnly /* = FALSE */)
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->Delete(*this, bRemoveReadOnly);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::SetCurrentDirectory()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->SetCurrentDirectory(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::GetCurrentDirectory()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetCurrentDirectory(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::GetWindowsDirectory()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetWindowsDirectory(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::GetSystemDirectory()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetSystemDirectory(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::GetApplicationDirectory()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetApplicationDirectory(*this);
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::GetTemporaryDirectory()
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetTemporaryDirectory(*this);
return (SUCCEEDED(m_nLastError));
}
LONGLONG COXUNC::GetSize()
{
ASSERT_VALID(m_pActor);
DWORDLONG nSize;
m_nLastError = m_pActor->GetSize(*this, nSize);
if (SUCCEEDED(m_nLastError))
return nSize;
else
return (LONGLONG)-1;
}
LONGLONG COXUNC::GetCompressedSize()
{
ASSERT_VALID(m_pActor);
DWORDLONG nSize;
m_nLastError = m_pActor->GetCompressedSize(*this, nSize);
if (SUCCEEDED(m_nLastError))
return nSize;
else
return (LONGLONG)-1;
}
BOOL COXUNC::SetSize(LONGLONG nNewSize)
{
ASSERT_VALID(m_pActor);
if (nNewSize < 0)
nNewSize = 0;
m_nLastError = m_pActor->SetSize(*this, (DWORDLONG)nNewSize);
return (SUCCEEDED(m_nLastError));
}
COXUNC COXUNC::GetShortName()
{
COXUNC shortUNC;
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetShortName(*this, shortUNC);
return shortUNC;
}
COXUNC COXUNC::GetLongName()
{
COXUNC longUNC;
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->GetLongName(*this, longUNC);
return longUNC;
}
BOOL COXUNC::GetLogicalDrives(CStringArray& drives)
{
ASSERT_VALID(m_pActor);
CString sDrives;
m_nLastError = m_pActor->GetLogicalDrives(sDrives);
drives.RemoveAll();
if (SUCCEEDED(m_nLastError))
{
// Parse string (delimiter is '|') and put each drive in the array
LPTSTR pszDrives = sDrives.GetBuffer(0);
TCHAR * p;
LPTSTR pszDrive = UTBStr::tcstok(pszDrives, _T("|"), &p);
while (pszDrive != NULL)
{
drives.Add(pszDrive);
pszDrive = UTBStr::tcstok(pszDrives, _T("|"), &p);
}
sDrives.ReleaseBuffer();
}
return (SUCCEEDED(m_nLastError));
}
LONGLONG COXUNC::GetTotalDiskSpace()
{
ASSERT_VALID(m_pActor);
DWORDLONG nTotalSpace;
m_nLastError = m_pActor->GetTotalDiskSpace(*this, nTotalSpace);
if (SUCCEEDED(m_nLastError))
return nTotalSpace;
else
return (LONGLONG)-1;
}
LONGLONG COXUNC::GetFreeDiskSpace()
{
ASSERT_VALID(m_pActor);
DWORDLONG nFreeSpace;
m_nLastError = m_pActor->GetFreeDiskSpace(*this, nFreeSpace);
if (SUCCEEDED(m_nLastError))
return nFreeSpace;
else
return (LONGLONG)-1;
}
UINT COXUNC::GetDriveType()
{
ASSERT_VALID(m_pActor);
UINT nDriveType;
m_nLastError = m_pActor->GetDriveType(*this, nDriveType);
if (SUCCEEDED(m_nLastError))
return nDriveType;
else
return (UINT)0;
}
CString COXUNC::GetDiskName()
{
ASSERT_VALID(m_pActor);
CString sName;
DWORD nSerialNumber = 0;
DWORD nMaximumComponentLength = 0;
DWORD nFileSystemFlags = 0;
CString sFileSystemName;
m_nLastError = m_pActor->GetDiskInformation(*this, sName, nSerialNumber,
nMaximumComponentLength, nFileSystemFlags, sFileSystemName);
if (SUCCEEDED(m_nLastError))
return sName;
else
return _T("");
}
BOOL COXUNC::SetDiskName(LPCTSTR pszDiskName)
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->SetDiskName(*this, pszDiskName);
return (SUCCEEDED(m_nLastError));
}
DWORD COXUNC::GetDiskSerialNumber()
{
ASSERT_VALID(m_pActor);
CString sName;
DWORD nSerialNumber = 0;
DWORD nMaximumComponentLength = 0;
DWORD nFileSystemFlags = 0;
CString sFileSystemName;
m_nLastError = m_pActor->GetDiskInformation(*this, sName, nSerialNumber,
nMaximumComponentLength, nFileSystemFlags, sFileSystemName);
if (SUCCEEDED(m_nLastError))
return nSerialNumber;
else
return 0;
}
DWORD COXUNC::GetDiskMaximumComponentLength()
{
ASSERT_VALID(m_pActor);
CString sName;
DWORD nSerialNumber = 0;
DWORD nMaximumComponentLength = 0;
DWORD nFileSystemFlags = 0;
CString sFileSystemName;
m_nLastError = m_pActor->GetDiskInformation(*this, sName, nSerialNumber,
nMaximumComponentLength, nFileSystemFlags, sFileSystemName);
if (SUCCEEDED(m_nLastError))
return nMaximumComponentLength;
else
return 0;
}
DWORD COXUNC::GetDiskFileSystemFlags()
{
ASSERT_VALID(m_pActor);
CString sName;
DWORD nSerialNumber = 0;
DWORD nMaximumComponentLength = 0;
DWORD nFileSystemFlags = 0;
CString sFileSystemName;
m_nLastError = m_pActor->GetDiskInformation(*this, sName, nSerialNumber,
nMaximumComponentLength, nFileSystemFlags, sFileSystemName);
if (SUCCEEDED(m_nLastError))
return nFileSystemFlags;
else
return 0;
}
CString COXUNC::GetDiskFileSystemName()
{
ASSERT_VALID(m_pActor);
CString sName;
DWORD nSerialNumber = 0;
DWORD nMaximumComponentLength = 0;
DWORD nFileSystemFlags = 0;
CString sFileSystemName;
m_nLastError = m_pActor->GetDiskInformation(*this, sName, nSerialNumber,
nMaximumComponentLength, nFileSystemFlags, sFileSystemName);
if (SUCCEEDED(m_nLastError))
return sFileSystemName;
else
return _T("");
}
DWORD COXUNC::GetAttributes()
{
ASSERT_VALID(m_pActor);
DWORD nAttributes = 0;
m_nLastError = m_pActor->GetAttributes(*this, nAttributes);
if (SUCCEEDED(m_nLastError))
return nAttributes;
else
return MAXDWORD;
}
BOOL COXUNC::ModifyAttributes(DWORD nRemoveAttributes, DWORD nAddAttributes)
{
ASSERT_VALID(m_pActor);
// Get the current (old) attributes
DWORD nOldAttributes = GetAttributes();
if (nOldAttributes == MAXDWORD)
{
ASSERT(FAILED(m_nLastError));
return FALSE;
}
// Compute the new attributes
DWORD nNewAttributes = (nOldAttributes & ~nRemoveAttributes) | nAddAttributes;
if (nNewAttributes == nOldAttributes)
{
ASSERT(SUCCEEDED(m_nLastError));
return TRUE;
}
// Set the attributes
m_nLastError = m_pActor->SetAttributes(*this, nNewAttributes);
// Change the compression state if necessary
BOOL bOldCompressed = (nOldAttributes & FILE_ATTRIBUTE_COMPRESSED);
BOOL bNewCompressed = (nNewAttributes & FILE_ATTRIBUTE_COMPRESSED);
if (SUCCEEDED(m_nLastError) && (bOldCompressed != bNewCompressed))
{
USHORT nNewCompressionState = 0;
if (bNewCompressed)
nNewCompressionState = (USHORT)COMPRESSION_FORMAT_DEFAULT;
else
nNewCompressionState = (USHORT)COMPRESSION_FORMAT_NONE;
m_nLastError = m_pActor->SetCompression(*this, nNewCompressionState);
}
return (SUCCEEDED(m_nLastError));
}
CTime COXUNC::GetCreationTime()
{
ASSERT_VALID(m_pActor);
CTime creationTime;
CTime lastAccessTime;
CTime lastWriteTime;
m_nLastError = m_pActor->GetTime(*this, creationTime, lastAccessTime, lastWriteTime);
if (SUCCEEDED(m_nLastError))
return creationTime;
else
return CTime(0);
}
CTime COXUNC::GetLastAccessTime()
{
ASSERT_VALID(m_pActor);
CTime creationTime;
CTime lastAccessTime;
CTime lastWriteTime;
m_nLastError = m_pActor->GetTime(*this, creationTime, lastAccessTime, lastWriteTime);
if (SUCCEEDED(m_nLastError))
return lastAccessTime;
else
return CTime(0);
}
CTime COXUNC::GetLastWriteTime()
{
ASSERT_VALID(m_pActor);
CTime creationTime;
CTime lastAccessTime;
CTime lastWriteTime;
m_nLastError = m_pActor->GetTime(*this, creationTime, lastAccessTime, lastWriteTime);
if (SUCCEEDED(m_nLastError))
return lastWriteTime;
else
return CTime(0);
}
BOOL COXUNC::SetCreationTime(CTime newCreationTime)
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->SetTime(*this, newCreationTime, CTime(0), CTime(0));
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::SetLastAccessTime(CTime newLastAccessTime)
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->SetTime(*this, CTime(0), newLastAccessTime, CTime(0));
return (SUCCEEDED(m_nLastError));
}
BOOL COXUNC::SetLastWriteTime(CTime newLastWriteTime)
{
ASSERT_VALID(m_pActor);
m_nLastError = m_pActor->SetTime(*this, CTime(0), CTime(0), newLastWriteTime);
return (SUCCEEDED(m_nLastError));
}
COXUNC COXUNC::GetRoot() const
{
COXUNC rootUNC(*this);
// ... MakeAbsolute may fail
rootUNC.MakeAbsolute();
// ... Remove directory and file name
rootUNC.Directory() = PreferedSlash();
rootUNC.File().Empty();
return rootUNC;
}
COXUNC COXUNC::GetTitle() const
{
COXUNC titleUNC(*this);
// ... MakeAbsolute may fail
titleUNC.MakeAbsolute();
// ... Remove extension
titleUNC.File() = titleUNC.Base();
return titleUNC;
}
CString COXUNC::GetAbbreviation(int nMaxLength, BOOL bAtLeastFile /* = TRUE */) const
// See also the MFC function AbbreviateName() in filelist.cpp
{
CString sUNC = Full();
CString sServer;
CString sShare;
CString sDirectory;
CString sFile;
// If nMaxLength is more than enough to hold the full UNC name, we're done.
// This is probably a pretty common case, so we'll put it first.
if (sUNC.GetLength() <= nMaxLength)
return Full();
// If nMaxLength isn't enough to hold at least the filename, we're done
sFile = File();
if (nMaxLength < sFile.GetLength())
{
if (bAtLeastFile)
return sFile;
else
return _T("");
}
// If nMaxLength isn't enough to hold at least <server><share>\...\<file>, the
// result is the filename.
sServer = Server();
sShare = Share();
sDirectory = Directory();
CString sAbbr = PreferedSlash() + CString(_T("...")) + PreferedSlash();
int nServerShareFileLength = sServer.GetLength() + sShare.GetLength() + sFile.GetLength();
if (nMaxLength < nServerShareFileLength + sAbbr.GetLength())
return sFile;
// Now loop through the remaining directory components until something
// of the form <server><share>\...\<one_or_more_dirs>\<file> fits.
int nRemainingSpace = nMaxLength - nServerShareFileLength - sAbbr.GetLength();
ASSERT(0 <= nRemainingSpace);
LPCTSTR pszStartDirectory = (LPCTSTR)sDirectory;
LPCTSTR pszSearchDirectory = pszStartDirectory + sDirectory.GetLength();
LPCTSTR pszUsableDirectoryPart = pszSearchDirectory;
// ... Add one to the remainings space for the directory
// bacause we are counting the number of characters in the directory
// but we will remove its leading slash (so one extra character is allowed)
nRemainingSpace++;
while ((pszStartDirectory < pszSearchDirectory) && (0 < nRemainingSpace))
{
pszSearchDirectory--;
nRemainingSpace--;
if (_tcschr(m_pszSlashes, *pszSearchDirectory) != NULL)
// ... Do not include the leading slash
pszUsableDirectoryPart = pszSearchDirectory + 1;
}
return sServer + sShare + sAbbr + pszUsableDirectoryPart + sFile;
}
#ifdef _DEBUG
#endif //_DEBUG
COXUNC::~COXUNC()
{
// ... Remove association with the actor (do not delete the standard actor)
m_pActor = NULL;
}
// protected:
void COXUNC::BuildMain()
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Builds the main UNC from the parts
{
if (IsMainBuilt())
{
// ... Re-adjust main data (may have changed)
AdjustMain();
return;
}
if (!ArePartsBuilt())
{
// Nothing has been built yet, clean everything and set to built
Empty();
SetPartsBuilt();
return;
}
// ... Adjust parts before we use them
ASSERT(ArePartsBuilt());
AdjustParts();
// Build main data
m_sUNC = m_sServer + m_sShare + m_sDirectory + m_sFile;
// ... Adjust main after we have built it
AdjustMain();
// ... Mark that the main data has been built now
SetMainBuilt();
return;
}
void COXUNC::BuildParts()
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Builds the different parts from the full UNC
{
if (ArePartsBuilt())
{
// ... Re-adjust parts data (may have changed)
AdjustParts();
return;
}
if (!IsMainBuilt())
{
// Nothing has been built yet, clean everything and set to built
Empty();
SetMainBuilt();
return;
}
// ... Adjust main before we use it
ASSERT(IsMainBuilt());
AdjustMain();
// Build the parts
// There are three possibilities for server
// 1. An actual UNC name (e.g. \\Comp1\Share\Dir\File.ext : \\Comp1, \Share, \Dir\, File.ext)
// Always starts with two (back)slashes
// 2. A TCP/IP server name (e.g. server.company.com/Dir/File.ext : server.company.com, , /Dir/, File.ext)
// m_bURLPart == TRUE
// 3. A local file specification (e.g. C:\Dir\File.ext : C:, ,\Dir\, File.ext)
// ... First make a copy with only normal slashes (no backslashes) and lowercase characters
// Possibility 2 and 3 can be handled the same way
// All parts are empty by default
m_sServer.Empty();
m_sShare.Empty();
m_sDirectory.Empty();
m_sFile.Empty();
if ((2 <= m_sUNC.GetLength()) &&
(_tcschr(m_pszSlashes, *(LPCTSTR)m_sUNC) != NULL) &&
(_tcschr(m_pszSlashes, *((LPCTSTR)m_sUNC + 1)) != NULL) )
{
// Possibility 1 : Actual UNC
// ... Search for first slash after Server name
LPCTSTR pszShare = _tcspbrk((LPCTSTR)m_sUNC + 2, m_pszSlashes);
if (pszShare != NULL)
{
// ... Share found
INT_PTR nServerLength = pszShare - (LPCTSTR)m_sUNC;
UTBStr::tcsncpy(m_sServer.GetBufferSetLength((int)nServerLength), (int)nServerLength+1, m_sUNC, (int)nServerLength);
// ... Search for first slash after Share name
LPCTSTR pszDir = _tcspbrk(pszShare + 1, m_pszSlashes);
if (pszDir != NULL)
{
// ... Directory found
INT_PTR nShareLength = pszDir - pszShare;
UTBStr::tcsncpy(m_sShare.GetBufferSetLength((int)nShareLength), (int)nShareLength+1, pszShare, (int)nShareLength);
// ... Search for last slash after Share name
LPCTSTR pszLastSlash = _tcsrchr(pszDir + 1, m_cSlash);
LPCTSTR pszLastBackslash = _tcsrchr(pszDir + 1, m_cBackslash);
LPCTSTR pszFile = pszLastSlash < pszLastBackslash ? pszLastBackslash : pszLastSlash;
if (pszFile != NULL)
{
// ... File found (skip leading slash)
pszFile++;
INT_PTR nDirLength = pszFile - pszDir;
UTBStr::tcsncpy(m_sDirectory.GetBufferSetLength((int)nDirLength), (int)nDirLength+1, pszDir, (int)nDirLength);
m_sFile = pszFile;
}
else
{
// ... No file found after directory, interpret directory as file
// and use root as directory
// E.g. \Test -> Dir : \, File : Test
// ... First character must be a slash
ASSERT(_tcschr(m_pszSlashes, *pszDir) != NULL);
UTBStr::tcsncpy(m_sDirectory.GetBufferSetLength(1), 2, pszDir, 1);
m_sFile = pszDir + 1;
}
}
else
{
// ... Directory not found
m_sShare = pszShare;
}
}
else
{
// ... Share not found
m_sServer = m_sUNC;
}
}
else if (URLPart() && (_tcschr(m_sUNC, m_cColon) == NULL))
{
// Possibility 2 : A TCP/IP URL part
// A URL should contain an absolute specification so by checking
// for a colon we can see whether it is a TCP/IP name or local name
// ... Search for first slash after Server name
LPCTSTR pszDir = _tcspbrk(m_sUNC, m_pszSlashes);
if (pszDir != NULL)
{
// ... Directory found
INT_PTR nServerLength = pszDir - (LPCTSTR)m_sUNC;
UTBStr::tcsncpy(m_sServer.GetBufferSetLength((int)nServerLength), (int)nServerLength+1, m_sUNC, (int)nServerLength);
// ... Search for last slash after Directory name
LPCTSTR pszLastSlash = _tcsrchr(pszDir + 1, m_cSlash);
LPCTSTR pszLastBackslash = _tcsrchr(pszDir + 1, m_cBackslash);
LPCTSTR pszFile = pszLastSlash < pszLastBackslash ? pszLastBackslash : pszLastSlash;
if (pszFile != NULL)
{
// ... File found (skip leading slash)
pszFile++;
INT_PTR nDirLength = pszFile - pszDir;
UTBStr::tcsncpy(m_sDirectory.GetBufferSetLength((int)nDirLength), (int)nDirLength+1, pszDir, (int)nDirLength);
m_sFile = pszFile;
}
else
{
// ... No file found after directory, interpret directory as file
// and use root as directory
// E.g. \Test -> Dir : \, File : Test
// ... First character must be a slash
ASSERT(_tcschr(m_pszSlashes, *pszDir) != NULL);
UTBStr::tcsncpy(m_sDirectory.GetBufferSetLength(1), 2, pszDir, 1);
m_sFile = pszDir + 1;
}
}
else
{
// ... Directory not found
m_sServer = m_sUNC;
}
}
else
{
// Possibility 3 : A local file
CString sBaseName;
CString sExtension;
// ... _tsplitpath will return the current directory if m_sUNC is empty
// We do not want that.
if (!m_sUNC.IsEmpty())
{
UTBStr::tsplitpath(m_sUNC, m_sServer.GetBuffer(_MAX_DRIVE), _MAX_DRIVE,
m_sDirectory.GetBuffer(_MAX_DIR), _MAX_DIR,
sBaseName.GetBuffer(_MAX_FNAME), _MAX_FNAME,
sExtension.GetBuffer(_MAX_EXT), _MAX_EXT);
m_sServer.ReleaseBuffer();
m_sDirectory.ReleaseBuffer();
sBaseName.ReleaseBuffer();
sExtension.ReleaseBuffer();
m_sFile = sBaseName + sExtension;
}
}
// ... Adjust parts after we have built them
AdjustParts();
// ... Mark that the parts data has been built now
SetPartsBuilt();
return;
}
void COXUNC::AdjustMain()
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Adjust the main (full URL)
{
Trim(m_sUNC);
}
void COXUNC::AdjustParts()
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Adjust the URL parts
{
Trim(m_sServer);
Trim(m_sShare);
Trim(m_sDirectory);
Trim(m_sFile);
// Adjust server
// ... Is a share exists, make sure the server starts with a double (back)slash
if (!m_sShare.IsEmpty())
if (_tcschr(m_pszSlashes, *(LPCTSTR)m_sServer) == NULL)
// ... Add two backslashes
m_sServer = CString(m_cBackslash) + m_cBackslash + m_sServer;
else if (_tcschr(m_pszSlashes, *((LPCTSTR)m_sServer + 1)) == NULL)
// ... Duplicate the first character
m_sServer = *(LPCTSTR)m_sServer + m_sServer;
// Adjust share
// ... Add leading backslash if necessary
// (if the share is not empty then it must end in a backslash)
if (!m_sShare.IsEmpty() &&
(*(LPCTSTR)m_sShare != m_cBackslash) &&
(*(LPCTSTR)m_sShare != m_cSlash) )
m_sShare = m_cBackslash + m_sShare;
// Adjust directory
// ... Add leading backslash if necessary
// (If the server is not empty and does not end in a colon
// or the share is not empty then the directory must start with a backslash)
if ( ((!m_sServer.IsEmpty() && (m_sServer.Right(1) != m_cColon)) ||
!m_sShare.IsEmpty()) &&
!m_sDirectory.IsEmpty() &&
(*(LPCTSTR)m_sDirectory != m_cBackslash) &&
(*(LPCTSTR)m_sDirectory != m_cSlash) )
m_sDirectory = PreferedSlash() + m_sDirectory;
// ... Add trailing backslash if necessary
// (if the directory is not empty then it must end in a backslash)
if (!m_sDirectory.IsEmpty() &&
(m_sDirectory.Right(1) != m_cBackslash) &&
(m_sDirectory.Right(1) != m_cSlash) )
m_sDirectory += PreferedSlash();
// Adjust file
// ... If the file ends in a backslash, it is a directory, not a file
if (!m_sFile.IsEmpty() &&
(m_sFile.Right(1) == m_cBackslash) ||
(m_sFile.Right(1) == m_cSlash) )
{
m_sDirectory += m_sFile;
m_sFile.Empty();
// Recheck the directory
// ... Add leading backslash if necessary
// (If the server is not empty and does not end in a colon
// or the share is not empty then the directory must start with a backslash)
ASSERT(!m_sDirectory.IsEmpty());
if ( ((!m_sServer.IsEmpty() && (m_sServer.Right(1) != m_cColon)) ||
!m_sShare.IsEmpty()) &&
(*(LPCTSTR)m_sDirectory != m_cBackslash) &&
(*(LPCTSTR)m_sDirectory != m_cSlash) )
m_sDirectory = PreferedSlash() + m_sDirectory;
}
}
void COXUNC::Trim(CString& sText)
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Removes invalid characters and leading and trailing spaces
{
// ... Remove invalid chars <>|"
int nInvalidCharPos = sText.FindOneOf(m_pszInvalidChars);
while (0 <= nInvalidCharPos)
{
sText = sText.Left(nInvalidCharPos) + sText.Mid(nInvalidCharPos + 1);
nInvalidCharPos = sText.FindOneOf(m_pszInvalidChars);
}
// ... Remove leading and trailng spaces
sText.TrimLeft();
sText.TrimRight();
}
void COXUNC::ConvertBackslashToSlash(CString& sText)
// --- In : sText
// --- Out : sText
// --- Returns :
// --- Effect : Converts all ocurrences of a backslash to a slash
{
LPTSTR pszText = sText.GetBuffer(0);
while (*pszText != m_cNull)
{
if (*pszText == m_cBackslash)
*pszText = m_cSlash;
pszText++;
}
sText.ReleaseBuffer();
}
void COXUNC::ConvertSlashToBackslash(CString& sText)
// --- In : sText
// --- Out : sText
// --- Returns :
// --- Effect : Converts all ocurrences of a slash to a backslash
{
LPTSTR pszText = sText.GetBuffer(0);
while (*pszText != m_cNull)
{
if (*pszText == m_cSlash)
*pszText = m_cBackslash;
pszText++;
}
sText.ReleaseBuffer();
}
// private:
// ==========================================================================