• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
base64DecoderValue(uint8_t val)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 
Base64DecodePiece(const char src[4],int32_t iChars,FX_BASE64DATA & dst,int32_t & iBytes)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 
Base64DecodeW(const wchar_t * pSrc,int32_t iSrcLen,uint8_t * pDst)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 
CXFA_FFDoc(CXFA_FFApp * pApp,IXFA_DocEnvironment * pDocEnvironment)161 CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocEnvironment* pDocEnvironment)
162     : m_pDocEnvironment(pDocEnvironment), m_pApp(pApp) {}
163 
~CXFA_FFDoc()164 CXFA_FFDoc::~CXFA_FFDoc() {
165   CloseDoc();
166 }
167 
StartLoad()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 
XFA_GetPDFContentsFromPDFXML(CFX_XMLNode * pPDFElement,uint8_t * & pByteBuffer,int32_t & iBufferSize)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 }
XFA_XPDPacket_MergeRootNode(CXFA_Node * pOriginRoot,CXFA_Node * pNewRoot)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 
DoLoad()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 
StopLoad()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 
CreateDocView()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 
GetDocView(CXFA_LayoutProcessor * pLayout)279 CXFA_FFDocView* CXFA_FFDoc::GetDocView(CXFA_LayoutProcessor* pLayout) {
280   return m_DocView && m_DocView->GetXFALayout() == pLayout ? m_DocView.get()
281                                                            : nullptr;
282 }
283 
GetDocView()284 CXFA_FFDocView* CXFA_FFDoc::GetDocView() {
285   return m_DocView.get();
286 }
287 
OpenDoc(CPDF_Document * pPDFDoc)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 
CloseDoc()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 
GetPDFNamedImage(const WideStringView & wsName,int32_t & iImageXDpi,int32_t & iImageYDpi)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 
SavePackage(CXFA_Node * pNode,const RetainPtr<IFX_SeekableStream> & pFile,CFX_ChecksumContext * pCSContext)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 
ImportData(const RetainPtr<IFX_SeekableStream> & pStream,bool bXDP)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