windows-nt/Source/XPSP1/NT/enduser/troubleshoot/msinfo/v500file.cpp
2020-09-26 16:20:57 +08:00

425 lines
12 KiB
C++

// File5Src.cpp Implementation of Version 5.00 data file methods.
//
// Copyright (c) 1998-1999 Microsoft Corporation
#include "DataSrc.h"
#ifndef IDS_V500FILENODE
#include "resource.h"
#endif
#ifndef _UNICODE
#define _ttoupper toupper
#define _ttolower tolower
#define _tislower islower
#define _tisupper isupper
#else
#define _ttoupper towupper
#define _ttolower towlower
#define _tislower iswlower
#define _tisupper iswupper
#endif
/*
* CBufferV500DataSource - Construct the DataSource from a file, which mostly
* means constructing all the folder.
*
* History: a-jsari 10/17/97 Initial version
*/
CBufferV500DataSource::CBufferV500DataSource(CMSInfoFile *pFileSink)
:CBufferDataSource(pFileSink)
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CBufferFolder *pFolder;
CBufferFolder *pLast;
unsigned uReadCase;
try {
ReadHeader(pFileSink);
m_szFileName = pFileSink->GetFileName();
unsigned cFolders = 0;
ReadFolder(pFileSink, (CFolder * &)pLast, NULL);
// CFolders read by our ReadFolder are guaranteed to be CBufferFolder's.
m_RootFolder = pLast;
do {
pFileSink->ReadUnsignedInt(uReadCase);
// Only switch off the flags, not the extended bits.
switch (uReadCase & CBufferV500DataSource::MASK) {
case CBufferV500DataSource::CHILD:
ReadFolder(pFileSink, (CFolder * &)(pFolder), pLast);
ASSERT(pLast->m_ChildFolder == NULL);
pLast->m_ChildFolder = pFolder;
break;
case CBufferV500DataSource::NEXT:
ReadFolder(pFileSink, (CFolder * &)(pFolder), pLast->GetParentNode());
// Attach the folder to the tree.
pLast->m_NextFolder = pFolder;
break;
case CBufferV500DataSource::PARENT:
unsigned iDepth;
// Ascend to the right level in the tree.
iDepth = (uReadCase & ~CBufferV500DataSource::MASK);
while (iDepth--) {
pLast = (CBufferFolder *)pLast->GetParentNode();
}
ReadFolder(pFileSink, (CFolder * &)pFolder, pLast->GetParentNode());
// Now attach the folder as a sibling at the right level.
while (pLast->m_NextFolder != NULL) {
pLast = (CBufferFolder *)pLast->m_NextFolder;
}
pLast->m_NextFolder = pFolder;
break;
case CBufferV500DataSource::END:
return;
break;
default:
ThrowFileFormatException();
break;
}
pLast = pFolder;
// Never intended to exit until END key is read or an exception occurs.
} while (TRUE);
}
catch (CException *e) {
CString strMessage, strTitle;
strMessage.LoadString( IDS_CORRUPTEDFILE);
strTitle.LoadString( IDS_DESCRIPTION);
::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strMessage, strTitle, MB_OK);
delete pFolder;
throw e;
}
catch (...) {
ASSERT(FALSE);
}
}
/*
* ~CBufferDataSource - Destructor. Does nothing; the file created here
* is deleted in the CDataSource destructor.
*
* History: a-jsari 10/17/97 Initial version
*/
CBufferV500DataSource::~CBufferV500DataSource()
{
}
/*
* GetNodeName - Return in strName the formatted name for the root node.
*
* History: a-jsari 1/16/98 Initial version
*/
BOOL CBufferV500DataSource::GetNodeName(CString &strName)
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CString strFileName = FileName();
LPCTSTR szFilePart = ::_tcsrchr((LPCTSTR)strFileName, '\\');
ASSERT(szFilePart != NULL);
if (szFilePart == NULL)
szFilePart = strFileName;
else
++szFilePart;
strName.Format(IDS_V500FILENODE, szFilePart);
return TRUE;
}
/*
* ReadElements - Read all of the element data into our buffers.
*
* History: a-jsari 11/3/97 Initial version
*/
void CBufferV500DataSource::ReadElements(CMSInfoFile *pFileSink, CBufferFolder *pFolder)
{
pFileSink->ReadUnsignedInt(pFolder->m_cColumns);
if (pFolder->m_cColumns == 0) {
pFolder->m_cRows = 0;
return;
}
unsigned iColumn = pFolder->m_cColumns;
BYTE bComplexity;
DataComplexity dcComplexity;
pFolder->m_uWidths.SetSize(iColumn);
pFolder->m_szColumns.SetSize(iColumn);
pFolder->m_SortData.SetColumns(iColumn);
while (iColumn--) {
unsigned wSortType;
pFileSink->ReadUnsignedInt(pFolder->m_uWidths[iColumn]);
pFileSink->ReadString(pFolder->m_szColumns[iColumn]);
pFileSink->ReadUnsignedInt(wSortType);
pFileSink->ReadByte(bComplexity);
dcComplexity = (DataComplexity)bComplexity;
if (dcComplexity != BASIC && dcComplexity != ADVANCED)
dcComplexity = BASIC;
pFolder->m_dcColumns.SetAtGrow(iColumn, dcComplexity);
if (pFolder->m_SortData.SetSortType(iColumn, wSortType) == FALSE)
if (pFolder->m_SortData.SetSortType(iColumn, NOSORT) == FALSE)
::ThrowFileFormatException();
}
pFileSink->ReadUnsignedInt(pFolder->m_cRows);
pFolder->m_szElements.SetSize(pFolder->m_cRows);
pFolder->m_SortData.SetRows(pFolder->m_cRows);
iColumn = pFolder->m_cColumns;
unsigned iRow = pFolder->m_cRows;
// Size the rows.
while (iRow--) {
pFolder->m_szElements[iRow].SetSize(pFolder->m_cColumns);
pFileSink->ReadByte(bComplexity);
dcComplexity = (DataComplexity)bComplexity;
pFolder->m_dcRows.SetAtGrow(iRow, dcComplexity);
}
while (iColumn--) {
iRow = pFolder->m_cRows;
while (iRow--) {
pFileSink->ReadString(pFolder->m_szElements[iRow][iColumn]);
}
pFolder->m_SortData.ReadSortValues(pFileSink, iColumn);
}
}
/*
* ReadFolder - Reads the data of a folder
*
* History: a-jsari 10/17/97 Initial version
*/
void CBufferV500DataSource::ReadFolder(CMSInfoFile *pFileSink, CFolder * &pFolder, CFolder *pParentFolder)
{
CBufferFolder *pBufferFolder = new CBufferFolder(this, pParentFolder);
if (pBufferFolder == NULL) ::AfxThrowMemoryException();
pFileSink->ReadString(pBufferFolder->m_szName);
ReadElements(pFileSink, pBufferFolder);
pFolder = pBufferFolder;
}
/*
* ReadHeader - Read header information for this buffer
*
* History: a-jsari 10/17/97 Initial version
*/
void CBufferV500DataSource::ReadHeader(CMSInfoFile *pFileSink)
{
LONG l;
ASSERT(pFileSink != NULL);
pFileSink->ReadLong(l); // Save time.
m_tsSaveTime = (ULONG) l;
#ifdef _WIN64
pFileSink->ReadLong(l); // Save time.
m_tsSaveTime |= ((time_t) l) << 32;
#endif
CString szDummy;
pFileSink->ReadString(szDummy); // Network machine name
pFileSink->ReadString(szDummy); // Network user name
}
/*
* VerifyFileVersion - Read the top two unsigned ints, and verify that they
* have the expected values.
*
* History: a-jsari 11/23/97 Initial version
*/
BOOL CBufferV500DataSource::VerifyFileVersion(CMSInfoFile *pFile)
{
UINT uVersion;
pFile->ReadUnsignedInt(uVersion);
ASSERT(uVersion == CMSInfoFile::VERSION_500_MAGIC_NUMBER);
if (uVersion != CMSInfoFile::VERSION_500_MAGIC_NUMBER)
return FALSE;
pFile->ReadUnsignedInt(uVersion);
ASSERT(uVersion == 0x0500);
return (uVersion == 0x0500);
}
/*
* Save - Save initialization information to the IStream passed in.
*
* History: a-jsari 11/13/97 Initial version
*/
HRESULT CBufferV500DataSource::Save(IStream *pStm)
{
unsigned wValue;
ULONG dwSize;
HRESULT hResult;
USES_CONVERSION;
do {
wValue = GetType();
hResult = pStm->Write(&wValue, sizeof(wValue), &dwSize);
ASSERT(SUCCEEDED(hResult) && (dwSize == sizeof(wValue)));
if (FAILED(hResult)) break;
wValue = m_szFileName.GetLength();
hResult = pStm->Write(&wValue, sizeof(wValue), &dwSize);
ASSERT(SUCCEEDED(hResult) && (dwSize == sizeof(wValue)));
if (FAILED(hResult)) break;
wValue *= sizeof(WCHAR);
// Save the file name as a wide character string to avoid different
// types of save filenames.
hResult = pStm->Write(T2CW((LPCTSTR)m_szFileName), wValue, &dwSize);
ASSERT(SUCCEEDED(hResult) && (dwSize == wValue));
} while (FALSE);
return hResult;
}
/*
* CaseInsensitiveMatch - Compare two TCHARs without regard to case.
*
* History: a-jsari 12/31/97 Initial version
*/
static inline BOOL CaseInsensitiveMatch(TCHAR aChar, TCHAR bChar)
{
if (::_tisupper(aChar))
aChar = ::_ttolower(aChar);
#if 0
// We've already guaranteed that the second string is all lowercase.
if (::_tisupper(bChar))
bChar = ::_ttolower(bChar);
#endif
return aChar == bChar;
}
/*
* FindCaseInsensitive - Like CString::Find, but not case sensitive.
*
* History: a-jsari 12/31/97 Initial version
*/
static inline int FindCaseInsensitive(LPCTSTR szSearch, LPCTSTR szMatch)
{
int iString;
// Set the number of iterations through the string: the number of
// substrings we'll need to test.
int iCount = ::_tcslen(szSearch)-::_tcslen(szMatch)+1;
// Set the size so that we can return the proper index when we
// successfully find the substring.
int nSize = iCount-1;
// We can't find a substring larger than our search string.
if (iCount <= 0) return -1;
while (iCount--) {
iString = 0;
while (CaseInsensitiveMatch(szSearch[iString], szMatch[iString])) {
if (szMatch[++iString] == 0) {
// End of match string; return index.
return nSize-iCount;
}
}
// Increment our search string.
++szSearch;
}
// End of search string; failure.
return -1;
}
/*
* FolderContains - Test to see if the fCurrent folder contains the substring
*
* History: a-jsari 12/16/97 Initial version.
*/
BOOL CBufferV500DataSource::FolderContains(const CListViewFolder *fCurrent,
const CString &strSearch, int &wRow, long lFolderOptions)
{
CString strName;
int wRowMax = fCurrent->GetRows();
unsigned uColMax = fCurrent->GetColumns();
CString strLowerSearch = strSearch;
strLowerSearch.MakeLower();
fCurrent->GetName(strName);
if (wRow == -1) {
if (FindCaseInsensitive(strName, strLowerSearch) != -1)
return TRUE;
wRow = 0;
}
// Don't check the data elements if we are only checking categories.
if ((lFolderOptions & FIND_OPTION_CATEGORY_ONLY) == FIND_OPTION_CATEGORY_ONLY)
return FALSE;
for ( ; wRow < wRowMax ; ++wRow) {
unsigned iCol = uColMax;
while (iCol--) {
fCurrent->GetSubElement(wRow, iCol, strName);
if (FindCaseInsensitive(strName, strLowerSearch) != -1) {
return TRUE;
}
if (FindStopped() == TRUE)
return FALSE;
}
}
return FALSE;
}
/*
* Find - Traverse the tree looking for a match.
*
* History: a-jsari 12/11/97 Initial version
*/
BOOL CBufferV500DataSource::Find(const CString &strSearch, long lFindOptions)
{
// Record our depth in the tree so we don't go above our initial search
// category when ascending.
static int iDepth;
CFolder *pfNext;
CString strName;
ASSERT(strSearch.GetLength() != 0);
StartSearch();
if (m_pfLast == NULL || (lFindOptions & FIND_OPTION_REPEAT_SEARCH) == 0) {
// If we are searching all categories, reset to the root, otherwise
// our root is set for us.
if ((lFindOptions & FIND_OPTION_ONE_CATEGORY) == 0)
m_pfLast = GetRootNode();
iDepth = 0;
} else
++m_iLine;
while (m_pfLast) {
if (FolderContains(dynamic_cast<CListViewFolder *>(m_pfLast),
strSearch, m_iLine, lFindOptions)) {
m_pfLast->InternalName(m_strPath);
StopSearch();
return TRUE;
}
else if (FindStopped() == TRUE)
return FALSE;
// For the next folder searched, start with the folder name
m_iLine = -1;
do {
// Depth-first
pfNext = m_pfLast->GetChildNode();
if (pfNext != NULL) {
++iDepth;
break;
}
pfNext = m_pfLast->GetNextNode();
if (pfNext != NULL) break;
pfNext = m_pfLast->GetParentNode();
if (pfNext) {
// Check that we don't ascend back above our current category.
if (--iDepth == 0 && (lFindOptions & FIND_OPTION_ONE_CATEGORY)
== FIND_OPTION_ONE_CATEGORY) {
pfNext = NULL;
break;
}
pfNext = pfNext->GetNextNode();
}
} while (FALSE);
m_pfLast = pfNext;
}
// No matches; restart the next search at the beginning.
m_pfLast = NULL;
return FALSE;
}
#if 0
/*
* StopSearch - Ends the current search.
*
* History: a-jsari 1/19/98 Initial version
*/
BOOL CBufferV500DataSource::StopSearch()
{
if (m_fSearching == TRUE) {
m_fSearching = FALSE;
return TRUE;
}
return FALSE;
}
#endif