// 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(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