| // Copyright 2016 The PDFium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
 |  | 
 | #include "fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "core/fpdfapi/parser/cpdf_array.h" | 
 | #include "core/fpdfapi/parser/cpdf_dictionary.h" | 
 | #include "core/fpdfapi/parser/cpdf_stream.h" | 
 | #include "core/fpdfapi/parser/cpdf_stream_acc.h" | 
 | #include "core/fpdfapi/parser/cpdf_string.h" | 
 | #include "core/fxcrt/retain_ptr.h" | 
 | #include "fpdfsdk/cpdfsdk_formfillenvironment.h" | 
 | #include "fpdfsdk/cpdfsdk_helpers.h" | 
 | #include "fpdfsdk/cpdfsdk_interactiveform.h" | 
 | #include "fpdfsdk/cpdfsdk_pageview.h" | 
 | #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h" | 
 | #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" | 
 | #include "third_party/base/check.h" | 
 | #include "xfa/fxfa/cxfa_ffdocview.h" | 
 | #include "xfa/fxfa/cxfa_ffwidget.h" | 
 | #include "xfa/fxfa/cxfa_ffwidgethandler.h" | 
 | #include "xfa/fxfa/cxfa_readynodeiterator.h" | 
 | #include "xfa/fxfa/parser/cxfa_node.h" | 
 | #include "xfa/fxfa/parser/cxfa_submit.h" | 
 |  | 
 | #define IDS_XFA_Validate_Input                                          \ | 
 |   "At least one required field was empty. Please fill in the required " \ | 
 |   "fields\r\n(highlighted) before continuing." | 
 |  | 
 | // submit | 
 | #define FXFA_CONFIG 0x00000001 | 
 | #define FXFA_TEMPLATE 0x00000010 | 
 | #define FXFA_LOCALESET 0x00000100 | 
 | #define FXFA_DATASETS 0x00001000 | 
 | #define FXFA_XMPMETA 0x00010000 | 
 | #define FXFA_XFDF 0x00100000 | 
 | #define FXFA_FORM 0x01000000 | 
 | #define FXFA_PDF 0x10000000 | 
 | #define FXFA_XFA_ALL 0x01111111 | 
 |  | 
 | // Although there isn't direct casting between these types at present, | 
 | // keep the internal and exernal types in sync. | 
 | static_assert(FXFA_PAGEVIEWEVENT_POSTADDED == | 
 |                   static_cast<int>(CXFA_FFDoc::PageViewEvent::kPostAdded), | 
 |               "kPostAdded mismatch"); | 
 | static_assert(FXFA_PAGEVIEWEVENT_POSTREMOVED == | 
 |                   static_cast<int>(CXFA_FFDoc::PageViewEvent::kPostRemoved), | 
 |               "kPostRemoved mismatch"); | 
 |  | 
 | CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext) | 
 |     : m_pContext(pContext) { | 
 |   DCHECK(m_pContext); | 
 | } | 
 |  | 
 | CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() = default; | 
 |  | 
 | void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) { | 
 |   if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv()) | 
 |     m_pContext->GetFormFillEnv()->SetChangeMark(); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::InvalidateRect(CXFA_FFPageView* pPageView, | 
 |                                             const CFX_RectF& rt) { | 
 |   if (!m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return; | 
 |  | 
 |   if (m_pContext->GetFormType() != FormType::kXFAFull) | 
 |     return; | 
 |  | 
 |   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView); | 
 |   if (!pPage) | 
 |     return; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return; | 
 |  | 
 |   pFormFillEnv->Invalidate(pPage.Get(), rt.ToFloatRect().ToFxRect()); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget, | 
 |                                           bool bVisible, | 
 |                                           const CFX_RectF* pRtAnchor) { | 
 |   if (!hWidget || !pRtAnchor || !m_pContext->GetXFADoc() || | 
 |       !m_pContext->GetFormFillEnv() || !m_pContext->GetXFADocView()) | 
 |     return; | 
 |  | 
 |   if (m_pContext->GetFormType() != FormType::kXFAFull) | 
 |     return; | 
 |  | 
 |   CXFA_FFWidgetHandler* pWidgetHandler = | 
 |       m_pContext->GetXFADocView()->GetWidgetHandler(); | 
 |   if (!pWidgetHandler) | 
 |     return; | 
 |  | 
 |   CXFA_FFPageView* pPageView = hWidget->GetPageView(); | 
 |   if (!pPageView) | 
 |     return; | 
 |  | 
 |   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView); | 
 |   if (!pPage) | 
 |     return; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return; | 
 |  | 
 |   CFX_FloatRect rcCaret = pRtAnchor->ToFloatRect(); | 
 |   pFormFillEnv->DisplayCaret(pPage.Get(), bVisible, rcCaret.left, rcCaret.top, | 
 |                              rcCaret.right, rcCaret.bottom); | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::GetPopupPos(CXFA_FFWidget* hWidget, | 
 |                                          float fMinPopup, | 
 |                                          float fMaxPopup, | 
 |                                          const CFX_RectF& rtAnchor, | 
 |                                          CFX_RectF* pPopupRect) { | 
 |   if (!hWidget) | 
 |     return false; | 
 |  | 
 |   CXFA_FFPageView* pXFAPageView = hWidget->GetPageView(); | 
 |   if (!pXFAPageView) | 
 |     return false; | 
 |  | 
 |   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView); | 
 |   if (!pPage) | 
 |     return false; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return false; | 
 |  | 
 |   FS_RECTF page_view_rect = pFormFillEnv->GetPageViewRect(pPage.Get()); | 
 |   int nRotate = hWidget->GetNode()->GetRotate(); | 
 |  | 
 |   int space_available_below_anchor; | 
 |   int space_available_above_anchor; | 
 |   switch (nRotate) { | 
 |     case 0: | 
 |     default: { | 
 |       space_available_below_anchor = | 
 |           static_cast<int>(page_view_rect.bottom - rtAnchor.bottom()); | 
 |       space_available_above_anchor = | 
 |           static_cast<int>(rtAnchor.top - page_view_rect.top); | 
 |  | 
 |       if (rtAnchor.left < page_view_rect.left) | 
 |         pPopupRect->left += page_view_rect.left - rtAnchor.left; | 
 |       if (rtAnchor.right() > page_view_rect.right) | 
 |         pPopupRect->left -= rtAnchor.right() - page_view_rect.right; | 
 |       break; | 
 |     } | 
 |     case 90: { | 
 |       space_available_below_anchor = | 
 |           static_cast<int>(page_view_rect.right - rtAnchor.right()); | 
 |       space_available_above_anchor = | 
 |           static_cast<int>(rtAnchor.left - page_view_rect.left); | 
 |  | 
 |       if (rtAnchor.bottom() > page_view_rect.bottom) | 
 |         pPopupRect->left += rtAnchor.bottom() - page_view_rect.bottom; | 
 |       if (rtAnchor.top < page_view_rect.top) | 
 |         pPopupRect->left -= page_view_rect.top - rtAnchor.top; | 
 |       break; | 
 |     } | 
 |     case 180: { | 
 |       space_available_below_anchor = | 
 |           static_cast<int>(rtAnchor.top - page_view_rect.top); | 
 |       space_available_above_anchor = | 
 |           static_cast<int>(page_view_rect.bottom - rtAnchor.bottom()); | 
 |  | 
 |       if (rtAnchor.right() > page_view_rect.right) | 
 |         pPopupRect->left += rtAnchor.right() - page_view_rect.right; | 
 |       if (rtAnchor.left < page_view_rect.left) | 
 |         pPopupRect->left -= page_view_rect.left - rtAnchor.left; | 
 |       break; | 
 |     } | 
 |     case 270: { | 
 |       space_available_below_anchor = | 
 |           static_cast<int>(rtAnchor.left - page_view_rect.left); | 
 |       space_available_above_anchor = | 
 |           static_cast<int>(page_view_rect.right - rtAnchor.right()); | 
 |  | 
 |       if (rtAnchor.top < page_view_rect.top) | 
 |         pPopupRect->left += page_view_rect.top - rtAnchor.top; | 
 |       if (rtAnchor.bottom() > page_view_rect.bottom) | 
 |         pPopupRect->left -= rtAnchor.bottom() - page_view_rect.bottom; | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   // If there is no space on either side, the popup can't be rendered. | 
 |   if (space_available_below_anchor <= 0 && space_available_above_anchor <= 0) | 
 |     return false; | 
 |  | 
 |   // Determine whether to draw above or below the anchor. | 
 |   bool draw_below_anchor; | 
 |   if (space_available_below_anchor <= 0) | 
 |     draw_below_anchor = false; | 
 |   else if (space_available_above_anchor <= 0) | 
 |     draw_below_anchor = true; | 
 |   else if (space_available_below_anchor > space_available_above_anchor) | 
 |     draw_below_anchor = true; | 
 |   else | 
 |     draw_below_anchor = false; | 
 |  | 
 |   int space_available = (draw_below_anchor ? space_available_below_anchor | 
 |                                            : space_available_above_anchor); | 
 |  | 
 |   // Set the popup height and y position according to what was decided above. | 
 |   float popup_height; | 
 |   if (space_available < fMinPopup) | 
 |     popup_height = fMinPopup; | 
 |   else if (space_available > fMaxPopup) | 
 |     popup_height = fMaxPopup; | 
 |   else | 
 |     popup_height = static_cast<float>(space_available); | 
 |  | 
 |   switch (nRotate) { | 
 |     case 0: | 
 |     case 180: { | 
 |       if (draw_below_anchor) | 
 |         pPopupRect->top = rtAnchor.height; | 
 |       else | 
 |         pPopupRect->top = -popup_height; | 
 |       break; | 
 |     } | 
 |     case 90: | 
 |     case 270: { | 
 |       if (draw_below_anchor) | 
 |         pPopupRect->top = rtAnchor.width; | 
 |       else | 
 |         pPopupRect->top = -popup_height; | 
 |       break; | 
 |     } | 
 |     default: | 
 |       break; | 
 |   } | 
 |  | 
 |   pPopupRect->height = popup_height; | 
 |   return true; | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::PopupMenu(CXFA_FFWidget* hWidget, | 
 |                                        const CFX_PointF& ptPopup) { | 
 |   if (!hWidget) | 
 |     return false; | 
 |  | 
 |   CXFA_FFPageView* pXFAPageView = hWidget->GetPageView(); | 
 |   if (!pXFAPageView) | 
 |     return false; | 
 |  | 
 |   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView); | 
 |   if (!pPage) | 
 |     return false; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return false; | 
 |  | 
 |   int menuFlag = 0; | 
 |   if (hWidget->CanUndo()) | 
 |     menuFlag |= FXFA_MENU_UNDO; | 
 |   if (hWidget->CanRedo()) | 
 |     menuFlag |= FXFA_MENU_REDO; | 
 |   if (hWidget->CanPaste()) | 
 |     menuFlag |= FXFA_MENU_PASTE; | 
 |   if (hWidget->CanCopy()) | 
 |     menuFlag |= FXFA_MENU_COPY; | 
 |   if (hWidget->CanCut()) | 
 |     menuFlag |= FXFA_MENU_CUT; | 
 |   if (hWidget->CanSelectAll()) | 
 |     menuFlag |= FXFA_MENU_SELECTALL; | 
 |  | 
 |   return pFormFillEnv->PopupMenu(pPage.Get(), menuFlag, ptPopup); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::OnPageViewEvent(CXFA_FFPageView* pPageView, | 
 |                                              CXFA_FFDoc::PageViewEvent eEvent) { | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return; | 
 |  | 
 |   if (m_pContext->GetLoadStatus() == CPDFXFA_Context::LoadStatus::kLoading || | 
 |       m_pContext->GetLoadStatus() == CPDFXFA_Context::LoadStatus::kClosing || | 
 |       eEvent != CXFA_FFDoc::PageViewEvent::kStopLayout) { | 
 |     return; | 
 |   } | 
 |   int nNewCount = m_pContext->GetPageCount(); | 
 |   if (nNewCount == m_pContext->GetOriginalPageCount()) | 
 |     return; | 
 |  | 
 |   CXFA_FFDocView* pXFADocView = m_pContext->GetXFADocView(); | 
 |   if (!pXFADocView) | 
 |     return; | 
 |  | 
 |   for (int i = 0; i < m_pContext->GetOriginalPageCount(); ++i) { | 
 |     RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(i); | 
 |     if (!pPage) | 
 |       continue; | 
 |  | 
 |     m_pContext->GetFormFillEnv()->RemovePageView(pPage.Get()); | 
 |     pPage->SetXFAPageViewIndex(i); | 
 |   } | 
 |  | 
 |   int flag = (nNewCount < m_pContext->GetOriginalPageCount()) | 
 |                  ? FXFA_PAGEVIEWEVENT_POSTREMOVED | 
 |                  : FXFA_PAGEVIEWEVENT_POSTADDED; | 
 |   int count = abs(nNewCount - m_pContext->GetOriginalPageCount()); | 
 |   m_pContext->SetOriginalPageCount(nNewCount); | 
 |   pFormFillEnv->PageEvent(count, flag); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::WidgetPostAdd(CXFA_FFWidget* hWidget) { | 
 |   if (m_pContext->GetFormType() != FormType::kXFAFull) | 
 |     return; | 
 |  | 
 |   CXFA_FFPageView* pPageView = hWidget->GetPageView(); | 
 |   if (!pPageView) | 
 |     return; | 
 |  | 
 |   RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView); | 
 |   if (!pXFAPage) | 
 |     return; | 
 |  | 
 |   auto* formfill = m_pContext->GetFormFillEnv(); | 
 |   formfill->GetOrCreatePageView(pXFAPage.Get())->AddAnnotForFFWidget(hWidget); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget) { | 
 |   if (m_pContext->GetFormType() != FormType::kXFAFull) | 
 |     return; | 
 |  | 
 |   CXFA_FFPageView* pPageView = hWidget->GetPageView(); | 
 |   if (!pPageView) | 
 |     return; | 
 |  | 
 |   RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView); | 
 |   if (!pXFAPage) | 
 |     return; | 
 |  | 
 |   CPDFSDK_PageView* pSdkPageView = | 
 |       m_pContext->GetFormFillEnv()->GetOrCreatePageView(pXFAPage.Get()); | 
 |   pSdkPageView->DeleteAnnotForFFWidget(hWidget); | 
 | } | 
 |  | 
 | int32_t CPDFXFA_DocEnvironment::CountPages(const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv()) | 
 |     return m_pContext->GetPageCount(); | 
 |   return 0; | 
 | } | 
 |  | 
 | int32_t CPDFXFA_DocEnvironment::GetCurrentPage(const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return -1; | 
 |  | 
 |   if (m_pContext->GetFormType() != FormType::kXFAFull) | 
 |     return -1; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   return pFormFillEnv ? pFormFillEnv->GetCurrentPageIndex() : -1; | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc, | 
 |                                             int32_t iCurPage) { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv() || | 
 |       !m_pContext->ContainsExtensionForm() || iCurPage < 0 || | 
 |       iCurPage >= m_pContext->GetFormFillEnv()->GetPageCount()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return; | 
 |  | 
 |   pFormFillEnv->SetCurrentPage(iCurPage); | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::IsCalculationsEnabled( | 
 |     const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return false; | 
 |   auto* pForm = m_pContext->GetFormFillEnv()->GetInteractiveForm(); | 
 |   return pForm->IsXfaCalculateEnabled(); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::SetCalculationsEnabled(CXFA_FFDoc* hDoc, | 
 |                                                     bool bEnabled) { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return; | 
 |   m_pContext->GetFormFillEnv()->GetInteractiveForm()->XfaEnableCalculate( | 
 |       bEnabled); | 
 | } | 
 |  | 
 | WideString CPDFXFA_DocEnvironment::GetTitle(const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return WideString(); | 
 |  | 
 |   CPDF_Document* pPDFDoc = m_pContext->GetPDFDoc(); | 
 |   if (!pPDFDoc) | 
 |     return WideString(); | 
 |  | 
 |   RetainPtr<const CPDF_Dictionary> pInfoDict = pPDFDoc->GetInfo(); | 
 |   if (!pInfoDict) | 
 |     return WideString(); | 
 |  | 
 |   ByteString csTitle = pInfoDict->GetByteStringFor("Title"); | 
 |   return WideString::FromDefANSI(csTitle.AsStringView()); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc, | 
 |                                       const WideString& wsTitle) { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return; | 
 |  | 
 |   CPDF_Document* pPDFDoc = m_pContext->GetPDFDoc(); | 
 |   if (!pPDFDoc) | 
 |     return; | 
 |  | 
 |   RetainPtr<CPDF_Dictionary> pInfoDict = pPDFDoc->GetInfo(); | 
 |   if (pInfoDict) | 
 |     pInfoDict->SetNewFor<CPDF_String>("Title", wsTitle.AsStringView()); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc, | 
 |                                         const WideString& wsFilePath, | 
 |                                         bool bXDP) { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return; | 
 |  | 
 |   if (!m_pContext->ContainsExtensionForm()) | 
 |     return; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return; | 
 |  | 
 |   int fileType = bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML; | 
 |   ByteString bs = wsFilePath.ToUTF16LE(); | 
 |   if (wsFilePath.IsEmpty()) { | 
 |     if (!pFormFillEnv->GetFormFillInfo() || | 
 |         !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform) { | 
 |       return; | 
 |     } | 
 |  | 
 |     WideString filepath = pFormFillEnv->JS_fieldBrowse(); | 
 |     bs = filepath.ToUTF16LE(); | 
 |   } | 
 |   FPDF_FILEHANDLER* pFileHandler = pFormFillEnv->OpenFile( | 
 |       bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML, AsFPDFWideString(&bs), "wb"); | 
 |   if (!pFileHandler) | 
 |     return; | 
 |  | 
 |   RetainPtr<IFX_SeekableStream> fileWrite = MakeSeekableStream(pFileHandler); | 
 |   if (fileType == FXFA_SAVEAS_XML) { | 
 |     fileWrite->WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"); | 
 |     CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc(); | 
 |     ffdoc->SavePackage( | 
 |         ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileWrite); | 
 |   } else if (fileType == FXFA_SAVEAS_XDP) { | 
 |     if (!m_pContext->GetPDFDoc()) | 
 |       return; | 
 |  | 
 |     const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot(); | 
 |     if (!pRoot) | 
 |       return; | 
 |  | 
 |     RetainPtr<const CPDF_Dictionary> pAcroForm = pRoot->GetDictFor("AcroForm"); | 
 |     if (!pAcroForm) | 
 |       return; | 
 |  | 
 |     RetainPtr<const CPDF_Array> pArray = | 
 |         ToArray(pAcroForm->GetObjectFor("XFA")); | 
 |     if (!pArray) | 
 |       return; | 
 |  | 
 |     for (size_t i = 1; i < pArray->size(); i += 2) { | 
 |       RetainPtr<const CPDF_Object> pPDFObj = pArray->GetObjectAt(i); | 
 |       RetainPtr<const CPDF_Object> pPrePDFObj = pArray->GetObjectAt(i - 1); | 
 |       if (!pPrePDFObj->IsString()) | 
 |         continue; | 
 |       if (!pPDFObj->IsReference()) | 
 |         continue; | 
 |  | 
 |       RetainPtr<const CPDF_Stream> pStream = ToStream(pPDFObj->GetDirect()); | 
 |       if (!pStream) | 
 |         continue; | 
 |       if (pPrePDFObj->GetString() == "form") { | 
 |         CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc(); | 
 |         ffdoc->SavePackage( | 
 |             ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)), | 
 |             fileWrite); | 
 |         continue; | 
 |       } | 
 |       if (pPrePDFObj->GetString() == "datasets") { | 
 |         CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc(); | 
 |         ffdoc->SavePackage( | 
 |             ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)), | 
 |             fileWrite); | 
 |         continue; | 
 |       } | 
 |       if (i == pArray->size() - 1) { | 
 |         WideString wPath = WideString::FromUTF16LE( | 
 |             reinterpret_cast<const unsigned short*>(bs.c_str()), | 
 |             bs.GetLength() / sizeof(unsigned short)); | 
 |         ByteString bPath = wPath.ToUTF8(); | 
 |         static const char kFormat[] = | 
 |             "\n<pdf href=\"%s\" xmlns=\"http://ns.adobe.com/xdp/pdf/\"/>"; | 
 |         ByteString content = ByteString::Format(kFormat, bPath.c_str()); | 
 |         fileWrite->WriteString(content.AsStringView()); | 
 |       } | 
 |       auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream)); | 
 |       pAcc->LoadAllDataFiltered(); | 
 |       fileWrite->WriteBlock(pAcc->GetSpan()); | 
 |     } | 
 |   } | 
 |   fileWrite->Flush(); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc, | 
 |                                      const WideString& wsURL) { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return; | 
 |  | 
 |   if (m_pContext->GetFormType() != FormType::kXFAFull) | 
 |     return; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return; | 
 |  | 
 |   pFormFillEnv->GotoURL(wsURL); | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::IsValidationsEnabled( | 
 |     const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return false; | 
 |  | 
 |   auto* pForm = m_pContext->GetFormFillEnv()->GetInteractiveForm(); | 
 |   return pForm->IsXfaValidationsEnabled(); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::SetValidationsEnabled(CXFA_FFDoc* hDoc, | 
 |                                                    bool bEnabled) { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return; | 
 |  | 
 |   m_pContext->GetFormFillEnv()->GetInteractiveForm()->XfaSetValidationsEnabled( | 
 |       bEnabled); | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::SetFocusWidget(CXFA_FFDoc* hDoc, | 
 |                                             CXFA_FFWidget* hWidget) { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return; | 
 |  | 
 |   if (!hWidget) { | 
 |     ObservedPtr<CPDFSDK_Annot> pNull; | 
 |     m_pContext->GetFormFillEnv()->SetFocusAnnot(pNull); | 
 |     return; | 
 |   } | 
 |  | 
 |   int pageViewCount = m_pContext->GetFormFillEnv()->GetPageViewCount(); | 
 |   for (int i = 0; i < pageViewCount; i++) { | 
 |     CPDFSDK_PageView* pPageView = | 
 |         m_pContext->GetFormFillEnv()->GetPageViewAtIndex(i); | 
 |     if (!pPageView) | 
 |       continue; | 
 |  | 
 |     ObservedPtr<CPDFSDK_Annot> pAnnot(pPageView->GetAnnotForFFWidget(hWidget)); | 
 |     if (pAnnot) { | 
 |       m_pContext->GetFormFillEnv()->SetFocusAnnot(pAnnot); | 
 |       break; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc, | 
 |                                    int32_t nStartPage, | 
 |                                    int32_t nEndPage, | 
 |                                    Mask<XFA_PrintOpt> dwOptions) { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv || !pFormFillEnv->GetFormFillInfo() || | 
 |       !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform || | 
 |       !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print) { | 
 |     return; | 
 |   } | 
 |  | 
 |   pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print( | 
 |       pFormFillEnv->GetFormFillInfo()->m_pJsPlatform, | 
 |       !!(dwOptions & XFA_PrintOpt::kShowDialog), nStartPage, nEndPage, | 
 |       !!(dwOptions & XFA_PrintOpt::kCanCancel), | 
 |       !!(dwOptions & XFA_PrintOpt::kShrinkPage), | 
 |       !!(dwOptions & XFA_PrintOpt::kAsImage), | 
 |       !!(dwOptions & XFA_PrintOpt::kReverseOrder), | 
 |       !!(dwOptions & XFA_PrintOpt::kPrintAnnot)); | 
 | } | 
 |  | 
 | FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor( | 
 |     const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | 
 |     return 0; | 
 |  | 
 |   CPDFSDK_InteractiveForm* pForm = | 
 |       m_pContext->GetFormFillEnv()->GetInteractiveForm(); | 
 |   return AlphaAndColorRefToArgb(pForm->GetHighlightAlpha(), | 
 |                                 pForm->GetHighlightColor(FormFieldType::kXFA)); | 
 | } | 
 |  | 
 | IJS_Runtime* CPDFXFA_DocEnvironment::GetIJSRuntime( | 
 |     const CXFA_FFDoc* hDoc) const { | 
 |   if (hDoc != m_pContext->GetXFADoc()) | 
 |     return nullptr; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   return pFormFillEnv ? pFormFillEnv->GetIJSRuntime() : nullptr; | 
 | } | 
 |  | 
 | CFX_XMLDocument* CPDFXFA_DocEnvironment::GetXMLDoc() const { | 
 |   return m_pContext->GetXMLDoc(); | 
 | } | 
 |  | 
 | RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile( | 
 |     CXFA_FFDoc* hDoc, | 
 |     const WideString& wsLink) { | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return nullptr; | 
 |  | 
 |   ByteString bs = wsLink.ToUTF16LE(); | 
 |   FPDF_FILEHANDLER* pFileHandler = | 
 |       pFormFillEnv->OpenFile(0, AsFPDFWideString(&bs), "rb"); | 
 |   if (!pFileHandler) | 
 |     return nullptr; | 
 |  | 
 |   return MakeSeekableStream(pFileHandler); | 
 | } | 
 |  | 
 | #ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED | 
 | bool CPDFXFA_DocEnvironment::Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) { | 
 |   if (!OnBeforeNotifySubmit() || !m_pContext->GetXFADocView()) | 
 |     return false; | 
 |  | 
 |   m_pContext->GetXFADocView()->UpdateDocView(); | 
 |   bool ret = SubmitInternal(hDoc, submit); | 
 |   OnAfterNotifySubmit(); | 
 |   return ret; | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::MailToInfo(WideString& csURL, | 
 |                                         WideString& csToAddress, | 
 |                                         WideString& csCCAddress, | 
 |                                         WideString& csBCCAddress, | 
 |                                         WideString& csSubject, | 
 |                                         WideString& csMsg) { | 
 |   WideString srcURL = csURL; | 
 |   srcURL.TrimLeft(); | 
 |   if (srcURL.Left(7).CompareNoCase(L"mailto:") != 0) | 
 |     return false; | 
 |  | 
 |   auto pos = srcURL.Find(L'?'); | 
 |  | 
 |   { | 
 |     WideString tmp; | 
 |     if (!pos.has_value()) { | 
 |       pos = srcURL.Find(L'@'); | 
 |       if (!pos.has_value()) | 
 |         return false; | 
 |  | 
 |       tmp = srcURL.Right(csURL.GetLength() - 7); | 
 |     } else { | 
 |       tmp = srcURL.Left(pos.value()); | 
 |       tmp = tmp.Right(tmp.GetLength() - 7); | 
 |     } | 
 |     tmp.Trim(); | 
 |     csToAddress = std::move(tmp); | 
 |   } | 
 |  | 
 |   srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1)); | 
 |   while (!srcURL.IsEmpty()) { | 
 |     srcURL.Trim(); | 
 |     pos = srcURL.Find(L'&'); | 
 |     WideString tmp = (!pos.has_value()) ? srcURL : srcURL.Left(pos.value()); | 
 |     tmp.Trim(); | 
 |     if (tmp.GetLength() >= 3 && tmp.Left(3).CompareNoCase(L"cc=") == 0) { | 
 |       tmp = tmp.Right(tmp.GetLength() - 3); | 
 |       if (!csCCAddress.IsEmpty()) | 
 |         csCCAddress += L';'; | 
 |       csCCAddress += tmp; | 
 |     } else if (tmp.GetLength() >= 4 && | 
 |                tmp.Left(4).CompareNoCase(L"bcc=") == 0) { | 
 |       tmp = tmp.Right(tmp.GetLength() - 4); | 
 |       if (!csBCCAddress.IsEmpty()) | 
 |         csBCCAddress += L';'; | 
 |       csBCCAddress += tmp; | 
 |     } else if (tmp.GetLength() >= 8 && | 
 |                tmp.Left(8).CompareNoCase(L"subject=") == 0) { | 
 |       tmp = tmp.Right(tmp.GetLength() - 8); | 
 |       csSubject += tmp; | 
 |     } else if (tmp.GetLength() >= 5 && | 
 |                tmp.Left(5).CompareNoCase(L"body=") == 0) { | 
 |       tmp = tmp.Right(tmp.GetLength() - 5); | 
 |       csMsg += tmp; | 
 |     } | 
 |     srcURL = pos.has_value() | 
 |                  ? srcURL.Right(csURL.GetLength() - (pos.value() + 1)) | 
 |                  : WideString(); | 
 |   } | 
 |   csToAddress.Replace(L",", L";"); | 
 |   csCCAddress.Replace(L",", L";"); | 
 |   csBCCAddress.Replace(L",", L";"); | 
 |   return true; | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::ExportSubmitFile(FPDF_FILEHANDLER* pFileHandler, | 
 |                                               int fileType, | 
 |                                               FPDF_DWORD encodeType, | 
 |                                               FPDF_DWORD flag) { | 
 |   if (!m_pContext->GetXFADocView()) | 
 |     return false; | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return false; | 
 |  | 
 |   CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc(); | 
 |   RetainPtr<IFX_SeekableStream> fileStream = MakeSeekableStream(pFileHandler); | 
 |   if (fileType == FXFA_SAVEAS_XML) { | 
 |     fileStream->WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"); | 
 |     ffdoc->SavePackage( | 
 |         ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), | 
 |         fileStream); | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (fileType != FXFA_SAVEAS_XDP) | 
 |     return true; | 
 |  | 
 |   if (!flag) { | 
 |     flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS | | 
 |            FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM; | 
 |   } | 
 |   if (!m_pContext->GetPDFDoc()) { | 
 |     fileStream->Flush(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot(); | 
 |   if (!pRoot) { | 
 |     fileStream->Flush(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   RetainPtr<const CPDF_Dictionary> pAcroForm = pRoot->GetDictFor("AcroForm"); | 
 |   if (!pAcroForm) { | 
 |     fileStream->Flush(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   RetainPtr<const CPDF_Array> pArray = ToArray(pAcroForm->GetObjectFor("XFA")); | 
 |   if (!pArray) { | 
 |     fileStream->Flush(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   for (size_t i = 1; i < pArray->size(); i += 2) { | 
 |     RetainPtr<const CPDF_Object> pPDFObj = pArray->GetObjectAt(i); | 
 |     RetainPtr<const CPDF_Object> pPrePDFObj = pArray->GetObjectAt(i - 1); | 
 |     if (!pPrePDFObj->IsString()) | 
 |       continue; | 
 |     if (!pPDFObj->IsReference()) | 
 |       continue; | 
 |  | 
 |     RetainPtr<const CPDF_Object> pDirectObj = pPDFObj->GetDirect(); | 
 |     if (!pDirectObj->IsStream()) | 
 |       continue; | 
 |     ByteString bsType = pPrePDFObj->GetString(); | 
 |     if (bsType == "config" && !(flag & FXFA_CONFIG)) | 
 |       continue; | 
 |     if (bsType == "template" && !(flag & FXFA_TEMPLATE)) | 
 |       continue; | 
 |     if (bsType == "localeSet" && !(flag & FXFA_LOCALESET)) | 
 |       continue; | 
 |     if (bsType == "datasets" && !(flag & FXFA_DATASETS)) | 
 |       continue; | 
 |     if (bsType == "xmpmeta" && !(flag & FXFA_XMPMETA)) | 
 |       continue; | 
 |     if (bsType == "xfdf" && !(flag & FXFA_XFDF)) | 
 |       continue; | 
 |     if (bsType == "form" && !(flag & FXFA_FORM)) | 
 |       continue; | 
 |  | 
 |     if (bsType == "form") { | 
 |       ffdoc->SavePackage( | 
 |           ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)), | 
 |           fileStream); | 
 |     } else if (pPrePDFObj->GetString() == "datasets") { | 
 |       ffdoc->SavePackage( | 
 |           ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)), | 
 |           fileStream); | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::ToXFAContentFlags(WideString csSrcContent, | 
 |                                                FPDF_DWORD& flag) { | 
 |   if (csSrcContent.Contains(L" config ")) | 
 |     flag |= FXFA_CONFIG; | 
 |   if (csSrcContent.Contains(L" template ")) | 
 |     flag |= FXFA_TEMPLATE; | 
 |   if (csSrcContent.Contains(L" localeSet ")) | 
 |     flag |= FXFA_LOCALESET; | 
 |   if (csSrcContent.Contains(L" datasets ")) | 
 |     flag |= FXFA_DATASETS; | 
 |   if (csSrcContent.Contains(L" xmpmeta ")) | 
 |     flag |= FXFA_XMPMETA; | 
 |   if (csSrcContent.Contains(L" xfdf ")) | 
 |     flag |= FXFA_XFDF; | 
 |   if (csSrcContent.Contains(L" form ")) | 
 |     flag |= FXFA_FORM; | 
 |   if (flag == 0) { | 
 |     flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS | | 
 |            FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM; | 
 |   } | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::OnBeforeNotifySubmit() { | 
 |   if (!m_pContext->ContainsXFAForm()) | 
 |     return true; | 
 |  | 
 |   CXFA_FFDocView* docView = m_pContext->GetXFADocView(); | 
 |   if (!docView) | 
 |     return true; | 
 |  | 
 |   CXFA_FFWidgetHandler* pWidgetHandler = docView->GetWidgetHandler(); | 
 |   if (!pWidgetHandler) | 
 |     return true; | 
 |  | 
 |   auto it = docView->CreateReadyNodeIterator(); | 
 |   if (it) { | 
 |     CXFA_EventParam Param; | 
 |     Param.m_eType = XFA_EVENT_PreSubmit; | 
 |     while (CXFA_Node* pNode = it->MoveToNext()) | 
 |       pWidgetHandler->ProcessEvent(pNode, &Param); | 
 |   } | 
 |  | 
 |   it = docView->CreateReadyNodeIterator(); | 
 |   if (!it) | 
 |     return true; | 
 |  | 
 |   (void)it->MoveToNext(); | 
 |   CXFA_Node* pNode = it->MoveToNext(); | 
 |  | 
 |   while (pNode) { | 
 |     if (pNode->ProcessValidate(docView, -1) == XFA_EventError::kError) { | 
 |       CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |       if (!pFormFillEnv) | 
 |         return false; | 
 |  | 
 |       pFormFillEnv->JS_appAlert(WideString::FromDefANSI(IDS_XFA_Validate_Input), | 
 |                                 WideString(), JSPLATFORM_ALERT_BUTTON_OK, | 
 |                                 JSPLATFORM_ALERT_ICON_WARNING); | 
 |       return false; | 
 |     } | 
 |     pNode = it->MoveToNext(); | 
 |   } | 
 |  | 
 |   docView->UpdateDocView(); | 
 |   return true; | 
 | } | 
 |  | 
 | void CPDFXFA_DocEnvironment::OnAfterNotifySubmit() { | 
 |   if (!m_pContext->ContainsXFAForm()) | 
 |     return; | 
 |  | 
 |   if (!m_pContext->GetXFADocView()) | 
 |     return; | 
 |  | 
 |   CXFA_FFWidgetHandler* pWidgetHandler = | 
 |       m_pContext->GetXFADocView()->GetWidgetHandler(); | 
 |   if (!pWidgetHandler) | 
 |     return; | 
 |  | 
 |   auto it = m_pContext->GetXFADocView()->CreateReadyNodeIterator(); | 
 |   if (!it) | 
 |     return; | 
 |  | 
 |   CXFA_EventParam Param; | 
 |   Param.m_eType = XFA_EVENT_PostSubmit; | 
 |   CXFA_Node* pNode = it->MoveToNext(); | 
 |   while (pNode) { | 
 |     pWidgetHandler->ProcessEvent(pNode, &Param); | 
 |     pNode = it->MoveToNext(); | 
 |   } | 
 |   m_pContext->GetXFADocView()->UpdateDocView(); | 
 | } | 
 |  | 
 | bool CPDFXFA_DocEnvironment::SubmitInternal(CXFA_FFDoc* hDoc, | 
 |                                             CXFA_Submit* submit) { | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return false; | 
 |  | 
 |   WideString csURL = submit->GetSubmitTarget(); | 
 |   if (csURL.IsEmpty()) { | 
 |     pFormFillEnv->JS_appAlert(WideString::FromDefANSI("Submit cancelled."), | 
 |                               WideString(), JSPLATFORM_ALERT_BUTTON_OK, | 
 |                               JSPLATFORM_ALERT_ICON_ASTERISK); | 
 |     return false; | 
 |   } | 
 |  | 
 |   FPDF_FILEHANDLER* pFileHandler = nullptr; | 
 |   int fileFlag = -1; | 
 |   switch (submit->GetSubmitFormat()) { | 
 |     case XFA_AttributeValue::Xdp: { | 
 |       WideString csContent = submit->GetSubmitXDPContent(); | 
 |       csContent.Trim(); | 
 |  | 
 |       WideString space = WideString::FromDefANSI(" "); | 
 |       csContent = space + csContent + space; | 
 |       FPDF_DWORD flag = 0; | 
 |       if (submit->IsSubmitEmbedPDF()) | 
 |         flag |= FXFA_PDF; | 
 |  | 
 |       ToXFAContentFlags(csContent, flag); | 
 |       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XDP, nullptr, "wb"); | 
 |       fileFlag = FXFA_SAVEAS_XDP; | 
 |       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XDP, 0, flag); | 
 |       break; | 
 |     } | 
 |     case XFA_AttributeValue::Xml: | 
 |       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb"); | 
 |       fileFlag = FXFA_SAVEAS_XML; | 
 |       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL); | 
 |       break; | 
 |     case XFA_AttributeValue::Pdf: | 
 |       break; | 
 |     case XFA_AttributeValue::Urlencoded: | 
 |       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb"); | 
 |       fileFlag = FXFA_SAVEAS_XML; | 
 |       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL); | 
 |       break; | 
 |     default: | 
 |       return false; | 
 |   } | 
 |   if (!pFileHandler) | 
 |     return false; | 
 |  | 
 |   if (csURL.Left(7).CompareNoCase(L"mailto:") == 0) { | 
 |     WideString csToAddress; | 
 |     WideString csCCAddress; | 
 |     WideString csBCCAddress; | 
 |     WideString csSubject; | 
 |     WideString csMsg; | 
 |     if (!MailToInfo(csURL, csToAddress, csCCAddress, csBCCAddress, csSubject, | 
 |                     csMsg)) { | 
 |       return false; | 
 |     } | 
 |     ByteString bsTo = WideString(csToAddress).ToUTF16LE(); | 
 |     ByteString bsCC = WideString(csCCAddress).ToUTF16LE(); | 
 |     ByteString bsBcc = WideString(csBCCAddress).ToUTF16LE(); | 
 |     ByteString bsSubject = WideString(csSubject).ToUTF16LE(); | 
 |     ByteString bsMsg = WideString(csMsg).ToUTF16LE(); | 
 |     pFormFillEnv->EmailTo(pFileHandler, AsFPDFWideString(&bsTo), | 
 |                           AsFPDFWideString(&bsSubject), AsFPDFWideString(&bsCC), | 
 |                           AsFPDFWideString(&bsBcc), AsFPDFWideString(&bsMsg)); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // HTTP or FTP | 
 |   ByteString bs = csURL.ToUTF16LE(); | 
 |   pFormFillEnv->UploadTo(pFileHandler, fileFlag, AsFPDFWideString(&bs)); | 
 |   return true; | 
 | } | 
 | #endif  // PDF_XFA_ELEMENT_SUBMIT_ENABLED |