summaryrefslogtreecommitdiffstats
path: root/content/includes/xmltools.js
diff options
context:
space:
mode:
Diffstat (limited to 'content/includes/xmltools.js')
-rw-r--r--content/includes/xmltools.js155
1 files changed, 155 insertions, 0 deletions
diff --git a/content/includes/xmltools.js b/content/includes/xmltools.js
new file mode 100644
index 0000000..68b69d0
--- /dev/null
+++ b/content/includes/xmltools.js
@@ -0,0 +1,155 @@
+/*
+ * This file is part of EAS-4-TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+ "use strict";
+
+var xmltools = {
+
+ isString : function (obj) {
+ return (Object.prototype.toString.call(obj) === '[object String]');
+ },
+
+ checkString : function(d, fallback = "") {
+ if (this.isString(d)) return d;
+ else return fallback;
+ },
+
+ nodeAsArray : function (node) {
+ let a = [];
+ if (node) {
+ //return, if already an array
+ if (node instanceof Array) return node;
+
+ //else push node into an array
+ a.push(node);
+ }
+ return a;
+ },
+
+ hasWbxmlDataField: function(wbxmlData, path) {
+ if (wbxmlData) {
+ let pathElements = path.split(".");
+ let data = wbxmlData;
+ for (let x = 0; x < pathElements.length; x++) {
+ if (data[pathElements[x]]) data = data[pathElements[x]];
+ else return false;
+ }
+ return true;
+ }
+ return false;
+ },
+
+ getWbxmlDataField: function(wbxmlData,path) {
+ if (wbxmlData) {
+ let pathElements = path.split(".");
+ let data = wbxmlData;
+ let valid = true;
+ for (let x = 0; valid && x < pathElements.length; x++) {
+ if (data[pathElements[x]]) data = data[pathElements[x]];
+ else valid = false;
+ }
+ if (valid) return data;
+ }
+ return false
+ },
+
+ //print content of xml data object (if debug output enabled)
+ printXmlData : function (data, printApplicationData) {
+ if (TbSync.prefs.getIntPref("log.userdatalevel") > 1 || (TbSync.prefs.getIntPref("log.userdatalevel") == 1 && printApplicationData)) {
+ let dump = JSON.stringify(data);
+ TbSync.dump("Extracted XML data", "\n" + dump);
+ }
+ },
+
+ getDataFromXMLString: function (str) {
+ let data = null;
+ let xml = "";
+ if (str == "") return data;
+
+ let oParser = (Services.vc.compare(Services.appinfo.platformVersion, "61.*") >= 0) ? new DOMParser() : Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
+ try {
+ xml = oParser.parseFromString(str, "application/xml");
+ } catch (e) {
+ //however, domparser does not throw an error, it returns an error document
+ //https://developer.mozilla.org/de/docs/Web/API/DOMParser
+ //just in case
+ throw eas.sync.finish("error", "malformed-xml");
+ }
+
+ //check if xml is error document
+ if (xml.documentElement.nodeName == "parsererror") {
+ TbSync.dump("BAD XML", "The above XML and WBXML could not be parsed correctly, something is wrong.");
+ throw eas.sync.finish("error", "malformed-xml");
+ }
+
+ try {
+ data = this.getDataFromXML(xml);
+ } catch (e) {
+ throw eas.sync.finish("error", "mailformed-data");
+ }
+
+ return data;
+ },
+
+ //create data object from XML node
+ getDataFromXML : function (nodes) {
+
+ /*
+ * The passed nodes value could be an entire document in a single node (type 9) or a
+ * single element node (type 1) as returned by getElementById. It could however also
+ * be an array of nodes as returned by getElementsByTagName or a nodeList as returned
+ * by childNodes. In that case node.length is defined.
+ */
+
+ // create the return object
+ let obj = {};
+ let nodeList = [];
+ let multiplicity = {};
+
+ if (nodes.length === undefined) nodeList.push(nodes);
+ else nodeList = nodes;
+
+ // nodelist contains all childs, if two childs have the same name, we cannot add the chils as an object, but as an array of objects
+ for (let node of nodeList) {
+ if (node.nodeType == 1 || node.nodeType == 3) {
+ if (!multiplicity.hasOwnProperty(node.nodeName)) multiplicity[node.nodeName] = 0;
+ multiplicity[node.nodeName]++;
+ //if this nodeName has multiplicity > 1, prepare obj (but only once)
+ if (multiplicity[node.nodeName]==2) obj[node.nodeName] = [];
+ }
+ }
+
+ // process nodes
+ for (let node of nodeList) {
+ switch (node.nodeType) {
+ case 9:
+ //document node, dive directly and process all children
+ if (node.hasChildNodes) obj = this.getDataFromXML(node.childNodes);
+ break;
+ case 1:
+ //element node
+ if (node.hasChildNodes) {
+ //if this is an element with only one text child, do not dive, but get text childs value
+ let o;
+ if (node.childNodes.length == 1 && node.childNodes.item(0).nodeType==3) {
+ //the passed xml is a save xml with all special chars in the user data encoded by encodeURIComponent
+ o = decodeURIComponent(node.childNodes.item(0).nodeValue);
+ } else {
+ o = this.getDataFromXML(node.childNodes);
+ }
+ //check, if we can add the object directly, or if we have to push it into an array
+ if (multiplicity[node.nodeName]>1) obj[node.nodeName].push(o)
+ else obj[node.nodeName] = o;
+ }
+ break;
+ }
+ }
+ return obj;
+ }
+
+};