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/src/foxitlib.h"
8#include "xfa/src/fxfa/src/common/xfa_utils.h"
9#include "xfa/src/fxfa/src/common/xfa_object.h"
10#include "xfa/src/fxfa/src/common/xfa_document.h"
11#include "xfa/src/fxfa/src/common/xfa_parser.h"
12#include "xfa/src/fxfa/src/common/xfa_script.h"
13#include "xfa/src/fxfa/src/common/xfa_docdata.h"
14#include "xfa/src/fxfa/src/common/xfa_doclayout.h"
15#include "xfa/src/fxfa/src/common/xfa_localemgr.h"
16#include "xfa/src/fxfa/src/common/xfa_fm2jsapi.h"
17#include "xfa_document_serialize.h"
18IXFA_PacketImport* IXFA_PacketImport::Create(CXFA_Document* pDocument) {
19  return new CXFA_DataImporter(pDocument);
20}
21CXFA_DataImporter::CXFA_DataImporter(CXFA_Document* pDocument)
22    : m_pDocument(pDocument) {
23  ASSERT(m_pDocument != NULL);
24}
25FX_BOOL CXFA_DataImporter::ImportData(IFX_FileRead* pDataDocument) {
26  IXFA_Parser* pDataDocumentParser = IXFA_Parser::Create(m_pDocument);
27  if (!pDataDocumentParser) {
28    return FALSE;
29  }
30  if (pDataDocumentParser->StartParse(pDataDocument, XFA_XDPPACKET_Datasets) !=
31      XFA_PARSESTATUS_Ready) {
32    pDataDocumentParser->Release();
33    return FALSE;
34  }
35  if (pDataDocumentParser->DoParse(NULL) < XFA_PARSESTATUS_Done) {
36    pDataDocumentParser->Release();
37    return FALSE;
38  }
39  CXFA_Node* pImportDataRoot = pDataDocumentParser->GetRootNode();
40  if (!pImportDataRoot) {
41    pDataDocumentParser->Release();
42    return FALSE;
43  }
44  CXFA_Node* pDataModel =
45      (CXFA_Node*)m_pDocument->GetXFANode(XFA_HASHCODE_Datasets);
46  if (!pDataModel) {
47    pDataDocumentParser->Release();
48    return FALSE;
49  }
50  CXFA_Node* pDataNode = (CXFA_Node*)m_pDocument->GetXFANode(XFA_HASHCODE_Data);
51  if (pDataNode) {
52    pDataModel->RemoveChild(pDataNode);
53  }
54  if (pImportDataRoot->GetClassID() == XFA_ELEMENT_DataModel) {
55    while (CXFA_Node* pChildNode =
56               pImportDataRoot->GetNodeItem(XFA_NODEITEM_FirstChild)) {
57      pImportDataRoot->RemoveChild(pChildNode);
58      pDataModel->InsertChild(pChildNode);
59    }
60  } else {
61    IFDE_XMLNode* pXMLNode = pImportDataRoot->GetXMLMappingNode();
62    IFDE_XMLNode* pParentXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::Parent);
63    if (pParentXMLNode) {
64      pParentXMLNode->RemoveChildNode(pXMLNode);
65    }
66    pDataModel->InsertChild(pImportDataRoot);
67  }
68  m_pDocument->DoDataRemerge(FALSE);
69  pDataDocumentParser->Release();
70  return TRUE;
71}
72CFX_WideString XFA_ExportEncodeAttribute(const CFX_WideString& str) {
73  CFX_WideTextBuf textBuf;
74  int32_t iLen = str.GetLength();
75  for (int32_t i = 0; i < iLen; i++) {
76    switch (str[i]) {
77      case '&':
78        textBuf << FX_WSTRC(L"&amp;");
79        break;
80      case '<':
81        textBuf << FX_WSTRC(L"&lt;");
82        break;
83      case '>':
84        textBuf << FX_WSTRC(L"&gt;");
85        break;
86      case '\'':
87        textBuf << FX_WSTRC(L"&apos;");
88        break;
89      case '\"':
90        textBuf << FX_WSTRC(L"&quot;");
91        break;
92      default:
93        textBuf.AppendChar(str[i]);
94    }
95  }
96  return textBuf.GetWideString();
97}
98CFX_WideString XFA_ExportEncodeContent(const CFX_WideStringC& str) {
99  CFX_WideTextBuf textBuf;
100  int32_t iLen = str.GetLength();
101  for (int32_t i = 0; i < iLen; i++) {
102    FX_WCHAR ch = str.GetAt(i);
103    if (!FDE_IsXMLValidChar(ch)) {
104      continue;
105    }
106    if (ch == '&') {
107      textBuf << FX_WSTRC(L"&amp;");
108    } else if (ch == '<') {
109      textBuf << FX_WSTRC(L"&lt;");
110    } else if (ch == '>') {
111      textBuf << FX_WSTRC(L"&gt;");
112    } else if (ch == '\'') {
113      textBuf << FX_WSTRC(L"&apos;");
114    } else if (ch == '\"') {
115      textBuf << FX_WSTRC(L"&quot;");
116    } else if (ch == ' ') {
117      if (i && str.GetAt(i - 1) != ' ') {
118        textBuf.AppendChar(' ');
119      } else {
120        textBuf << FX_WSTRC(L"&#x20;");
121      }
122    } else {
123      textBuf.AppendChar(str.GetAt(i));
124    }
125  }
126  return textBuf.GetWideString();
127}
128static void XFA_SaveAttribute(CXFA_Node* pNode,
129                              XFA_ATTRIBUTE eName,
130                              const CFX_WideStringC& wsName,
131                              FX_BOOL bProto,
132                              CFX_WideString& wsOutput) {
133  CFX_WideString wsValue;
134  if ((!bProto && !pNode->HasAttribute((XFA_ATTRIBUTE)eName, bProto)) ||
135      !pNode->GetAttribute((XFA_ATTRIBUTE)eName, wsValue, FALSE)) {
136    return;
137  }
138  wsValue = XFA_ExportEncodeAttribute(wsValue);
139  wsOutput += FX_WSTRC(L" ");
140  wsOutput += wsName;
141  wsOutput += FX_WSTRC(L"=\"");
142  wsOutput += wsValue;
143  wsOutput += FX_WSTRC(L"\"");
144}
145static FX_BOOL XFA_DataExporter_AttributeSaveInDataModel(
146    CXFA_Node* pNode,
147    XFA_ATTRIBUTE eAttribute) {
148  FX_BOOL bSaveInDataModel = FALSE;
149  if (pNode->GetClassID() != XFA_ELEMENT_Image) {
150    return bSaveInDataModel;
151  }
152  CXFA_Node* pValueNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
153  if (!pValueNode || pValueNode->GetClassID() != XFA_ELEMENT_Value) {
154    return bSaveInDataModel;
155  }
156  CXFA_Node* pFieldNode = pValueNode->GetNodeItem(XFA_NODEITEM_Parent);
157  if (pFieldNode && pFieldNode->GetBindData() &&
158      eAttribute == XFA_ATTRIBUTE_Href) {
159    bSaveInDataModel = TRUE;
160  }
161  return bSaveInDataModel;
162}
163FX_BOOL XFA_DataExporter_ContentNodeNeedtoExport(CXFA_Node* pContentNode) {
164  CFX_WideString wsContent;
165  if (!pContentNode->TryContent(wsContent, FALSE, FALSE)) {
166    return FALSE;
167  }
168  FXSYS_assert(pContentNode->GetObjectType() == XFA_OBJECTTYPE_ContentNode);
169  CXFA_Node* pParentNode = pContentNode->GetNodeItem(XFA_NODEITEM_Parent);
170  if (!pParentNode || pParentNode->GetClassID() != XFA_ELEMENT_Value) {
171    return TRUE;
172  }
173  CXFA_Node* pGrandParentNode = pParentNode->GetNodeItem(XFA_NODEITEM_Parent);
174  if (!pGrandParentNode ||
175      pGrandParentNode->GetObjectType() != XFA_OBJECTTYPE_ContainerNode) {
176    return TRUE;
177  }
178  if (pGrandParentNode->GetBindData()) {
179    return FALSE;
180  }
181  CXFA_WidgetData* pWidgetData = pGrandParentNode->GetWidgetData();
182  XFA_ELEMENT eUIType = pWidgetData->GetUIType();
183  if (eUIType == XFA_ELEMENT_PasswordEdit) {
184    return FALSE;
185  }
186  return TRUE;
187}
188static void XFA_DataExporter_RecognizeXFAVersionNumber(
189    CXFA_Node* pTemplateRoot,
190    CFX_WideString& wsVersionNumber) {
191  wsVersionNumber.Empty();
192  if (!pTemplateRoot) {
193    return;
194  }
195  CFX_WideString wsTemplateNS;
196  if (!pTemplateRoot->TryNamespace(wsTemplateNS)) {
197    return;
198  }
199  XFA_VERSION eVersion =
200      pTemplateRoot->GetDocument()->RecognizeXFAVersionNumber(wsTemplateNS);
201  if (eVersion == XFA_VERSION_UNKNOWN) {
202    eVersion = XFA_VERSION_DEFAULT;
203  }
204  wsVersionNumber.Format(L"%i.%i", eVersion / 100, eVersion % 100);
205}
206static void XFA_DataExporter_RegenerateFormFile_Changed(
207    CXFA_Node* pNode,
208    CFX_WideTextBuf& buf,
209    FX_BOOL bSaveXML = FALSE) {
210  CFX_WideString wsAttrs;
211  int32_t iAttrs = 0;
212  const uint8_t* pAttrs = XFA_GetElementAttributes(pNode->GetClassID(), iAttrs);
213  while (iAttrs--) {
214    XFA_LPCATTRIBUTEINFO pAttr =
215        XFA_GetAttributeByID((XFA_ATTRIBUTE)pAttrs[iAttrs]);
216    if (pAttr->eName == XFA_ATTRIBUTE_Name ||
217        (XFA_DataExporter_AttributeSaveInDataModel(pNode, pAttr->eName) &&
218         !bSaveXML)) {
219      continue;
220    }
221    CFX_WideString wsAttr;
222    XFA_SaveAttribute(pNode, pAttr->eName, pAttr->pName, bSaveXML, wsAttr);
223    wsAttrs += wsAttr;
224  }
225  CFX_WideString wsChildren;
226  switch (pNode->GetObjectType()) {
227    case XFA_OBJECTTYPE_ContentNode: {
228      if (!bSaveXML && !XFA_DataExporter_ContentNodeNeedtoExport(pNode)) {
229        break;
230      }
231      CXFA_Node* pRawValueNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
232      while (pRawValueNode &&
233             pRawValueNode->GetClassID() != XFA_ELEMENT_SharpxHTML &&
234             pRawValueNode->GetClassID() != XFA_ELEMENT_Sharptext &&
235             pRawValueNode->GetClassID() != XFA_ELEMENT_Sharpxml) {
236        pRawValueNode = pRawValueNode->GetNodeItem(XFA_NODEITEM_NextSibling);
237      }
238      if (!pRawValueNode) {
239        break;
240      }
241      CFX_WideString wsContentType;
242      pNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, FALSE);
243      if (pRawValueNode->GetClassID() == XFA_ELEMENT_SharpxHTML &&
244          wsContentType.Equal(FX_WSTRC(L"text/html"))) {
245        IFDE_XMLNode* pExDataXML = pNode->GetXMLMappingNode();
246        if (!pExDataXML) {
247          break;
248        }
249        IFDE_XMLNode* pRichTextXML =
250            pExDataXML->GetNodeItem(IFDE_XMLNode::FirstChild);
251        if (!pRichTextXML) {
252          break;
253        }
254        IFX_MemoryStream* pMemStream = FX_CreateMemoryStream(TRUE);
255        IFX_Stream* pTempStream = IFX_Stream::CreateStream(
256            (IFX_FileWrite*)pMemStream, FX_STREAMACCESS_Text |
257                                            FX_STREAMACCESS_Write |
258                                            FX_STREAMACCESS_Append);
259        pTempStream->SetCodePage(FX_CODEPAGE_UTF8);
260        pRichTextXML->SaveXMLNode(pTempStream);
261        wsChildren += CFX_WideString::FromUTF8(
262            (const FX_CHAR*)pMemStream->GetBuffer(), pMemStream->GetSize());
263        pTempStream->Release();
264        pMemStream->Release();
265      } else if (pRawValueNode->GetClassID() == XFA_ELEMENT_Sharpxml &&
266                 wsContentType.Equal(FX_WSTRC(L"text/xml"))) {
267        CFX_WideString wsRawValue;
268        pRawValueNode->GetAttribute(XFA_ATTRIBUTE_Value, wsRawValue, FALSE);
269        if (wsRawValue.IsEmpty()) {
270          break;
271        }
272        CFX_WideStringArray wsSelTextArray;
273        int32_t iStart = 0;
274        int32_t iEnd = wsRawValue.Find(L'\n', iStart);
275        iEnd = (iEnd == -1) ? wsRawValue.GetLength() : iEnd;
276        while (iEnd >= iStart) {
277          wsSelTextArray.Add(wsRawValue.Mid(iStart, iEnd - iStart));
278          iStart = iEnd + 1;
279          if (iStart >= wsRawValue.GetLength()) {
280            break;
281          }
282          iEnd = wsRawValue.Find(L'\n', iStart);
283        }
284        CXFA_Node* pParentNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
285        FXSYS_assert(pParentNode);
286        CXFA_Node* pGrandparentNode =
287            pParentNode->GetNodeItem(XFA_NODEITEM_Parent);
288        FXSYS_assert(pGrandparentNode);
289        CFX_WideString bodyTagName;
290        bodyTagName = pGrandparentNode->GetCData(XFA_ATTRIBUTE_Name);
291        if (bodyTagName.IsEmpty()) {
292          bodyTagName = FX_WSTRC(L"ListBox1");
293        }
294        buf << FX_WSTRC(L"<");
295        buf << bodyTagName;
296        buf << FX_WSTRC(L" xmlns=\"\"\n>");
297        for (int32_t i = 0; i < wsSelTextArray.GetSize(); i++) {
298          buf << FX_WSTRC(L"<value\n>");
299          buf << XFA_ExportEncodeContent(wsSelTextArray[i]);
300          buf << FX_WSTRC(L"</value\n>");
301        }
302        buf << FX_WSTRC(L"</");
303        buf << bodyTagName;
304        buf << FX_WSTRC(L"\n>");
305        wsChildren += buf.GetWideString();
306        buf.Clear();
307      } else {
308        CFX_WideStringC wsValue = pRawValueNode->GetCData(XFA_ATTRIBUTE_Value);
309        wsChildren += XFA_ExportEncodeContent(wsValue);
310      }
311    } break;
312    case XFA_OBJECTTYPE_TextNode:
313    case XFA_OBJECTTYPE_NodeC:
314    case XFA_OBJECTTYPE_NodeV: {
315      CFX_WideStringC wsValue = pNode->GetCData(XFA_ATTRIBUTE_Value);
316      wsChildren += XFA_ExportEncodeContent(wsValue);
317    } break;
318    default:
319      if (pNode->GetClassID() == XFA_ELEMENT_Items) {
320        CXFA_Node* pTemplateNode = pNode->GetTemplateNode();
321        if (!pTemplateNode ||
322            pTemplateNode->CountChildren(XFA_ELEMENT_UNKNOWN) !=
323                pNode->CountChildren(XFA_ELEMENT_UNKNOWN)) {
324          bSaveXML = TRUE;
325        }
326      }
327      CFX_WideTextBuf newBuf;
328      CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
329      while (pChildNode) {
330        XFA_DataExporter_RegenerateFormFile_Changed(pChildNode, newBuf,
331                                                    bSaveXML);
332        wsChildren += newBuf.GetWideString();
333        newBuf.Clear();
334        pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
335      }
336      if (!bSaveXML && !wsChildren.IsEmpty() &&
337          pNode->GetClassID() == XFA_ELEMENT_Items) {
338        wsChildren.Empty();
339        bSaveXML = TRUE;
340        CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
341        while (pChildNode) {
342          XFA_DataExporter_RegenerateFormFile_Changed(pChildNode, newBuf,
343                                                      bSaveXML);
344          wsChildren += newBuf.GetWideString();
345          newBuf.Clear();
346          pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
347        }
348      }
349      break;
350  }
351  if (!wsChildren.IsEmpty() || !wsAttrs.IsEmpty() ||
352      pNode->HasAttribute(XFA_ATTRIBUTE_Name)) {
353    CFX_WideStringC wsElement;
354    pNode->GetClassName(wsElement);
355    CFX_WideString wsName;
356    XFA_SaveAttribute(pNode, XFA_ATTRIBUTE_Name, FX_WSTRC(L"name"), TRUE,
357                      wsName);
358    buf << FX_WSTRC(L"<");
359    buf << wsElement;
360    buf << wsName;
361    buf << wsAttrs;
362    if (wsChildren.IsEmpty()) {
363      buf << FX_WSTRC(L"\n/>");
364    } else {
365      buf << FX_WSTRC(L"\n>");
366      buf << wsChildren;
367      buf << FX_WSTRC(L"</");
368      buf << wsElement;
369      buf << FX_WSTRC(L"\n>");
370    }
371  }
372}
373static void XFA_DataExporter_RegenerateFormFile_Container(
374    CXFA_Node* pNode,
375    IFX_Stream* pStream,
376    FX_BOOL bSaveXML = FALSE) {
377  XFA_ELEMENT eElement = pNode->GetClassID();
378  if (eElement == XFA_ELEMENT_Field || eElement == XFA_ELEMENT_Draw ||
379      !pNode->IsContainerNode()) {
380    CFX_WideTextBuf buf;
381    XFA_DataExporter_RegenerateFormFile_Changed(pNode, buf, bSaveXML);
382    FX_STRSIZE nLen = buf.GetLength();
383    if (nLen > 0) {
384      pStream->WriteString((const FX_WCHAR*)buf.GetBuffer(), nLen);
385    }
386    return;
387  }
388  CFX_WideStringC wsElement;
389  pNode->GetClassName(wsElement);
390  pStream->WriteString(L"<", 1);
391  pStream->WriteString(wsElement.GetPtr(), wsElement.GetLength());
392  CFX_WideString wsOutput;
393  XFA_SaveAttribute(pNode, XFA_ATTRIBUTE_Name, FX_WSTRC(L"name"), TRUE,
394                    wsOutput);
395  CFX_WideString wsAttrs;
396  int32_t iAttrs = 0;
397  const uint8_t* pAttrs = XFA_GetElementAttributes(pNode->GetClassID(), iAttrs);
398  while (iAttrs--) {
399    XFA_LPCATTRIBUTEINFO pAttr =
400        XFA_GetAttributeByID((XFA_ATTRIBUTE)pAttrs[iAttrs]);
401    if (pAttr->eName == XFA_ATTRIBUTE_Name) {
402      continue;
403    }
404    CFX_WideString wsAttr;
405    XFA_SaveAttribute(pNode, pAttr->eName, pAttr->pName, FALSE, wsAttr);
406    wsOutput += wsAttr;
407  }
408  if (!wsOutput.IsEmpty()) {
409    pStream->WriteString((const FX_WCHAR*)wsOutput, wsOutput.GetLength());
410  }
411  CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
412  if (pChildNode) {
413    pStream->WriteString(L"\n>", 2);
414    while (pChildNode) {
415      XFA_DataExporter_RegenerateFormFile_Container(pChildNode, pStream,
416                                                    bSaveXML);
417      pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
418    }
419    pStream->WriteString(L"</", 2);
420    pStream->WriteString(wsElement.GetPtr(), wsElement.GetLength());
421    pStream->WriteString(L"\n>", 2);
422  } else {
423    pStream->WriteString(L"\n/>", 3);
424  }
425}
426void XFA_DataExporter_RegenerateFormFile(CXFA_Node* pNode,
427                                         IFX_Stream* pStream,
428                                         const FX_CHAR* pChecksum,
429                                         FX_BOOL bSaveXML) {
430  if (pNode->GetObjectType() == XFA_OBJECTTYPE_ModelNode) {
431    static const FX_WCHAR* s_pwsTagName = L"<form";
432    static const FX_WCHAR* s_pwsClose = L"</form\n>";
433    pStream->WriteString(s_pwsTagName, FXSYS_wcslen(s_pwsTagName));
434    if (pChecksum != NULL) {
435      static const FX_WCHAR* s_pwChecksum = L" checksum=\"";
436      CFX_WideString wsChecksum =
437          CFX_WideString::FromUTF8(pChecksum, FXSYS_strlen(pChecksum));
438      pStream->WriteString(s_pwChecksum, FXSYS_wcslen(s_pwChecksum));
439      pStream->WriteString((const FX_WCHAR*)wsChecksum, wsChecksum.GetLength());
440      pStream->WriteString(L"\"", 1);
441    }
442    pStream->WriteString(L" xmlns=\"", FXSYS_wcslen(L" xmlns=\""));
443    const FX_WCHAR* pURI = XFA_GetPacketByIndex(XFA_PACKET_Form)->pURI;
444    pStream->WriteString(pURI, FXSYS_wcslen(pURI));
445    CFX_WideString wsVersionNumber;
446    XFA_DataExporter_RecognizeXFAVersionNumber(
447        (CXFA_Node*)pNode->GetDocument()->GetXFANode(XFA_XDPPACKET_Template),
448        wsVersionNumber);
449    if (wsVersionNumber.IsEmpty()) {
450      wsVersionNumber = FX_WSTRC(L"2.8");
451    }
452    wsVersionNumber += FX_WSTRC(L"/\"\n>");
453    pStream->WriteString((const FX_WCHAR*)wsVersionNumber,
454                         wsVersionNumber.GetLength());
455    CXFA_Node* pChildNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
456    while (pChildNode) {
457      XFA_DataExporter_RegenerateFormFile_Container(pChildNode, pStream);
458      pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling);
459    }
460    pStream->WriteString(s_pwsClose, FXSYS_wcslen(s_pwsClose));
461  } else {
462    XFA_DataExporter_RegenerateFormFile_Container(pNode, pStream, bSaveXML);
463  }
464}
465IXFA_PacketExport* IXFA_PacketExport::Create(CXFA_Document* pDocument,
466                                             XFA_DATAFORMAT eFormat) {
467  return new CXFA_DataExporter(pDocument);
468}
469CXFA_DataExporter::CXFA_DataExporter(CXFA_Document* pDocument)
470    : m_pDocument(pDocument) {
471  ASSERT(m_pDocument != NULL);
472}
473FX_BOOL CXFA_DataExporter::Export(IFX_FileWrite* pWrite) {
474  return Export(pWrite, m_pDocument->GetRoot());
475}
476FX_BOOL CXFA_DataExporter::Export(IFX_FileWrite* pWrite,
477                                  CXFA_Node* pNode,
478                                  FX_DWORD dwFlag,
479                                  const FX_CHAR* pChecksum) {
480  ASSERT(pWrite != NULL);
481  if (pWrite == NULL) {
482    return FALSE;
483  }
484  IFX_Stream* pStream = IFX_Stream::CreateStream(
485      pWrite,
486      FX_STREAMACCESS_Text | FX_STREAMACCESS_Write | FX_STREAMACCESS_Append);
487  if (pStream == NULL) {
488    return FALSE;
489  }
490  pStream->SetCodePage(FX_CODEPAGE_UTF8);
491  FX_BOOL bRet = Export(pStream, pNode, dwFlag, pChecksum);
492  pStream->Release();
493  return bRet;
494}
495FX_BOOL CXFA_DataExporter::Export(IFX_Stream* pStream,
496                                  CXFA_Node* pNode,
497                                  FX_DWORD dwFlag,
498                                  const FX_CHAR* pChecksum) {
499  IFDE_XMLDoc* pXMLDoc = m_pDocument->GetParser()->GetXMLDoc();
500  if (pNode->GetObjectType() == XFA_OBJECTTYPE_ModelNode) {
501    switch (pNode->GetPacketID()) {
502      case XFA_XDPPACKET_XDP: {
503        static const FX_WCHAR* s_pwsPreamble =
504            L"<xdp:xdp xmlns:xdp=\"http://ns.adobe.com/xdp/\">";
505        pStream->WriteString(s_pwsPreamble, FXSYS_wcslen(s_pwsPreamble));
506        for (CXFA_Node* pChild = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
507             pChild; pChild = pChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
508          Export(pStream, pChild, dwFlag, pChecksum);
509        }
510        static const FX_WCHAR* s_pwsPostamble = L"</xdp:xdp\n>";
511        pStream->WriteString(s_pwsPostamble, FXSYS_wcslen(s_pwsPostamble));
512      } break;
513      case XFA_XDPPACKET_Datasets: {
514        IFDE_XMLElement* pElement =
515            (IFDE_XMLElement*)pNode->GetXMLMappingNode();
516        if (!pElement || pElement->GetType() != FDE_XMLNODE_Element) {
517          return FALSE;
518        }
519        CXFA_Node* pDataNode = pNode->GetNodeItem(XFA_NODEITEM_FirstChild);
520        FXSYS_assert(pDataNode != NULL);
521        XFA_DataExporter_DealWithDataGroupNode(pDataNode);
522        pXMLDoc->SaveXMLNode(pStream, pElement);
523      } break;
524      case XFA_XDPPACKET_Form: {
525        XFA_DataExporter_RegenerateFormFile(pNode, pStream, pChecksum);
526      } break;
527      case XFA_XDPPACKET_Template:
528      default: {
529        IFDE_XMLElement* pElement =
530            (IFDE_XMLElement*)pNode->GetXMLMappingNode();
531        if (!pElement || pElement->GetType() != FDE_XMLNODE_Element) {
532          return FALSE;
533        }
534        pXMLDoc->SaveXMLNode(pStream, pElement);
535      } break;
536    }
537  } else {
538    CXFA_Node* pDataNode = pNode->GetNodeItem(XFA_NODEITEM_Parent);
539    CXFA_Node* pExportNode = pNode;
540    for (CXFA_Node* pChildNode =
541             pDataNode->GetNodeItem(XFA_NODEITEM_FirstChild);
542         pChildNode;
543         pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
544      if (pChildNode != pNode) {
545        pExportNode = pDataNode;
546        break;
547      }
548    }
549    IFDE_XMLElement* pElement =
550        (IFDE_XMLElement*)pExportNode->GetXMLMappingNode();
551    if (!pElement || pElement->GetType() != FDE_XMLNODE_Element) {
552      return FALSE;
553    }
554    XFA_DataExporter_DealWithDataGroupNode(pExportNode);
555    pElement->SetString(FX_WSTRC(L"xmlns:xfa"),
556                        FX_WSTRC(L"http://www.xfa.org/schema/xfa-data/1.0/"));
557    pXMLDoc->SaveXMLNode(pStream, pElement);
558    pElement->RemoveAttribute(L"xmlns:xfa");
559  }
560  return TRUE;
561}
562void XFA_DataExporter_DealWithDataGroupNode(CXFA_Node* pDataNode) {
563  if (!pDataNode || pDataNode->GetClassID() == XFA_ELEMENT_DataValue) {
564    return;
565  }
566  int32_t iChildNum = 0;
567  for (CXFA_Node* pChildNode = pDataNode->GetNodeItem(XFA_NODEITEM_FirstChild);
568       pChildNode;
569       pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
570    iChildNum++;
571    XFA_DataExporter_DealWithDataGroupNode(pChildNode);
572  }
573  if (pDataNode->GetClassID() == XFA_ELEMENT_DataGroup) {
574    if (iChildNum > 0) {
575      IFDE_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
576      FXSYS_assert(pXMLNode->GetType() == FDE_XMLNODE_Element);
577      IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode;
578      if (pXMLElement->HasAttribute(L"xfa:dataNode")) {
579        pXMLElement->RemoveAttribute(L"xfa:dataNode");
580      }
581    } else {
582      IFDE_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
583      FXSYS_assert(pXMLNode->GetType() == FDE_XMLNODE_Element);
584      ((IFDE_XMLElement*)pXMLNode)
585          ->SetString(FX_WSTRC(L"xfa:dataNode"), FX_WSTRC(L"dataGroup"));
586    }
587  }
588}
589