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