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