// Copyright 2014 PDFium Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
#include "../../../include/fpdfapi/fpdf_page.h" | |
#include "../../../include/fpdfapi/fpdf_module.h" | |
#include "../../../include/fxcodec/fx_codec.h" | |
#include "pageint.h" | |
#include <limits.h> | |
extern const FX_LPCSTR _PDF_OpCharType = | |
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII" | |
"IIVIIIIVIIVIIIIIVVIIIIIIIIIIIIII" | |
"IIVVVVVVIVVVVVVIVVVVVIIVVIIIIIII" | |
"IIVVVVVVVVVVVVVVIVVVIIVVIVVIIIII" | |
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII" | |
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII" | |
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII" | |
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"; | |
FX_BOOL _PDF_HasInvalidOpChar(FX_LPCSTR op) | |
{ | |
if(!op) { | |
return FALSE; | |
} | |
FX_BYTE ch; | |
while((ch = *op++)) { | |
if(_PDF_OpCharType[ch] == 'I') { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
FX_DWORD CPDF_StreamContentParser::Parse(FX_LPCBYTE pData, FX_DWORD dwSize, FX_DWORD max_cost) | |
{ | |
if (m_Level > _FPDF_MAX_FORM_LEVEL_) { | |
return dwSize; | |
} | |
FX_DWORD InitObjCount = m_pObjectList->CountObjects(); | |
CPDF_StreamParser syntax(pData, dwSize); | |
m_pSyntax = &syntax; | |
m_CompatCount = 0; | |
while (1) { | |
FX_DWORD cost = m_pObjectList->CountObjects() - InitObjCount; | |
if (max_cost && cost >= max_cost) { | |
break; | |
} | |
switch (syntax.ParseNextElement()) { | |
case CPDF_StreamParser::EndOfData: | |
return m_pSyntax->GetPos(); | |
case CPDF_StreamParser::Keyword: | |
if(!OnOperator((char*)syntax.GetWordBuf()) && _PDF_HasInvalidOpChar((char*)syntax.GetWordBuf())) { | |
m_bAbort = TRUE; | |
} | |
if (m_bAbort) { | |
return m_pSyntax->GetPos(); | |
} | |
ClearAllParams(); | |
break; | |
case CPDF_StreamParser::Number: | |
AddNumberParam((char*)syntax.GetWordBuf(), syntax.GetWordSize()); | |
break; | |
case CPDF_StreamParser::Name: | |
AddNameParam((FX_LPCSTR)syntax.GetWordBuf() + 1, syntax.GetWordSize() - 1); | |
break; | |
default: | |
AddObjectParam(syntax.GetObject()); | |
} | |
} | |
return m_pSyntax->GetPos(); | |
} | |
void _PDF_ReplaceAbbr(CPDF_Object* pObj); | |
void CPDF_StreamContentParser::Handle_BeginImage() | |
{ | |
FX_FILESIZE savePos = m_pSyntax->GetPos(); | |
CPDF_Dictionary* pDict = CPDF_Dictionary::Create(); | |
while (1) { | |
CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement(); | |
if (type == CPDF_StreamParser::Keyword) { | |
CFX_ByteString bsKeyword(m_pSyntax->GetWordBuf(), m_pSyntax->GetWordSize()); | |
if (bsKeyword != FX_BSTRC("ID")) { | |
m_pSyntax->SetPos(savePos); | |
pDict->Release(); | |
return; | |
} | |
} | |
if (type != CPDF_StreamParser::Name) { | |
break; | |
} | |
CFX_ByteString key((FX_LPCSTR)m_pSyntax->GetWordBuf() + 1, m_pSyntax->GetWordSize() - 1); | |
CPDF_Object* pObj = m_pSyntax->ReadNextObject(); | |
if (!key.IsEmpty()) { | |
pDict->SetAt(key, pObj, m_pDocument); | |
} else { | |
pObj->Release(); | |
} | |
} | |
_PDF_ReplaceAbbr(pDict); | |
CPDF_Object* pCSObj = NULL; | |
if (pDict->KeyExist(FX_BSTRC("ColorSpace"))) { | |
pCSObj = pDict->GetElementValue(FX_BSTRC("ColorSpace")); | |
if (pCSObj->GetType() == PDFOBJ_NAME) { | |
CFX_ByteString name = pCSObj->GetString(); | |
if (name != FX_BSTRC("DeviceRGB") && name != FX_BSTRC("DeviceGray") && name != FX_BSTRC("DeviceCMYK")) { | |
pCSObj = FindResourceObj(FX_BSTRC("ColorSpace"), name); | |
if (pCSObj && !pCSObj->GetObjNum()) { | |
pCSObj = pCSObj->Clone(); | |
pDict->SetAt(FX_BSTRC("ColorSpace"), pCSObj, m_pDocument); | |
} | |
} | |
} | |
} | |
CPDF_Stream* pStream = m_pSyntax->ReadInlineStream(m_pDocument, pDict, pCSObj, m_Options.m_bDecodeInlineImage); | |
while (1) { | |
CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement(); | |
if (type == CPDF_StreamParser::EndOfData) { | |
break; | |
} | |
if (type != CPDF_StreamParser::Keyword) { | |
continue; | |
} | |
if (m_pSyntax->GetWordSize() == 2 && m_pSyntax->GetWordBuf()[0] == 'E' && | |
m_pSyntax->GetWordBuf()[1] == 'I') { | |
break; | |
} | |
} | |
if (m_Options.m_bTextOnly) { | |
if (pStream) { | |
pStream->Release(); | |
} else { | |
pDict->Release(); | |
} | |
return; | |
} | |
pDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Image")); | |
CPDF_ImageObject *pImgObj = AddImage(pStream, NULL, TRUE); | |
if (!pImgObj) { | |
if (pStream) { | |
pStream->Release(); | |
} else { | |
pDict->Release(); | |
} | |
} | |
} | |
void CPDF_StreamContentParser::ParsePathObject() | |
{ | |
FX_FLOAT params[6] = {0}; | |
int nParams = 0; | |
int last_pos = m_pSyntax->GetPos(); | |
while (1) { | |
CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement(); | |
FX_BOOL bProcessed = TRUE; | |
switch (type) { | |
case CPDF_StreamParser::EndOfData: | |
return; | |
case CPDF_StreamParser::Keyword: { | |
int len = m_pSyntax->GetWordSize(); | |
if (len == 1) { | |
switch (m_pSyntax->GetWordBuf()[0]) { | |
case 'm': | |
AddPathPoint(params[0], params[1], FXPT_MOVETO); | |
nParams = 0; | |
break; | |
case 'l': | |
AddPathPoint(params[0], params[1], FXPT_LINETO); | |
nParams = 0; | |
break; | |
case 'c': | |
AddPathPoint(params[0], params[1], FXPT_BEZIERTO); | |
AddPathPoint(params[2], params[3], FXPT_BEZIERTO); | |
AddPathPoint(params[4], params[5], FXPT_BEZIERTO); | |
nParams = 0; | |
break; | |
case 'v': | |
AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_BEZIERTO); | |
AddPathPoint(params[0], params[1], FXPT_BEZIERTO); | |
AddPathPoint(params[2], params[3], FXPT_BEZIERTO); | |
nParams = 0; | |
break; | |
case 'y': | |
AddPathPoint(params[0], params[1], FXPT_BEZIERTO); | |
AddPathPoint(params[2], params[3], FXPT_BEZIERTO); | |
AddPathPoint(params[2], params[3], FXPT_BEZIERTO); | |
nParams = 0; | |
break; | |
case 'h': | |
Handle_ClosePath(); | |
nParams = 0; | |
break; | |
default: | |
bProcessed = FALSE; | |
break; | |
} | |
} else if (len == 2) { | |
if (m_pSyntax->GetWordBuf()[0] == 'r' && m_pSyntax->GetWordBuf()[1] == 'e') { | |
AddPathRect(params[0], params[1], params[2], params[3]); | |
nParams = 0; | |
} else { | |
bProcessed = FALSE; | |
} | |
} else { | |
bProcessed = FALSE; | |
} | |
if (bProcessed) { | |
last_pos = m_pSyntax->GetPos(); | |
} | |
break; | |
} | |
case CPDF_StreamParser::Number: { | |
if (nParams == 6) { | |
break; | |
} | |
FX_BOOL bInteger; | |
int value; | |
FX_atonum(CFX_ByteStringC(m_pSyntax->GetWordBuf(), m_pSyntax->GetWordSize()), bInteger, &value); | |
params[nParams++] = bInteger ? (FX_FLOAT)value : *(FX_FLOAT*)&value; | |
break; | |
} | |
default: | |
bProcessed = FALSE; | |
} | |
if (!bProcessed) { | |
m_pSyntax->SetPos(last_pos); | |
return; | |
} | |
} | |
} | |
CPDF_StreamParser::CPDF_StreamParser(const FX_BYTE* pData, FX_DWORD dwSize) | |
{ | |
m_pBuf = pData; | |
m_Size = dwSize; | |
m_Pos = 0; | |
m_pLastObj = NULL; | |
} | |
CPDF_StreamParser::~CPDF_StreamParser() | |
{ | |
if (m_pLastObj) { | |
m_pLastObj->Release(); | |
} | |
} | |
FX_DWORD _DecodeAllScanlines(ICodec_ScanlineDecoder* pDecoder, FX_LPBYTE& dest_buf, FX_DWORD& dest_size) | |
{ | |
if (pDecoder == NULL) { | |
return (FX_DWORD) - 1; | |
} | |
int ncomps = pDecoder->CountComps(); | |
int bpc = pDecoder->GetBPC(); | |
int width = pDecoder->GetWidth(); | |
int height = pDecoder->GetHeight(); | |
int pitch = (width * ncomps * bpc + 7) / 8; | |
if (height == 0 || pitch > (1 << 30) / height) { | |
delete pDecoder; | |
return -1; | |
} | |
dest_size = pitch * height; | |
dest_buf = FX_Alloc( FX_BYTE, dest_size); | |
for (int row = 0; row < height; row ++) { | |
FX_LPBYTE pLine = pDecoder->GetScanline(row); | |
if (pLine == NULL) { | |
break; | |
} | |
FXSYS_memcpy32(dest_buf + row * pitch, pLine, pitch); | |
} | |
FX_DWORD srcoff = pDecoder->GetSrcOffset(); | |
delete pDecoder; | |
return srcoff; | |
} | |
ICodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, | |
const CPDF_Dictionary* pParams); | |
FX_DWORD _A85Decode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size); | |
FX_DWORD _HexDecode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size); | |
FX_DWORD FPDFAPI_FlateOrLZWDecode(FX_BOOL bLZW, const FX_BYTE* src_buf, FX_DWORD src_size, CPDF_Dictionary* pParams, | |
FX_DWORD estimated_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size); | |
FX_DWORD PDF_DecodeInlineStream(const FX_BYTE* src_buf, FX_DWORD limit, | |
int width, int height, CFX_ByteString& decoder, | |
CPDF_Dictionary* pParam, FX_LPBYTE& dest_buf, FX_DWORD& dest_size) | |
{ | |
if (decoder == FX_BSTRC("CCITTFaxDecode") || decoder == FX_BSTRC("CCF")) { | |
ICodec_ScanlineDecoder* pDecoder = FPDFAPI_CreateFaxDecoder(src_buf, limit, width, height, pParam); | |
return _DecodeAllScanlines(pDecoder, dest_buf, dest_size); | |
} else if (decoder == FX_BSTRC("ASCII85Decode") || decoder == FX_BSTRC("A85")) { | |
return _A85Decode(src_buf, limit, dest_buf, dest_size); | |
} else if (decoder == FX_BSTRC("ASCIIHexDecode") || decoder == FX_BSTRC("AHx")) { | |
return _HexDecode(src_buf, limit, dest_buf, dest_size); | |
} else if (decoder == FX_BSTRC("FlateDecode") || decoder == FX_BSTRC("Fl")) { | |
return FPDFAPI_FlateOrLZWDecode(FALSE, src_buf, limit, pParam, dest_size, dest_buf, dest_size); | |
} else if (decoder == FX_BSTRC("LZWDecode") || decoder == FX_BSTRC("LZW")) { | |
return FPDFAPI_FlateOrLZWDecode(TRUE, src_buf, limit, pParam, 0, dest_buf, dest_size); | |
} else if (decoder == FX_BSTRC("DCTDecode") || decoder == FX_BSTRC("DCT")) { | |
ICodec_ScanlineDecoder* pDecoder = CPDF_ModuleMgr::Get()->GetJpegModule()->CreateDecoder( | |
src_buf, limit, width, height, 0, pParam ? pParam->GetInteger(FX_BSTRC("ColorTransform"), 1) : 1); | |
return _DecodeAllScanlines(pDecoder, dest_buf, dest_size); | |
} else if (decoder == FX_BSTRC("RunLengthDecode") || decoder == FX_BSTRC("RL")) { | |
return RunLengthDecode(src_buf, limit, dest_buf, dest_size); | |
} | |
dest_size = 0; | |
dest_buf = 0; | |
return (FX_DWORD) - 1; | |
} | |
extern const FX_LPCSTR _PDF_CharType; | |
CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc, CPDF_Dictionary* pDict, CPDF_Object* pCSObj, FX_BOOL bDecode) | |
{ | |
if (m_Pos == m_Size) { | |
return NULL; | |
} | |
if (_PDF_CharType[m_pBuf[m_Pos]] == 'W') { | |
m_Pos ++; | |
} | |
CFX_ByteString Decoder; | |
CPDF_Dictionary* pParam = NULL; | |
CPDF_Object* pFilter = pDict->GetElementValue(FX_BSTRC("Filter")); | |
if (pFilter == NULL) { | |
} else if (pFilter->GetType() == PDFOBJ_ARRAY) { | |
Decoder = ((CPDF_Array*)pFilter)->GetString(0); | |
CPDF_Array* pParams = pDict->GetArray(FX_BSTRC("DecodeParms")); | |
if (pParams) { | |
pParam = pParams->GetDict(0); | |
} | |
} else { | |
Decoder = pFilter->GetString(); | |
pParam = pDict->GetDict(FX_BSTRC("DecodeParms")); | |
} | |
FX_DWORD width = pDict->GetInteger(FX_BSTRC("Width")); | |
FX_DWORD height = pDict->GetInteger(FX_BSTRC("Height")); | |
FX_DWORD OrigSize = 0; | |
if (pCSObj != NULL) { | |
FX_DWORD bpc = pDict->GetInteger(FX_BSTRC("BitsPerComponent")); | |
FX_DWORD nComponents = 1; | |
CPDF_ColorSpace* pCS = pDoc->LoadColorSpace(pCSObj); | |
if (pCS == NULL) { | |
nComponents = 3; | |
} else { | |
nComponents = pCS->CountComponents(); | |
pDoc->GetPageData()->ReleaseColorSpace(pCSObj); | |
} | |
FX_DWORD pitch = width; | |
if (bpc && pitch > INT_MAX / bpc) { | |
return NULL; | |
} | |
pitch *= bpc; | |
if (nComponents && pitch > INT_MAX / nComponents) { | |
return NULL; | |
} | |
pitch *= nComponents; | |
if (pitch > INT_MAX - 7) { | |
return NULL; | |
} | |
pitch += 7; | |
pitch /= 8; | |
OrigSize = pitch; | |
} else { | |
if (width > INT_MAX - 7) { | |
return NULL; | |
} | |
OrigSize = ((width + 7) / 8); | |
} | |
if (height && OrigSize > INT_MAX / height) { | |
return NULL; | |
} | |
OrigSize *= height; | |
FX_LPBYTE pData = NULL; | |
FX_DWORD dwStreamSize; | |
if (Decoder.IsEmpty()) { | |
if (OrigSize > m_Size - m_Pos) { | |
OrigSize = m_Size - m_Pos; | |
} | |
pData = FX_Alloc(FX_BYTE, OrigSize); | |
FXSYS_memcpy32(pData, m_pBuf + m_Pos, OrigSize); | |
dwStreamSize = OrigSize; | |
m_Pos += OrigSize; | |
} else { | |
FX_DWORD dwDestSize = OrigSize; | |
dwStreamSize = PDF_DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height, Decoder, pParam, | |
pData, dwDestSize); | |
if ((int)dwStreamSize < 0) { | |
return NULL; | |
} | |
if (bDecode) { | |
m_Pos += dwStreamSize; | |
dwStreamSize = dwDestSize; | |
if (pFilter->GetType() == PDFOBJ_ARRAY) { | |
((CPDF_Array*)pFilter)->RemoveAt(0); | |
CPDF_Array* pParams = pDict->GetArray(FX_BSTRC("DecodeParms")); | |
if (pParams) { | |
pParams->RemoveAt(0); | |
} | |
} else { | |
pDict->RemoveAt(FX_BSTRC("Filter")); | |
pDict->RemoveAt(FX_BSTRC("DecodeParms")); | |
} | |
} else { | |
if (pData) { | |
FX_Free(pData); | |
} | |
FX_DWORD dwSavePos = m_Pos; | |
m_Pos += dwStreamSize; | |
while (1) { | |
FX_DWORD dwPrevPos = m_Pos; | |
CPDF_StreamParser::SyntaxType type = ParseNextElement(); | |
if (type == CPDF_StreamParser::EndOfData) { | |
break; | |
} | |
if (type != CPDF_StreamParser::Keyword) { | |
dwStreamSize += m_Pos - dwPrevPos; | |
continue; | |
} | |
if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' && | |
GetWordBuf()[1] == 'I') { | |
m_Pos = dwPrevPos; | |
break; | |
} | |
dwStreamSize += m_Pos - dwPrevPos; | |
} | |
m_Pos = dwSavePos; | |
pData = FX_Alloc(FX_BYTE, dwStreamSize); | |
FXSYS_memcpy32(pData, m_pBuf + m_Pos, dwStreamSize); | |
m_Pos += dwStreamSize; | |
} | |
} | |
pDict->SetAtInteger(FX_BSTRC("Length"), (int)dwStreamSize); | |
return CPDF_Stream::Create(pData, dwStreamSize, pDict); | |
} | |
#define MAX_WORD_BUFFER 256 | |
#define MAX_STRING_LENGTH 32767 | |
#define FXDWORD_TRUE FXDWORD_FROM_LSBFIRST(0x65757274) | |
#define FXDWORD_NULL FXDWORD_FROM_LSBFIRST(0x6c6c756e) | |
#define FXDWORD_FALS FXDWORD_FROM_LSBFIRST(0x736c6166) | |
CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() | |
{ | |
if (m_pLastObj) { | |
m_pLastObj->Release(); | |
m_pLastObj = NULL; | |
} | |
m_WordSize = 0; | |
FX_BOOL bIsNumber = TRUE; | |
if (m_Pos >= m_Size) { | |
return EndOfData; | |
} | |
int ch = m_pBuf[m_Pos++]; | |
int type = _PDF_CharType[ch]; | |
while (1) { | |
while (type == 'W') { | |
if (m_Size <= m_Pos) { | |
return EndOfData; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
} | |
if (ch != '%') { | |
break; | |
} | |
while (1) { | |
if (m_Size <= m_Pos) { | |
return EndOfData; | |
} | |
ch = m_pBuf[m_Pos++]; | |
if (ch == '\r' || ch == '\n') { | |
break; | |
} | |
} | |
type = _PDF_CharType[ch]; | |
} | |
if (type == 'D' && ch != '/') { | |
m_Pos --; | |
m_pLastObj = ReadNextObject(); | |
return Others; | |
} | |
while (1) { | |
if (m_WordSize < MAX_WORD_BUFFER) { | |
m_WordBuffer[m_WordSize++] = ch; | |
} | |
if (type != 'N') { | |
bIsNumber = FALSE; | |
} | |
if (m_Size <= m_Pos) { | |
break; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
if (type == 'D' || type == 'W') { | |
m_Pos --; | |
break; | |
} | |
} | |
m_WordBuffer[m_WordSize] = 0; | |
if (bIsNumber) { | |
return Number; | |
} | |
if (m_WordBuffer[0] == '/') { | |
return Name; | |
} | |
if (m_WordSize == 4) { | |
if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) { | |
m_pLastObj = CPDF_Boolean::Create(TRUE); | |
return Others; | |
} | |
if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) { | |
m_pLastObj = CPDF_Null::Create(); | |
return Others; | |
} | |
} else if (m_WordSize == 5) { | |
if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') { | |
m_pLastObj = CPDF_Boolean::Create(FALSE); | |
return Others; | |
} | |
} | |
return Keyword; | |
} | |
void CPDF_StreamParser::SkipPathObject() | |
{ | |
FX_DWORD command_startpos = m_Pos; | |
if (m_Pos >= m_Size) { | |
return; | |
} | |
int ch = m_pBuf[m_Pos++]; | |
int type = _PDF_CharType[ch]; | |
while (1) { | |
while (type == 'W') { | |
if (m_Pos >= m_Size) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
} | |
if (type != 'N') { | |
m_Pos = command_startpos; | |
return; | |
} | |
while (1) { | |
while (type != 'W') { | |
if (m_Pos >= m_Size) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
} | |
while (type == 'W') { | |
if (m_Pos >= m_Size) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
} | |
if (type == 'N') { | |
continue; | |
} | |
FX_DWORD op_startpos = m_Pos - 1; | |
while (type != 'W' && type != 'D') { | |
if (m_Pos >= m_Size) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
} | |
if (m_Pos - op_startpos == 2) { | |
int op = m_pBuf[op_startpos]; | |
if (op == 'm' || op == 'l' || op == 'c' || op == 'v' || op == 'y') { | |
command_startpos = m_Pos; | |
break; | |
} | |
} else if (m_Pos - op_startpos == 3) { | |
if (m_pBuf[op_startpos] == 'r' && m_pBuf[op_startpos + 1] == 'e') { | |
command_startpos = m_Pos; | |
break; | |
} | |
} | |
m_Pos = command_startpos; | |
return; | |
} | |
} | |
} | |
CPDF_Object* CPDF_StreamParser::ReadNextObject(FX_BOOL bAllowNestedArray, FX_BOOL bInArray) | |
{ | |
FX_BOOL bIsNumber; | |
GetNextWord(bIsNumber); | |
if (m_WordSize == 0) { | |
return NULL; | |
} | |
if (bIsNumber) { | |
m_WordBuffer[m_WordSize] = 0; | |
return CPDF_Number::Create(CFX_ByteStringC(m_WordBuffer, m_WordSize)); | |
} | |
int first_char = m_WordBuffer[0]; | |
if (first_char == '/') { | |
return CPDF_Name::Create(PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1))); | |
} | |
if (first_char == '(') { | |
return CPDF_String::Create(ReadString()); | |
} | |
if (first_char == '<') { | |
if (m_WordSize == 1) { | |
return CPDF_String::Create(ReadHexString(), TRUE); | |
} | |
CPDF_Dictionary* pDict = CPDF_Dictionary::Create(); | |
while (1) { | |
GetNextWord(bIsNumber); | |
if (m_WordSize == 0) { | |
pDict->Release(); | |
return NULL; | |
} | |
if (m_WordSize == 2 && m_WordBuffer[0] == '>') { | |
break; | |
} | |
if (m_WordBuffer[0] != '/') { | |
pDict->Release(); | |
return NULL; | |
} | |
CFX_ByteString key = PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)); | |
CPDF_Object* pObj = ReadNextObject(TRUE); | |
if (pObj == NULL) { | |
if (pDict) { | |
pDict->Release(); | |
} | |
return NULL; | |
} | |
if (!key.IsEmpty()) { | |
pDict->SetAt(key, pObj); | |
} else { | |
pObj->Release(); | |
} | |
} | |
return pDict; | |
} | |
if (first_char == '[') { | |
if (!bAllowNestedArray && bInArray) { | |
return NULL; | |
} | |
CPDF_Array* pArray = CPDF_Array::Create(); | |
while (1) { | |
CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, TRUE); | |
if (pObj == NULL) { | |
if (m_WordSize == 0 || m_WordBuffer[0] == ']') { | |
return pArray; | |
} | |
if (m_WordBuffer[0] == '[') { | |
continue; | |
} | |
} else { | |
pArray->Add(pObj); | |
} | |
} | |
} | |
if (m_WordSize == 4) { | |
if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) { | |
return CPDF_Boolean::Create(TRUE); | |
} | |
if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) { | |
return CPDF_Null::Create(); | |
} | |
} else if (m_WordSize == 5) { | |
if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') { | |
return CPDF_Boolean::Create(FALSE); | |
} | |
} | |
return NULL; | |
} | |
void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) | |
{ | |
m_WordSize = 0; | |
bIsNumber = TRUE; | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
int ch = m_pBuf[m_Pos++]; | |
int type = _PDF_CharType[ch]; | |
while (1) { | |
while (type == 'W') { | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
} | |
if (ch != '%') { | |
break; | |
} | |
while (1) { | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
if (ch == '\r' || ch == '\n') { | |
break; | |
} | |
} | |
type = _PDF_CharType[ch]; | |
} | |
if (type == 'D') { | |
bIsNumber = FALSE; | |
m_WordBuffer[m_WordSize++] = ch; | |
if (ch == '/') { | |
while (1) { | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
if (type != 'R' && type != 'N') { | |
m_Pos --; | |
return; | |
} | |
if (m_WordSize < MAX_WORD_BUFFER) { | |
m_WordBuffer[m_WordSize++] = ch; | |
} | |
} | |
} else if (ch == '<') { | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
if (ch == '<') { | |
m_WordBuffer[m_WordSize++] = ch; | |
} else { | |
m_Pos --; | |
} | |
} else if (ch == '>') { | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
if (ch == '>') { | |
m_WordBuffer[m_WordSize++] = ch; | |
} else { | |
m_Pos --; | |
} | |
} | |
return; | |
} | |
while (1) { | |
if (m_WordSize < MAX_WORD_BUFFER) { | |
m_WordBuffer[m_WordSize++] = ch; | |
} | |
if (type != 'N') { | |
bIsNumber = FALSE; | |
} | |
if (m_Size <= m_Pos) { | |
return; | |
} | |
ch = m_pBuf[m_Pos++]; | |
type = _PDF_CharType[ch]; | |
if (type == 'D' || type == 'W') { | |
m_Pos --; | |
break; | |
} | |
} | |
} | |
CFX_ByteString CPDF_StreamParser::ReadString() | |
{ | |
if (m_Size <= m_Pos) { | |
return CFX_ByteString(); | |
} | |
int ch = m_pBuf[m_Pos++]; | |
CFX_ByteTextBuf buf; | |
int parlevel = 0; | |
int status = 0, iEscCode = 0; | |
while (1) { | |
switch (status) { | |
case 0: | |
if (ch == ')') { | |
if (parlevel == 0) { | |
if (buf.GetLength() > MAX_STRING_LENGTH) { | |
return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH); | |
} | |
return buf.GetByteString(); | |
} | |
parlevel --; | |
buf.AppendChar(')'); | |
} else if (ch == '(') { | |
parlevel ++; | |
buf.AppendChar('('); | |
} else if (ch == '\\') { | |
status = 1; | |
} else { | |
buf.AppendChar((char)ch); | |
} | |
break; | |
case 1: | |
if (ch >= '0' && ch <= '7') { | |
iEscCode = ch - '0'; | |
status = 2; | |
break; | |
} | |
if (ch == 'n') { | |
buf.AppendChar('\n'); | |
} else if (ch == 'r') { | |
buf.AppendChar('\r'); | |
} else if (ch == 't') { | |
buf.AppendChar('\t'); | |
} else if (ch == 'b') { | |
buf.AppendChar('\b'); | |
} else if (ch == 'f') { | |
buf.AppendChar('\f'); | |
} else if (ch == '\r') { | |
status = 4; | |
break; | |
} else if (ch == '\n') { | |
} else { | |
buf.AppendChar(ch); | |
} | |
status = 0; | |
break; | |
case 2: | |
if (ch >= '0' && ch <= '7') { | |
iEscCode = iEscCode * 8 + ch - '0'; | |
status = 3; | |
} else { | |
buf.AppendChar(iEscCode); | |
status = 0; | |
continue; | |
} | |
break; | |
case 3: | |
if (ch >= '0' && ch <= '7') { | |
iEscCode = iEscCode * 8 + ch - '0'; | |
buf.AppendChar(iEscCode); | |
status = 0; | |
} else { | |
buf.AppendChar(iEscCode); | |
status = 0; | |
continue; | |
} | |
break; | |
case 4: | |
status = 0; | |
if (ch != '\n') { | |
continue; | |
} | |
break; | |
} | |
if (m_Size <= m_Pos) { | |
break; | |
} | |
ch = m_pBuf[m_Pos++]; | |
} | |
if (m_Size > m_Pos) { | |
ch = m_pBuf[m_Pos++]; | |
} | |
if (buf.GetLength() > MAX_STRING_LENGTH) { | |
return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH); | |
} | |
return buf.GetByteString(); | |
} | |
CFX_ByteString CPDF_StreamParser::ReadHexString() | |
{ | |
if (m_Size <= m_Pos) { | |
return CFX_ByteString(); | |
} | |
int ch = m_pBuf[m_Pos++]; | |
CFX_ByteTextBuf buf; | |
FX_BOOL bFirst = TRUE; | |
int code = 0; | |
while (1) { | |
if (ch == '>') { | |
break; | |
} | |
if (ch >= '0' && ch <= '9') { | |
if (bFirst) { | |
code = (ch - '0') * 16; | |
} else { | |
code += ch - '0'; | |
buf.AppendChar((char)code); | |
} | |
bFirst = !bFirst; | |
} else if (ch >= 'A' && ch <= 'F') { | |
if (bFirst) { | |
code = (ch - 'A' + 10) * 16; | |
} else { | |
code += ch - 'A' + 10; | |
buf.AppendChar((char)code); | |
} | |
bFirst = !bFirst; | |
} else if (ch >= 'a' && ch <= 'f') { | |
if (bFirst) { | |
code = (ch - 'a' + 10) * 16; | |
} else { | |
code += ch - 'a' + 10; | |
buf.AppendChar((char)code); | |
} | |
bFirst = !bFirst; | |
} | |
if (m_Size <= m_Pos) { | |
break; | |
} | |
ch = m_pBuf[m_Pos++]; | |
} | |
if (!bFirst) { | |
buf.AppendChar((char)code); | |
} | |
if (buf.GetLength() > MAX_STRING_LENGTH) { | |
return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH); | |
} | |
return buf.GetByteString(); | |
} | |
#define PAGEPARSE_STAGE_GETCONTENT 1 | |
#define PAGEPARSE_STAGE_PARSE 2 | |
#define PAGEPARSE_STAGE_CHECKCLIP 3 | |
CPDF_ContentParser::CPDF_ContentParser() | |
{ | |
m_pParser = NULL; | |
m_pStreamArray = NULL; | |
m_pSingleStream = NULL; | |
m_pData = NULL; | |
m_Status = Ready; | |
m_pType3Char = NULL; | |
} | |
CPDF_ContentParser::~CPDF_ContentParser() | |
{ | |
Clear(); | |
} | |
void CPDF_ContentParser::Clear() | |
{ | |
if (m_pParser) { | |
delete m_pParser; | |
} | |
if (m_pSingleStream) { | |
delete m_pSingleStream; | |
} | |
if (m_pStreamArray) { | |
for (FX_DWORD i = 0; i < m_nStreams; i ++) | |
if (m_pStreamArray[i]) { | |
delete m_pStreamArray[i]; | |
} | |
FX_Free(m_pStreamArray); | |
} | |
if (m_pData && m_pSingleStream == NULL) { | |
FX_Free((void*)m_pData); | |
} | |
m_pParser = NULL; | |
m_pStreamArray = NULL; | |
m_pSingleStream = NULL; | |
m_pData = NULL; | |
m_Status = Ready; | |
} | |
void CPDF_ContentParser::Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions) | |
{ | |
if (m_Status != Ready || pPage == NULL || pPage->m_pDocument == NULL || pPage->m_pFormDict == NULL) { | |
m_Status = Done; | |
return; | |
} | |
m_pObjects = pPage; | |
m_bForm = FALSE; | |
if (pOptions) { | |
m_Options = *pOptions; | |
} | |
m_Status = ToBeContinued; | |
m_InternalStage = PAGEPARSE_STAGE_GETCONTENT; | |
m_CurrentOffset = 0; | |
CPDF_Object* pContent = pPage->m_pFormDict->GetElementValue(FX_BSTRC("Contents")); | |
if (pContent == NULL) { | |
m_Status = Done; | |
return; | |
} | |
if (pContent->GetType() == PDFOBJ_STREAM) { | |
m_nStreams = 0; | |
m_pSingleStream = FX_NEW CPDF_StreamAcc; | |
m_pSingleStream->LoadAllData((CPDF_Stream*)pContent, FALSE); | |
} else if (pContent->GetType() == PDFOBJ_ARRAY) { | |
CPDF_Array* pArray = (CPDF_Array*)pContent; | |
m_nStreams = pArray->GetCount(); | |
if (m_nStreams == 0) { | |
m_Status = Done; | |
return; | |
} | |
m_pStreamArray = FX_Alloc(CPDF_StreamAcc*, m_nStreams); | |
FXSYS_memset32(m_pStreamArray, 0, sizeof(CPDF_StreamAcc*) * m_nStreams); | |
} else { | |
m_Status = Done; | |
return; | |
} | |
} | |
void CPDF_ContentParser::Start(CPDF_Form* pForm, CPDF_AllStates* pGraphicStates, | |
CFX_AffineMatrix* pParentMatrix, CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level) | |
{ | |
m_pType3Char = pType3Char; | |
m_pObjects = pForm; | |
m_bForm = TRUE; | |
CFX_AffineMatrix form_matrix = pForm->m_pFormDict->GetMatrix(FX_BSTRC("Matrix")); | |
if (pGraphicStates) { | |
form_matrix.Concat(pGraphicStates->m_CTM); | |
} | |
CPDF_Array* pBBox = pForm->m_pFormDict->GetArray(FX_BSTRC("BBox")); | |
CFX_FloatRect form_bbox; | |
CPDF_Path ClipPath; | |
if (pBBox) { | |
form_bbox = pBBox->GetRect(); | |
ClipPath.New(); | |
ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right, form_bbox.top); | |
ClipPath.Transform(&form_matrix); | |
if (pParentMatrix) { | |
ClipPath.Transform(pParentMatrix); | |
} | |
form_bbox.Transform(&form_matrix); | |
if (pParentMatrix) { | |
form_bbox.Transform(pParentMatrix); | |
} | |
} | |
CPDF_Dictionary* pResources = pForm->m_pFormDict->GetDict(FX_BSTRC("Resources")); | |
m_pParser = FX_NEW CPDF_StreamContentParser; | |
m_pParser->Initialize(); | |
m_pParser->PrepareParse(pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources, pParentMatrix, pForm, | |
pResources, &form_bbox, pOptions, pGraphicStates, level); | |
m_pParser->m_pCurStates->m_CTM = form_matrix; | |
m_pParser->m_pCurStates->m_ParentMatrix = form_matrix; | |
if (ClipPath.NotNull()) { | |
m_pParser->m_pCurStates->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING, TRUE); | |
} | |
if (pForm->m_Transparency & PDFTRANS_GROUP) { | |
CPDF_GeneralStateData* pData = m_pParser->m_pCurStates->m_GeneralState.GetModify(); | |
pData->m_BlendType = FXDIB_BLEND_NORMAL; | |
pData->m_StrokeAlpha = 1.0f; | |
pData->m_FillAlpha = 1.0f; | |
pData->m_pSoftMask = NULL; | |
} | |
m_nStreams = 0; | |
m_pSingleStream = FX_NEW CPDF_StreamAcc; | |
if (pForm->m_pDocument) { | |
m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE); | |
} else { | |
m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE); | |
} | |
m_pData = (FX_LPBYTE)m_pSingleStream->GetData(); | |
m_Size = m_pSingleStream->GetSize(); | |
m_Status = ToBeContinued; | |
m_InternalStage = PAGEPARSE_STAGE_PARSE; | |
m_CurrentOffset = 0; | |
} | |
void CPDF_ContentParser::Continue(IFX_Pause* pPause) | |
{ | |
int steps = 0; | |
while (m_Status == ToBeContinued) { | |
if (m_InternalStage == PAGEPARSE_STAGE_GETCONTENT) { | |
if (m_CurrentOffset == m_nStreams) { | |
if (m_pStreamArray) { | |
m_Size = 0; | |
FX_DWORD i; | |
for (i = 0; i < m_nStreams; i ++) { | |
FX_DWORD size = m_pStreamArray[i]->GetSize(); | |
if (m_Size + size + 1 <= m_Size) { | |
m_Status = Done; | |
return; | |
} | |
m_Size += size + 1; | |
} | |
m_pData = FX_Alloc(FX_BYTE, m_Size); | |
if (!m_pData) { | |
m_Status = Done; | |
return; | |
} | |
FX_DWORD pos = 0; | |
for (i = 0; i < m_nStreams; i ++) { | |
FXSYS_memcpy32(m_pData + pos, m_pStreamArray[i]->GetData(), m_pStreamArray[i]->GetSize()); | |
pos += m_pStreamArray[i]->GetSize() + 1; | |
m_pData[pos - 1] = ' '; | |
delete m_pStreamArray[i]; | |
} | |
FX_Free(m_pStreamArray); | |
m_pStreamArray = NULL; | |
} else { | |
m_pData = (FX_LPBYTE)m_pSingleStream->GetData(); | |
m_Size = m_pSingleStream->GetSize(); | |
} | |
m_InternalStage = PAGEPARSE_STAGE_PARSE; | |
m_CurrentOffset = 0; | |
} else { | |
CPDF_Array* pContent = m_pObjects->m_pFormDict->GetArray(FX_BSTRC("Contents")); | |
m_pStreamArray[m_CurrentOffset] = FX_NEW CPDF_StreamAcc; | |
CPDF_Stream* pStreamObj = (CPDF_Stream*)pContent->GetElementValue(m_CurrentOffset); | |
m_pStreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE); | |
m_CurrentOffset ++; | |
} | |
} | |
if (m_InternalStage == PAGEPARSE_STAGE_PARSE) { | |
if (m_pParser == NULL) { | |
m_pParser = FX_NEW CPDF_StreamContentParser; | |
m_pParser->Initialize(); | |
m_pParser->PrepareParse(m_pObjects->m_pDocument, m_pObjects->m_pPageResources, NULL, NULL, m_pObjects, | |
m_pObjects->m_pResources, &m_pObjects->m_BBox, &m_Options, NULL, 0); | |
m_pParser->m_pCurStates->m_ColorState.GetModify()->Default(); | |
} | |
if (m_CurrentOffset >= m_Size) { | |
m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP; | |
} else { | |
m_CurrentOffset += m_pParser->Parse(m_pData + m_CurrentOffset, m_Size - m_CurrentOffset, PARSE_STEP_LIMIT); | |
if (m_pParser->m_bAbort) { | |
m_InternalStage = PAGEPARSE_STAGE_CHECKCLIP; | |
continue; | |
} | |
} | |
} | |
if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) { | |
if (m_pType3Char) { | |
m_pType3Char->m_bColored = m_pParser->m_bColored; | |
m_pType3Char->m_Width = FXSYS_round(m_pParser->m_Type3Data[0] * 1000); | |
m_pType3Char->m_BBox.left = FXSYS_round(m_pParser->m_Type3Data[2] * 1000); | |
m_pType3Char->m_BBox.bottom = FXSYS_round(m_pParser->m_Type3Data[3] * 1000); | |
m_pType3Char->m_BBox.right = FXSYS_round(m_pParser->m_Type3Data[4] * 1000); | |
m_pType3Char->m_BBox.top = FXSYS_round(m_pParser->m_Type3Data[5] * 1000); | |
} | |
FX_POSITION pos = m_pObjects->m_ObjectList.GetHeadPosition(); | |
while (pos) { | |
CPDF_PageObject* pObj = (CPDF_PageObject*)m_pObjects->m_ObjectList.GetNext(pos); | |
if (pObj->m_ClipPath.IsNull()) { | |
continue; | |
} | |
if (pObj->m_ClipPath.GetPathCount() != 1) { | |
continue; | |
} | |
if (pObj->m_ClipPath.GetTextCount()) { | |
continue; | |
} | |
CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0); | |
if (!ClipPath.IsRect() || pObj->m_Type == PDFPAGE_SHADING) { | |
continue; | |
} | |
CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0), | |
ClipPath.GetPointX(2), ClipPath.GetPointY(2)); | |
CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top); | |
if (old_rect.Contains(obj_rect)) { | |
pObj->m_ClipPath.SetNull(); | |
} | |
} | |
m_Status = Done; | |
return; | |
} | |
steps ++; | |
if (pPause && pPause->NeedToPauseNow()) { | |
break; | |
} | |
} | |
} | |
int CPDF_ContentParser::EstimateProgress() | |
{ | |
if (m_Status == Ready) { | |
return 0; | |
} | |
if (m_Status == Done) { | |
return 100; | |
} | |
if (m_InternalStage == PAGEPARSE_STAGE_GETCONTENT) { | |
return 10; | |
} | |
if (m_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) { | |
return 90; | |
} | |
return 10 + 80 * m_CurrentOffset / m_Size; | |
} |