123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- /**
- * 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 ('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));
-
- }
- }
|