#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/check.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 "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 …
#define FXFA_CONFIG …
#define FXFA_TEMPLATE …
#define FXFA_LOCALESET …
#define FXFA_DATASETS …
#define FXFA_XMPMETA …
#define FXFA_XFDF …
#define FXFA_FORM …
#define FXFA_PDF …
#define FXFA_XFA_ALL …
static_assert …;
static_assert …;
CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext)
: … { … }
CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() = default;
void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) { … }
void CPDFXFA_DocEnvironment::InvalidateRect(CXFA_FFPageView* pPageView,
const CFX_RectF& rt) { … }
void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget,
bool bVisible,
const CFX_RectF* pRtAnchor) { … }
bool CPDFXFA_DocEnvironment::GetPopupPos(CXFA_FFWidget* hWidget,
float fMinPopup,
float fMaxPopup,
const CFX_RectF& rtAnchor,
CFX_RectF* pPopupRect) { … }
bool CPDFXFA_DocEnvironment::PopupMenu(CXFA_FFWidget* hWidget,
const CFX_PointF& ptPopup) { … }
void CPDFXFA_DocEnvironment::OnPageViewEvent(CXFA_FFPageView* pPageView,
CXFA_FFDoc::PageViewEvent eEvent) { … }
void CPDFXFA_DocEnvironment::WidgetPostAdd(CXFA_FFWidget* hWidget) { … }
void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget) { … }
int32_t CPDFXFA_DocEnvironment::CountPages(const CXFA_FFDoc* hDoc) const { … }
int32_t CPDFXFA_DocEnvironment::GetCurrentPage(const CXFA_FFDoc* hDoc) const { … }
void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc,
int32_t iCurPage) { … }
bool CPDFXFA_DocEnvironment::IsCalculationsEnabled(
const CXFA_FFDoc* hDoc) const { … }
void CPDFXFA_DocEnvironment::SetCalculationsEnabled(CXFA_FFDoc* hDoc,
bool bEnabled) { … }
WideString CPDFXFA_DocEnvironment::GetTitle(const CXFA_FFDoc* hDoc) const { … }
void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc,
const WideString& wsTitle) { … }
void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc,
const WideString& wsFilePath,
bool bXDP) { … }
void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc,
const WideString& wsURL) { … }
bool CPDFXFA_DocEnvironment::IsValidationsEnabled(
const CXFA_FFDoc* hDoc) const { … }
void CPDFXFA_DocEnvironment::SetValidationsEnabled(CXFA_FFDoc* hDoc,
bool bEnabled) { … }
void CPDFXFA_DocEnvironment::SetFocusWidget(CXFA_FFDoc* hDoc,
CXFA_FFWidget* hWidget) { … }
void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc,
int32_t nStartPage,
int32_t nEndPage,
Mask<XFA_PrintOpt> dwOptions) { … }
FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor(
const CXFA_FFDoc* hDoc) const { … }
IJS_Runtime* CPDFXFA_DocEnvironment::GetIJSRuntime(
const CXFA_FFDoc* hDoc) const { … }
CFX_XMLDocument* CPDFXFA_DocEnvironment::GetXMLDoc() const { … }
RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile(
CXFA_FFDoc* hDoc,
const WideString& wsLink) { … }
#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.TrimWhitespaceFront();
if (!srcURL.Left(7).EqualsASCIINoCase("mailto:")) {
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.TrimWhitespace();
csToAddress = std::move(tmp);
}
srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1));
while (!srcURL.IsEmpty()) {
srcURL.TrimWhitespace();
pos = srcURL.Find(L'&');
WideString tmp = (!pos.has_value()) ? srcURL : srcURL.Left(pos.value());
tmp.TrimWhitespace();
if (tmp.GetLength() >= 3 && tmp.Left(3).EqualsASCIINoCase("cc=")) {
tmp = tmp.Right(tmp.GetLength() - 3);
if (!csCCAddress.IsEmpty())
csCCAddress += L';';
csCCAddress += tmp;
} else if (tmp.GetLength() >= 4 && tmp.Left(4).EqualsASCIINoCase("bcc=")) {
tmp = tmp.Right(tmp.GetLength() - 4);
if (!csBCCAddress.IsEmpty())
csBCCAddress += L';';
csBCCAddress += tmp;
} else if (tmp.GetLength() >= 8 &&
tmp.Left(8).EqualsASCIINoCase("subject=")) {
tmp = tmp.Right(tmp.GetLength() - 8);
csSubject += tmp;
} else if (tmp.GetLength() >= 5 && tmp.Left(5).EqualsASCIINoCase("body=")) {
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.TrimWhitespace();
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).EqualsASCIINoCase("mailto:")) {
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;
}
ByteString bs = csURL.ToUTF16LE();
pFormFillEnv->UploadTo(pFileHandler, fileFlag, AsFPDFWideString(&bs));
return true;
}
#endif