// Copyright 2014 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 "xfa/fxfa/parser/cxfa_dataexporter.h"
#include "core/fxcrt/fx_basic.h"
#include "xfa/fde/xml/fde_xml_imp.h"
#include "xfa/fgas/crt/fgas_codepage.h"
#include "xfa/fxfa/parser/cxfa_document.h"
#include "xfa/fxfa/parser/cxfa_widgetdata.h"
#include "xfa/fxfa/parser/xfa_object.h"
namespace {
CFX_WideString ExportEncodeAttribute(const CFX_WideString& str) {
CFX_WideTextBuf textBuf;
int32_t iLen = str.GetLength();
for (int32_t i = 0; i < iLen; i++) {
switch (str[i]) {
case '&':
textBuf << FX_WSTRC(L"&");
break;
case '<':
textBuf << FX_WSTRC(L"<");
break;
case '>':
textBuf << FX_WSTRC(L">");
break;
case '\'':
textBuf << FX_WSTRC(L"'");
break;
case '\"':
textBuf << FX_WSTRC(L""");
break;
default:
textBuf.AppendChar(str[i]);
}
}
return textBuf.MakeString();
}
CFX_WideString ExportEncodeContent(const CFX_WideStringC& str) {
CFX_WideTextBuf textBuf;
int32_t iLen = str.GetLength();
for (int32_t i = 0; i < iLen; i++) {
FX_WCHAR ch = str.GetAt(i);
if (!FDE_IsXMLValidChar(ch))
continue;
if (ch == '&') {
textBuf << FX_WSTRC(L"&");
} else if (ch == '<') {
textBuf << FX_WSTRC(L"<");
} else if (ch == '>') {
textBuf << FX_WSTRC(L">");
} else if (ch == '\'') {
textBuf << FX_WSTRC(L"'");
} else if (ch == '\"') {
textBuf << FX_WSTRC(L""");
} else if (ch == ' ') {
if (i && str.GetAt(i - 1) != ' ') {
textBuf.AppendChar(' ');
} else {
textBuf << FX_WSTRC(L" ");
}
} else {
textBuf.AppendChar(str.GetAt(i));
}
}
return textBuf.MakeString();
}
void SaveAttribute(CXFA_Node* pNode,
XFA_ATTRIBUTE eName,
const CFX_WideStringC& wsName,
FX_BOOL bProto,
CFX_WideString& wsOutput) {
CFX_WideString wsValue;
if ((!bProto && !pNode->HasAttribute((XFA_ATTRIBUTE)eName, bProto)) ||
!pNode->GetAttribute((XFA_ATTRIBUTE)eName, wsValue, FALSE)) {
return;
}
wsValue = ExportEncodeAttribute(wsValue);
wsOutput += FX_WSTRC(L" ");
wsOutput += wsName;
wsOutput += FX_WSTRC(L"=\"");
wsOutput += wsValue;
wsOutput += FX_WSTRC(L"\"");
}
FX_BOOL AttributeSaveInDataModel(CXFA_Node* pNode, XFA_ATTRIBUTE eAttribute) {
FX_BOOL bSaveInDataModel = FALSE;
if (pNode->GetElementType() != XFA_Element::Image)
return bSaveInDataModel;
CXFA_Node* pValueNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
if (!pValueNode || pValueNode->GetElementType() != XFA_Element::Value)
return bSaveInDataModel;
CXFA_Node* pFieldNode = pValueNode->GetNodeItem(XFA_NODEITEM_Parent);
if (pFieldNode && pFieldNode->GetBindData() &&
eAttribute == XFA_ATTRIBUTE_Href) {
bSaveInDataModel = TRUE;
}
return bSaveInDataModel;
}
FX_BOOL ContentNodeNeedtoExport(CXFA_Node* pContentNode) {
CFX_WideString wsContent;
if (!pContentNode->TryContent(wsContent, FALSE, FALSE))
return FALSE;
ASSERT(pContentNode->IsContentNode());
CXFA_Node* pParentNode = pContentNode->GetNodeItem(XFA_NODEITEM_Parent);
if (!pParentNode || pParentNode->GetElementType() != XFA_Element::Value)
return TRUE;
CXFA_Node* pGrandParentNode = pParentNode->GetNodeItem(XFA_NODEITEM_Parent);
if (!pGrandParentNode || !pGrandParentNode->IsContainerNode())
return TRUE;
if (pGrandParentNode->GetBindData())
return FALSE;
CXFA_WidgetData* pWidgetData = pGrandParentNode->GetWidgetData();
XFA_Element eUIType = pWidgetData->GetUIType();
if (eUIType == XFA_Element::PasswordEdit)
return FALSE;
return TRUE;
}
void RecognizeXFAVersionNumber(CXFA_Node* pTemplateRoot,
CFX_WideString& wsVersionNumber) {
wsVersionNumber.clear();
if (!pTemplateRoot)
return;
CFX_WideString wsTemplateNS;
if (!pTemplateRoot->TryNamespace(wsTemplateNS))
return;
XFA_VERSION eVersion =
pTemplateRoot->GetDocument()->RecognizeXFAVersionNumber(wsTemplateNS);
if (eVersion == XFA_VERSION_UNKNOWN)
eVersion = XFA_VERSION_DEFAULT;
wsVersionNumber.Format(L"%i.%i", eVersion / 100, eVersion % 100);
}
void RegenerateFormFile_Changed(CXFA_Node* pNode,
CFX_WideTextBuf& buf,
FX_BOOL bSaveXML) {
CFX_WideString wsAttrs;
int32_t iAttrs = 0;
const uint8_t* pAttrs =
XFA_GetElementAttributes(pNode->GetElementType(), iAttrs);
while (iAttrs--) {
const XFA_ATTRIBUTEINFO* pAttr =
XFA_GetAttributeByID((XFA_ATTRIBUTE)pAttrs[iAttrs]);
if (pAttr->eName == XFA_ATTRIBUTE_Name ||
(AttributeSaveInDataModel(pNode, pAttr->eName) && !bSaveXML)) {
continue;
}
CFX_WideString wsAttr;
SaveAttribute(pNode, pAttr->eName, pAttr->pName, bSaveXML, wsAttr);
wsAttrs += wsAttr;
}
CFX_WideString wsChildren;
switch (pNode->GetObjectType()) {
case XFA_ObjectType::ContentNode: {
if (!bSaveXML && !ContentNodeNeedtoExport(pNode))
break;
CXFA_Node* pRawValueNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
while (pRawValueNode &&
pRawValueNode->GetElementType() != XFA_Element::SharpxHTML &&
pRawValueNode->GetElementType() != XFA_Element::Sharptext &&
pRawValueNode->GetElementType() != XFA_Element::Sharpxml) {
pRawValueNode = pRawValueNode->GetNodeItem(XFA_NODEITEM_NextSibling);
}
if (!pRawValueNode)
break;
CFX_WideString wsContentType;
pNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, FALSE);
if (pRawValueNode->GetElementType() == XFA_Element::SharpxHTML &&
wsContentType == FX_WSTRC(L"text/html")) {
CFDE_XMLNode* pExDataXML = pNode->GetXMLMappingNode();
if (!pExDataXML)
break;
CFDE_XMLNode* pRichTextXML =
pExDataXML->GetNodeItem(CFDE_XMLNode::FirstChild);
if (!pRichTextXML)
break;
IFX_MemoryStream* pMemStream = FX_CreateMemoryStream(TRUE);
IFX_Stream* pTempStream = IFX_Stream::CreateStream(
(IFX_SeekableWriteStream*)pMemStream, FX_STREAMACCESS_Text |
FX_STREAMACCESS_Write |
FX_STREAMACCESS_Append);
pTempStream->SetCodePage(FX_CODEPAGE_UTF8);
pRichTextXML->SaveXMLNode(pTempStream);
wsChildren += CFX_WideString::FromUTF8(
CFX_ByteStringC(pMemStream->GetBuffer(), pMemStream->GetSize()));
pTempStream->Release();
pMemStream->Release();
} else if (pRawValueNode->GetElementType() == XFA_Element::Sharpxml &&
wsContentType == FX_WSTRC(L"text/xml")) {
CFX_WideString wsRawValue;
pRawValueNode->GetAttribute(XFA_ATTRIBUTE_Value, wsRawValue, FALSE);
if (wsRawValue.IsEmpty())
break;
CFX_WideStringArray wsSelTextArray;
int32_t iStart = 0;
int32_t iEnd = wsRawValue.Find(L'\n', iStart);
iEnd = (iEnd == -1) ? wsRawValue.GetLength() : iEnd;
while (iEnd >= iStart) {
wsSelTextArray.Add(wsRawValue.Mid(iStart, iEnd - iStart));
iStart = iEnd + 1;
if (iStart >= wsRawValue.GetLength())
break;
iEnd = wsRawValue.Find(L'\n', iStart);
}
CXFA_Node* pParentNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
ASSERT(pParentNode);
CXFA_Node* pGrandparentNode =
pParentNode->GetNodeItem(XFA_NODEITEM_Parent);
ASSERT(pGrandparentNode);
CFX_WideString bodyTagName;
bodyTagName = pGrandparentNode->GetCData(XFA_ATTRIBUTE_Name);
if (bodyTagName.IsEmpty())
bodyTagName = FX_WSTRC(L"ListBox1");
buf << FX_WSTRC(L"<");
buf << bodyTagName;
buf << FX_WSTRC(L" xmlns=\"\"\n>");
for (int32_t i = 0; i < wsSelTextArray.GetSize(); i++) {
buf << FX_WSTRC(L"