Home | History | Annotate | Download | only in parser
      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"
     18 IXFA_PacketImport* IXFA_PacketImport::Create(CXFA_Document* pDocument) {
     19   return new CXFA_DataImporter(pDocument);
     20 }
     21 CXFA_DataImporter::CXFA_DataImporter(CXFA_Document* pDocument)
     22     : m_pDocument(pDocument) {
     23   ASSERT(m_pDocument != NULL);
     24 }
     25 FX_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 }
     72 CFX_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 }
     98 CFX_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 }
    128 static 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 }
    145 static 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 }
    163 FX_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 }
    188 static 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 }
    206 static 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 }
    373 static 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 }
    426 void 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 }
    465 IXFA_PacketExport* IXFA_PacketExport::Create(CXFA_Document* pDocument,
    466                                              XFA_DATAFORMAT eFormat) {
    467   return new CXFA_DataExporter(pDocument);
    468 }
    469 CXFA_DataExporter::CXFA_DataExporter(CXFA_Document* pDocument)
    470     : m_pDocument(pDocument) {
    471   ASSERT(m_pDocument != NULL);
    472 }
    473 FX_BOOL CXFA_DataExporter::Export(IFX_FileWrite* pWrite) {
    474   return Export(pWrite, m_pDocument->GetRoot());
    475 }
    476 FX_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 }
    495 FX_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 }
    562 void 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