⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chmfile.cpp

📁 Windows Mobile,ppc,wince下的chm格式文件阅读器源代码
💻 CPP
字号:
// CHMFile.cpp: implementation of the CCHMFile class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CHMFile.h"
#include "AtlConv.h"
#include ".\chmfile.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCHMFile::CCHMFile()
{	
	m_pCHMFile=NULL;
}

CCHMFile::~CCHMFile()
{
	ResetFileList();
	ResetTocList();
	if (m_pCHMFile)
		chm_close(m_pCHMFile);
	m_pCHMFile=NULL;
}

BOOL CCHMFile::ResetFileList()
{
	// Free Memory
	POSITION pos=m_FileList.GetHeadPosition();
	while(pos!=NULL)
	{
		CCHMFileInfo *pInfo=(CCHMFileInfo*)m_FileList.GetNext(pos);		
		delete pInfo;
	}
	m_FileList.RemoveAll();
	return true;
}

BOOL CCHMFile::ResetTocList()
{
	// Free Memory
	POSITION pos=m_TOC.GetHeadPosition();
	while(pos!=NULL)
	{
		CCHMToc *pInfo=(CCHMToc *)m_TOC.GetNext(pos);		
		delete pInfo;
	}
	m_TOC.RemoveAll();
	return true;
}

BOOL CCHMFile::Open(CString FileName)
{
	m_FileName=FileName;

	if (m_pCHMFile!=NULL)
		chm_close(m_pCHMFile);

	m_pCHMFile=NULL;
	ResetFileList();
	ResetTocList();

	USES_CONVERSION;
	m_pCHMFile=chm_open(T2A((LPTSTR)(LPCTSTR)FileName));
	if (m_pCHMFile==NULL)
		return false;

	m_Split.ResetData();
	m_Split.SplitPath(FileName);

	if (!ReadListOfFiles())
		return false;

	return true;
}

void CCHMFile::Close()
{
	if (m_pCHMFile)
	{
		chm_close(m_pCHMFile);
		m_pCHMFile=NULL;
	}
	ResetFileList();
	ResetTocList();
	DeleteFiles(_T("/Temp/"));
}

BOOL CCHMFile::Load(CString FileName)
{
	if (!Open(FileName))
		return false;		

	CCHMFileInfo* pHHCFile=GetHHCFile();
	if (pHHCFile!=NULL)
	{
		CString HHCText=GetTextFile(pHHCFile);
		
		CString Title;
		CString File;
		int Level=0;

		TRACE(_T("Processing HCC file : %s\n"),FileName);

		// Parse HHCText file to build TOC
		// <UL> = Go in Level		
		// </UL> = Go out level
		// <param name="Name" value="Cover"> = Title
		// <param name="Local" value="webappshtml/00co01a.htm">	= File to navigate to				

		CString Text;
		BOOL bNeedToAdd=false;
		for(int i=0;i<HHCText.GetLength();i++)
		{			
			if (HHCText.GetAt(i)==_T('<'))
			{
				if (HHCText.Mid(i,4).CompareNoCase(_T("<UL>"))==0)
				{
					if (bNeedToAdd)
					{
						m_TOC.AddTail(new CCHMToc(Title,"",Level));
						bNeedToAdd=false;
					}
					Level++;
				}
				if (HHCText.Mid(i,5).CompareNoCase(_T("</UL>"))==0)
				{
					Level--;
					if (bNeedToAdd)
					{
						m_TOC.AddTail(new CCHMToc(Title,"",Level));
						bNeedToAdd=false;
					}
				}
				if (HHCText.Mid(i,26).CompareNoCase(_T("<param name=\"Name\" value=\""))==0)
				{
					int idx=HHCText.Find(_T("\">"),i+26);
					Title=HHCText.Mid(i+26,idx-i-26);
					bNeedToAdd=true;
				}
				if (HHCText.Mid(i,27).CompareNoCase(_T("<param name=\"Local\" value=\""))==0)
				{
					int idx=HHCText.Find(_T("\">"),i+27);
					File=HHCText.Mid(i+27,idx-i-27);
					File=_T("/")+File;
					m_TOC.AddTail(new CCHMToc(Title,File,Level));
					bNeedToAdd=false;
				}
			}
		}		
	}
	else
		TRACE(_T("NO HCC Contents file found\n"));

	// All Done
	return true;
}

BOOL CCHMFile::GetFile(CString FileName, CString FilePath)
{
	CCHMFileInfo *pInfo=CheckFileExists(FileName);
	return GetFile(pInfo,FilePath);
}

// Get File from CHM & Store onto Disk using FilePath
BOOL CCHMFile::GetFile(CCHMFileInfo *pInfo, CString FilePath)
{	
	if (pInfo==NULL)
		return false;

	BYTE* pBuffer=GetFile(pInfo);
	if (pBuffer==NULL)
		return false;
	
	// Create File
	TRACE(_T("Get File : Saving file to %s as %s\n"),pInfo->m_FileName,FilePath);
	CFile F;
	if (F.Open(FilePath,CFile::modeWrite|CFile::modeCreate))
	{
		F.Write(pBuffer,pInfo->m_Length);
		F.Close();		
	}
	else
	{
		TRACE(_T("Failed to create file : %s as %s\n"),pInfo->m_FileName,FilePath);
	}

	return true;
}

CString CCHMFile::GetTextFile(CCHMFileInfo *pInfo)
{
	if (pInfo==NULL)
		return CString("");
	
	BYTE *pBuffer=GetFile(pInfo);
	if (pBuffer==NULL)
		return CString("");	
	
	CString FileText;

	CStringEx Text;
	for(unsigned long i=0;i<pInfo->m_Length;i++)
	{
		Text+=(TCHAR)pBuffer[i];
	}
	int idx=Text.FindNoCase(_T("UTF-8"));
	if ((idx>-1) && (idx<200))
	{
		DWORD dwSize=(pInfo->m_Length*sizeof(TCHAR))+100;
		BYTE *pBuffer2=new BYTE[dwSize];
		ZeroMemory(pBuffer2,dwSize);
		int nRes=MultiByteToWideChar(CP_UTF8,0,(LPCSTR)pBuffer,pInfo->m_Length,(LPWSTR)pBuffer2,dwSize);

		FileText.Format(_T("%s"),(LPWSTR)pBuffer2);

		delete pBuffer2;
		pBuffer2=NULL;
	}
	else
	{
		FileText=Text;
	}

	delete pBuffer;
	pBuffer=NULL;
	
	return CString(FileText);
}

BYTE* CCHMFile::GetFile(CCHMFileInfo *pInfo)
{	
	if (m_pCHMFile==NULL)
	{
		TRACE(_T("Get File : Failed - pCHMFile =NULL\n"));
		return NULL;
	}	
	if (pInfo==NULL)
	{
		TRACE(_T("Get File : File not found in List of files\n"));
		return NULL;
	}

	TRACE(_T("Get File : %s\n"),pInfo->m_FileName);
	struct chmUnitInfo ui;
	USES_CONVERSION;
	int rc=chm_resolve_object(m_pCHMFile, T2A((LPTSTR)(LPCTSTR)pInfo->m_FileName), &ui);	
	if (rc==1)
	{
		TRACE(_T("Get File : Failed to resolve file\n"));
		return NULL;
	}
	
	BYTE *pBuffer=new BYTE[pInfo->m_Length+10];
	LONGINT64 rc2=chm_retrieve_object(m_pCHMFile, &ui, pBuffer, 0, pInfo->m_Length);	

	return pBuffer;
}

int CCHMFile::EnumListOfFiles(struct chmFile *h,struct chmUnitInfo *ui,void *context)
{
	CCHMFile *pCHMFIle=(CCHMFile*)context;	
	pCHMFIle->AddFileInfo(ui->path,(DWORD)ui->length, (DWORD)ui->space, (DWORD)ui->start);
    return CHM_ENUMERATOR_CONTINUE;
}

BOOL CCHMFile::AddFileInfo(CString FileName, DWORD Length, DWORD Space, DWORD Start)
{
	CCHMFileInfo *pFileInfo=new CCHMFileInfo(FileName, Length, Space,Start);
	m_FileList.AddTail(pFileInfo);
	return true;
}

// Read CHM File List
BOOL CCHMFile::ReadListOfFiles(void)
{
	if (m_pCHMFile==NULL)
		return false;

	ResetFileList();

	// Read TOC	
	int rc=chm_enumerate(m_pCHMFile, CHM_ENUMERATE_ALL, CCHMFile::EnumListOfFiles, (void *)this);

	// All Done
	return true;
}

CCHMFileInfo* CCHMFile::CheckFileExists(CString FileName)
{
	if (FileName.Left(3).Compare(_T("/.."))==0)
		FileName=FileName.Mid(3);

	if (FileName.Left(7).CompareNoCase(_T("MS-ITS:"))==0)
	{		
		FileName=FileName.Mid(7);
		int idx=FileName.Find(_T("::"));
		CString CHMFileName=FileName.Left(idx);
		FileName=FileName.Mid(idx+2);

		if (CHMFileName.CompareNoCase(m_Split.GetFilename()+m_Split.GetExtension())!=0)
			return NULL;
	}
	if (FileName.Left(8).CompareNoCase(_T("/MS-ITS:"))==0)
	{		
		FileName=FileName.Mid(8);
		int idx=FileName.Find(_T("::"));
		CString CHMFileName=FileName.Left(idx);
		FileName=FileName.Mid(idx+2);
		if (CHMFileName.CompareNoCase(m_Split.GetFilename()+m_Split.GetExtension())!=0)
			return NULL;
	}

	// Ensure all filenames start with '/'
	if (FileName.Left(1).Compare(_T("/"))!=0)
		FileName=_T("/")+FileName;

	int idx=FileName.ReverseFind(_T('/'));	
	CString FileName2=FileName.Mid(idx+1);
	CString FileNameHTML;
	FileNameHTML.Format(_T("/html%s"),FileName);
	POSITION pos=m_FileList.GetHeadPosition();
	while(pos!=NULL)
	{
		CCHMFileInfo *pInfo=(CCHMFileInfo*)m_FileList.GetNext(pos);		
		if (pInfo)
		{
			if (pInfo->m_FileName.CompareNoCase(FileName)==0)
			{
				return pInfo;
			}
			if (pInfo->m_FileName.CompareNoCase(FileNameHTML)==0)
			{
				return pInfo;
			}
		}
	}	
	
	return NULL;
}


CCHMFileInfo* CCHMFile::GetHHCFile()
{
	POSITION pos=m_FileList.GetHeadPosition();
	while(pos!=NULL)
	{
		CCHMFileInfo *pInfo=(CCHMFileInfo*)m_FileList.GetNext(pos);		
		if (pInfo)
		{
			if (pInfo->m_FileName.Right(4).CompareNoCase(_T(".hhc"))==0)
			{
				return pInfo;
			}
		}
	}	
	return NULL;
}

int CCHMFile::CheckStringArray(CStringArray *pStrings, CString Item, BOOL bNoCase)
{
	if (pStrings==NULL)
		return -1;

	for(int i=0;i<pStrings->GetSize();i++)
	{
		if (bNoCase)
		{
			if (pStrings->GetAt(i).CompareNoCase(Item)==0)
				return i;
		}
		else
		{
			if (pStrings->GetAt(i).Compare(Item)==0)
				return i;
		}
	}
	return -1;
}


BOOL CCHMFile::DeleteFiles(CString Dir)
{	
	for(int i=0;i<m_ImageList.GetSize();i++)
	{
		CString FileName=m_ImageList.GetAt(i);

		int idx=FileName.ReverseFind(_T('/'));
		CString FilePath;
		FilePath.Format(_T("%s\\%s"),Dir,FileName.Mid(idx+1));
		DeleteFile(FilePath);
	}
	m_ImageList.RemoveAll();
	return true;
}

CString CCHMFile::GetHTMLFile(CString FileName, CString Dir)
{		
	CCHMFileInfo *pInfo=CheckFileExists(FileName);
	if (pInfo==NULL)
		return CString("");

	CStringEx HTMLText=GetTextFile(pInfo);
	if (HTMLText.IsEmpty())
		return CString ("");

	// Get Root Directory.

	// Store for later.

	TRACE(_T("Processing HTML Text file : %s\n"),FileName);
	m_ImageList.RemoveAll();		
	int iStartPos=0;
	int iLinkPos=-1;
	do
	{
		iLinkPos=HTMLText.FindNoCase(_T("<link"),iStartPos);
		if (iLinkPos!=-1)
		{
			int idx=HTMLText.FindNoCase(_T("href="),iLinkPos+5);
			if (idx>-1)
			{
				int idx2=HTMLText.Mid(idx+6).FindOneOf(_T("'\""));
				if (idx2>-1)
				{										
					CStringEx HRef=HTMLText.Mid(idx+6,idx2);					
					TRACE(_T("Found HRef : %s\n"),HRef);

					if (CheckStringArray(&m_ImageList,HRef, true)==-1)	
						m_ImageList.Add(HRef);

					CString Insert;
					if (HRef.FindNoCase(_T("MS-ITS:"))==0)
					{
						int idx3=HRef.Find(_T("::"));
						CString NewName=HRef.Mid(7,idx3-7);
						CString Insert;
						Insert.Format(_T("file://%s/%s"),Dir,HRef.Mid(idx3+3));
						HTMLText=HTMLText.Left(idx+6)+Insert+HTMLText.Mid(idx+idx2);
						iStartPos=idx+6+Insert.GetLength();
					}
					else
					{
						if (HRef.GetAt(0)!=_T('/'))
						{
							CSplitPath Split(pInfo->m_FileName,_T('/'));
							HRef=Split.GetPath()+HRef;
						}					
						Insert.Format(_T("file://%s"),Dir);
						HTMLText.Insert(idx+6,Insert);				
						CString Text=HTMLText.Mid(idx);
						iStartPos=idx+Insert.GetLength()+2;
					}				
				}
			}			
			continue;
		}

		// Remove Script entries
		iLinkPos=HTMLText.FindNoCase(_T("<script"),iStartPos);
		if (iLinkPos!=-1)
		{
			int idx=HTMLText.FindNoCase(_T("</script>"),iLinkPos);
			HTMLText=HTMLText.Left(iLinkPos)+HTMLText.Mid(idx+9);
			continue;
		}

		// Remove XML Entries.
		iLinkPos=HTMLText.FindNoCase(_T("<xml"),iStartPos);
		if (iLinkPos!=-1)
		{
			int idx=HTMLText.FindNoCase(_T("</xml>"),iLinkPos);
			HTMLText=HTMLText.Left(iLinkPos)+HTMLText.Mid(idx+6);
			continue;
		}

	}
	while (iLinkPos!=-1);
	
	// Extract StyleSheet Files
	for(int i=0;i<m_ImageList.GetSize();i++)
	{		
		CStringEx FN=m_ImageList.GetAt(i);
		CCHMFileInfo *pInfo=CheckFileExists(FN);

		CCHMFile ExternalCHM;											
		CCHMFile *pCHMFile=this;	
		if (pInfo==NULL)
		{
			CSplitPath Split(FileName,_T('/'));
			CString NameEx;						
			NameEx=Split.GetPath()+FN;						
			pInfo=CheckFileExists(NameEx);
		}
		if ((pInfo==NULL) && (FN.FindNoCase(_T("MS-ITS:"))==0))
		{
			CString ExternalCHMName;				
			int idx=FN.Find(_T("::"));
			ExternalCHMName=FN.Mid(7,idx-7);

			CStringEx Text;			
			int idx2=FN.ReverseFind(_T('/'));
			Text=FN.Right(FN.GetLength()-idx2-1);

			// Get file from external source.						
			if (ExternalCHM.Open(GetSplit().GetPath()+ExternalCHMName))
			{	
				pInfo=ExternalCHM.CheckFileExists(Text);
				pCHMFile=&ExternalCHM;
			}		
		}

		if (pInfo)
		{			
			CStringEx Text;			
			int idx=pInfo->m_FileName.ReverseFind(_T('/'));
			Text=pInfo->m_FileName.Right(pInfo->m_FileName.GetLength()-idx-1);

			CString FilePath;
			FilePath.Format(_T("%s%s"),Dir,Text);
			pCHMFile->GetFile(pInfo,FilePath);			
		}
	}

	WORD w=0;
	w=(WORD)HTMLText.GetAt(0);
	if (w==0xfeff)
		HTMLText=HTMLText.Mid(1);

	return CString(HTMLText);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -