1189 lines
25 KiB
C++
1189 lines
25 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: filelist.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/* File: filelist.cpp
|
|
|
|
Description: Simplifies the transmission of a list of share and
|
|
associated file names between components of the CSC UI. See
|
|
description in filelist.h for details.
|
|
|
|
Classes:
|
|
|
|
CscFilenameList
|
|
CscFilenameList::HSHARE
|
|
CscFilenameList::ShareIter
|
|
CscFilenameList::FileIter
|
|
|
|
Note: This module was written to be used by any part of the CSCUI,
|
|
not just the viewer. Therefore, I don't assume that the
|
|
new operator will throw an exception on allocation failures.
|
|
I don't like all the added code to detect allocation failures
|
|
but it's not reasonable to expect code in the other components
|
|
to become exception-aware with respect to "new" failures.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
11/28/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "filelist.h"
|
|
|
|
#ifdef FILELIST_TEST
|
|
#include <stdio.h>
|
|
#include <tchar.h>
|
|
#endif
|
|
|
|
|
|
static LPTSTR DupStr(LPCTSTR psz)
|
|
{
|
|
LPTSTR pszNew = new TCHAR[lstrlen(psz) + 1];
|
|
if (NULL != pszNew)
|
|
{
|
|
lstrcpy(pszNew, psz);
|
|
}
|
|
return pszNew;
|
|
}
|
|
|
|
|
|
int CscFilenameList::m_cGrow = 4;
|
|
int CscFilenameList::Share::m_cGrow = 10;
|
|
|
|
|
|
CscFilenameList::CscFilenameList(
|
|
void
|
|
) : m_cShares(0),
|
|
m_cAllocated(0),
|
|
m_rgpShares(NULL),
|
|
m_bValid(true)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::CscFilenameList(
|
|
PCSC_NAMELIST_HDR pbNames,
|
|
bool bCopy
|
|
) : m_cShares(0),
|
|
m_cAllocated(0),
|
|
m_rgpShares(NULL),
|
|
m_bValid(true)
|
|
{
|
|
m_bValid = LoadFromBuffer(pbNames, bCopy);
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::~CscFilenameList(
|
|
void
|
|
)
|
|
{
|
|
for (int i = 0; i < m_cShares; i++)
|
|
{
|
|
delete m_rgpShares[i];
|
|
}
|
|
delete[] m_rgpShares;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::LoadFromBuffer(
|
|
PCSC_NAMELIST_HDR pHdr,
|
|
bool bCopy
|
|
)
|
|
{
|
|
LPBYTE pbBuffer = reinterpret_cast<LPBYTE>(pHdr);
|
|
CSC_NAMELIST_SHARE_DESC *pShareDesc = (CSC_NAMELIST_SHARE_DESC *)(pbBuffer + sizeof(CSC_NAMELIST_HDR));
|
|
for (UINT i = 0; i < pHdr->cShares; i++)
|
|
{
|
|
LPCTSTR pszShareName = (LPCTSTR)(pbBuffer + pShareDesc->cbOfsShareName);
|
|
LPCTSTR pszFileName = (LPCTSTR)(pbBuffer + pShareDesc->cbOfsFileNames);
|
|
HSHARE hShare;
|
|
|
|
if (!AddShare(pszShareName, &hShare, bCopy))
|
|
{
|
|
return false; // memory allocation failure.
|
|
}
|
|
else
|
|
{
|
|
for (UINT j = 0; j < pShareDesc->cFiles; j++)
|
|
{
|
|
//
|
|
// Note that we always pass "false" for the bDirectory
|
|
// argument to AddFile(). Passing true causes the
|
|
// string "\*" to be appended to the filename stored
|
|
// in the collection. Since we're getting names from
|
|
// an existing namelist buffer, directories will already
|
|
// have the "\*" appended. We don't want to append a
|
|
// second instance.
|
|
//
|
|
if (!AddFile(hShare, pszFileName, false, bCopy))
|
|
{
|
|
return false; // memory allocation failure.
|
|
}
|
|
pszFileName += (lstrlen(pszFileName) + 1);
|
|
}
|
|
}
|
|
pShareDesc++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::AddShare(
|
|
LPCTSTR pszShare,
|
|
HSHARE *phShare,
|
|
bool bCopy
|
|
)
|
|
{
|
|
bool bResult = true;
|
|
if (m_cShares == m_cAllocated)
|
|
bResult = GrowSharePtrList();
|
|
|
|
if (bResult)
|
|
{
|
|
bResult = false;
|
|
Share *pShare = new Share(pszShare, bCopy);
|
|
if (NULL != pShare)
|
|
{
|
|
m_rgpShares[m_cShares++] = pShare;
|
|
*phShare = HSHARE(pShare);
|
|
bResult = true;
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::AddFile(
|
|
HSHARE& hShare,
|
|
LPCTSTR pszFile,
|
|
bool bDirectory,
|
|
bool bCopy
|
|
)
|
|
{
|
|
return hShare.m_pShare->AddFile(pszFile, bDirectory, bCopy);
|
|
}
|
|
|
|
|
|
//
|
|
// Given a full UNC path name, separate the share and file names with
|
|
// a nul character and return the address of the share and file name
|
|
// parts. Note that the buffer pointed to by pszFullPath is modified.
|
|
//
|
|
void
|
|
CscFilenameList::ParseFullPath(
|
|
LPTSTR pszFullPath,
|
|
LPTSTR *ppszShare,
|
|
LPTSTR *ppszFile
|
|
) const
|
|
{
|
|
*ppszShare = NULL;
|
|
*ppszFile = pszFullPath;
|
|
|
|
LPTSTR psz = pszFullPath;
|
|
if (*psz && *psz == TEXT('\\'))
|
|
{
|
|
psz++;
|
|
if (*psz && *psz == TEXT('\\'))
|
|
{
|
|
*ppszShare = pszFullPath; // Assume a share name.
|
|
*ppszFile = NULL;
|
|
|
|
psz++;
|
|
while(*psz && *psz != TEXT('\\'))
|
|
{
|
|
psz = CharNext(psz);
|
|
}
|
|
if (*psz)
|
|
psz = CharNext(psz);
|
|
while(*psz && *psz != TEXT('\\'))
|
|
{
|
|
psz = CharNext(psz);
|
|
}
|
|
if (*psz)
|
|
{
|
|
*ppszFile = CharNext(psz);
|
|
*psz = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::AddFile(
|
|
LPCTSTR pszFullPath,
|
|
bool bDirectory,
|
|
bool bCopy
|
|
)
|
|
{
|
|
bool bResult = false;
|
|
LPTSTR pszShare = NULL;
|
|
LPTSTR pszFile = NULL;
|
|
LPTSTR pszParsedPath = DupStr(pszFullPath);
|
|
|
|
if (NULL != pszParsedPath)
|
|
{
|
|
TCHAR szBackslash[] = TEXT("\\");
|
|
ParseFullPath(pszParsedPath, &pszShare, &pszFile);
|
|
if (NULL == pszFile || TEXT('\0') == *pszFile)
|
|
{
|
|
//
|
|
// Path was just a share name with no file or subdirectory.
|
|
//
|
|
pszFile = szBackslash;
|
|
}
|
|
|
|
if (NULL != pszShare)
|
|
{
|
|
bResult = AddFile(pszShare, pszFile, bDirectory, bCopy);
|
|
}
|
|
delete[] pszParsedPath;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::AddFile(
|
|
LPCTSTR pszShare,
|
|
LPCTSTR pszFile,
|
|
bool bDirectory,
|
|
bool bCopy
|
|
)
|
|
{
|
|
HSHARE hShare;
|
|
if (!GetShareHandle(pszShare, &hShare))
|
|
{
|
|
if (!AddShare(pszShare, &hShare, bCopy))
|
|
{
|
|
return false; // memory allocation failure.
|
|
}
|
|
}
|
|
return AddFile(hShare, pszFile, bDirectory, bCopy);
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::RemoveFile(
|
|
HSHARE& hShare,
|
|
LPCTSTR pszFile
|
|
)
|
|
{
|
|
return hShare.m_pShare->RemoveFile(pszFile);
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::RemoveFile(
|
|
LPCTSTR pszFullPath
|
|
)
|
|
{
|
|
bool bResult = false;
|
|
LPTSTR pszShare = NULL;
|
|
LPTSTR pszFile = NULL;
|
|
LPTSTR pszParsedPath = DupStr(pszFullPath);
|
|
|
|
if (NULL != pszParsedPath)
|
|
{
|
|
TCHAR szBackslash[] = TEXT("\\");
|
|
ParseFullPath(pszParsedPath, &pszShare, &pszFile);
|
|
if (NULL == pszFile || TEXT('\0') == *pszFile)
|
|
{
|
|
//
|
|
// Path was just a share name with no file or subdirectory.
|
|
//
|
|
pszFile = szBackslash;
|
|
}
|
|
|
|
if (NULL != pszShare)
|
|
{
|
|
bResult = RemoveFile(pszShare, pszFile);
|
|
}
|
|
delete[] pszParsedPath;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::RemoveFile(
|
|
LPCTSTR pszShare,
|
|
LPCTSTR pszFile
|
|
)
|
|
{
|
|
HSHARE hShare;
|
|
if (!GetShareHandle(pszShare, &hShare))
|
|
{
|
|
return false; // doesn't exist
|
|
}
|
|
return RemoveFile(hShare, pszFile);
|
|
}
|
|
|
|
|
|
LPCTSTR
|
|
CscFilenameList::GetShareName(
|
|
HSHARE& hShare
|
|
) const
|
|
{
|
|
return static_cast<LPCTSTR>(hShare.m_pShare->m_pszShareName);
|
|
}
|
|
|
|
|
|
int
|
|
CscFilenameList::GetShareCount(
|
|
void
|
|
) const
|
|
{
|
|
return m_cShares;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
CscFilenameList::GetFileCount(
|
|
void
|
|
) const
|
|
{
|
|
int cFiles = 0;
|
|
ShareIter si = CreateShareIterator();
|
|
HSHARE hShare;
|
|
while(si.Next(&hShare))
|
|
{
|
|
cFiles += GetShareFileCount(hShare);
|
|
}
|
|
return cFiles;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
CscFilenameList::GetShareFileCount(
|
|
HSHARE& hShare
|
|
) const
|
|
{
|
|
return hShare.m_pShare->m_cFiles;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::ShareExists(
|
|
LPCTSTR pszShare
|
|
) const
|
|
{
|
|
HSHARE hShare;
|
|
return GetShareHandle(pszShare, &hShare);
|
|
}
|
|
|
|
|
|
//
|
|
// Replacement for lstrcmpi that adds a little twist for the
|
|
// filename list.
|
|
// If the *pbExact argument [in] is false AND if the s1
|
|
// string argument is appended with "\*", it is assumed to be a
|
|
// directory name and all descendents of that directory produce a
|
|
// match. *pbExact is modified to indicate if the match was
|
|
// an exact match or a wildcard match as just described.
|
|
// If *pbExact is false on entry, the function works just like
|
|
// lstrcmpi except that the return value is true/false instead
|
|
// of <0, 0, >0.
|
|
//
|
|
bool
|
|
CscFilenameList::Compare(
|
|
LPCTSTR s1,
|
|
LPCTSTR s2,
|
|
bool *pbExact
|
|
)
|
|
{
|
|
LPCTSTR s1First = s1;
|
|
bool bMatch = false;
|
|
|
|
TraceAssert((NULL != pbExact));
|
|
|
|
while(*s1 || *s2)
|
|
{
|
|
//
|
|
// Do a case-insensitive comparison.
|
|
//
|
|
if (PtrToUlong(CharUpper((LPTSTR)(*s1))) == PtrToUlong(CharUpper((LPTSTR)(*s2))))
|
|
{
|
|
s1 = CharNext(s1);
|
|
s2 = CharNext(s2);
|
|
}
|
|
else
|
|
{
|
|
if (!(*pbExact))
|
|
{
|
|
//
|
|
// An exact match is not required. Now check for
|
|
// wildcard match.
|
|
//
|
|
if (TEXT('\0') == *s2 &&
|
|
TEXT('\\') == *s1 &&
|
|
TEXT('*') == *(s1+1))
|
|
{
|
|
//
|
|
// At end of key string provided by user.
|
|
// We have a match if the string being tested
|
|
// contains "\*" at current test location.
|
|
//
|
|
// i.e. "foo\bar" matches "foo\bar\*"
|
|
//
|
|
bMatch = true;
|
|
*pbExact = false;
|
|
}
|
|
else if (TEXT('*') == *s1)
|
|
{
|
|
//
|
|
// We hit a '*' in the stored string.
|
|
// Since we've matched up to this point, the
|
|
// user's string is an automatic match.
|
|
//
|
|
bMatch = TEXT('\0') == *(s1+1);
|
|
*pbExact = false;
|
|
}
|
|
}
|
|
goto return_result;
|
|
}
|
|
}
|
|
if (TEXT('\0') == *s1 && TEXT('\0') == *s2)
|
|
{
|
|
//
|
|
// Exact match.
|
|
//
|
|
*pbExact = bMatch = true;
|
|
goto return_result;
|
|
}
|
|
|
|
return_result:
|
|
return bMatch;
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::FileExists(
|
|
HSHARE& hShare,
|
|
LPCTSTR pszFile,
|
|
bool bExact // Default == true
|
|
) const
|
|
{
|
|
FileIter fi = CreateFileIterator(hShare);
|
|
//
|
|
// Skip past any leading backslashes for matching purposes.
|
|
// File names (paths) stored in the filename list don't have
|
|
// leading backslashes. It's implied as the root directory.
|
|
//
|
|
while(*pszFile && TEXT('\\') == *pszFile)
|
|
pszFile = CharNext(pszFile);
|
|
|
|
LPCTSTR psz;
|
|
while(NULL != (psz = fi.Next()))
|
|
{
|
|
bool bExactResult = bExact;
|
|
if (Compare(psz, pszFile, &bExactResult)) // Modifies bExactResult.
|
|
{
|
|
return !bExact || (bExact && bExactResult);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool
|
|
CscFilenameList::FileExists(
|
|
LPCTSTR pszShare,
|
|
LPCTSTR pszFile,
|
|
bool bExact // Default == true
|
|
) const
|
|
{
|
|
HSHARE hShare;
|
|
return (GetShareHandle(pszShare, &hShare) &&
|
|
FileExists(hShare, pszFile, bExact));
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::FileExists(
|
|
LPCTSTR pszFullPath,
|
|
bool bExact // Default = true
|
|
) const
|
|
{
|
|
bool bResult = false;
|
|
LPTSTR pszShare = NULL;
|
|
LPTSTR pszFile = NULL;
|
|
LPTSTR pszParsedPath = DupStr(pszFullPath);
|
|
if (NULL != pszParsedPath)
|
|
{
|
|
ParseFullPath(pszParsedPath, &pszShare, &pszFile);
|
|
if (NULL != pszShare && NULL != pszFile)
|
|
{
|
|
bResult = FileExists(pszShare, pszFile, bExact);
|
|
}
|
|
delete[] pszParsedPath;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::FileIter
|
|
CscFilenameList::CreateFileIterator(
|
|
HSHARE& hShare
|
|
) const
|
|
{
|
|
return FileIter(hShare.m_pShare);
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::ShareIter
|
|
CscFilenameList::CreateShareIterator(
|
|
void
|
|
) const
|
|
{
|
|
return ShareIter(*this);
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::GetShareHandle(
|
|
LPCTSTR pszShare,
|
|
HSHARE *phShare
|
|
) const
|
|
{
|
|
Share *pShare = NULL;
|
|
for (int i = 0; i < m_cShares; i++)
|
|
{
|
|
pShare = m_rgpShares[i];
|
|
if (pShare->m_pszShareName.IsValid() && 0 == lstrcmpi(pszShare, pShare->m_pszShareName))
|
|
{
|
|
*phShare = HSHARE(pShare);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::GrowSharePtrList(
|
|
void
|
|
)
|
|
{
|
|
Share **rgpShares = new Share *[m_cAllocated + m_cGrow];
|
|
if (NULL != rgpShares)
|
|
{
|
|
if (NULL != m_rgpShares)
|
|
CopyMemory(rgpShares, m_rgpShares, m_cAllocated * sizeof(Share *));
|
|
delete[] m_rgpShares;
|
|
m_rgpShares = rgpShares;
|
|
m_cAllocated += m_cGrow;
|
|
}
|
|
return (NULL != rgpShares);
|
|
}
|
|
|
|
|
|
//
|
|
// Create a memory buffer to hold the contents of the name list.
|
|
// The buffer is formatted as described in the header of filelist.h.
|
|
//
|
|
PCSC_NAMELIST_HDR
|
|
CscFilenameList::CreateListBuffer(
|
|
void
|
|
) const
|
|
{
|
|
int i;
|
|
|
|
//
|
|
// Calculate the required buffer size and allocate buffer.
|
|
//
|
|
int cbOfsNames = sizeof(CSC_NAMELIST_HDR) +
|
|
sizeof(CSC_NAMELIST_SHARE_DESC) * m_cShares;
|
|
int cbBuffer = cbOfsNames;
|
|
|
|
for (i = 0; i < m_cShares; i++)
|
|
{
|
|
cbBuffer += m_rgpShares[i]->ByteCount();
|
|
}
|
|
|
|
LPBYTE pbBuffer = new BYTE[cbBuffer];
|
|
PCSC_NAMELIST_HDR pHdr = reinterpret_cast<PCSC_NAMELIST_HDR>(pbBuffer);
|
|
if (NULL != pbBuffer)
|
|
{
|
|
LPTSTR pszNames = reinterpret_cast<LPTSTR>(pbBuffer + cbOfsNames);
|
|
CSC_NAMELIST_SHARE_DESC *pShareDescs = reinterpret_cast<CSC_NAMELIST_SHARE_DESC *>(pbBuffer + sizeof(CSC_NAMELIST_HDR));
|
|
int cchNames = (cbBuffer - cbOfsNames) / sizeof(TCHAR);
|
|
//
|
|
// Write the share and file name strings.
|
|
//
|
|
for (i = 0; i < m_cShares; i++)
|
|
{
|
|
CSC_NAMELIST_SHARE_DESC *pDesc = pShareDescs + i;
|
|
Share *pShare = m_rgpShares[i];
|
|
|
|
int cch = pShare->Write(pbBuffer,
|
|
pDesc,
|
|
pszNames,
|
|
cchNames);
|
|
cchNames -= cch;
|
|
pszNames += cch;
|
|
}
|
|
//
|
|
// Fill in the buffer header.
|
|
//
|
|
pHdr->cbSize = cbBuffer;
|
|
pHdr->cShares = m_cShares;
|
|
}
|
|
|
|
return pHdr;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CscFilenameList::FreeListBuffer(
|
|
PCSC_NAMELIST_HDR pbNames
|
|
)
|
|
{
|
|
delete[] pbNames;
|
|
}
|
|
|
|
#ifdef FILELIST_TEST
|
|
void
|
|
CscFilenameList::Dump(
|
|
void
|
|
) const
|
|
{
|
|
_tprintf(TEXT("Dump share name list at 0x%08X\n"), (DWORD)this);
|
|
_tprintf(TEXT("\tm_cShares......: %d\n"), m_cShares);
|
|
_tprintf(TEXT("\tm_cAllocated...: %d\n"), m_cAllocated);
|
|
|
|
|
|
for (int i = 0; i < m_cShares; i++)
|
|
{
|
|
m_rgpShares[i]->Dump();
|
|
}
|
|
}
|
|
|
|
void
|
|
CscFilenameList::DumpListBuffer(
|
|
PCSC_NAMELIST_HDR pHdr
|
|
) const
|
|
{
|
|
LPBYTE pbBuffer = (LPBYTE)pHdr;
|
|
_tprintf(TEXT("Dump buffer at 0x%08X\n"), (DWORD)pbBuffer);
|
|
_tprintf(TEXT("hdr.cbSize......: %d\n"), pHdr->cbSize);
|
|
_tprintf(TEXT("hdr.flags.......: %d\n"), pHdr->flags);
|
|
_tprintf(TEXT("hdr.cShares.....: %d\n"), pHdr->cShares);
|
|
CSC_NAMELIST_SHARE_DESC *pDesc = (CSC_NAMELIST_SHARE_DESC *)(pbBuffer + sizeof(CSC_NAMELIST_HDR));
|
|
for (UINT i = 0; i < pHdr->cShares; i++)
|
|
{
|
|
_tprintf(TEXT("\tShare [%d] header\n"), i);
|
|
_tprintf(TEXT("\t\tcbOfsShareName..:%d\n"), pDesc->cbOfsShareName);
|
|
_tprintf(TEXT("\t\tcbOfsFileNames..:%d\n"), pDesc->cbOfsFileNames);
|
|
_tprintf(TEXT("\t\tcFiles..........:%d\n"), pDesc->cFiles);
|
|
LPTSTR pszName = (LPTSTR)(pbBuffer + pDesc->cbOfsShareName);
|
|
_tprintf(TEXT("\t\tShare name......: \"%s\"\n"), pszName);
|
|
pszName += lstrlen(pszName) + 1;
|
|
for (UINT j = 0; j < pDesc->cFiles; j++)
|
|
{
|
|
_tprintf(TEXT("\t\tFile[%3d] name...: \"%s\"\n"), j, pszName);
|
|
pszName += lstrlen(pszName) + 1;
|
|
}
|
|
pDesc++;
|
|
}
|
|
}
|
|
|
|
#endif // FILELIST_TEST
|
|
|
|
CscFilenameList::Share::Share(
|
|
LPCTSTR pszShare,
|
|
bool bCopy
|
|
) : m_pszShareName(pszShare, bCopy),
|
|
m_cFiles(0),
|
|
m_cAllocated(0),
|
|
m_cchFileNames(0),
|
|
m_cchShareName(lstrlen(pszShare) + 1),
|
|
m_rgpszFileNames(NULL)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::Share::~Share(
|
|
void
|
|
)
|
|
{
|
|
delete[] m_rgpszFileNames;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::Share::AddFile(
|
|
LPCTSTR pszFile,
|
|
bool bDirectory,
|
|
bool bCopy
|
|
)
|
|
{
|
|
bool bResult = true;
|
|
|
|
TraceAssert((NULL != pszFile && TEXT('\0') != *pszFile));
|
|
if (NULL == pszFile || TEXT('\0') == *pszFile)
|
|
return false;
|
|
|
|
if (m_cFiles == m_cAllocated)
|
|
bResult = GrowFileNamePtrList();
|
|
|
|
if (bResult)
|
|
{
|
|
LPTSTR pszFileCopy = NULL;
|
|
if (bDirectory)
|
|
{
|
|
int cchFile = lstrlen(pszFile);
|
|
pszFileCopy = new TCHAR[cchFile + 3]; // length + "\*" + nul
|
|
if (NULL == pszFileCopy)
|
|
return false; // memory alloc failure.
|
|
//
|
|
// Append "\*" to a directory entry.
|
|
// This will allow us to do lookups on files that
|
|
// are descendants of a directory. See
|
|
// CscFilenameList::FileExists() for details.
|
|
//
|
|
lstrcpy(pszFileCopy, pszFile);
|
|
if (TEXT('\\') == *(pszFileCopy + cchFile - 1))
|
|
{
|
|
//
|
|
// Guard against pszFile already having a trailing backslash.
|
|
//
|
|
cchFile--;
|
|
}
|
|
lstrcpy(pszFileCopy + cchFile, TEXT("\\*"));
|
|
pszFile = pszFileCopy;
|
|
}
|
|
|
|
//
|
|
// Skip past any leading backslash.
|
|
//
|
|
while(*pszFile && TEXT('\\') == *pszFile)
|
|
pszFile = CharNext(pszFile);
|
|
|
|
NamePtr np(pszFile, bCopy);
|
|
if (bResult = np.IsValid())
|
|
{
|
|
m_rgpszFileNames[m_cFiles++] = np;
|
|
m_cchFileNames += (lstrlen(pszFile) + 1);
|
|
}
|
|
delete[] pszFileCopy;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::Share::RemoveFile(
|
|
LPCTSTR pszFile
|
|
)
|
|
{
|
|
TraceAssert((NULL != pszFile && TEXT('\0') != *pszFile));
|
|
if (NULL == pszFile || TEXT('\0') == *pszFile)
|
|
return false;
|
|
|
|
//
|
|
// Skip past any leading backslashes for matching purposes.
|
|
// File names (paths) stored in the filename list don't have
|
|
// leading backslashes. It's implied as the root directory.
|
|
//
|
|
while(*pszFile && TEXT('\\') == *pszFile)
|
|
pszFile = CharNext(pszFile);
|
|
|
|
for(int i = 0; i < m_cFiles; i++)
|
|
{
|
|
bool bExactResult = true;
|
|
if (Compare(m_rgpszFileNames[i], pszFile, &bExactResult)
|
|
&& bExactResult)
|
|
{
|
|
// Found an exact match. Move the last file into the
|
|
// current array location and decrement the count.
|
|
m_rgpszFileNames[i] = m_rgpszFileNames[--m_cFiles];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::Share::GrowFileNamePtrList(
|
|
void
|
|
)
|
|
{
|
|
CscFilenameList::NamePtr *rgpsz = new CscFilenameList::NamePtr[m_cAllocated + m_cGrow];
|
|
if (NULL != rgpsz)
|
|
{
|
|
m_cAllocated += m_cGrow;
|
|
if (NULL != m_rgpszFileNames)
|
|
{
|
|
for (int i = 0; i < m_cFiles; i++)
|
|
{
|
|
rgpsz[i] = m_rgpszFileNames[i];
|
|
}
|
|
}
|
|
delete[] m_rgpszFileNames;
|
|
m_rgpszFileNames = rgpsz;
|
|
}
|
|
return (NULL != rgpsz);
|
|
}
|
|
|
|
|
|
//
|
|
// Write the share name and file names to a text buffer.
|
|
//
|
|
int
|
|
CscFilenameList::Share::Write(
|
|
LPBYTE pbBufferStart, // Address of buffer start.
|
|
CSC_NAMELIST_SHARE_DESC *pShare, // Address of share descriptor.
|
|
LPTSTR pszBuffer, // Address of name buffer
|
|
int cchBuffer // Chars left in name buffer.
|
|
) const
|
|
{
|
|
pShare->cbOfsShareName = (DWORD)((LPBYTE)pszBuffer - pbBufferStart);
|
|
int cch = WriteName(pszBuffer, cchBuffer);
|
|
cchBuffer -= cch;
|
|
pszBuffer += cch;
|
|
pShare->cbOfsFileNames = (DWORD)((LPBYTE)pszBuffer - pbBufferStart);
|
|
cch += WriteFileNames(pszBuffer, cchBuffer, &pShare->cFiles);
|
|
return cch;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Write the share name to a text buffer.
|
|
//
|
|
int
|
|
CscFilenameList::Share::WriteName(
|
|
LPTSTR pszBuffer,
|
|
int cchBuffer
|
|
) const
|
|
{
|
|
if (m_pszShareName.IsValid() && m_cchShareName <= cchBuffer)
|
|
{
|
|
lstrcpy(pszBuffer, m_pszShareName);
|
|
return m_cchShareName;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Write the file names to a text buffer.
|
|
//
|
|
int
|
|
CscFilenameList::Share::WriteFileNames(
|
|
LPTSTR pszBuffer,
|
|
int cchBuffer,
|
|
DWORD *pcFilesWritten // [out]. Count of files written.
|
|
) const
|
|
{
|
|
int cchWritten = 0;
|
|
DWORD cFilesWritten = 0;
|
|
|
|
if (m_cchFileNames <= cchBuffer)
|
|
{
|
|
for (int i = 0; i < m_cFiles; i++)
|
|
{
|
|
if (m_rgpszFileNames[i].IsValid())
|
|
{
|
|
lstrcpy(pszBuffer, m_rgpszFileNames[i]);
|
|
int cch = (lstrlen(m_rgpszFileNames[i]) + 1);
|
|
pszBuffer += cch;
|
|
cchWritten += cch;
|
|
cFilesWritten++;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pcFilesWritten)
|
|
{
|
|
*pcFilesWritten = cFilesWritten;
|
|
}
|
|
return cchWritten;
|
|
}
|
|
|
|
#ifdef FILELIST_TEST
|
|
|
|
void
|
|
CscFilenameList::Share::Dump(
|
|
void
|
|
) const
|
|
{
|
|
_tprintf(TEXT("Share \"%s\"\n"), (LPCTSTR)m_pszShareName ? (LPCTSTR)m_pszShareName : TEXT("<null>"));
|
|
_tprintf(TEXT("\tm_cFiles........: %d\n"), m_cFiles);
|
|
_tprintf(TEXT("\tm_cAllocated....: %d\n"), m_cAllocated);
|
|
_tprintf(TEXT("\tm_cchShareName..: %d\n"), m_cchShareName);
|
|
_tprintf(TEXT("\tm_cchFileNames..: %d\n"), m_cchFileNames);
|
|
for (int i = 0; i < m_cFiles; i++)
|
|
{
|
|
_tprintf(TEXT("\tFile[%3d].......: \"%s\"\n"), i, (LPCTSTR)m_rgpszFileNames[i] ? (LPCTSTR)m_rgpszFileNames[i] : TEXT("<null>"));
|
|
}
|
|
}
|
|
|
|
#endif // FILELIST_TEST
|
|
|
|
|
|
CscFilenameList::FileIter::FileIter(
|
|
const CscFilenameList::Share *pShare
|
|
) : m_pShare(pShare),
|
|
m_iFile(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::FileIter::FileIter(
|
|
void
|
|
) : m_pShare(NULL),
|
|
m_iFile(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::FileIter::FileIter(
|
|
const CscFilenameList::FileIter& rhs
|
|
)
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::FileIter&
|
|
CscFilenameList::FileIter::operator = (
|
|
const CscFilenameList::FileIter& rhs
|
|
)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
m_pShare = rhs.m_pShare;
|
|
m_iFile = rhs.m_iFile;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
LPCTSTR
|
|
CscFilenameList::FileIter::Next(
|
|
void
|
|
)
|
|
{
|
|
if (0 < m_pShare->m_cFiles && m_iFile < m_pShare->m_cFiles)
|
|
return m_pShare->m_rgpszFileNames[m_iFile++];
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CscFilenameList::FileIter::Reset(
|
|
void
|
|
)
|
|
{
|
|
m_iFile = 0;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::ShareIter::ShareIter(
|
|
const CscFilenameList& fnl
|
|
) : m_pfnl(&fnl),
|
|
m_iShare(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::ShareIter::ShareIter(
|
|
void
|
|
) : m_pfnl(NULL),
|
|
m_iShare(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::ShareIter::ShareIter(
|
|
const CscFilenameList::ShareIter& rhs
|
|
)
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::ShareIter&
|
|
CscFilenameList::ShareIter::operator = (
|
|
const CscFilenameList::ShareIter& rhs
|
|
)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
m_pfnl = rhs.m_pfnl;
|
|
m_iShare = rhs.m_iShare;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CscFilenameList::ShareIter::Next(
|
|
HSHARE *phShare
|
|
)
|
|
{
|
|
if (0 < m_pfnl->m_cShares && m_iShare < m_pfnl->m_cShares)
|
|
{
|
|
*phShare = HSHARE(m_pfnl->m_rgpShares[m_iShare++]);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CscFilenameList::ShareIter::Reset(
|
|
void
|
|
)
|
|
{
|
|
m_iShare = 0;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::NamePtr::NamePtr(
|
|
LPCTSTR pszName,
|
|
bool bCopy
|
|
) : m_pszName(pszName),
|
|
m_bOwns(bCopy)
|
|
{
|
|
if (bCopy)
|
|
{
|
|
m_pszName = DupStr(pszName);
|
|
m_bOwns = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::NamePtr::~NamePtr(
|
|
void
|
|
)
|
|
{
|
|
if (m_bOwns)
|
|
{
|
|
delete[] const_cast<LPTSTR>(m_pszName);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::NamePtr::NamePtr(
|
|
CscFilenameList::NamePtr& rhs
|
|
)
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::NamePtr&
|
|
CscFilenameList::NamePtr::operator = (
|
|
CscFilenameList::NamePtr& rhs
|
|
)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
if (m_bOwns)
|
|
delete[] (LPTSTR)m_pszName;
|
|
|
|
m_pszName = rhs.m_pszName;
|
|
m_bOwns = false;
|
|
if (rhs.m_bOwns)
|
|
{
|
|
//
|
|
// Assume ownership of the buffer.
|
|
//
|
|
rhs.m_bOwns = false;
|
|
m_bOwns = true;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::HSHARE::HSHARE(
|
|
void
|
|
) : m_pShare(NULL)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::HSHARE::HSHARE(
|
|
const HSHARE& rhs
|
|
)
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
|
|
|
|
CscFilenameList::HSHARE&
|
|
CscFilenameList::HSHARE::operator = (
|
|
const CscFilenameList::HSHARE& rhs
|
|
)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
m_pShare = rhs.m_pShare;
|
|
}
|
|
return *this;
|
|
}
|