📄 bpdf.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 + -