Home | History | Annotate | Download | only in app
      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/xfa_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/fx_ext.h"
     18 #include "core/fxcrt/fx_memory.h"
     19 #include "third_party/base/ptr_util.h"
     20 #include "xfa/fde/xml/fde_xml_imp.h"
     21 #include "xfa/fwl/cfwl_notedriver.h"
     22 #include "xfa/fxfa/app/xfa_ffnotify.h"
     23 #include "xfa/fxfa/parser/cxfa_dataexporter.h"
     24 #include "xfa/fxfa/parser/cxfa_dataimporter.h"
     25 #include "xfa/fxfa/parser/cxfa_document.h"
     26 #include "xfa/fxfa/xfa_checksum.h"
     27 #include "xfa/fxfa/xfa_ffapp.h"
     28 #include "xfa/fxfa/xfa_ffdocview.h"
     29 #include "xfa/fxfa/xfa_ffwidget.h"
     30 #include "xfa/fxfa/xfa_fontmgr.h"
     31 
     32 namespace {
     33 
     34 struct FX_BASE64DATA {
     35   uint32_t data1 : 2;
     36   uint32_t data2 : 6;
     37   uint32_t data3 : 4;
     38   uint32_t data4 : 4;
     39   uint32_t data5 : 6;
     40   uint32_t data6 : 2;
     41   uint32_t data7 : 8;
     42 };
     43 
     44 const uint8_t kStartValuesRemoved = 43;
     45 const uint8_t kDecoderMapSize = 80;
     46 const uint8_t g_FXBase64DecoderMap[kDecoderMapSize] = {
     47     0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
     48     0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
     49     0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
     50     0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
     51     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
     52     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
     53     0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33,
     54 };
     55 
     56 uint8_t base64DecoderValue(uint8_t val) {
     57   if (val < kStartValuesRemoved || val >= kStartValuesRemoved + kDecoderMapSize)
     58     return 0xFF;
     59   return g_FXBase64DecoderMap[val - kStartValuesRemoved];
     60 }
     61 
     62 void Base64DecodePiece(const FX_CHAR src[4],
     63                        int32_t iChars,
     64                        FX_BASE64DATA& dst,
     65                        int32_t& iBytes) {
     66   ASSERT(iChars > 0 && iChars < 5);
     67   iBytes = 1;
     68   dst.data2 = base64DecoderValue(static_cast<uint8_t>(src[0]));
     69   if (iChars > 1) {
     70     uint8_t b = base64DecoderValue(static_cast<uint8_t>(src[1]));
     71     dst.data1 = b >> 4;
     72     dst.data4 = b;
     73     if (iChars > 2) {
     74       iBytes = 2;
     75       b = base64DecoderValue(static_cast<uint8_t>(src[2]));
     76       dst.data3 = b >> 2;
     77       dst.data6 = b;
     78       if (iChars > 3) {
     79         iBytes = 3;
     80         dst.data5 = base64DecoderValue(static_cast<uint8_t>(src[3]));
     81       } else {
     82         dst.data5 = 0;
     83       }
     84     } else {
     85       dst.data3 = 0;
     86     }
     87   } else {
     88     dst.data1 = 0;
     89   }
     90 }
     91 
     92 int32_t Base64DecodeW(const FX_WCHAR* pSrc, int32_t iSrcLen, uint8_t* pDst) {
     93   ASSERT(pSrc);
     94   if (iSrcLen < 1) {
     95     return 0;
     96   }
     97   while (iSrcLen > 0 && pSrc[iSrcLen - 1] == '=') {
     98     iSrcLen--;
     99   }
    100   if (iSrcLen < 1) {
    101     return 0;
    102   }
    103   if (!pDst) {
    104     int32_t iDstLen = iSrcLen / 4 * 3;
    105     iSrcLen %= 4;
    106     if (iSrcLen == 1) {
    107       iDstLen += 1;
    108     } else if (iSrcLen == 2) {
    109       iDstLen += 1;
    110     } else if (iSrcLen == 3) {
    111       iDstLen += 2;
    112     }
    113     return iDstLen;
    114   }
    115   FX_CHAR srcData[4];
    116   FX_BASE64DATA dstData;
    117   int32_t iChars = 4, iBytes;
    118   uint8_t* pDstEnd = pDst;
    119   while (iSrcLen > 0) {
    120     if (iSrcLen > 3) {
    121       srcData[0] = (FX_CHAR)*pSrc++;
    122       srcData[1] = (FX_CHAR)*pSrc++;
    123       srcData[2] = (FX_CHAR)*pSrc++;
    124       srcData[3] = (FX_CHAR)*pSrc++;
    125       iSrcLen -= 4;
    126     } else {
    127       *((uint32_t*)&dstData) = 0;
    128       *((uint32_t*)srcData) = 0;
    129       srcData[0] = (FX_CHAR)*pSrc++;
    130       if (iSrcLen > 1) {
    131         srcData[1] = (FX_CHAR)*pSrc++;
    132       }
    133       if (iSrcLen > 2) {
    134         srcData[2] = (FX_CHAR)*pSrc++;
    135       }
    136       iChars = iSrcLen;
    137       iSrcLen = 0;
    138     }
    139     Base64DecodePiece(srcData, iChars, dstData, iBytes);
    140     *pDstEnd++ = ((uint8_t*)&dstData)[0];
    141     if (iBytes > 1) {
    142       *pDstEnd++ = ((uint8_t*)&dstData)[1];
    143     }
    144     if (iBytes > 2) {
    145       *pDstEnd++ = ((uint8_t*)&dstData)[2];
    146     }
    147   }
    148   return pDstEnd - pDst;
    149 }
    150 
    151 }  // namespace
    152 
    153 CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocEnvironment* pDocEnvironment)
    154     : m_pDocEnvironment(pDocEnvironment),
    155       m_pDocumentParser(nullptr),
    156       m_pApp(pApp),
    157       m_pNotify(nullptr),
    158       m_pPDFDoc(nullptr),
    159       m_dwDocType(XFA_DOCTYPE_Static) {}
    160 
    161 CXFA_FFDoc::~CXFA_FFDoc() {
    162   CloseDoc();
    163 }
    164 
    165 uint32_t CXFA_FFDoc::GetDocType() {
    166   return m_dwDocType;
    167 }
    168 
    169 int32_t CXFA_FFDoc::StartLoad() {
    170   m_pNotify = pdfium::MakeUnique<CXFA_FFNotify>(this);
    171   m_pDocumentParser = pdfium::MakeUnique<CXFA_DocumentParser>(m_pNotify.get());
    172   return m_pDocumentParser->StartParse(m_pStream, XFA_XDPPACKET_XDP);
    173 }
    174 
    175 bool XFA_GetPDFContentsFromPDFXML(CFDE_XMLNode* pPDFElement,
    176                                   uint8_t*& pByteBuffer,
    177                                   int32_t& iBufferSize) {
    178   CFDE_XMLElement* pDocumentElement = nullptr;
    179   for (CFDE_XMLNode* pXMLNode =
    180            pPDFElement->GetNodeItem(CFDE_XMLNode::FirstChild);
    181        pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
    182     if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
    183       CFX_WideString wsTagName;
    184       CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
    185       pXMLElement->GetTagName(wsTagName);
    186       if (wsTagName == L"document") {
    187         pDocumentElement = pXMLElement;
    188         break;
    189       }
    190     }
    191   }
    192   if (!pDocumentElement) {
    193     return false;
    194   }
    195   CFDE_XMLElement* pChunkElement = nullptr;
    196   for (CFDE_XMLNode* pXMLNode =
    197            pDocumentElement->GetNodeItem(CFDE_XMLNode::FirstChild);
    198        pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
    199     if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
    200       CFX_WideString wsTagName;
    201       CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
    202       pXMLElement->GetTagName(wsTagName);
    203       if (wsTagName == L"chunk") {
    204         pChunkElement = pXMLElement;
    205         break;
    206       }
    207     }
    208   }
    209   if (!pChunkElement) {
    210     return false;
    211   }
    212   CFX_WideString wsPDFContent;
    213   pChunkElement->GetTextData(wsPDFContent);
    214   iBufferSize =
    215       Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), nullptr);
    216   pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1);
    217   pByteBuffer[iBufferSize] = '0';  // FIXME: I bet this is wrong.
    218   Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), pByteBuffer);
    219   return true;
    220 }
    221 void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) {
    222   CXFA_Node* pChildNode = pNewRoot->GetNodeItem(XFA_NODEITEM_FirstChild);
    223   while (pChildNode) {
    224     CXFA_Node* pOriginChild =
    225         pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash());
    226     if (pOriginChild) {
    227       pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
    228     } else {
    229       CXFA_Node* pNextSibling =
    230           pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
    231       pNewRoot->RemoveChild(pChildNode);
    232       pOriginRoot->InsertChild(pChildNode);
    233       pChildNode = pNextSibling;
    234       pNextSibling = nullptr;
    235     }
    236   }
    237 }
    238 
    239 int32_t CXFA_FFDoc::DoLoad(IFX_Pause* pPause) {
    240   int32_t iStatus = m_pDocumentParser->DoParse(pPause);
    241   if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc)
    242     return XFA_PARSESTATUS_SyntaxErr;
    243   return iStatus;
    244 }
    245 
    246 void CXFA_FFDoc::StopLoad() {
    247   m_pApp->GetXFAFontMgr()->LoadDocFonts(this);
    248   m_dwDocType = XFA_DOCTYPE_Static;
    249   CXFA_Node* pConfig = ToNode(
    250       m_pDocumentParser->GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
    251   if (!pConfig) {
    252     return;
    253   }
    254   CXFA_Node* pAcrobat = pConfig->GetFirstChildByClass(XFA_Element::Acrobat);
    255   if (!pAcrobat) {
    256     return;
    257   }
    258   CXFA_Node* pAcrobat7 = pAcrobat->GetFirstChildByClass(XFA_Element::Acrobat7);
    259   if (!pAcrobat7) {
    260     return;
    261   }
    262   CXFA_Node* pDynamicRender =
    263       pAcrobat7->GetFirstChildByClass(XFA_Element::DynamicRender);
    264   if (!pDynamicRender) {
    265     return;
    266   }
    267   CFX_WideString wsType;
    268   if (pDynamicRender->TryContent(wsType) && wsType == L"required") {
    269     m_dwDocType = XFA_DOCTYPE_Dynamic;
    270   }
    271 }
    272 
    273 CXFA_FFDocView* CXFA_FFDoc::CreateDocView(uint32_t dwView) {
    274   if (!m_TypeToDocViewMap[dwView])
    275     m_TypeToDocViewMap[dwView] = pdfium::MakeUnique<CXFA_FFDocView>(this);
    276 
    277   return m_TypeToDocViewMap[dwView].get();
    278 }
    279 
    280 CXFA_FFDocView* CXFA_FFDoc::GetDocView(CXFA_LayoutProcessor* pLayout) {
    281   for (const auto& pair : m_TypeToDocViewMap) {
    282     if (pair.second->GetXFALayout() == pLayout)
    283       return pair.second.get();
    284   }
    285   return nullptr;
    286 }
    287 
    288 CXFA_FFDocView* CXFA_FFDoc::GetDocView() {
    289   auto it = m_TypeToDocViewMap.begin();
    290   return it != m_TypeToDocViewMap.end() ? it->second.get() : nullptr;
    291 }
    292 
    293 bool CXFA_FFDoc::OpenDoc(const CFX_RetainPtr<IFX_SeekableReadStream>& pStream) {
    294   m_pStream = pStream;
    295   return true;
    296 }
    297 bool CXFA_FFDoc::OpenDoc(CPDF_Document* pPDFDoc) {
    298   if (!pPDFDoc)
    299     return false;
    300 
    301   CPDF_Dictionary* pRoot = pPDFDoc->GetRoot();
    302   if (!pRoot)
    303     return false;
    304 
    305   CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
    306   if (!pAcroForm)
    307     return false;
    308 
    309   CPDF_Object* pElementXFA = pAcroForm->GetDirectObjectFor("XFA");
    310   if (!pElementXFA)
    311     return false;
    312 
    313   std::vector<CPDF_Stream*> xfaStreams;
    314   if (pElementXFA->IsArray()) {
    315     CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA;
    316     for (size_t i = 0; i < pXFAArray->GetCount() / 2; i++) {
    317       if (CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1))
    318         xfaStreams.push_back(pStream);
    319     }
    320   } else if (pElementXFA->IsStream()) {
    321     xfaStreams.push_back((CPDF_Stream*)pElementXFA);
    322   }
    323   if (xfaStreams.empty())
    324     return false;
    325 
    326   m_pPDFDoc = pPDFDoc;
    327   m_pStream = MakeSeekableReadStream(xfaStreams);
    328   return true;
    329 }
    330 
    331 bool CXFA_FFDoc::CloseDoc() {
    332   for (const auto& pair : m_TypeToDocViewMap)
    333     pair.second->RunDocClose();
    334 
    335   CXFA_Document* doc =
    336       m_pDocumentParser ? m_pDocumentParser->GetDocument() : nullptr;
    337   if (doc)
    338     doc->ClearLayoutData();
    339 
    340   m_TypeToDocViewMap.clear();
    341 
    342   m_pNotify.reset(nullptr);
    343   m_pApp->GetXFAFontMgr()->ReleaseDocFonts(this);
    344 
    345   for (const auto& pair : m_HashToDibDpiMap)
    346     delete pair.second.pDibSource;
    347 
    348   m_HashToDibDpiMap.clear();
    349   m_pApp->ClearEventTargets();
    350   return true;
    351 }
    352 void CXFA_FFDoc::SetDocType(uint32_t dwType) {
    353   m_dwDocType = dwType;
    354 }
    355 CPDF_Document* CXFA_FFDoc::GetPDFDoc() {
    356   return m_pPDFDoc;
    357 }
    358 
    359 CFX_DIBitmap* CXFA_FFDoc::GetPDFNamedImage(const CFX_WideStringC& wsName,
    360                                            int32_t& iImageXDpi,
    361                                            int32_t& iImageYDpi) {
    362   if (!m_pPDFDoc)
    363     return nullptr;
    364 
    365   uint32_t dwHash = FX_HashCode_GetW(wsName, false);
    366   auto it = m_HashToDibDpiMap.find(dwHash);
    367   if (it != m_HashToDibDpiMap.end()) {
    368     iImageXDpi = it->second.iImageXDpi;
    369     iImageYDpi = it->second.iImageYDpi;
    370     return static_cast<CFX_DIBitmap*>(it->second.pDibSource);
    371   }
    372 
    373   CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();
    374   if (!pRoot)
    375     return nullptr;
    376 
    377   CPDF_Dictionary* pNames = pRoot->GetDictFor("Names");
    378   if (!pNames)
    379     return nullptr;
    380 
    381   CPDF_Dictionary* pXFAImages = pNames->GetDictFor("XFAImages");
    382   if (!pXFAImages)
    383     return nullptr;
    384 
    385   CPDF_NameTree nametree(pXFAImages);
    386   CFX_ByteString bsName = PDF_EncodeText(wsName.c_str(), wsName.GetLength());
    387   CPDF_Object* pObject = nametree.LookupValue(bsName);
    388   if (!pObject) {
    389     for (size_t i = 0; i < nametree.GetCount(); i++) {
    390       CFX_ByteString bsTemp;
    391       CPDF_Object* pTempObject = nametree.LookupValue(i, bsTemp);
    392       if (bsTemp == bsName) {
    393         pObject = pTempObject;
    394         break;
    395       }
    396     }
    397   }
    398 
    399   CPDF_Stream* pStream = ToStream(pObject);
    400   if (!pStream)
    401     return nullptr;
    402 
    403   CPDF_StreamAcc streamAcc;
    404   streamAcc.LoadAllData(pStream);
    405 
    406   CFX_RetainPtr<IFX_SeekableReadStream> pImageFileRead =
    407       IFX_MemoryStream::Create((uint8_t*)streamAcc.GetData(),
    408                                streamAcc.GetSize());
    409 
    410   CFX_DIBitmap* pDibSource = XFA_LoadImageFromBuffer(
    411       pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi);
    412   m_HashToDibDpiMap[dwHash] = {pDibSource, iImageXDpi, iImageYDpi};
    413   return pDibSource;
    414 }
    415 
    416 bool CXFA_FFDoc::SavePackage(
    417     XFA_HashCode code,
    418     const CFX_RetainPtr<IFX_SeekableWriteStream>& pFile,
    419     CXFA_ChecksumContext* pCSContext) {
    420   CXFA_Document* doc = m_pDocumentParser->GetDocument();
    421   std::unique_ptr<CXFA_DataExporter> pExport(new CXFA_DataExporter(doc));
    422   CXFA_Node* pNode = code == XFA_HASHCODE_Xfa ? doc->GetRoot()
    423                                               : ToNode(doc->GetXFAObject(code));
    424   if (!pNode)
    425     return !!pExport->Export(pFile);
    426 
    427   CFX_ByteString bsChecksum;
    428   if (pCSContext)
    429     bsChecksum = pCSContext->GetChecksum();
    430 
    431   return !!pExport->Export(
    432       pFile, pNode, 0, bsChecksum.GetLength() ? bsChecksum.c_str() : nullptr);
    433 }
    434 
    435 bool CXFA_FFDoc::ImportData(
    436     const CFX_RetainPtr<IFX_SeekableReadStream>& pStream,
    437     bool bXDP) {
    438   auto importer =
    439       pdfium::MakeUnique<CXFA_DataImporter>(m_pDocumentParser->GetDocument());
    440   return importer->ImportData(pStream);
    441 }
    442