diff options
Diffstat (limited to 'xfa/fxfa/cxfa_ffdoc.cpp')
-rw-r--r-- | xfa/fxfa/cxfa_ffdoc.cpp | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/xfa/fxfa/cxfa_ffdoc.cpp b/xfa/fxfa/cxfa_ffdoc.cpp new file mode 100644 index 0000000000..fdeacf7f0f --- /dev/null +++ b/xfa/fxfa/cxfa_ffdoc.cpp @@ -0,0 +1,430 @@ +// 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 "xfa/fxfa/cxfa_ffdoc.h" + +#include <algorithm> +#include <memory> +#include <vector> + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fpdfdoc/cpdf_nametree.h" +#include "core/fxcrt/fx_ext.h" +#include "core/fxcrt/fx_memory.h" +#include "third_party/base/ptr_util.h" +#include "xfa/fde/xml/fde_xml_imp.h" +#include "xfa/fwl/cfwl_notedriver.h" +#include "xfa/fxfa/app/xfa_ffnotify.h" +#include "xfa/fxfa/cxfa_checksumcontext.h" +#include "xfa/fxfa/cxfa_ffapp.h" +#include "xfa/fxfa/cxfa_ffdocview.h" +#include "xfa/fxfa/cxfa_ffwidget.h" +#include "xfa/fxfa/cxfa_fontmgr.h" +#include "xfa/fxfa/parser/cxfa_dataexporter.h" +#include "xfa/fxfa/parser/cxfa_dataimporter.h" +#include "xfa/fxfa/parser/cxfa_document.h" + +namespace { + +struct FX_BASE64DATA { + uint32_t data1 : 2; + uint32_t data2 : 6; + uint32_t data3 : 4; + uint32_t data4 : 4; + uint32_t data5 : 6; + uint32_t data6 : 2; + uint32_t data7 : 8; +}; + +const uint8_t kStartValuesRemoved = 43; +const uint8_t kDecoderMapSize = 80; +const uint8_t g_FXBase64DecoderMap[kDecoderMapSize] = { + 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, + 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, + 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, +}; + +uint8_t base64DecoderValue(uint8_t val) { + if (val < kStartValuesRemoved || val >= kStartValuesRemoved + kDecoderMapSize) + return 0xFF; + return g_FXBase64DecoderMap[val - kStartValuesRemoved]; +} + +void Base64DecodePiece(const char src[4], + int32_t iChars, + FX_BASE64DATA& dst, + int32_t& iBytes) { + ASSERT(iChars > 0 && iChars < 5); + iBytes = 1; + dst.data2 = base64DecoderValue(static_cast<uint8_t>(src[0])); + if (iChars > 1) { + uint8_t b = base64DecoderValue(static_cast<uint8_t>(src[1])); + dst.data1 = b >> 4; + dst.data4 = b; + if (iChars > 2) { + iBytes = 2; + b = base64DecoderValue(static_cast<uint8_t>(src[2])); + dst.data3 = b >> 2; + dst.data6 = b; + if (iChars > 3) { + iBytes = 3; + dst.data5 = base64DecoderValue(static_cast<uint8_t>(src[3])); + } else { + dst.data5 = 0; + } + } else { + dst.data3 = 0; + } + } else { + dst.data1 = 0; + } +} + +int32_t Base64DecodeW(const wchar_t* pSrc, int32_t iSrcLen, uint8_t* pDst) { + ASSERT(pSrc); + if (iSrcLen < 1) { + return 0; + } + while (iSrcLen > 0 && pSrc[iSrcLen - 1] == '=') { + iSrcLen--; + } + if (iSrcLen < 1) { + return 0; + } + if (!pDst) { + int32_t iDstLen = iSrcLen / 4 * 3; + iSrcLen %= 4; + if (iSrcLen == 1) { + iDstLen += 1; + } else if (iSrcLen == 2) { + iDstLen += 1; + } else if (iSrcLen == 3) { + iDstLen += 2; + } + return iDstLen; + } + char srcData[4]; + FX_BASE64DATA dstData; + int32_t iChars = 4, iBytes; + uint8_t* pDstEnd = pDst; + while (iSrcLen > 0) { + if (iSrcLen > 3) { + srcData[0] = (char)*pSrc++; + srcData[1] = (char)*pSrc++; + srcData[2] = (char)*pSrc++; + srcData[3] = (char)*pSrc++; + iSrcLen -= 4; + } else { + *((uint32_t*)&dstData) = 0; + *((uint32_t*)srcData) = 0; + srcData[0] = (char)*pSrc++; + if (iSrcLen > 1) { + srcData[1] = (char)*pSrc++; + } + if (iSrcLen > 2) { + srcData[2] = (char)*pSrc++; + } + iChars = iSrcLen; + iSrcLen = 0; + } + Base64DecodePiece(srcData, iChars, dstData, iBytes); + *pDstEnd++ = ((uint8_t*)&dstData)[0]; + if (iBytes > 1) { + *pDstEnd++ = ((uint8_t*)&dstData)[1]; + } + if (iBytes > 2) { + *pDstEnd++ = ((uint8_t*)&dstData)[2]; + } + } + return pDstEnd - pDst; +} + +} // namespace + +CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocEnvironment* pDocEnvironment) + : m_pDocEnvironment(pDocEnvironment), + m_pDocumentParser(nullptr), + m_pApp(pApp), + m_pNotify(nullptr), + m_pPDFDoc(nullptr), + m_dwDocType(XFA_DocType::Static) {} + +CXFA_FFDoc::~CXFA_FFDoc() { + CloseDoc(); +} + +int32_t CXFA_FFDoc::StartLoad() { + m_pNotify = pdfium::MakeUnique<CXFA_FFNotify>(this); + m_pDocumentParser = pdfium::MakeUnique<CXFA_DocumentParser>(m_pNotify.get()); + return m_pDocumentParser->StartParse(m_pStream, XFA_XDPPACKET_XDP); +} + +bool XFA_GetPDFContentsFromPDFXML(CFDE_XMLNode* pPDFElement, + uint8_t*& pByteBuffer, + int32_t& iBufferSize) { + CFDE_XMLElement* pDocumentElement = nullptr; + for (CFDE_XMLNode* pXMLNode = + pPDFElement->GetNodeItem(CFDE_XMLNode::FirstChild); + pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { + if (pXMLNode->GetType() == FDE_XMLNODE_Element) { + CFX_WideString wsTagName; + CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode); + pXMLElement->GetTagName(wsTagName); + if (wsTagName == L"document") { + pDocumentElement = pXMLElement; + break; + } + } + } + if (!pDocumentElement) { + return false; + } + CFDE_XMLElement* pChunkElement = nullptr; + for (CFDE_XMLNode* pXMLNode = + pDocumentElement->GetNodeItem(CFDE_XMLNode::FirstChild); + pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { + if (pXMLNode->GetType() == FDE_XMLNODE_Element) { + CFX_WideString wsTagName; + CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode); + pXMLElement->GetTagName(wsTagName); + if (wsTagName == L"chunk") { + pChunkElement = pXMLElement; + break; + } + } + } + if (!pChunkElement) { + return false; + } + CFX_WideString wsPDFContent; + pChunkElement->GetTextData(wsPDFContent); + iBufferSize = + Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), nullptr); + pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1); + pByteBuffer[iBufferSize] = '0'; // FIXME: I bet this is wrong. + Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), pByteBuffer); + return true; +} +void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) { + CXFA_Node* pChildNode = pNewRoot->GetNodeItem(XFA_NODEITEM_FirstChild); + while (pChildNode) { + CXFA_Node* pOriginChild = + pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash()); + if (pOriginChild) { + pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling); + } else { + CXFA_Node* pNextSibling = + pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling); + pNewRoot->RemoveChild(pChildNode); + pOriginRoot->InsertChild(pChildNode); + pChildNode = pNextSibling; + pNextSibling = nullptr; + } + } +} + +int32_t CXFA_FFDoc::DoLoad(IFX_Pause* pPause) { + int32_t iStatus = m_pDocumentParser->DoParse(pPause); + if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc) + return XFA_PARSESTATUS_SyntaxErr; + return iStatus; +} + +void CXFA_FFDoc::StopLoad() { + m_pApp->GetXFAFontMgr()->LoadDocFonts(this); + m_dwDocType = XFA_DocType::Static; + CXFA_Node* pConfig = ToNode( + m_pDocumentParser->GetDocument()->GetXFAObject(XFA_HASHCODE_Config)); + if (!pConfig) + return; + + CXFA_Node* pAcrobat = pConfig->GetFirstChildByClass(XFA_Element::Acrobat); + if (!pAcrobat) + return; + + CXFA_Node* pAcrobat7 = pAcrobat->GetFirstChildByClass(XFA_Element::Acrobat7); + if (!pAcrobat7) + return; + + CXFA_Node* pDynamicRender = + pAcrobat7->GetFirstChildByClass(XFA_Element::DynamicRender); + if (!pDynamicRender) + return; + + CFX_WideString wsType; + if (pDynamicRender->TryContent(wsType) && wsType == L"required") + m_dwDocType = XFA_DocType::Dynamic; +} + +CXFA_FFDocView* CXFA_FFDoc::CreateDocView() { + if (!m_DocView) + m_DocView = pdfium::MakeUnique<CXFA_FFDocView>(this); + + return m_DocView.get(); +} + +CXFA_FFDocView* CXFA_FFDoc::GetDocView(CXFA_LayoutProcessor* pLayout) { + return m_DocView && m_DocView->GetXFALayout() == pLayout ? m_DocView.get() + : nullptr; +} + +CXFA_FFDocView* CXFA_FFDoc::GetDocView() { + return m_DocView.get(); +} + +bool CXFA_FFDoc::OpenDoc(const CFX_RetainPtr<IFX_SeekableReadStream>& pStream) { + m_pStream = pStream; + return true; +} + +bool CXFA_FFDoc::OpenDoc(CPDF_Document* pPDFDoc) { + if (!pPDFDoc) + return false; + + CPDF_Dictionary* pRoot = pPDFDoc->GetRoot(); + if (!pRoot) + return false; + + CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); + if (!pAcroForm) + return false; + + CPDF_Object* pElementXFA = pAcroForm->GetDirectObjectFor("XFA"); + if (!pElementXFA) + return false; + + std::vector<CPDF_Stream*> xfaStreams; + if (pElementXFA->IsArray()) { + CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA; + for (size_t i = 0; i < pXFAArray->GetCount() / 2; i++) { + if (CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1)) + xfaStreams.push_back(pStream); + } + } else if (pElementXFA->IsStream()) { + xfaStreams.push_back((CPDF_Stream*)pElementXFA); + } + if (xfaStreams.empty()) + return false; + + m_pPDFDoc = pPDFDoc; + m_pStream = MakeSeekableReadStream(xfaStreams); + return true; +} + +bool CXFA_FFDoc::CloseDoc() { + if (m_DocView) + m_DocView->RunDocClose(); + + CXFA_Document* doc = + m_pDocumentParser ? m_pDocumentParser->GetDocument() : nullptr; + if (doc) + doc->ClearLayoutData(); + + m_DocView.reset(); + m_pNotify.reset(nullptr); + m_pApp->GetXFAFontMgr()->ReleaseDocFonts(this); + + for (const auto& pair : m_HashToDibDpiMap) + delete pair.second.pDibSource; + + m_HashToDibDpiMap.clear(); + m_pApp->ClearEventTargets(); + return true; +} + +CPDF_Document* CXFA_FFDoc::GetPDFDoc() { + return m_pPDFDoc; +} + +CFX_DIBitmap* CXFA_FFDoc::GetPDFNamedImage(const CFX_WideStringC& wsName, + int32_t& iImageXDpi, + int32_t& iImageYDpi) { + if (!m_pPDFDoc) + return nullptr; + + uint32_t dwHash = FX_HashCode_GetW(wsName, false); + auto it = m_HashToDibDpiMap.find(dwHash); + if (it != m_HashToDibDpiMap.end()) { + iImageXDpi = it->second.iImageXDpi; + iImageYDpi = it->second.iImageYDpi; + return static_cast<CFX_DIBitmap*>(it->second.pDibSource); + } + + CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot(); + if (!pRoot) + return nullptr; + + CPDF_Dictionary* pNames = pRoot->GetDictFor("Names"); + if (!pNames) + return nullptr; + + CPDF_Dictionary* pXFAImages = pNames->GetDictFor("XFAImages"); + if (!pXFAImages) + return nullptr; + + CPDF_NameTree nametree(pXFAImages); + CFX_ByteString bsName = PDF_EncodeText(wsName.c_str(), wsName.GetLength()); + CPDF_Object* pObject = nametree.LookupValue(bsName); + if (!pObject) { + for (size_t i = 0; i < nametree.GetCount(); i++) { + CFX_ByteString bsTemp; + CPDF_Object* pTempObject = nametree.LookupValue(i, bsTemp); + if (bsTemp == bsName) { + pObject = pTempObject; + break; + } + } + } + + CPDF_Stream* pStream = ToStream(pObject); + if (!pStream) + return nullptr; + + CPDF_StreamAcc streamAcc; + streamAcc.LoadAllData(pStream); + + CFX_RetainPtr<IFX_SeekableReadStream> pImageFileRead = + IFX_MemoryStream::Create((uint8_t*)streamAcc.GetData(), + streamAcc.GetSize()); + + CFX_DIBitmap* pDibSource = XFA_LoadImageFromBuffer( + pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi); + m_HashToDibDpiMap[dwHash] = {pDibSource, iImageXDpi, iImageYDpi}; + return pDibSource; +} + +bool CXFA_FFDoc::SavePackage( + XFA_HashCode code, + const CFX_RetainPtr<IFX_SeekableWriteStream>& pFile, + CXFA_ChecksumContext* pCSContext) { + CXFA_Document* doc = m_pDocumentParser->GetDocument(); + std::unique_ptr<CXFA_DataExporter> pExport(new CXFA_DataExporter(doc)); + CXFA_Node* pNode = code == XFA_HASHCODE_Xfa ? doc->GetRoot() + : ToNode(doc->GetXFAObject(code)); + if (!pNode) + return !!pExport->Export(pFile); + + CFX_ByteString bsChecksum; + if (pCSContext) + bsChecksum = pCSContext->GetChecksum(); + + return !!pExport->Export( + pFile, pNode, 0, bsChecksum.GetLength() ? bsChecksum.c_str() : nullptr); +} + +bool CXFA_FFDoc::ImportData( + const CFX_RetainPtr<IFX_SeekableReadStream>& pStream, + bool bXDP) { + auto importer = + pdfium::MakeUnique<CXFA_DataImporter>(m_pDocumentParser->GetDocument()); + return importer->ImportData(pStream); +} |