aboutsummaryrefslogtreecommitdiff
path: root/generator/node_modules/plist/lib
diff options
context:
space:
mode:
Diffstat (limited to 'generator/node_modules/plist/lib')
-rw-r--r--generator/node_modules/plist/lib/build.js143
-rw-r--r--generator/node_modules/plist/lib/parse.js227
2 files changed, 370 insertions, 0 deletions
diff --git a/generator/node_modules/plist/lib/build.js b/generator/node_modules/plist/lib/build.js
new file mode 100644
index 0000000..c2a84b1
--- /dev/null
+++ b/generator/node_modules/plist/lib/build.js
@@ -0,0 +1,143 @@
+/**
+ * Module dependencies.
+ */
+
+var base64 = require('base64-js');
+var xmlbuilder = require('xmlbuilder');
+
+/**
+ * Module exports.
+ */
+
+exports.build = build;
+
+/**
+ * Accepts a `Date` instance and returns an ISO date string.
+ *
+ * @param {Date} d - Date instance to serialize
+ * @returns {String} ISO date string representation of `d`
+ * @api private
+ */
+
+function ISODateString(d){
+ function pad(n){
+ return n < 10 ? '0' + n : n;
+ }
+ return d.getUTCFullYear()+'-'
+ + pad(d.getUTCMonth()+1)+'-'
+ + pad(d.getUTCDate())+'T'
+ + pad(d.getUTCHours())+':'
+ + pad(d.getUTCMinutes())+':'
+ + pad(d.getUTCSeconds())+'Z';
+}
+
+/**
+ * Returns the internal "type" of `obj` via the
+ * `Object.prototype.toString()` trick.
+ *
+ * @param {Mixed} obj - any value
+ * @returns {String} the internal "type" name
+ * @api private
+ */
+
+var toString = Object.prototype.toString;
+function type (obj) {
+ var m = toString.call(obj).match(/\[object (.*)\]/);
+ return m ? m[1] : m;
+}
+
+/**
+ * Generate an XML plist string from the input object `obj`.
+ *
+ * @param {Object} obj - the object to convert
+ * @param {Object} [opts] - optional options object
+ * @returns {String} converted plist XML string
+ * @api public
+ */
+
+function build (obj, opts) {
+ var XMLHDR = {
+ version: '1.0',
+ encoding: 'UTF-8'
+ };
+
+ var XMLDTD = {
+ pubid: '-//Apple//DTD PLIST 1.0//EN',
+ sysid: 'http://www.apple.com/DTDs/PropertyList-1.0.dtd'
+ };
+
+ var doc = xmlbuilder.create('plist');
+
+ doc.dec(XMLHDR.version, XMLHDR.encoding, XMLHDR.standalone);
+ doc.dtd(XMLDTD.pubid, XMLDTD.sysid);
+ doc.att('version', '1.0');
+
+ walk_obj(obj, doc);
+
+ if (!opts) opts = {};
+ // default `pretty` to `true`
+ opts.pretty = opts.pretty !== false;
+ return doc.end(opts);
+}
+
+/**
+ * depth first, recursive traversal of a javascript object. when complete,
+ * next_child contains a reference to the build XML object.
+ *
+ * @api private
+ */
+
+function walk_obj(next, next_child) {
+ var tag_type, i, prop;
+ var name = type(next);
+
+ if ('Undefined' == name) {
+ return;
+ } else if (Array.isArray(next)) {
+ next_child = next_child.ele('array');
+ for (i = 0; i < next.length; i++) {
+ walk_obj(next[i], next_child);
+ }
+
+ } else if (Buffer.isBuffer(next)) {
+ next_child.ele('data').raw(next.toString('base64'));
+
+ } else if ('Object' == name) {
+ next_child = next_child.ele('dict');
+ for (prop in next) {
+ if (next.hasOwnProperty(prop)) {
+ next_child.ele('key').txt(prop);
+ walk_obj(next[prop], next_child);
+ }
+ }
+
+ } else if ('Number' == name) {
+ // detect if this is an integer or real
+ // TODO: add an ability to force one way or another via a "cast"
+ tag_type = (next % 1 === 0) ? 'integer' : 'real';
+ next_child.ele(tag_type).txt(next.toString());
+
+ } else if ('BigInt' == name) {
+ next_child.ele('integer').txt(next);
+
+ } else if ('Date' == name) {
+ next_child.ele('date').txt(ISODateString(new Date(next)));
+
+ } else if ('Boolean' == name) {
+ next_child.ele(next ? 'true' : 'false');
+
+ } else if ('String' == name) {
+ next_child.ele('string').txt(next);
+
+ } else if ('ArrayBuffer' == name) {
+ next_child.ele('data').raw(base64.fromByteArray(next));
+
+ } else if (next && next.buffer && 'ArrayBuffer' == type(next.buffer)) {
+ // a typed array
+ next_child.ele('data').raw(base64.fromByteArray(new Uint8Array(next.buffer), next_child));
+
+ } else if ('Null' === name) {
+ next_child.ele('null').txt('');
+
+ }
+}
diff --git a/generator/node_modules/plist/lib/parse.js b/generator/node_modules/plist/lib/parse.js
new file mode 100644
index 0000000..b5e7496
--- /dev/null
+++ b/generator/node_modules/plist/lib/parse.js
@@ -0,0 +1,227 @@
+/**
+ * Module dependencies.
+ */
+
+const { DOMParser } = require('@xmldom/xmldom');
+
+/**
+ * Module exports.
+ */
+
+exports.parse = parse;
+
+var TEXT_NODE = 3;
+var CDATA_NODE = 4;
+var COMMENT_NODE = 8;
+
+
+/**
+ * We ignore raw text (usually whitespace), <!-- xml comments -->,
+ * and raw CDATA nodes.
+ *
+ * @param {Element} node
+ * @returns {Boolean}
+ * @api private
+ */
+
+function shouldIgnoreNode (node) {
+ return node.nodeType === TEXT_NODE
+ || node.nodeType === COMMENT_NODE
+ || node.nodeType === CDATA_NODE;
+}
+
+/**
+ * Check if the node is empty. Some plist file has such node:
+ * <key />
+ * this node shoud be ignored.
+ *
+ * @see https://github.com/TooTallNate/plist.js/issues/66
+ * @param {Element} node
+ * @returns {Boolean}
+ * @api private
+ */
+function isEmptyNode(node){
+ if(!node.childNodes || node.childNodes.length === 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+function invariant(test, message) {
+ if (!test) {
+ throw new Error(message);
+ }
+}
+
+/**
+ * Parses a Plist XML string. Returns an Object.
+ *
+ * @param {String} xml - the XML String to decode
+ * @returns {Mixed} the decoded value from the Plist XML
+ * @api public
+ */
+
+function parse (xml) {
+ var doc = new DOMParser().parseFromString(xml);
+ invariant(
+ doc.documentElement.nodeName === 'plist',
+ 'malformed document. First element should be <plist>'
+ );
+ var plist = parsePlistXML(doc.documentElement);
+
+ // the root <plist> node gets interpreted as an Array,
+ // so pull out the inner data first
+ if (plist.length == 1) plist = plist[0];
+
+ return plist;
+}
+
+/**
+ * Convert an XML based plist document into a JSON representation.
+ *
+ * @param {Object} xml_node - current XML node in the plist
+ * @returns {Mixed} built up JSON object
+ * @api private
+ */
+
+function parsePlistXML (node) {
+ var i, new_obj, key, val, new_arr, res, counter, type;
+
+ if (!node)
+ return null;
+
+ if (node.nodeName === 'plist') {
+ new_arr = [];
+ if (isEmptyNode(node)) {
+ return new_arr;
+ }
+ for (i=0; i < node.childNodes.length; i++) {
+ if (!shouldIgnoreNode(node.childNodes[i])) {
+ new_arr.push( parsePlistXML(node.childNodes[i]));
+ }
+ }
+ return new_arr;
+ } else if (node.nodeName === 'dict') {
+ new_obj = {};
+ key = null;
+ counter = 0;
+ if (isEmptyNode(node)) {
+ return new_obj;
+ }
+ for (i=0; i < node.childNodes.length; i++) {
+ if (shouldIgnoreNode(node.childNodes[i])) continue;
+ if (counter % 2 === 0) {
+ invariant(
+ node.childNodes[i].nodeName === 'key',
+ 'Missing key while parsing <dict/>.'
+ );
+ key = parsePlistXML(node.childNodes[i]);
+ } else {
+ invariant(
+ node.childNodes[i].nodeName !== 'key',
+ 'Unexpected key "'
+ + parsePlistXML(node.childNodes[i])
+ + '" while parsing <dict/>.'
+ );
+ new_obj[key] = parsePlistXML(node.childNodes[i]);
+ }
+ counter += 1;
+ }
+ if (counter % 2 === 1) {
+ new_obj[key] = '';
+ }
+
+ return new_obj;
+
+ } else if (node.nodeName === 'array') {
+ new_arr = [];
+ if (isEmptyNode(node)) {
+ return new_arr;
+ }
+ for (i=0; i < node.childNodes.length; i++) {
+ if (!shouldIgnoreNode(node.childNodes[i])) {
+ res = parsePlistXML(node.childNodes[i]);
+ if (null != res) new_arr.push(res);
+ }
+ }
+ return new_arr;
+
+ } else if (node.nodeName === '#text') {
+ // TODO: what should we do with text types? (CDATA sections)
+
+ } else if (node.nodeName === 'key') {
+ if (isEmptyNode(node)) {
+ return '';
+ }
+
+ invariant(
+ node.childNodes[0].nodeValue !== '__proto__',
+ '__proto__ keys can lead to prototype pollution. More details on CVE-2022-22912'
+ );
+
+ return node.childNodes[0].nodeValue;
+ } else if (node.nodeName === 'string') {
+ res = '';
+ if (isEmptyNode(node)) {
+ return res;
+ }
+ for (i=0; i < node.childNodes.length; i++) {
+ var type = node.childNodes[i].nodeType;
+ if (type === TEXT_NODE || type === CDATA_NODE) {
+ res += node.childNodes[i].nodeValue;
+ }
+ }
+ return res;
+
+ } else if (node.nodeName === 'integer') {
+ invariant(
+ !isEmptyNode(node),
+ 'Cannot parse "" as integer.'
+ );
+ return parseInt(node.childNodes[0].nodeValue, 10);
+
+ } else if (node.nodeName === 'real') {
+ invariant(
+ !isEmptyNode(node),
+ 'Cannot parse "" as real.'
+ );
+ res = '';
+ for (i=0; i < node.childNodes.length; i++) {
+ if (node.childNodes[i].nodeType === TEXT_NODE) {
+ res += node.childNodes[i].nodeValue;
+ }
+ }
+ return parseFloat(res);
+
+ } else if (node.nodeName === 'data') {
+ res = '';
+ if (isEmptyNode(node)) {
+ return Buffer.from(res, 'base64');
+ }
+ for (i=0; i < node.childNodes.length; i++) {
+ if (node.childNodes[i].nodeType === TEXT_NODE) {
+ res += node.childNodes[i].nodeValue.replace(/\s+/g, '');
+ }
+ }
+ return Buffer.from(res, 'base64');
+
+ } else if (node.nodeName === 'date') {
+ invariant(
+ !isEmptyNode(node),
+ 'Cannot parse "" as Date.'
+ )
+ return new Date(node.childNodes[0].nodeValue);
+
+ } else if (node.nodeName === 'null') {
+ return null;
+
+ } else if (node.nodeName === 'true') {
+ return true;
+
+ } else if (node.nodeName === 'false') {
+ return false;
+ } else {
+ throw new Error('Invalid PLIST tag ' + node.nodeName);
+ }
+}