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

📄 bpdf.cpp

📁 这是一个PDF文件查看的程序
💻 CPP
字号:
// BPdf.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "BPdfObject.h"
#include "BPdf.h"

BOOL CBPdf::Open(CString strFilePath)
{
	CString str;

	m_dwTrailerPos = 0;
	m_raw.Open(strFilePath);
	m_raw.GetNextLine(m_strHeader);
	if (m_strHeader.Left(5) != "%PDF-")
	{
		m_raw.Close();
		return FALSE;
	}
	m_raw.GotoEnd();
	m_raw.AssertPreviousLine("%%EOF");
	m_raw.GetPreviousLine(str);
	DWORD dwStartXref = atoi(str);
	m_raw.AssertPreviousLine("startxref");

	m_raw.GotoPos(dwStartXref);
	GetXref();
	return TRUE;
}

void CBPdf::Close()
{
	m_arrayXref.RemoveAll();
	m_mapXref.RemoveAll();
	delete m_pobjTrailer;
	m_raw.Close();
}

BOOL CBPdf::IsOpen()
{
	return m_raw.IsOpen();
}

void CBPdf::GetXref()
{
	CString str;

	m_raw.AssertNextLine("xref");
	for (;;)
	{
		m_raw.GetNextLine(str);
		if (str == "trailer")
		{
			if (m_dwTrailerPos == 0)
				m_dwTrailerPos = m_raw.GetPos();
			break;
		}

		DWORD dwObjectNumber = 0;
		DWORD dwGroupCount = 0;

		sscanf(str.GetBuffer(0), "%d %d", &dwObjectNumber, &dwGroupCount);
		for (DWORD i = 0; i < dwGroupCount;)
		{
			if (m_raw.GetNextLine(str) == FALSE)
			{
				AfxMessageBox("Error in cross reference table");
				AfxThrowUserException();
			}

			if (str == "")
				continue;

			i++;

			int dwOffset = 0;
			int dwGeneration = 0;
			char cType = 0;

			sscanf(str, "%d %d %c", &dwOffset, &dwGeneration, &cType);

			if (cType == 'n')
			{
				CBXrefEntry entry(dwObjectNumber, dwOffset);
				m_arrayXref.Add(entry);
				m_mapXref.SetAt(dwObjectNumber, dwOffset);
			}
			dwObjectNumber++;
		}
	}
	CBPdfDictionary* pdict = (CBPdfDictionary*)GetObject(NULL);
	CBPdfObject* pprev;
	if (!pdict->Lookup("/Prev", &pprev))
	{
		delete pdict;
		return;
	}
	DWORD dwPos = atoi(((CBPdfValue*)pprev)->GetString());
	delete pdict;
	m_raw.GotoPos(dwPos);
	GetXref();
}

CBPdfObject* CBPdf::GetObject(CBPdfObject* pobjParent)
{
	CString str;

	DWORD dwPos = m_raw.GetPos();
	m_raw.GetNextToken(str);
	if (str == "<<")
	{
		m_raw.GotoPos(dwPos);
		return GetDictionary(pobjParent);
	}
	if (str == "[")
	{
		m_raw.GotoPos(dwPos);
		return GetArray(pobjParent);
	}
	if (str.Right(2) == " R")
	{
		CBPdfReference* pstr = new CBPdfReference(pobjParent, str);
		return pstr;
	}
	CBPdfValue* pstr = new CBPdfValue(pobjParent, str);
	return pstr;
}

CBPdfObject* CBPdf::GetArray(CBPdfObject* pobjParent)
{
	CString str;

	m_raw.AssertNextToken("[");
	CBPdfArray* parray = new CBPdfArray(pobjParent);
	for (;;)
	{
		DWORD dwPos = m_raw.GetPos();
		m_raw.GetNextToken(str);
 		if (str == "]")
			break;

		m_raw.GotoPos(dwPos);
		parray->Add(GetObject(pobjParent));
	}
	return parray;
}

CBPdfObject* CBPdf::GetDictionary(CBPdfObject* pobjParent)
{
	CString str;

	m_raw.AssertNextToken("<<");
	CBPdfDictionary* pdict = new CBPdfDictionary(pobjParent);
	for (;;)
	{
		m_raw.GetNextToken(str);
 		if (str == ">>")
			break;

		pdict->Add(str, GetObject(pdict));
	}

	DWORD dwPos = m_raw.GetPos();
	m_raw.GetNextToken(str);
	if (str != "stream")
	{
		m_raw.GotoPos(dwPos);
		return pdict;
	}

	m_raw.AssertNextLine("");

	DWORD dwStreamSize = 0;
	DWORD dwStreamPos = m_raw.GetPos();

	CBPdfObject* pobjLength;
	pdict->Lookup("/Length", &pobjLength);
	if (pobjLength->GetType() == "Value")
	{
		CBPdfValue* pobjValue = (CBPdfValue*)pobjLength;
		dwStreamSize = atoi(pobjValue->GetString());
	}
	else if (pobjLength->GetType() == "Reference")
	{
		CBPdfReference* pobjReference = (CBPdfReference*)pobjLength;

		DWORD dwPos0 = m_raw.GetPos();
		if (GotoReference(pobjReference->GetString()))
		{
			pobjLength = GetObject(NULL);
			CBPdfValue* pobjValue = (CBPdfValue*)pobjLength;
			dwStreamSize = atoi(pobjValue->GetString());
			delete pobjLength;
		}
		m_raw.GotoPos(dwPos0);
	}

	m_raw.GotoPos(m_raw.GetPos() + dwStreamSize);
	m_raw.AssertNextToken("endstream");

	CBPdfStream* pstream = new CBPdfStream(pobjParent, pdict, dwStreamPos, dwStreamSize);
	return pstream;
}

BOOL CBPdf::GetMem(BYTE* pabBuffer, DWORD dwPos, DWORD dwSize)
{
	m_raw.GetMem(pabBuffer, dwPos, dwSize);
	return TRUE;
}

BOOL CBPdf::GotoReference(CString strReference)
{
	DWORD dwObject = 0;
	DWORD dwGeneration = 0;
	char cType = 0;

	DWORD dwOffset;

	sscanf(strReference.GetBuffer(0), "%d %d %c", &dwObject, &dwGeneration, &cType);
	if (m_mapXref.Lookup(dwObject, dwOffset) == FALSE)
		return FALSE;
	if (dwOffset == 0)
		return FALSE;

	m_raw.GotoPos(dwOffset);

	CString str;

	str.Format("%d", dwObject);
	m_raw.AssertNextToken(str);
	m_raw.GetNextToken(str);
	m_raw.AssertNextToken("obj");
	return TRUE;
}

CString CBPdf::Colorize(CString strString)
{
	CString str;
	DWORD dwStart = 0;

	strString.Replace("{", "\\{");
	strString.Replace("}", "\\}");
	strString.Replace("\\", "\\\\");

	for (;;)
	{
		DWORD dwIndex = strString.Find(" obj", dwStart);
		if (dwIndex == -1)
		{
			str += strString.Mid(dwStart);
			str += "\\par\r\n";
			return str;
			break;
		}

		str += strString.Mid(dwStart, dwIndex - dwStart);
		str += "\\cf1 ";
		str += " obj";
		str += "\\cf0 ";
		dwStart = dwIndex + 4;
	}
}

void CBPdf::GetRichText(CFile* pfile)
{
	CString str;

	str = "{\\rtf1\\ansi\\deff0";
	pfile->Write(str, str.GetLength());
	str = "{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset162 Lucida Console;}}";
	pfile->Write(str, str.GetLength());
	str = "{\\colortbl ;\\red255\\green0\\blue0;}";
	pfile->Write(str, str.GetLength());
	str = "{\\uc1\\pard\\fs20\\f0";
	pfile->Write(str, str.GetLength());

	m_raw.GotoPos(0);
	for (int i = 0; i < 6000; i++)
	{
		CString strLine;
		if (!m_raw.GetNextLine(strLine))
			break;

		CString strRtf = Colorize(strLine);
		pfile->Write(strRtf, strRtf.GetLength());
		if ((strLine.Right(6) == "stream") && (strLine.Right(9) != "endstream"))
			m_raw.GotoLine("endstream");
	}
	str = "}";
	pfile->Write(str, str.GetLength());
	str = "}";
	pfile->Write(str, str.GetLength());
	DWORD dw = str.GetLength();
	pfile->Write(str, str.GetLength());
}

DWORD CALLBACK CBPdf::MyStreamInCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	MyStreamInStruct* pmsis = (MyStreamInStruct*)(ULONGLONG)dwCookie;

	DWORD dwBlockSize = (DWORD)(pmsis->pfile->GetLength() - pmsis->pfile->GetPosition());
	*pcb = cb;
	if ((DWORD)*pcb > dwBlockSize)
		*pcb = dwBlockSize;

	pmsis->pfile->Read(pbBuff, *pcb);
	return 0;
}

void CBPdf::Draw(CRichEditCtrl* pctrl)
{
	CMemFile file;
	GetRichText(&file);

	MyStreamInStruct msis;
	msis.pfile = &file;
	file.SeekToBegin();

	EDITSTREAM es;
	es.dwCookie = (DWORD_PTR)&msis;
	es.pfnCallback = MyStreamInCallback; 
	pctrl->StreamIn(SF_RTF, es);
}

void CBPdf::Draw(CTreeCtrl* ptree)
{
	CString str;

	ptree->DeleteAllItems();
	HTREEITEM htiParent = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
		"Pdf", 2, 2, 0, 0, NULL, TVI_ROOT, TVI_LAST);

	HTREEITEM htiHeader = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
		"Header", 4, 4, 0, 0, NULL, htiParent, TVI_LAST);
	HTREEITEM hti = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
		m_strHeader, 4, 4, 0, 0, NULL, htiHeader, TVI_FIRST);

	HTREEITEM htiTrailer = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
		"Trailer", 8, 8, 0, 0, NULL, htiParent, TVI_LAST);
	m_raw.GotoPos(m_dwTrailerPos);
	m_pobjTrailer = GetObject(NULL);

	DWORD dwDepth = 0;
	DWORD dwMaxDepth = 1;

	m_pobjTrailer->Draw(this, ptree, htiTrailer, dwDepth, dwMaxDepth);

	HTREEITEM htiXref = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
		"Cross Reference Table", 3, 3, 0, 0, NULL, htiParent, TVI_LAST);

	/*
	POSITION pos = m_mapXref.GetStartPosition();
	while (pos != NULL)
	{
		DWORD dwObjectNumber;
		DWORD dwOffset;

		m_mapXref.GetNextAssoc(pos, dwObjectNumber, dwOffset);
		str.Format("%d %d", dwObjectNumber, dwOffset);
		HTREEITEM hti = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
			str, 5, 5, 0, 0, NULL, htiXref, TVI_FIRST);
	}
	*/
	for (int i = 0; i < m_arrayXref.GetCount(); i++)
	{
		CBXrefEntry entry = m_arrayXref.GetAt(i);
		str.Format("%d %d", entry.m_dwObjectNumber, entry.m_dwOffset);
		HTREEITEM hti = ptree->InsertItem(TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT,
			str, 5, 5, 0, 0, NULL, htiXref, TVI_LAST);
	}
}

void CBPdf::SaveAsDot()
{
	if (IsOpen() == FALSE)
		return;

	if (m_arrayXref.GetCount() > 250)
	{
		AfxMessageBox("PDF too complex: PDF file has more than 250 objects.");
		return;
	}
	char szFilter[] = "Dot Files (*.dot)|*.dot|All Files (*.*)|*.*||";
	CFileDialog dlg(FALSE, "dot", NULL, OFN_OVERWRITEPROMPT, szFilter);
	if (dlg.DoModal() != IDOK)
		return;

	CString str;

	CStdioFile file;

	file.Open(dlg.GetFileName().GetBuffer(0), CFile::modeCreate | CFile::modeWrite);

	str.Format("digraph PdfView {\n");
	file.WriteString(str);
	str.Format("node [color=black, fontname = \"Verdana\", fontsize = 8, height=\"0,1\" shape = record, style=filled];\n");
	file.WriteString(str);

	m_pobjTrailer->SaveAsDot(this, &file, "Trailer", 0, 3);

	for (int i = 0; i < m_arrayXref.GetCount(); i++)
	{
		CBXrefEntry entry = m_arrayXref.GetAt(i);
		if ((entry.m_dwObjectNumber == 0) || (entry.m_dwOffset == 0))
			continue;

		m_raw.GotoPos(entry.m_dwOffset);
		m_raw.GetNextToken(str);
		m_raw.GetNextToken(str);
		m_raw.AssertNextToken("obj");

		CBPdfObject* pobj;

		pobj = GetObject(NULL);
		str.Format("%d %d", entry.m_dwObjectNumber, 0);
		pobj->SaveAsDot(this, &file, str, 0, 5);
		delete pobj;
	}
	str.Format("}\r\n");
	file.WriteString(str);
	file.Close();
}

⌨️ 快捷键说明

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