Home | History | Annotate | Download | only in fxfa
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "xfa/fxfa/cxfa_ffdoc.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <vector>
     12 
     13 #include "core/fpdfapi/parser/cpdf_array.h"
     14 #include "core/fpdfapi/parser/cpdf_document.h"
     15 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
     16 #include "core/fpdfdoc/cpdf_nametree.h"
     17 #include "core/fxcrt/cfx_checksumcontext.h"
     18 #include "core/fxcrt/cfx_memorystream.h"
     19 #include "core/fxcrt/cfx_seekablemultistream.h"
     20 #include "core/fxcrt/fx_extension.h"
     21 #include "core/fxcrt/fx_memory.h"
     22 #include "core/fxcrt/xml/cfx_xmlelement.h"
     23 #include "core/fxcrt/xml/cfx_xmlnode.h"
     24 #include "fxjs/xfa/cjx_object.h"
     25 #include "third_party/base/ptr_util.h"
     26 #include "xfa/fwl/cfwl_notedriver.h"
     27 #include "xfa/fxfa/cxfa_ffapp.h"
     28 #include "xfa/fxfa/cxfa_ffdocview.h"
     29 #include "xfa/fxfa/cxfa_ffnotify.h"
     30 #include "xfa/fxfa/cxfa_ffwidget.h"
     31 #include "xfa/fxfa/cxfa_fontmgr.h"
     32 #include "xfa/fxfa/parser/cxfa_acrobat.h"
     33 #include "xfa/fxfa/parser/cxfa_acrobat7.h"
     34 #include "xfa/fxfa/parser/cxfa_dataexporter.h"
     35 #include "xfa/fxfa/parser/cxfa_dataimporter.h"
     36 #include "xfa/fxfa/parser/cxfa_document.h"
     37 #include "xfa/fxfa/parser/cxfa_dynamicrender.h"
     38 #include "xfa/fxfa/parser/cxfa_node.h"
     39 
     40 namespace {
     41 
     42 struct FX_BASE64DATA {
     43   uint32_t data1 : 2;
     44   uint32_t data2 : 6;
     45   uint32_t data3 : 4;
     46   uint32_t data4 : 4;
     47   uint32_t data5 : 6;
     48   uint32_t data6 : 2;
     49   uint32_t data7 : 8;
     50 };
     51 
     52 const uint8_t kStartValuesRemoved = 43;
     53 const uint8_t kDecoderMapSize = 80;
     54 const uint8_t g_FXBase64DecoderMap[kDecoderMapSize] = {
     55     0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
     56     0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
     57     0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
     58     0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
     59     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
     60     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
     61     0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33,
     62 };
     63 
     64 uint8_t base64DecoderValue(uint8_t val) {
     65   if (val < kStartValuesRemoved || val >= kStartValuesRemoved + kDecoderMapSize)
     66     return 0xFF;
     67   return g_FXBase64DecoderMap[val - kStartValuesRemoved];
     68 }
     69 
     70 void Base64DecodePiece(const char src[4],
     71                        int32_t iChars,
     72                        FX_BASE64DATA& dst,
     73                        int32_t& iBytes) {
     74   ASSERT(iChars > 0 && iChars < 5);
     75   iBytes = 1;
     76   dst.data2 = base64DecoderValue(static_cast<uint8_t>(src[0]));
     77   if (iChars > 1) {
     78     uint8_t b = base64DecoderValue(static_cast<uint8_t>(src[1]));
     79     dst.data1 = b >> 4;
     80     dst.data4 = b;
     81     if (iChars > 2) {
     82       iBytes = 2;
     83       b = base64DecoderValue(static_cast<uint8_t>(src[2]));
     84       dst.data3 = b >> 2;
     85       dst.data6 = b;
     86       if (iChars > 3) {
     87         iBytes = 3;
     88         dst.data5 = base64DecoderValue(static_cast<uint8_t>(src[3]));
     89       } else {
     90         dst.data5 = 0;
     91       }
     92     } else {
     93       dst.data3 = 0;
     94     }
     95   } else {
     96     dst.data1 = 0;
     97   }
     98 }
     99 
    100 int32_t Base64DecodeW(const wchar_t* pSrc, int32_t iSrcLen, uint8_t* pDst) {
    101   ASSERT(pSrc);
    102   if (iSrcLen < 1) {
    103     return 0;
    104   }
    105   while (iSrcLen > 0 && pSrc[iSrcLen - 1] == '=') {
    106     iSrcLen--;
    107   }
    108   if (iSrcLen < 1) {
    109     return 0;
    110   }
    111   if (!pDst) {
    112     int32_t iDstLen = iSrcLen / 4 * 3;
    113     iSrcLen %= 4;
    114     if (iSrcLen == 1) {
    115       iDstLen += 1;
    116     } else if (iSrcLen == 2) {
    117       iDstLen += 1;
    118     } else if (iSrcLen == 3) {
    119       iDstLen += 2;
    120     }
    121     return iDstLen;
    122   }
    123   char srcData[4];
    124   FX_BASE64DATA dstData;
    125   int32_t iChars = 4, iBytes;
    126   uint8_t* pDstEnd = pDst;
    127   while (iSrcLen > 0) {
    128     if (iSrcLen > 3) {
    129       srcData[0] = (char)*pSrc++;
    130       srcData[1] = (char)*pSrc++;
    131       srcData[2] = (char)*pSrc++;
    132       srcData[3] = (char)*pSrc++;
    133       iSrcLen -= 4;
    134     } else {
    135       *((uint32_t*)&dstData) = 0;
    136       *((uint32_t*)srcData) = 0;
    137       srcData[0] = (char)*pSrc++;
    138       if (iSrcLen > 1) {
    139         srcData[1] = (char)*pSrc++;
    140       }
    141       if (iSrcLen > 2) {
    142         srcData[2] = (char)*pSrc++;
    143       }
    144       iChars = iSrcLen;
    145       iSrcLen = 0;
    146     }
    147     Base64DecodePiece(srcData, iChars, dstData, iBytes);
    148     *pDstEnd++ = ((uint8_t*)&dstData)[0];
    149     if (iBytes > 1) {
    150       *pDstEnd++ = ((uint8_t*)&dstData)[1];
    151     }
    152     if (iBytes > 2) {
    153       *pDstEnd++ = ((uint8_t*)&dstData)[2];
    154     }
    155   }
    156   return pDstEnd - pDst;
    157 }
    158 
    159 }  // namespace
    160 
    161 CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocEnvironment* pDocEnvironment)
    162     : m_pDocEnvironment(pDocEnvironment), m_pApp(pApp) {}
    163 
    164 CXFA_FFDoc::~CXFA_FFDoc() {
    165   CloseDoc();
    166 }
    167 
    168 int32_t CXFA_FFDoc::StartLoad() {
    169   m_pNotify = pdfium::MakeUnique<CXFA_FFNotify>(this);
    170   m_pDocumentParser = pdfium::MakeUnique<CXFA_DocumentParser>(m_pNotify.get());
    171   return m_pDocumentParser->StartParse(m_pStream, XFA_PacketType::Xdp);
    172 }
    173 
    174 bool XFA_GetPDFContentsFromPDFXML(CFX_XMLNode* pPDFElement,
    175                                   uint8_t*& pByteBuffer,
    176                                   int32_t& iBufferSize) {
    177   CFX_XMLElement* pDocumentElement = nullptr;
    178   for (CFX_XMLNode* pXMLNode =
    179            pPDFElement->GetNodeItem(CFX_XMLNode::FirstChild);
    180        pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
    181     if (pXMLNode->GetType() == FX_XMLNODE_Element) {
    182       CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
    183       WideString wsTagName = pXMLElement->GetName();
    184       if (wsTagName == L"document") {
    185         pDocumentElement = pXMLElement;
    186         break;
    187       }
    188     }
    189   }
    190   if (!pDocumentElement) {
    191     return false;
    192   }
    193   CFX_XMLElement* pChunkElement = nullptr;
    194   for (CFX_XMLNode* pXMLNode =
    195            pDocumentElement->GetNodeItem(CFX_XMLNode::FirstChild);
    196        pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
    197     if (pXMLNode->GetType() == FX_XMLNODE_Element) {
    198       CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
    199       WideString wsTagName = pXMLElement->GetName();
    200       if (wsTagName == L"chunk") {
    201         pChunkElement = pXMLElement;
    202         break;
    203       }
    204     }
    205   }
    206   if (!pChunkElement) {
    207     return false;
    208   }
    209   WideString wsPDFContent = pChunkElement->GetTextData();
    210   iBufferSize =
    211       Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), nullptr);
    212   pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1);
    213   pByteBuffer[iBufferSize] = '0';  // FIXME: I bet this is wrong.
    214   Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), pByteBuffer);
    215   return true;
    216 }
    217 void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) {
    218   CXFA_Node* pChildNode = pNewRoot->GetFirstChild();
    219   while (pChildNode) {
    220     CXFA_Node* pOriginChild =
    221         pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash());
    222     if (pOriginChild) {
    223       pChildNode = pChildNode->GetNextSibling();
    224     } else {
    225       CXFA_Node* pNextSibling = pChildNode->GetNextSibling();
    226       pNewRoot->RemoveChild(pChildNode, true);
    227       pOriginRoot->InsertChild(pChildNode, nullptr);
    228       pChildNode = pNextSibling;
    229       pNextSibling = nullptr;
    230     }
    231   }
    232 }
    233 
    234 int32_t CXFA_FFDoc::DoLoad() {
    235   int32_t iStatus = m_pDocumentParser->DoParse();
    236   if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc)
    237     return XFA_PARSESTATUS_SyntaxErr;
    238   return iStatus;
    239 }
    240 
    241 void CXFA_FFDoc::StopLoad() {
    242   m_pPDFFontMgr = pdfium::MakeUnique<CFGAS_PDFFontMgr>(
    243       GetPDFDoc(), GetApp()->GetFDEFontMgr());
    244 
    245   m_FormType = FormType::kXFAForeground;
    246   CXFA_Node* pConfig = ToNode(
    247       m_pDocumentParser->GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
    248   if (!pConfig)
    249     return;
    250 
    251   CXFA_Acrobat* pAcrobat =
    252       pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat);
    253   if (!pAcrobat)
    254     return;
    255 
    256   CXFA_Acrobat7* pAcrobat7 =
    257       pAcrobat->GetFirstChildByClass<CXFA_Acrobat7>(XFA_Element::Acrobat7);
    258   if (!pAcrobat7)
    259     return;
    260 
    261   CXFA_DynamicRender* pDynamicRender =
    262       pAcrobat7->GetFirstChildByClass<CXFA_DynamicRender>(
    263           XFA_Element::DynamicRender);
    264   if (!pDynamicRender)
    265     return;
    266 
    267   WideString wsType = pDynamicRender->JSObject()->GetContent(false);
    268   if (wsType == L"required")
    269     m_FormType = FormType::kXFAFull;
    270 }
    271 
    272 CXFA_FFDocView* CXFA_FFDoc::CreateDocView() {
    273   if (!m_DocView)
    274     m_DocView = pdfium::MakeUnique<CXFA_FFDocView>(this);
    275 
    276   return m_DocView.get();
    277 }
    278 
    279 CXFA_FFDocView* CXFA_FFDoc::GetDocView(CXFA_LayoutProcessor* pLayout) {
    280   return m_DocView && m_DocView->GetXFALayout() == pLayout ? m_DocView.get()
    281                                                            : nullptr;
    282 }
    283 
    284 CXFA_FFDocView* CXFA_FFDoc::GetDocView() {
    285   return m_DocView.get();
    286 }
    287 
    288 bool CXFA_FFDoc::OpenDoc(CPDF_Document* pPDFDoc) {
    289   if (!pPDFDoc)
    290     return false;
    291 
    292   const CPDF_Dictionary* pRoot = pPDFDoc->GetRoot();
    293   if (!pRoot)
    294     return false;
    295 
    296   CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
    297   if (!pAcroForm)
    298     return false;
    299 
    300   CPDF_Object* pElementXFA = pAcroForm->GetDirectObjectFor("XFA");
    301   if (!pElementXFA)
    302     return false;
    303 
    304   std::vector<CPDF_Stream*> xfaStreams;
    305   if (pElementXFA->IsArray()) {
    306     CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA;
    307     for (size_t i = 0; i < pXFAArray->GetCount() / 2; i++) {
    308       if (CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1))
    309         xfaStreams.push_back(pStream);
    310     }
    311   } else if (pElementXFA->IsStream()) {
    312     xfaStreams.push_back((CPDF_Stream*)pElementXFA);
    313   }
    314   if (xfaStreams.empty())
    315     return false;
    316 
    317   m_pPDFDoc = pPDFDoc;
    318   m_pStream = pdfium::MakeRetain<CFX_SeekableMultiStream>(xfaStreams);
    319   return true;
    320 }
    321 
    322 void CXFA_FFDoc::CloseDoc() {
    323   if (m_DocView) {
    324     m_DocView->RunDocClose();
    325     m_DocView.reset();
    326   }
    327   CXFA_Document* doc =
    328       m_pDocumentParser ? m_pDocumentParser->GetDocument() : nullptr;
    329   if (doc)
    330     doc->ClearLayoutData();
    331 
    332   m_pDocumentParser.reset();
    333   m_pNotify.reset();
    334   m_pPDFFontMgr.reset();
    335   m_HashToDibDpiMap.clear();
    336   m_pApp->ClearEventTargets();
    337 }
    338 
    339 RetainPtr<CFX_DIBitmap> CXFA_FFDoc::GetPDFNamedImage(
    340     const WideStringView& wsName,
    341     int32_t& iImageXDpi,
    342     int32_t& iImageYDpi) {
    343   if (!m_pPDFDoc)
    344     return nullptr;
    345 
    346   uint32_t dwHash = FX_HashCode_GetW(wsName, false);
    347   auto it = m_HashToDibDpiMap.find(dwHash);
    348   if (it != m_HashToDibDpiMap.end()) {
    349     iImageXDpi = it->second.iImageXDpi;
    350     iImageYDpi = it->second.iImageYDpi;
    351     return it->second.pDibSource.As<CFX_DIBitmap>();
    352   }
    353 
    354   const CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();
    355   if (!pRoot)
    356     return nullptr;
    357 
    358   CPDF_Dictionary* pNames = pRoot->GetDictFor("Names");
    359   if (!pNames)
    360     return nullptr;
    361 
    362   CPDF_Dictionary* pXFAImages = pNames->GetDictFor("XFAImages");
    363   if (!pXFAImages)
    364     return nullptr;
    365 
    366   CPDF_NameTree nametree(pXFAImages);
    367   CPDF_Object* pObject = nametree.LookupValue(WideString(wsName));
    368   if (!pObject) {
    369     for (size_t i = 0; i < nametree.GetCount(); i++) {
    370       WideString wsTemp;
    371       CPDF_Object* pTempObject = nametree.LookupValueAndName(i, &wsTemp);
    372       if (wsTemp == wsName) {
    373         pObject = pTempObject;
    374         break;
    375       }
    376     }
    377   }
    378 
    379   CPDF_Stream* pStream = ToStream(pObject);
    380   if (!pStream)
    381     return nullptr;
    382 
    383   auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
    384   pAcc->LoadAllDataFiltered();
    385 
    386   RetainPtr<IFX_SeekableStream> pImageFileRead =
    387       pdfium::MakeRetain<CFX_MemoryStream>(
    388           const_cast<uint8_t*>(pAcc->GetData()), pAcc->GetSize(), false);
    389 
    390   RetainPtr<CFX_DIBitmap> pDibSource = XFA_LoadImageFromBuffer(
    391       pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi);
    392   m_HashToDibDpiMap[dwHash] = {pDibSource, iImageXDpi, iImageYDpi};
    393   return pDibSource;
    394 }
    395 
    396 bool CXFA_FFDoc::SavePackage(CXFA_Node* pNode,
    397                              const RetainPtr<IFX_SeekableStream>& pFile,
    398                              CFX_ChecksumContext* pCSContext) {
    399   auto pExport = pdfium::MakeUnique<CXFA_DataExporter>(GetXFADoc());
    400   if (!pNode)
    401     return !!pExport->Export(pFile);
    402 
    403   ByteString bsChecksum;
    404   if (pCSContext)
    405     bsChecksum = pCSContext->GetChecksum();
    406 
    407   return !!pExport->Export(
    408       pFile, pNode, 0, bsChecksum.GetLength() ? bsChecksum.c_str() : nullptr);
    409 }
    410 
    411 bool CXFA_FFDoc::ImportData(const RetainPtr<IFX_SeekableStream>& pStream,
    412                             bool bXDP) {
    413   auto importer =
    414       pdfium::MakeUnique<CXFA_DataImporter>(m_pDocumentParser->GetDocument());
    415   return importer->ImportData(pStream);
    416 }
    417