From 5dc7f4ade8c9407d8ec947d536332324c438abe4 Mon Sep 17 00:00:00 2001
From: Calixte Denizet <calixte.denizet@gmail.com>
Date: Sun, 6 Jun 2021 16:28:22 +0200
Subject: [PATCH] XFA - CDATA can be xml so parse it when required

---
 src/core/xfa/parser.js       |  9 +++++++++
 src/core/xfa/template.js     |  5 +++++
 src/core/xfa/xfa_object.js   |  6 ++++++
 test/unit/xfa_parser_spec.js | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 52 insertions(+)

diff --git a/src/core/xfa/parser.js b/src/core/xfa/parser.js
index 326cca0a6..2c2c97289 100644
--- a/src/core/xfa/parser.js
+++ b/src/core/xfa/parser.js
@@ -16,7 +16,9 @@
 import {
   $acceptWhitespace,
   $clean,
+  $content,
   $finalize,
+  $isCDATAXml,
   $nsAttributes,
   $onChild,
   $onText,
@@ -150,6 +152,13 @@ class XFAParser extends XMLParserBase {
 
   onEndElement(name) {
     const node = this._current;
+    if (node[$isCDATAXml]() && typeof node[$content] === "string") {
+      const parser = new XFAParser();
+      const root = parser.parse(node[$content]);
+      node[$content] = null;
+      node[$onChild](root);
+    }
+
     node[$finalize]();
     this._current = this._stack.pop();
     if (this._current[$onChild](node)) {
diff --git a/src/core/xfa/template.js b/src/core/xfa/template.js
index 1906bb1de..794c684a7 100644
--- a/src/core/xfa/template.js
+++ b/src/core/xfa/template.js
@@ -29,6 +29,7 @@ import {
   $hasItem,
   $hasSettableValue,
   $ids,
+  $isCDATAXml,
   $isTransparent,
   $namespaceId,
   $nodeName,
@@ -1746,6 +1747,10 @@ class ExData extends ContentObject {
     this.usehref = attributes.usehref || "";
   }
 
+  [$isCDATAXml]() {
+    return this.contentType === "text/html";
+  }
+
   [$onChild](child) {
     if (
       this.contentType === "text/html" &&
diff --git a/src/core/xfa/xfa_object.js b/src/core/xfa/xfa_object.js
index 1234ae91e..685b805eb 100644
--- a/src/core/xfa/xfa_object.js
+++ b/src/core/xfa/xfa_object.js
@@ -51,6 +51,7 @@ const $hasSettableValue = Symbol();
 const $ids = Symbol();
 const $indexOf = Symbol();
 const $insertAt = Symbol();
+const $isCDATAXml = Symbol();
 const $isDataValue = Symbol();
 const $isDescendent = Symbol();
 const $isTransparent = Symbol();
@@ -148,6 +149,10 @@ class XFAObject {
     return false;
   }
 
+  [$isCDATAXml]() {
+    return false;
+  }
+
   [$setId](ids) {
     if (this.id && this[$namespaceId] === NamespaceIds.template.id) {
       ids.set(this.id, this);
@@ -970,6 +975,7 @@ export {
   $ids,
   $indexOf,
   $insertAt,
+  $isCDATAXml,
   $isDataValue,
   $isDescendent,
   $isTransparent,
diff --git a/test/unit/xfa_parser_spec.js b/test/unit/xfa_parser_spec.js
index d080a870c..a0f6f448d 100644
--- a/test/unit/xfa_parser_spec.js
+++ b/test/unit/xfa_parser_spec.js
@@ -256,6 +256,38 @@ describe("XFAParser", function () {
       expect(root[$dump]()).toEqual(expected);
     });
 
+    it("should parse a xfa document and parse CDATA when needed", function () {
+      const xml = `
+<?xml version="1.0"?>
+<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
+  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
+    <subform>
+      <field>
+        <extras>
+          <exData contentType="text/html" name="foo">
+            <![CDATA[<body xmlns="http://www.w3.org/1999/xhtml">
+              <span>hello</span></body>]]>
+          </exData>
+        </extra>
+      </field>
+    </subform>
+  </template>
+</xdp:xdp>
+      `;
+      const root = new XFAParser().parse(xml);
+      const exdata = searchNode(root, root, "foo")[0];
+      const body = exdata[$dump]().$content[$dump]();
+      const expected = {
+        $name: "body",
+        attributes: {},
+        children: [
+          { $content: "hello", $name: "span", attributes: {}, children: [] },
+        ],
+      };
+
+      expect(body).toEqual(expected);
+    });
+
     it("should parse a xfa document and apply some prototypes", function () {
       const xml = `
 <?xml version="1.0"?>