// 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 "pageint.h" #include #include "core/include/fpdfapi/fpdf_module.h" #include "core/include/fpdfapi/fpdf_page.h" #include "core/include/fxcodec/fx_codec.h" namespace { const char kPathOperatorSubpath = 'm'; const char kPathOperatorLine = 'l'; const char kPathOperatorCubicBezier1 = 'c'; const char kPathOperatorCubicBezier2 = 'v'; const char kPathOperatorCubicBezier3 = 'y'; const char kPathOperatorClosePath = 'h'; const char kPathOperatorRectangle[] = "re"; } // namespace class CPDF_StreamParserAutoClearer { public: CPDF_StreamParserAutoClearer(CPDF_StreamParser** scoped_variable, CPDF_StreamParser* new_parser) : scoped_variable_(scoped_variable) { *scoped_variable_ = new_parser; } ~CPDF_StreamParserAutoClearer() { *scoped_variable_ = NULL; } private: CPDF_StreamParser** scoped_variable_; }; FX_DWORD CPDF_StreamContentParser::Parse(const uint8_t* 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); CPDF_StreamParserAutoClearer auto_clearer(&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: OnOperator((char*)syntax.GetWordBuf()); ClearAllParams(); break; case CPDF_StreamParser::Number: AddNumberParam((char*)syntax.GetWordBuf(), syntax.GetWordSize()); break; case CPDF_StreamParser::Name: AddNameParam((const FX_CHAR*)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((const FX_CHAR*)m_pSyntax->GetWordBuf() + 1, m_pSyntax->GetWordSize() - 1); nonstd::unique_ptr> pObj( m_pSyntax->ReadNextObject()); if (!key.IsEmpty()) { FX_DWORD dwObjNum = pObj ? pObj->GetObjNum() : 0; if (dwObjNum) pDict->SetAtReference(key, m_pDocument, dwObjNum); else pDict->SetAt(key, pObj.release()); } } _PDF_ReplaceAbbr(pDict); CPDF_Object* pCSObj = NULL; if (pDict->KeyExist(FX_BSTRC("ColorSpace"))) { pCSObj = pDict->GetElementValue(FX_BSTRC("ColorSpace")); if (pCSObj->IsName()) { 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); } } } } 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] = {}; 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 kPathOperatorSubpath: AddPathPoint(params[0], params[1], FXPT_MOVETO); nParams = 0; break; case kPathOperatorLine: AddPathPoint(params[0], params[1], FXPT_LINETO); nParams = 0; break; case kPathOperatorCubicBezier1: 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 kPathOperatorCubicBezier2: 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 kPathOperatorCubicBezier3: 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 kPathOperatorClosePath: Handle_ClosePath(); nParams = 0; break; default: bProcessed = FALSE; break; } } else if (len == 2) { if (m_pSyntax->GetWordBuf()[0] == kPathOperatorRectangle[0] && m_pSyntax->GetWordBuf()[1] == kPathOperatorRectangle[1]) { 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 uint8_t* 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, uint8_t*& 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_buf = FX_Alloc2D(uint8_t, pitch, height); dest_size = pitch * height; // Safe since checked alloc returned. for (int row = 0; row < height; row++) { const uint8_t* pLine = pDecoder->GetScanline(row); if (!pLine) break; FXSYS_memcpy(dest_buf + row * pitch, pLine, pitch); } FX_DWORD srcoff = pDecoder->GetSrcOffset(); delete pDecoder; return srcoff; } ICodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder( const uint8_t* src_buf, FX_DWORD src_size, int width, int height, const CPDF_Dictionary* pParams); FX_DWORD PDF_DecodeInlineStream(const uint8_t* src_buf, FX_DWORD limit, int width, int height, CFX_ByteString& decoder, CPDF_Dictionary* pParam, uint8_t*& 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); } if (decoder == FX_BSTRC("ASCII85Decode") || decoder == FX_BSTRC("A85")) { return A85Decode(src_buf, limit, dest_buf, dest_size); } if (decoder == FX_BSTRC("ASCIIHexDecode") || decoder == FX_BSTRC("AHx")) { return HexDecode(src_buf, limit, dest_buf, dest_size); } if (decoder == FX_BSTRC("FlateDecode") || decoder == FX_BSTRC("Fl")) { return FPDFAPI_FlateOrLZWDecode(FALSE, src_buf, limit, pParam, dest_size, dest_buf, dest_size); } if (decoder == FX_BSTRC("LZWDecode") || decoder == FX_BSTRC("LZW")) { return FPDFAPI_FlateOrLZWDecode(TRUE, src_buf, limit, pParam, 0, dest_buf, dest_size); } 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); } 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; } CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc, CPDF_Dictionary* pDict, CPDF_Object* pCSObj, FX_BOOL bDecode) { if (m_Pos == m_Size) return nullptr; if (PDFCharIsWhitespace(m_pBuf[m_Pos])) m_Pos++; CFX_ByteString Decoder; CPDF_Dictionary* pParam = nullptr; CPDF_Object* pFilter = pDict->GetElementValue(FX_BSTRC("Filter")); if (pFilter) { if (CPDF_Array* pArray = pFilter->AsArray()) { Decoder = pArray->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; uint8_t* pData = NULL; FX_DWORD dwStreamSize; if (Decoder.IsEmpty()) { if (OrigSize > m_Size - m_Pos) { OrigSize = m_Size - m_Pos; } pData = FX_Alloc(uint8_t, OrigSize); FXSYS_memcpy(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) { FX_Free(pData); return NULL; } if (bDecode) { m_Pos += dwStreamSize; dwStreamSize = dwDestSize; if (CPDF_Array* pArray = pFilter->AsArray()) { pArray->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 { 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(uint8_t, dwStreamSize); FXSYS_memcpy(pData, m_pBuf + m_Pos, dwStreamSize); m_Pos += dwStreamSize; } } pDict->SetAtInteger(FX_BSTRC("Length"), (int)dwStreamSize); return new CPDF_Stream(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 = nullptr; } m_WordSize = 0; FX_BOOL bIsNumber = TRUE; if (!PositionIsInBounds()) return EndOfData; int ch = m_pBuf[m_Pos++]; while (1) { while (PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) return EndOfData; ch = m_pBuf[m_Pos++]; } if (ch != '%') break; while (1) { if (!PositionIsInBounds()) return EndOfData; ch = m_pBuf[m_Pos++]; if (PDFCharIsLineEnding(ch)) break; } } if (PDFCharIsDelimiter(ch) && ch != '/') { m_Pos--; m_pLastObj = ReadNextObject(); return Others; } while (1) { if (m_WordSize < MAX_WORD_BUFFER) m_WordBuffer[m_WordSize++] = ch; if (!PDFCharIsNumeric(ch)) bIsNumber = FALSE; if (!PositionIsInBounds()) break; ch = m_pBuf[m_Pos++]; if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { 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 (!PositionIsInBounds()) return; int ch = m_pBuf[m_Pos++]; while (1) { while (PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; } if (!PDFCharIsNumeric(ch)) { m_Pos = command_startpos; return; } while (1) { while (!PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; } while (PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; } if (PDFCharIsNumeric(ch)) continue; FX_DWORD op_startpos = m_Pos - 1; while (!PDFCharIsWhitespace(ch) && !PDFCharIsDelimiter(ch)) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; } if (m_Pos - op_startpos == 2) { int op = m_pBuf[op_startpos]; if (op == kPathOperatorSubpath || op == kPathOperatorLine || op == kPathOperatorCubicBezier1 || op == kPathOperatorCubicBezier2 || op == kPathOperatorCubicBezier3) { command_startpos = m_Pos; break; } } else if (m_Pos - op_startpos == 3) { if (m_pBuf[op_startpos] == kPathOperatorRectangle[0] && m_pBuf[op_startpos + 1] == kPathOperatorRectangle[1]) { 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 (!PositionIsInBounds()) return; int ch = m_pBuf[m_Pos++]; while (1) { while (PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) { return; } ch = m_pBuf[m_Pos++]; } if (ch != '%') break; while (1) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; if (PDFCharIsLineEnding(ch)) break; } } if (PDFCharIsDelimiter(ch)) { bIsNumber = FALSE; m_WordBuffer[m_WordSize++] = ch; if (ch == '/') { while (1) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { m_Pos--; return; } if (m_WordSize < MAX_WORD_BUFFER) m_WordBuffer[m_WordSize++] = ch; } } else if (ch == '<') { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; if (ch == '<') m_WordBuffer[m_WordSize++] = ch; else m_Pos--; } else if (ch == '>') { if (!PositionIsInBounds()) 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 (!PDFCharIsNumeric(ch)) bIsNumber = FALSE; if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { m_Pos--; break; } } } CFX_ByteString CPDF_StreamParser::ReadString() { if (!PositionIsInBounds()) 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 (!PositionIsInBounds()) break; ch = m_pBuf[m_Pos++]; } if (PositionIsInBounds()) 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 (!PositionIsInBounds()) 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 (!PositionIsInBounds()) 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(); } bool CPDF_StreamParser::PositionIsInBounds() const { return m_Pos < m_Size; } #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() { delete m_pParser; delete m_pSingleStream; if (m_pStreamArray) { for (FX_DWORD i = 0; i < m_nStreams; i++) delete m_pStreamArray[i]; FX_Free(m_pStreamArray); } if (!m_pSingleStream) FX_Free(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 (CPDF_Stream* pStream = pContent->AsStream()) { m_nStreams = 0; m_pSingleStream = new CPDF_StreamAcc; m_pSingleStream->LoadAllData(pStream, FALSE); } else if (CPDF_Array* pArray = pContent->AsArray()) { m_nStreams = pArray->GetCount(); if (m_nStreams == 0) { m_Status = Done; return; } m_pStreamArray = FX_Alloc(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 = new CPDF_StreamContentParser( pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources, pParentMatrix, pForm, pResources, &form_bbox, pOptions, pGraphicStates, level); m_pParser->GetCurStates()->m_CTM = form_matrix; m_pParser->GetCurStates()->m_ParentMatrix = form_matrix; if (ClipPath.NotNull()) { m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING, TRUE); } if (pForm->m_Transparency & PDFTRANS_GROUP) { CPDF_GeneralStateData* pData = m_pParser->GetCurStates()->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 = new CPDF_StreamAcc; if (pForm->m_pDocument) { m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE); } else { m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE); } m_pData = (uint8_t*)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(uint8_t, m_Size); FX_DWORD pos = 0; for (i = 0; i < m_nStreams; i++) { FXSYS_memcpy(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 = (uint8_t*)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] = new CPDF_StreamAcc; CPDF_Stream* pStreamObj = ToStream( pContent ? pContent->GetElementValue(m_CurrentOffset) : nullptr); m_pStreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE); m_CurrentOffset++; } } if (m_InternalStage == PAGEPARSE_STAGE_PARSE) { if (!m_pParser) { m_pParser = new CPDF_StreamContentParser( m_pObjects->m_pDocument, m_pObjects->m_pPageResources, nullptr, nullptr, m_pObjects, m_pObjects->m_pResources, &m_pObjects->m_BBox, &m_Options, nullptr, 0); m_pParser->GetCurStates()->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_InternalStage == PAGEPARSE_STAGE_CHECKCLIP) { if (m_pType3Char) { m_pType3Char->m_bColored = m_pParser->IsColored(); m_pType3Char->m_Width = FXSYS_round(m_pParser->GetType3Data()[0] * 1000); m_pType3Char->m_BBox.left = FXSYS_round(m_pParser->GetType3Data()[2] * 1000); m_pType3Char->m_BBox.bottom = FXSYS_round(m_pParser->GetType3Data()[3] * 1000); m_pType3Char->m_BBox.right = FXSYS_round(m_pParser->GetType3Data()[4] * 1000); m_pType3Char->m_BBox.top = FXSYS_round(m_pParser->GetType3Data()[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; } } }