blob: 4ebe8f92b94465cd9e92404368250d4cdd3b35ba [file] [log] [blame]
// Copyright 2016 PDFium Authors. All rights reserved.
// 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 <memory>
#include "core/fpdfapi/parser/cpdf_array.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_interform.h"
#include "fpdfsdk/cpdfsdk_pageview.h"
#include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
#include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
#include "fxjs/ijs_runtime.h"
#include "xfa/fxfa/cxfa_ffdocview.h"
#include "xfa/fxfa/cxfa_ffwidget.h"
#include "xfa/fxfa/cxfa_ffwidgethandler.h"
#include "xfa/fxfa/cxfa_widgetacciterator.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
CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext)
: m_pContext(pContext) {
ASSERT(m_pContext);
}
CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {}
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& rtPopup) {
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 pageViewRect = {0.0f, 0.0f, 0.0f, 0.0f};
pFormFillEnv->GetPageViewRect(pPage.Get(), pageViewRect);
int t1;
int t2;
CFX_FloatRect rcAnchor = rtAnchor.ToFloatRect();
int nRotate = hWidget->GetNode()->GetRotate();
switch (nRotate) {
case 90: {
t1 = (int)(pageViewRect.right - rcAnchor.right);
t2 = (int)(rcAnchor.left - pageViewRect.left);
if (rcAnchor.bottom < pageViewRect.bottom)
rtPopup.left += rcAnchor.bottom - pageViewRect.bottom;
break;
}
case 180: {
t2 = (int)(pageViewRect.top - rcAnchor.top);
t1 = (int)(rcAnchor.bottom - pageViewRect.bottom);
if (rcAnchor.left < pageViewRect.left)
rtPopup.left += rcAnchor.left - pageViewRect.left;
break;
}
case 270: {
t1 = (int)(rcAnchor.left - pageViewRect.left);
t2 = (int)(pageViewRect.right - rcAnchor.right);
if (rcAnchor.top > pageViewRect.top)
rtPopup.left -= rcAnchor.top - pageViewRect.top;
break;
}
case 0:
default: {
t1 = (int)(pageViewRect.top - rcAnchor.top);
t2 = (int)(rcAnchor.bottom - pageViewRect.bottom);
if (rcAnchor.right > pageViewRect.right)
rtPopup.left -= rcAnchor.right - pageViewRect.right;
break;
}
}
int t;
uint32_t dwPos;
if (t1 <= 0 && t2 <= 0)
return false;
if (t1 <= 0) {
t = t2;
dwPos = 1;
} else if (t2 <= 0) {
t = t1;
dwPos = 0;
} else if (t1 > t2) {
t = t1;
dwPos = 0;
} else {
t = t2;
dwPos = 1;
}
float fPopupHeight;
if (t < fMinPopup)
fPopupHeight = fMinPopup;
else if (t > fMaxPopup)
fPopupHeight = fMaxPopup;
else
fPopupHeight = static_cast<float>(t);
switch (nRotate) {
case 0:
case 180: {
if (dwPos == 0) {
rtPopup.top = rtAnchor.height;
rtPopup.height = fPopupHeight;
} else {
rtPopup.top = -fPopupHeight;
rtPopup.height = fPopupHeight;
}
break;
}
case 90:
case 270: {
if (dwPos == 0) {
rtPopup.top = rtAnchor.width;
rtPopup.height = fPopupHeight;
} else {
rtPopup.top = -fPopupHeight;
rtPopup.height = fPopupHeight;
}
break;
}
default:
break;
}
return true;
}
bool CPDFXFA_DocEnvironment::PopupMenu(CXFA_FFWidget* hWidget,
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(), hWidget, menuFlag, ptPopup);
}
void CPDFXFA_DocEnvironment::PageViewEvent(CXFA_FFPageView* pPageView,
uint32_t dwFlags) {
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
if (!pFormFillEnv)
return;
if (m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_LOADING ||
m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_CLOSING ||
XFA_PAGEVIEWEVENT_StopLayout != dwFlags)
return;
int nNewCount = m_pContext->GetPageCount();
if (nNewCount == m_pContext->GetOriginalPageCount())
return;
CXFA_FFDocView* pXFADocView = m_pContext->GetXFADocView();
if (!pXFADocView)
return;
for (int iPageIter = 0; iPageIter < m_pContext->GetOriginalPageCount();
iPageIter++) {
RetainPtr<CPDFXFA_Page> pPage = (*m_pContext->GetXFAPageList())[iPageIter];
if (!pPage)
continue;
m_pContext->GetFormFillEnv()->RemovePageView(pPage.Get());
pPage->SetXFAPageView(pXFADocView->GetPageView(iPageIter));
}
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,
CXFA_WidgetAcc* pWidgetAcc) {
if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
return;
CXFA_FFPageView* pPageView = hWidget->GetPageView();
if (!pPageView)
return;
RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
if (!pXFAPage)
return;
m_pContext->GetFormFillEnv()
->GetPageView(pXFAPage.Get(), true)
->AddAnnot(hWidget);
}
void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget,
CXFA_WidgetAcc* pWidgetAcc) {
if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
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()->GetPageView(pXFAPage.Get(), true);
CPDFSDK_Annot* pAnnot = pSdkPageView->GetAnnotByXFAWidget(hWidget);
if (pAnnot)
pSdkPageView->DeleteAnnot(pAnnot);
}
int32_t CPDFXFA_DocEnvironment::CountPages(CXFA_FFDoc* hDoc) {
if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv())
return m_pContext->GetPageCount();
return 0;
}
int32_t CPDFXFA_DocEnvironment::GetCurrentPage(CXFA_FFDoc* hDoc) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
return -1;
if (m_pContext->GetFormType() != FormType::kXFAFull)
return -1;
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
if (!pFormFillEnv)
return -1;
return pFormFillEnv->GetCurrentPageIndex(m_pContext.Get());
}
void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc,
int32_t iCurPage) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv() ||
m_pContext->GetFormType() != FormType::kXFAFull || iCurPage < 0 ||
iCurPage >= m_pContext->GetFormFillEnv()->GetPageCount()) {
return;
}
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
if (!pFormFillEnv)
return;
pFormFillEnv->SetCurrentPage(m_pContext.Get(), iCurPage);
}
bool CPDFXFA_DocEnvironment::IsCalculationsEnabled(CXFA_FFDoc* hDoc) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
return false;
if (m_pContext->GetFormFillEnv()->GetInterForm()) {
return m_pContext->GetFormFillEnv()
->GetInterForm()
->IsXfaCalculateEnabled();
}
return false;
}
void CPDFXFA_DocEnvironment::SetCalculationsEnabled(CXFA_FFDoc* hDoc,
bool bEnabled) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
return;
if (m_pContext->GetFormFillEnv()->GetInterForm()) {
m_pContext->GetFormFillEnv()->GetInterForm()->XfaEnableCalculate(bEnabled);
}
}
void CPDFXFA_DocEnvironment::GetTitle(CXFA_FFDoc* hDoc, WideString& wsTitle) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
return;
const CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
if (!pInfoDict)
return;
ByteString csTitle = pInfoDict->GetStringFor("Title");
wsTitle = wsTitle.FromLocal(csTitle.GetBuffer(csTitle.GetLength()));
csTitle.ReleaseBuffer(csTitle.GetLength());
}
void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc,
const WideString& wsTitle) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
return;
CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
if (pInfoDict)
pInfoDict->SetNewFor<CPDF_String>("Title", wsTitle);
}
void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc,
const WideString& wsFilePath,
bool bXDP) {
if (hDoc != m_pContext->GetXFADoc())
return;
if (!m_pContext->ContainsXFAForm())
return;
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
if (!pFormFillEnv)
return;
int fileType = bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML;
ByteString bs = wsFilePath.UTF16LE_Encode();
if (wsFilePath.IsEmpty()) {
if (!pFormFillEnv->GetFormFillInfo() ||
!pFormFillEnv->GetFormFillInfo()->m_pJsPlatform) {
return;
}
WideString filepath = pFormFillEnv->JS_fieldBrowse();
bs = filepath.UTF16LE_Encode();
}
int len = bs.GetLength();
FPDF_FILEHANDLER* pFileHandler =
pFormFillEnv->OpenFile(bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML,
(FPDF_WIDESTRING)bs.GetBuffer(len), "wb");
bs.ReleaseBuffer(len);
if (!pFileHandler)
return;
RetainPtr<IFX_SeekableStream> fileWrite = MakeSeekableStream(pFileHandler);
if (fileType == FXFA_SAVEAS_XML) {
ByteString content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
content.GetLength());
CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
ffdoc->SavePackage(
ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileWrite,
nullptr);
} else if (fileType == FXFA_SAVEAS_XDP) {
if (!m_pContext->GetPDFDoc())
return;
const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
if (!pRoot)
return;
CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
if (!pAcroForm)
return;
CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
if (!pArray)
return;
int size = pArray->GetCount();
for (int i = 1; i < size; i += 2) {
CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
if (!pPrePDFObj->IsString())
continue;
if (!pPDFObj->IsReference())
continue;
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, nullptr);
continue;
}
if (pPrePDFObj->GetString() == "datasets") {
CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
ffdoc->SavePackage(
ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
fileWrite, nullptr);
continue;
}
if (i == size - 1) {
WideString wPath = WideString::FromUTF16LE(
reinterpret_cast<const unsigned short*>(bs.c_str()),
bs.GetLength() / sizeof(unsigned short));
ByteString bPath = wPath.UTF8Encode();
const char* szFormat =
"\n<pdf href=\"%s\" xmlns=\"http://ns.adobe.com/xdp/pdf/\"/>";
ByteString content = ByteString::Format(szFormat, bPath.c_str());
fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
content.GetLength());
}
auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
pAcc->LoadAllDataFiltered();
fileWrite->WriteBlock(pAcc->GetData(), fileWrite->GetSize(),
pAcc->GetSize());
}
}
fileWrite->Flush();
}
void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc,
const WideString& bsURL) {
if (hDoc != m_pContext->GetXFADoc())
return;
if (m_pContext->GetFormType() != FormType::kXFAFull)
return;
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
if (!pFormFillEnv)
return;
WideStringView str(bsURL.c_str());
pFormFillEnv->GotoURL(m_pContext.Get(), str);
}
bool CPDFXFA_DocEnvironment::IsValidationsEnabled(CXFA_FFDoc* hDoc) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
return false;
if (m_pContext->GetFormFillEnv()->GetInterForm()) {
return m_pContext->GetFormFillEnv()
->GetInterForm()
->IsXfaValidationsEnabled();
}
return true;
}
void CPDFXFA_DocEnvironment::SetValidationsEnabled(CXFA_FFDoc* hDoc,
bool bEnabled) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
return;
if (m_pContext->GetFormFillEnv()->GetInterForm()) {
m_pContext->GetFormFillEnv()->GetInterForm()->XfaSetValidationsEnabled(
bEnabled);
}
}
void CPDFXFA_DocEnvironment::SetFocusWidget(CXFA_FFDoc* hDoc,
CXFA_FFWidget* hWidget) {
if (hDoc != m_pContext->GetXFADoc())
return;
if (!hWidget) {
CPDFSDK_Annot::ObservedPtr 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()->GetPageView(i);
if (!pPageView)
continue;
CPDFSDK_Annot::ObservedPtr pAnnot(pPageView->GetAnnotByXFAWidget(hWidget));
if (pAnnot) {
m_pContext->GetFormFillEnv()->SetFocusAnnot(&pAnnot);
break;
}
}
}
void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc,
int32_t nStartPage,
int32_t nEndPage,
uint32_t 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_ShowDialog, nStartPage, nEndPage,
dwOptions & XFA_PRINTOPT_CanCancel, dwOptions & XFA_PRINTOPT_ShrinkPage,
dwOptions & XFA_PRINTOPT_AsImage, dwOptions & XFA_PRINTOPT_ReverseOrder,
dwOptions & XFA_PRINTOPT_PrintAnnot);
}
FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor(CXFA_FFDoc* hDoc) {
if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
return 0;
CPDFSDK_InterForm* pInterForm = m_pContext->GetFormFillEnv()->GetInterForm();
if (!pInterForm)
return 0;
return ArgbEncode(pInterForm->GetHighlightAlpha(),
pInterForm->GetHighlightColor(FormFieldType::kXFA));
}
bool CPDFXFA_DocEnvironment::NotifySubmit(bool bPrevOrPost) {
if (bPrevOrPost)
return OnBeforeNotifySubmit();
OnAfterNotifySubmit();
return true;
}
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;
std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
docView->CreateWidgetAccIterator();
if (pWidgetAccIterator) {
CXFA_EventParam Param;
Param.m_eType = XFA_EVENT_PreSubmit;
while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext())
pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
}
pWidgetAccIterator = docView->CreateWidgetAccIterator();
if (!pWidgetAccIterator)
return true;
CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
pWidgetAcc = pWidgetAccIterator->MoveToNext();
while (pWidgetAcc) {
int fRet = pWidgetAcc->GetNode()->ProcessValidate(docView, -1);
if (fRet == XFA_EVENTERROR_Error) {
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
if (!pFormFillEnv)
return false;
WideString ws = WideString::FromLocal(IDS_XFA_Validate_Input);
ByteString bs = ws.UTF16LE_Encode();
int len = bs.GetLength();
pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len),
(FPDF_WIDESTRING)L"", 0, 1);
bs.ReleaseBuffer(len);
return false;
}
pWidgetAcc = pWidgetAccIterator->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;
std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
m_pContext->GetXFADocView()->CreateWidgetAccIterator();
if (!pWidgetAccIterator)
return;
CXFA_EventParam Param;
Param.m_eType = XFA_EVENT_PostSubmit;
CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
while (pWidgetAcc) {
pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
pWidgetAcc = pWidgetAccIterator->MoveToNext();
}
m_pContext->GetXFADocView()->UpdateDocView();
}
bool CPDFXFA_DocEnvironment::Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) {
if (!NotifySubmit(true) || !m_pContext->GetXFADocView())
return false;
m_pContext->GetXFADocView()->UpdateDocView();
bool ret = SubmitInternal(hDoc, submit);
NotifySubmit(false);
return ret;
}
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.UTF16LE_Encode();
int len = bs.GetLength();
FPDF_FILEHANDLER* pFileHandler =
pFormFillEnv->OpenFile(0, (FPDF_WIDESTRING)bs.GetBuffer(len), "rb");
bs.ReleaseBuffer(len);
if (!pFileHandler)
return nullptr;
return MakeSeekableStream(pFileHandler);
}
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) {
static constexpr char kContent[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
fileStream->WriteBlock(kContent, 0, strlen(kContent));
ffdoc->SavePackage(
ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileStream,
nullptr);
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;
}
CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
if (!pAcroForm) {
fileStream->Flush();
return false;
}
CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
if (!pArray) {
fileStream->Flush();
return false;
}
int size = pArray->GetCount();
for (int i = 1; i < size; i += 2) {
CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
if (!pPrePDFObj->IsString())
continue;
if (!pPDFObj->IsReference())
continue;
CPDF_Object* pDirectObj = pPDFObj->GetDirect();
if (!pDirectObj->IsStream())
continue;
if (pPrePDFObj->GetString() == "config" && !(flag & FXFA_CONFIG))
continue;
if (pPrePDFObj->GetString() == "template" && !(flag & FXFA_TEMPLATE))
continue;
if (pPrePDFObj->GetString() == "localeSet" && !(flag & FXFA_LOCALESET))
continue;
if (pPrePDFObj->GetString() == "datasets" && !(flag & FXFA_DATASETS))
continue;
if (pPrePDFObj->GetString() == "xmpmeta" && !(flag & FXFA_XMPMETA))
continue;
if (pPrePDFObj->GetString() == "xfdf" && !(flag & FXFA_XFDF))
continue;
if (pPrePDFObj->GetString() == "form" && !(flag & FXFA_FORM))
continue;
if (pPrePDFObj->GetString() == "form") {
ffdoc->SavePackage(
ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
fileStream, nullptr);
} else if (pPrePDFObj->GetString() == "datasets") {
ffdoc->SavePackage(
ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
fileStream, nullptr);
}
}
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::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 = tmp;
srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1));
while (!srcURL.IsEmpty()) {
srcURL.Trim();
pos = srcURL.Find(L'&');
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()
? L""
: srcURL.Right(csURL.GetLength() - (pos.value() + 1));
}
csToAddress.Replace(L",", L";");
csCCAddress.Replace(L",", L";");
csBCCAddress.Replace(L",", L";");
return true;
}
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()) {
WideString ws = WideString::FromLocal("Submit cancelled.");
ByteString bs = ws.UTF16LE_Encode();
int len = bs.GetLength();
pFormFillEnv->Alert(reinterpret_cast<FPDF_WIDESTRING>(bs.GetBuffer(len)),
reinterpret_cast<FPDF_WIDESTRING>(L""), 0, 4);
bs.ReleaseBuffer(len);
return false;
}
FPDF_FILEHANDLER* pFileHandler = nullptr;
int fileFlag = -1;
switch (submit->GetSubmitFormat()) {
case XFA_AttributeEnum::Xdp: {
WideString csContent = submit->GetSubmitXDPContent();
csContent.Trim();
WideString space = WideString::FromLocal(" ");
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_AttributeEnum::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_AttributeEnum::Pdf:
break;
case XFA_AttributeEnum::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).UTF16LE_Encode();
ByteString bsCC = WideString(csCCAddress).UTF16LE_Encode();
ByteString bsBcc = WideString(csBCCAddress).UTF16LE_Encode();
ByteString bsSubject = WideString(csSubject).UTF16LE_Encode();
ByteString bsMsg = WideString(csMsg).UTF16LE_Encode();
FPDF_WIDESTRING pTo = (FPDF_WIDESTRING)bsTo.GetBuffer(bsTo.GetLength());
FPDF_WIDESTRING pCC = (FPDF_WIDESTRING)bsCC.GetBuffer(bsCC.GetLength());
FPDF_WIDESTRING pBcc = (FPDF_WIDESTRING)bsBcc.GetBuffer(bsBcc.GetLength());
FPDF_WIDESTRING pSubject =
(FPDF_WIDESTRING)bsSubject.GetBuffer(bsSubject.GetLength());
FPDF_WIDESTRING pMsg = (FPDF_WIDESTRING)bsMsg.GetBuffer(bsMsg.GetLength());
pFormFillEnv->EmailTo(pFileHandler, pTo, pSubject, pCC, pBcc, pMsg);
bsTo.ReleaseBuffer(bsTo.GetStringLength());
bsCC.ReleaseBuffer(bsCC.GetStringLength());
bsBcc.ReleaseBuffer(bsBcc.GetStringLength());
bsSubject.ReleaseBuffer(bsSubject.GetStringLength());
bsMsg.ReleaseBuffer(bsMsg.GetStringLength());
} else {
// HTTP or FTP
WideString ws;
ByteString bs = csURL.UTF16LE_Encode();
int len = bs.GetLength();
pFormFillEnv->UploadTo(pFileHandler, fileFlag,
(FPDF_WIDESTRING)bs.GetBuffer(len));
bs.ReleaseBuffer(len);
}
return true;
}
bool CPDFXFA_DocEnvironment::SetGlobalProperty(CXFA_FFDoc* hDoc,
const ByteStringView& szPropName,
CFXJSE_Value* pValue) {
if (hDoc != m_pContext->GetXFADoc())
return false;
if (!m_pContext->GetFormFillEnv() ||
!m_pContext->GetFormFillEnv()->GetJSRuntime()) {
return false;
}
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
bool bRet = pFormFillEnv->GetJSRuntime()->SetValueByName(szPropName, pValue);
pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
return bRet;
}
bool CPDFXFA_DocEnvironment::GetGlobalProperty(CXFA_FFDoc* hDoc,
const ByteStringView& szPropName,
CFXJSE_Value* pValue) {
if (hDoc != m_pContext->GetXFADoc())
return false;
if (!m_pContext->GetFormFillEnv() ||
!m_pContext->GetFormFillEnv()->GetJSRuntime()) {
return false;
}
CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
bool bRet = pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue);
pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
return bRet;
}