plist.js
4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import xmlplist from 'plist';
import bplistCreate from 'bplist-creator';
import bplistParse from 'bplist-parser';
import fs from './fs';
import log from './logger';
import _ from 'lodash';
const BPLIST_IDENTIFIER = {
BUFFER: Buffer.from('bplist00'),
TEXT: 'bplist00'
};
const PLIST_IDENTIFIER = {
BUFFER: Buffer.from('<'),
TEXT: '<'
};
// XML Plist library helper
async function parseXmlPlistFile (plistFilename) {
let xmlContent = await fs.readFile(plistFilename, 'utf8');
return xmlplist.parse(xmlContent);
}
/**
* Parses a file in xml or binary format of plist
* @param {string} plist The plist file path
* @param {boolean} mustExist If set to false, this method will return an empty object when the file doesn't exist
* @param {boolean} quiet If set to false, the plist path will be logged in debug level
* @returns {Object} parsed plist JS Object
*/
async function parsePlistFile (plist, mustExist = true, quiet = true) {
// handle nonexistant file
if (!await fs.exists(plist)) {
if (mustExist) {
log.errorAndThrow(`Plist file doesn't exist: '${plist}'`);
} else {
log.debug(`Plist file '${plist}' does not exist. Returning an empty plist.`);
return {};
}
}
let obj = {};
let type = 'binary';
try {
obj = await bplistParse.parseFile(plist);
if (obj.length) {
obj = obj[0];
} else {
throw new Error(`Binary file '${plist}'' appears to be empty`);
}
} catch (ign) {
try {
obj = await parseXmlPlistFile(plist);
type = 'xml';
} catch (err) {
log.errorAndThrow(`Could not parse plist file '${plist}' as XML: ${err.message}`);
}
}
if (!quiet) {
log.debug(`Parsed plist file '${plist}' as ${type}`);
}
return obj;
}
/**
* Updates a plist file with the given fields
* @param {string} plist The plist file path
* @param {Object} updatedFields The updated fields-value pairs
* @param {boolean} binary If set to false, the file will be created as a xml plist
* @param {boolean} mustExist If set to false, this method will update an empty plist
* @param {boolean} quiet If set to false, the plist path will be logged in debug level
*/
async function updatePlistFile (plist, updatedFields, binary = true, mustExist = true, quiet = true) {
let obj;
try {
obj = await parsePlistFile(plist, mustExist);
} catch (err) {
log.errorAndThrow(`Could not update plist: ${err.message}`);
}
_.extend(obj, updatedFields);
let newPlist = binary ? bplistCreate(obj) : xmlplist.build(obj);
try {
await fs.writeFile(plist, newPlist);
} catch (err) {
log.errorAndThrow(`Could not save plist: ${err.message}`);
}
if (!quiet) {
log.debug(`Wrote plist file '${plist}'`);
}
}
/**
* Creates a binary plist Buffer from an object
* @param {Object} data The object to be turned into a binary plist
* @returns {Buffer} plist in the form of a binary buffer
*/
function createBinaryPlist (data) {
return bplistCreate(data);
}
/**
* Parses a Buffer into an Object
* @param {Buffer} data The beffer of a binary plist
*/
function parseBinaryPlist (data) {
return bplistParse.parseBuffer(data);
}
function getXmlPlist (data) {
if (_.isString(data) && data.startsWith(PLIST_IDENTIFIER.TEXT)) {
return data;
}
if (_.isBuffer(data) && PLIST_IDENTIFIER.BUFFER.compare(data, 0, PLIST_IDENTIFIER.BUFFER.length) === 0) {
return data.toString();
}
return null;
}
function getBinaryPlist (data) {
if (_.isString(data) && data.startsWith(BPLIST_IDENTIFIER.TEXT)) {
return Buffer.from(data);
}
if (_.isBuffer(data) && BPLIST_IDENTIFIER.BUFFER.compare(data, 0, BPLIST_IDENTIFIER.BUFFER.length) === 0) {
return data;
}
return null;
}
/**
* Creates a plist from an object
* @param {Object} object The JS object to be turned into a plist
* @param {boolean} binary Set it to true for a binary plist
* @returns {string|Buffer} returns a buffer or a string in respect to the binary parameter
*/
function createPlist (object, binary = false) {
if (binary) {
return createBinaryPlist(object);
} else {
return xmlplist.build(object);
}
}
/**
* Parses an buffer or a string to a JS object a plist from an object
* @param {string|Buffer} data The plist in the form of string or Buffer
* @returns {Object} parsed plist JS Object
* @throws Will throw an error if the plist type is unknown
*/
function parsePlist (data) {
let textPlist = getXmlPlist(data);
if (textPlist) {
return xmlplist.parse(textPlist);
}
let binaryPlist = getBinaryPlist(data);
if (binaryPlist) {
return parseBinaryPlist(binaryPlist)[0];
}
throw new Error(`Unknown type of plist, data: ${data.toString()}`);
}
export { parsePlistFile, parsePlist, createPlist, updatePlistFile, createBinaryPlist, parseBinaryPlist };