// // MODULE: CHMFileReader.CPP // // PURPOSE: implement CHM file reading class CCHMFileReader // // PROJECT: for Local Troubleshooter; not needed in Online TS // // COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com // // AUTHOR: Joe Mabel // // ORIGINAL DATE: 01-18-99 // // NOTES: // // Version Date By Comments //-------------------------------------------------------------------- // V3.1 01-18-99 JM // #include "stdafx.h" #include "fs.h" #include "CHMFileReader.h" // Utilize an unnamed namespace to limit scope to this source file namespace { const CString kstr_CHMfileExtension=_T("chm"); const CString kstr_CHMpathMarker= _T("mk:@msitstore:"); const CString kstr_CHMstreamMarker= _T("::/"); } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCHMFileReader::CCHMFileReader(CString strCHMPath, CString strStreamName) : m_strCHMPath(strCHMPath), m_strStreamName(strStreamName), m_pFileSystem(NULL), m_pSubFileSystem(NULL) { } CCHMFileReader::CCHMFileReader( CString strFullCHMname ) : m_pFileSystem(NULL), m_pSubFileSystem(NULL) { int nPosPathMarker, nPosStreamMarker; nPosPathMarker= strFullCHMname.Find( kstr_CHMpathMarker ); nPosStreamMarker= strFullCHMname.Find( kstr_CHMstreamMarker ); if ((nPosPathMarker == -1) || (nPosStreamMarker == -1)) { // >>> Need to think about how to handle this condition or whether we should // be checking for a 'valid' CHM path outside of a constructor. RAB-19990120. } else { // Extract the path and string names (bounds checking is handled by the CString class). nPosPathMarker+= kstr_CHMpathMarker.GetLength(); m_strCHMPath= strFullCHMname.Mid( nPosPathMarker, nPosStreamMarker - nPosPathMarker ); nPosStreamMarker+= kstr_CHMstreamMarker.GetLength(); m_strStreamName= strFullCHMname.Mid( nPosStreamMarker ); } } CCHMFileReader::~CCHMFileReader() { if (m_pSubFileSystem) delete m_pSubFileSystem; if (m_pFileSystem) delete m_pFileSystem; } // doesn't throw exception, therefore may be used by exception class. bool CCHMFileReader::CloseHandle() { if (m_pSubFileSystem) { delete m_pSubFileSystem; m_pSubFileSystem = NULL; } if (m_pFileSystem) { m_pFileSystem->Close(); delete m_pFileSystem; m_pFileSystem = NULL; } return true; } void CCHMFileReader::Open() { try { m_pFileSystem = new CFileSystem(); //[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool. if(!m_pFileSystem) { throw bad_alloc(); } m_pSubFileSystem = new CSubFileSystem(m_pFileSystem); //[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool. if(!m_pSubFileSystem) { throw bad_alloc(); } } catch (bad_alloc&) { CloseHandle(); throw CFileReaderException(this, CFileReaderException::eErrOpen, __FILE__, __LINE__); } HRESULT hr; if (RUNNING_FREE_THREADED()) hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); // Initialize COM library if (RUNNING_APARTMENT_THREADED()) hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // Initialize COM library if (SUCCEEDED(hr)) hr = m_pFileSystem->Init(); // >>> $BUG$ potential - not sure. Oleg. 02.04.99 // Theoretically we do not need COM library after class factory // was used in m_pFileSystem->Init() in order to obtain ITStorage pointer. // Oleg. 02.04.99 // MS v-amitse 07.16.2001 RAID 432425 - added check for successful initialization if ((RUNNING_FREE_THREADED() || RUNNING_APARTMENT_THREADED()) && SUCCEEDED(hr)) ::CoUninitialize(); // Uninitialize COM library if (SUCCEEDED(hr)) hr = m_pFileSystem->Open(m_strCHMPath); if (SUCCEEDED(hr)) hr = m_pSubFileSystem->OpenSub(m_strStreamName); if (! SUCCEEDED(hr) ) { CloseHandle(); throw CFileReaderException( this, CFileReaderException::eErrOpen, __FILE__, __LINE__ ); } } void CCHMFileReader::ReadData(LPTSTR * ppBuf) { if (!m_pSubFileSystem) throw CFileReaderException(this, CFileReaderException::eErrOpen, __FILE__, __LINE__); ULONG cb = m_pSubFileSystem->GetUncompressedSize(); ULONG cbRead = 0; try { *ppBuf = new TCHAR [cb/sizeof(TCHAR)+1]; //[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool. if(!*ppBuf) throw bad_alloc(); memset(*ppBuf, 0, cb+sizeof(TCHAR)); } catch (bad_alloc&) { throw CFileReaderException(this, CFileReaderException::eErrAllocateToRead, __FILE__, __LINE__); } HRESULT hr = m_pSubFileSystem->ReadSub(*ppBuf, cb, &cbRead); if (! SUCCEEDED(hr) ) throw CFileReaderException(this, CFileReaderException::eErrRead, __FILE__, __LINE__); } CString CCHMFileReader::GetPathName() const { return (kstr_CHMpathMarker + m_strCHMPath + kstr_CHMstreamMarker + m_strStreamName ); } CString CCHMFileReader::GetJustNameWithoutExtension() const { return CAbstractFileReader::GetJustNameWithoutExtension(m_strStreamName); } CString CCHMFileReader::GetJustExtension() const { return CAbstractFileReader::GetJustExtension(m_strStreamName); } bool CCHMFileReader::GetFileTime(CAbstractFileReader::EFileTime type, time_t& out) const { return CAbstractFileReader::GetFileTime(m_strCHMPath, type, out); } CString CCHMFileReader::GetNameToLog() const { return GetPathName(); } // Returns true if the first few characters of the path match a given string. /*static*/ bool CCHMFileReader::IsCHMfile( const CString& strPath ) { // Make a copy of the path. CString strTemp= strPath; // Check for the string that denotes the beginning of a CHM file. // The sequence must start in the initial byte of a left trimmed string. strTemp.TrimLeft(); strTemp.MakeLower(); if (strTemp.Find( kstr_CHMpathMarker ) == 0) return( true ); else return( false ); } /*static*/ bool CCHMFileReader::IsPathToCHMfile( const CString& strPath ) { CString strTemp = strPath; strTemp.TrimRight(); strTemp.MakeLower(); // New approach, test for ANY extension int dot_index = strTemp.ReverseFind(_T('.')); int back_slash_index = strTemp.ReverseFind(_T('\\')); int forward_slash_index = strTemp.ReverseFind(_T('/')); if (dot_index != -1 && dot_index > back_slash_index && dot_index > forward_slash_index ) { // Now test, if it is a real file WIN32_FIND_DATA find_data; HANDLE hFile = ::FindFirstFile(strTemp, &find_data); if (hFile != INVALID_HANDLE_VALUE) { ::FindClose(hFile); return true; } } // Old approach, test for ".chm" //if (CString(_T(".")) + kstr_CHMfileExtension == strTemp.Right(kstr_CHMfileExtension.GetLength() + 1)) // return true; return false; } /*static*/ CString CCHMFileReader::FormCHMPath( const CString strPathToCHMfile ) { return kstr_CHMpathMarker + strPathToCHMfile + kstr_CHMstreamMarker; }