plist 4.0.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -111
- package/dist/build-binary.d.ts +6 -0
- package/dist/build-binary.d.ts.map +1 -0
- package/dist/build-binary.js +284 -0
- package/dist/build-binary.js.map +1 -0
- package/dist/build.browser.d.ts +16 -0
- package/dist/build.browser.d.ts.map +1 -0
- package/dist/build.browser.js +107 -0
- package/dist/build.browser.js.map +1 -0
- package/dist/build.d.ts +16 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +94 -0
- package/dist/build.js.map +1 -0
- package/dist/index.browser.d.ts +7 -0
- package/dist/index.browser.d.ts.map +1 -0
- package/dist/index.browser.js +6 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/parse-binary.d.ts +6 -0
- package/dist/parse-binary.d.ts.map +1 -0
- package/dist/parse-binary.js +179 -0
- package/dist/parse-binary.js.map +1 -0
- package/dist/parse-openstep.d.ts +6 -0
- package/dist/parse-openstep.d.ts.map +1 -0
- package/dist/parse-openstep.js +197 -0
- package/dist/parse-openstep.js.map +1 -0
- package/dist/parse.browser.d.ts +11 -0
- package/dist/parse.browser.d.ts.map +1 -0
- package/dist/parse.browser.js +208 -0
- package/dist/parse.browser.js.map +1 -0
- package/dist/parse.d.ts +11 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +209 -0
- package/dist/parse.js.map +1 -0
- package/package.json +31 -8
- package/index.js +0 -2
- package/lib/build.js +0 -147
- package/lib/parse.js +0 -213
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
class OpenStepParser {
|
|
2
|
+
input;
|
|
3
|
+
pos;
|
|
4
|
+
constructor(input) {
|
|
5
|
+
this.input = input;
|
|
6
|
+
this.pos = 0;
|
|
7
|
+
}
|
|
8
|
+
skipWhitespaceAndComments() {
|
|
9
|
+
while (this.pos < this.input.length) {
|
|
10
|
+
const ch = this.input[this.pos];
|
|
11
|
+
if (/\s/.test(ch)) {
|
|
12
|
+
this.pos++;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (ch === '/' &&
|
|
16
|
+
this.pos + 1 < this.input.length &&
|
|
17
|
+
this.input[this.pos + 1] === '*') {
|
|
18
|
+
this.pos += 2;
|
|
19
|
+
const end = this.input.indexOf('*/', this.pos);
|
|
20
|
+
if (end === -1)
|
|
21
|
+
throw new Error('Unterminated block comment');
|
|
22
|
+
this.pos = end + 2;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (ch === '/' &&
|
|
26
|
+
this.pos + 1 < this.input.length &&
|
|
27
|
+
this.input[this.pos + 1] === '/') {
|
|
28
|
+
this.pos += 2;
|
|
29
|
+
const end = this.input.indexOf('\n', this.pos);
|
|
30
|
+
this.pos = end === -1 ? this.input.length : end + 1;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
parseValue() {
|
|
37
|
+
this.skipWhitespaceAndComments();
|
|
38
|
+
if (this.pos >= this.input.length) {
|
|
39
|
+
throw new Error('Unexpected end of input');
|
|
40
|
+
}
|
|
41
|
+
const ch = this.input[this.pos];
|
|
42
|
+
if (ch === '{')
|
|
43
|
+
return this.parseDict();
|
|
44
|
+
if (ch === '(')
|
|
45
|
+
return this.parseArray();
|
|
46
|
+
if (ch === '<')
|
|
47
|
+
return this.parseData();
|
|
48
|
+
if (ch === '"')
|
|
49
|
+
return this.parseQuotedString();
|
|
50
|
+
return this.parseUnquotedString();
|
|
51
|
+
}
|
|
52
|
+
parseDict() {
|
|
53
|
+
this.pos++; // skip {
|
|
54
|
+
const obj = {};
|
|
55
|
+
while (true) {
|
|
56
|
+
this.skipWhitespaceAndComments();
|
|
57
|
+
if (this.pos >= this.input.length)
|
|
58
|
+
throw new Error('Unterminated dictionary');
|
|
59
|
+
if (this.input[this.pos] === '}') {
|
|
60
|
+
this.pos++;
|
|
61
|
+
return obj;
|
|
62
|
+
}
|
|
63
|
+
const key = this.parseValue();
|
|
64
|
+
this.skipWhitespaceAndComments();
|
|
65
|
+
if (this.pos >= this.input.length || this.input[this.pos] !== '=')
|
|
66
|
+
throw new Error(`Expected '=' after key "${key}" at position ${this.pos}`);
|
|
67
|
+
this.pos++; // skip =
|
|
68
|
+
const value = this.parseValue();
|
|
69
|
+
obj[key] = value;
|
|
70
|
+
this.skipWhitespaceAndComments();
|
|
71
|
+
if (this.pos < this.input.length && this.input[this.pos] === ';') {
|
|
72
|
+
this.pos++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
parseArray() {
|
|
77
|
+
this.pos++; // skip (
|
|
78
|
+
const arr = [];
|
|
79
|
+
this.skipWhitespaceAndComments();
|
|
80
|
+
if (this.pos < this.input.length && this.input[this.pos] === ')') {
|
|
81
|
+
this.pos++;
|
|
82
|
+
return arr;
|
|
83
|
+
}
|
|
84
|
+
while (true) {
|
|
85
|
+
arr.push(this.parseValue());
|
|
86
|
+
this.skipWhitespaceAndComments();
|
|
87
|
+
if (this.pos >= this.input.length)
|
|
88
|
+
throw new Error('Unterminated array');
|
|
89
|
+
if (this.input[this.pos] === ')') {
|
|
90
|
+
this.pos++;
|
|
91
|
+
return arr;
|
|
92
|
+
}
|
|
93
|
+
if (this.input[this.pos] === ',') {
|
|
94
|
+
this.pos++;
|
|
95
|
+
// Allow trailing comma before )
|
|
96
|
+
this.skipWhitespaceAndComments();
|
|
97
|
+
if (this.pos < this.input.length && this.input[this.pos] === ')') {
|
|
98
|
+
this.pos++;
|
|
99
|
+
return arr;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw new Error(`Expected ',' or ')' in array at position ${this.pos}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
parseData() {
|
|
108
|
+
this.pos++; // skip <
|
|
109
|
+
let hex = '';
|
|
110
|
+
while (this.pos < this.input.length) {
|
|
111
|
+
const ch = this.input[this.pos];
|
|
112
|
+
if (ch === '>') {
|
|
113
|
+
this.pos++;
|
|
114
|
+
// Parse hex pairs
|
|
115
|
+
const clean = hex.replace(/\s+/g, '');
|
|
116
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
117
|
+
for (let i = 0; i < clean.length; i += 2) {
|
|
118
|
+
bytes[i / 2] = parseInt(clean.substring(i, i + 2), 16);
|
|
119
|
+
}
|
|
120
|
+
return bytes;
|
|
121
|
+
}
|
|
122
|
+
hex += ch;
|
|
123
|
+
this.pos++;
|
|
124
|
+
}
|
|
125
|
+
throw new Error('Unterminated data');
|
|
126
|
+
}
|
|
127
|
+
parseQuotedString() {
|
|
128
|
+
this.pos++; // skip opening "
|
|
129
|
+
let result = '';
|
|
130
|
+
while (this.pos < this.input.length) {
|
|
131
|
+
const ch = this.input[this.pos];
|
|
132
|
+
if (ch === '\\') {
|
|
133
|
+
this.pos++;
|
|
134
|
+
if (this.pos >= this.input.length)
|
|
135
|
+
throw new Error('Unterminated string escape');
|
|
136
|
+
const esc = this.input[this.pos];
|
|
137
|
+
switch (esc) {
|
|
138
|
+
case '"':
|
|
139
|
+
result += '"';
|
|
140
|
+
break;
|
|
141
|
+
case '\\':
|
|
142
|
+
result += '\\';
|
|
143
|
+
break;
|
|
144
|
+
case 'n':
|
|
145
|
+
result += '\n';
|
|
146
|
+
break;
|
|
147
|
+
case 't':
|
|
148
|
+
result += '\t';
|
|
149
|
+
break;
|
|
150
|
+
case 'r':
|
|
151
|
+
result += '\r';
|
|
152
|
+
break;
|
|
153
|
+
case '0':
|
|
154
|
+
result += '\0';
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
result += esc;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
this.pos++;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (ch === '"') {
|
|
164
|
+
this.pos++;
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
result += ch;
|
|
168
|
+
this.pos++;
|
|
169
|
+
}
|
|
170
|
+
throw new Error('Unterminated string');
|
|
171
|
+
}
|
|
172
|
+
parseUnquotedString() {
|
|
173
|
+
const start = this.pos;
|
|
174
|
+
while (this.pos < this.input.length) {
|
|
175
|
+
const ch = this.input[this.pos];
|
|
176
|
+
if (/[a-zA-Z0-9._\/$:-]/.test(ch)) {
|
|
177
|
+
this.pos++;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (this.pos === start) {
|
|
184
|
+
throw new Error(`Unexpected character '${this.input[this.pos]}' at position ${this.pos}`);
|
|
185
|
+
}
|
|
186
|
+
return this.input.substring(start, this.pos);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Parses an OpenStep/ASCII plist string into a PlistValue.
|
|
191
|
+
*/
|
|
192
|
+
export function parseOpenStep(input) {
|
|
193
|
+
const parser = new OpenStepParser(input);
|
|
194
|
+
const value = parser.parseValue();
|
|
195
|
+
return value;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=parse-openstep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-openstep.js","sourceRoot":"","sources":["../src/parse-openstep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type PlistValue = string | number | boolean | Date | Uint8Array | PlistValue[] | {
|
|
2
|
+
[key: string]: PlistValue;
|
|
3
|
+
} | null;
|
|
4
|
+
/**
|
|
5
|
+
* Parses a Plist XML string. Returns an Object.
|
|
6
|
+
*
|
|
7
|
+
* @param xml - the XML String to decode
|
|
8
|
+
* @returns the decoded value from the Plist XML
|
|
9
|
+
*/
|
|
10
|
+
export declare function parse(xml: string | Uint8Array | ArrayBuffer): PlistValue;
|
|
11
|
+
//# sourceMappingURL=parse.browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.browser.d.ts","sourceRoot":"","sources":["../src/parse.browser.ts"],"names":[],"mappings":"AAoDA,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,UAAU,GACV,UAAU,EAAE,GACZ;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,GAC7B,IAAI,CAAC;AAET;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAuCxE"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { parseBinary } from './parse-binary.js';
|
|
2
|
+
import { parseOpenStep } from './parse-openstep.js';
|
|
3
|
+
/**
|
|
4
|
+
* Decode a base64 string into a Uint8Array.
|
|
5
|
+
*/
|
|
6
|
+
function base64ToUint8Array(base64) {
|
|
7
|
+
const binary = atob(base64);
|
|
8
|
+
const bytes = new Uint8Array(binary.length);
|
|
9
|
+
for (let i = 0; i < binary.length; i++) {
|
|
10
|
+
bytes[i] = binary.charCodeAt(i);
|
|
11
|
+
}
|
|
12
|
+
return bytes;
|
|
13
|
+
}
|
|
14
|
+
const TEXT_NODE = 3;
|
|
15
|
+
const CDATA_NODE = 4;
|
|
16
|
+
const COMMENT_NODE = 8;
|
|
17
|
+
/**
|
|
18
|
+
* We ignore raw text (usually whitespace), <!-- xml comments -->,
|
|
19
|
+
* and raw CDATA nodes.
|
|
20
|
+
*/
|
|
21
|
+
function shouldIgnoreNode(node) {
|
|
22
|
+
return (node.nodeType === TEXT_NODE ||
|
|
23
|
+
node.nodeType === COMMENT_NODE ||
|
|
24
|
+
node.nodeType === CDATA_NODE);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if the node is empty. Some plist file has such node:
|
|
28
|
+
* <key />
|
|
29
|
+
* this node should be ignored.
|
|
30
|
+
*
|
|
31
|
+
* @see https://github.com/TooTallNate/plist.js/issues/66
|
|
32
|
+
*/
|
|
33
|
+
function isEmptyNode(node) {
|
|
34
|
+
if (!node.childNodes || node.childNodes.length === 0) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function invariant(test, message) {
|
|
42
|
+
if (!test) {
|
|
43
|
+
throw new Error(message);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parses a Plist XML string. Returns an Object.
|
|
48
|
+
*
|
|
49
|
+
* @param xml - the XML String to decode
|
|
50
|
+
* @returns the decoded value from the Plist XML
|
|
51
|
+
*/
|
|
52
|
+
export function parse(xml) {
|
|
53
|
+
// Handle binary plist input
|
|
54
|
+
if (xml instanceof ArrayBuffer) {
|
|
55
|
+
return parseBinary(new Uint8Array(xml));
|
|
56
|
+
}
|
|
57
|
+
if (xml instanceof Uint8Array) {
|
|
58
|
+
return parseBinary(xml);
|
|
59
|
+
}
|
|
60
|
+
if (typeof xml === 'string' && xml.startsWith('bplist')) {
|
|
61
|
+
const encoder = new TextEncoder();
|
|
62
|
+
return parseBinary(encoder.encode(xml));
|
|
63
|
+
}
|
|
64
|
+
// Detect OpenStep/ASCII plist format
|
|
65
|
+
if (typeof xml === 'string') {
|
|
66
|
+
const trimmed = xml.trimStart();
|
|
67
|
+
if ((trimmed[0] === '{' || trimmed[0] === '(') &&
|
|
68
|
+
!trimmed.startsWith('<?xml') &&
|
|
69
|
+
!trimmed.startsWith('<!DOCTYPE') &&
|
|
70
|
+
!trimmed.startsWith('<plist')) {
|
|
71
|
+
return parseOpenStep(xml);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const doc = new DOMParser().parseFromString(xml, "text/xml");
|
|
75
|
+
const root = doc.documentElement;
|
|
76
|
+
invariant(root !== null && root.nodeName === "plist", "malformed document. First element should be <plist>");
|
|
77
|
+
let plist = parsePlistXML(root);
|
|
78
|
+
// the root <plist> node gets interpreted as an Array,
|
|
79
|
+
// so pull out the inner data first
|
|
80
|
+
if (Array.isArray(plist) && plist.length == 1)
|
|
81
|
+
plist = plist[0];
|
|
82
|
+
return plist;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert an XML based plist document into a JSON representation.
|
|
86
|
+
*/
|
|
87
|
+
function parsePlistXML(node) {
|
|
88
|
+
if (!node)
|
|
89
|
+
return null;
|
|
90
|
+
if (node.nodeName === "plist") {
|
|
91
|
+
const new_arr = [];
|
|
92
|
+
if (isEmptyNode(node)) {
|
|
93
|
+
return new_arr;
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
96
|
+
if (!shouldIgnoreNode(node.childNodes[i])) {
|
|
97
|
+
new_arr.push(parsePlistXML(node.childNodes[i]));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return new_arr;
|
|
101
|
+
}
|
|
102
|
+
else if (node.nodeName === "dict") {
|
|
103
|
+
const new_obj = {};
|
|
104
|
+
let key = null;
|
|
105
|
+
let counter = 0;
|
|
106
|
+
if (isEmptyNode(node)) {
|
|
107
|
+
return new_obj;
|
|
108
|
+
}
|
|
109
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
110
|
+
if (shouldIgnoreNode(node.childNodes[i]))
|
|
111
|
+
continue;
|
|
112
|
+
if (counter % 2 === 0) {
|
|
113
|
+
invariant(node.childNodes[i].nodeName === "key", "Missing key while parsing <dict/>.");
|
|
114
|
+
key = parsePlistXML(node.childNodes[i]);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
invariant(node.childNodes[i].nodeName !== "key", "Unexpected <key> while parsing <dict/>. Keys and values must alternate.");
|
|
118
|
+
new_obj[key] = parsePlistXML(node.childNodes[i]);
|
|
119
|
+
}
|
|
120
|
+
counter += 1;
|
|
121
|
+
}
|
|
122
|
+
if (counter % 2 === 1) {
|
|
123
|
+
new_obj[key] = "";
|
|
124
|
+
}
|
|
125
|
+
return new_obj;
|
|
126
|
+
}
|
|
127
|
+
else if (node.nodeName === "array") {
|
|
128
|
+
const new_arr = [];
|
|
129
|
+
if (isEmptyNode(node)) {
|
|
130
|
+
return new_arr;
|
|
131
|
+
}
|
|
132
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
133
|
+
if (!shouldIgnoreNode(node.childNodes[i])) {
|
|
134
|
+
const res = parsePlistXML(node.childNodes[i]);
|
|
135
|
+
if (null != res)
|
|
136
|
+
new_arr.push(res);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return new_arr;
|
|
140
|
+
}
|
|
141
|
+
else if (node.nodeName === "#text") {
|
|
142
|
+
// TODO: what should we do with text types? (CDATA sections)
|
|
143
|
+
}
|
|
144
|
+
else if (node.nodeName === "key") {
|
|
145
|
+
if (isEmptyNode(node)) {
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
invariant(node.childNodes[0].nodeValue !== "__proto__", "__proto__ keys can lead to prototype pollution. More details on CVE-2022-22912");
|
|
149
|
+
return node.childNodes[0].nodeValue;
|
|
150
|
+
}
|
|
151
|
+
else if (node.nodeName === "string") {
|
|
152
|
+
let res = "";
|
|
153
|
+
if (isEmptyNode(node)) {
|
|
154
|
+
return res;
|
|
155
|
+
}
|
|
156
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
157
|
+
const type = node.childNodes[i].nodeType;
|
|
158
|
+
if (type === TEXT_NODE || type === CDATA_NODE) {
|
|
159
|
+
res += node.childNodes[i].nodeValue;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return res;
|
|
163
|
+
}
|
|
164
|
+
else if (node.nodeName === "integer") {
|
|
165
|
+
invariant(!isEmptyNode(node), 'Cannot parse "" as integer.');
|
|
166
|
+
return parseInt(node.childNodes[0].nodeValue, 10);
|
|
167
|
+
}
|
|
168
|
+
else if (node.nodeName === "real") {
|
|
169
|
+
invariant(!isEmptyNode(node), 'Cannot parse "" as real.');
|
|
170
|
+
let res = "";
|
|
171
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
172
|
+
if (node.childNodes[i].nodeType === TEXT_NODE) {
|
|
173
|
+
res += node.childNodes[i].nodeValue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return parseFloat(res);
|
|
177
|
+
}
|
|
178
|
+
else if (node.nodeName === "data") {
|
|
179
|
+
let res = "";
|
|
180
|
+
if (isEmptyNode(node)) {
|
|
181
|
+
return base64ToUint8Array(res);
|
|
182
|
+
}
|
|
183
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
184
|
+
if (node.childNodes[i].nodeType === TEXT_NODE) {
|
|
185
|
+
res += node.childNodes[i].nodeValue.replace(/\s+/g, "");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return base64ToUint8Array(res);
|
|
189
|
+
}
|
|
190
|
+
else if (node.nodeName === "date") {
|
|
191
|
+
invariant(!isEmptyNode(node), 'Cannot parse "" as Date.');
|
|
192
|
+
return new Date(node.childNodes[0].nodeValue);
|
|
193
|
+
}
|
|
194
|
+
else if (node.nodeName === "null") {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
else if (node.nodeName === "true") {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
else if (node.nodeName === "false") {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
throw new Error("Invalid PLIST tag " + node.nodeName);
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=parse.browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.browser.js","sourceRoot":"","sources":["../src/parse.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;GAEG;AACH,SAAS,kBAAkB,CAAC,MAAc;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,CAAC;AACpB,MAAM,UAAU,GAAG,CAAC,CAAC;AACrB,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAU;IAClC,OAAO,CACL,IAAI,CAAC,QAAQ,KAAK,SAAS;QAC3B,IAAI,CAAC,QAAQ,KAAK,YAAY;QAC9B,IAAI,CAAC,QAAQ,KAAK,UAAU,CAC7B,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,IAAU;IAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAa,EAAE,OAAe;IAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAYD;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,GAAsC;IAC1D,4BAA4B;IAC5B,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,qCAAqC;IACrC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;QAChC,IACE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;YAC1C,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;YAC5B,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC;YAChC,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAC7B,CAAC;YACD,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,CAAC;IACjC,SAAS,CACP,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAC1C,qDAAqD,CACtD,CAAC;IACF,IAAI,KAAK,GAAG,aAAa,CAAC,IAAuB,CAAC,CAAC;IAEnD,sDAAsD;IACtD,mCAAmC;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEhE,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,IAAU;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,MAAM,OAAO,GAAkC,EAAE,CAAC;QAClD,IAAI,GAAG,GAAkB,IAAI,CAAC;QAC9B,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACnD,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtB,SAAS,CACP,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,EACrC,oCAAoC,CACrC,CAAC;gBACF,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAW,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,SAAS,CACP,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,EACrC,yEAAyE,CAC1E,CAAC;gBACF,OAAO,CAAC,GAAI,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,IAAI,CAAC,CAAC;QACf,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAI,CAAC,GAAG,EAAE,CAAC;QACrB,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1C,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9C,IAAI,IAAI,IAAI,GAAG;oBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,4DAA4D;IAC9D,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QACnC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,SAAS,CACP,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,WAAW,EAC5C,gFAAgF,CACjF,CAAC;QAEF,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtC,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtC,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YACzC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9C,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACtC,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACvC,SAAS,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAC7D,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAU,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,SAAS,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,0BAA0B,CAAC,CAAC;QAC1D,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC9C,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACtC,CAAC;QACH,CAAC;QACD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC9C,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QACD,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,SAAS,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,0BAA0B,CAAC,CAAC;QAC1D,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAU,CAAC,CAAC;IACjD,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type PlistValue = string | number | boolean | Date | Uint8Array | PlistValue[] | {
|
|
2
|
+
[key: string]: PlistValue;
|
|
3
|
+
} | null;
|
|
4
|
+
/**
|
|
5
|
+
* Parses a Plist XML string. Returns an Object.
|
|
6
|
+
*
|
|
7
|
+
* @param xml - the XML String to decode
|
|
8
|
+
* @returns the decoded value from the Plist XML
|
|
9
|
+
*/
|
|
10
|
+
export declare function parse(xml: string | Uint8Array | ArrayBuffer): PlistValue;
|
|
11
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAqDA,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,UAAU,GACV,UAAU,EAAE,GACZ;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,GAC7B,IAAI,CAAC;AAET;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAuCxE"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { DOMParser } from '@xmldom/xmldom';
|
|
2
|
+
import { parseBinary } from './parse-binary.js';
|
|
3
|
+
import { parseOpenStep } from './parse-openstep.js';
|
|
4
|
+
/**
|
|
5
|
+
* Decode a base64 string into a Uint8Array.
|
|
6
|
+
*/
|
|
7
|
+
function base64ToUint8Array(base64) {
|
|
8
|
+
const binary = atob(base64);
|
|
9
|
+
const bytes = new Uint8Array(binary.length);
|
|
10
|
+
for (let i = 0; i < binary.length; i++) {
|
|
11
|
+
bytes[i] = binary.charCodeAt(i);
|
|
12
|
+
}
|
|
13
|
+
return bytes;
|
|
14
|
+
}
|
|
15
|
+
const TEXT_NODE = 3;
|
|
16
|
+
const CDATA_NODE = 4;
|
|
17
|
+
const COMMENT_NODE = 8;
|
|
18
|
+
/**
|
|
19
|
+
* We ignore raw text (usually whitespace), <!-- xml comments -->,
|
|
20
|
+
* and raw CDATA nodes.
|
|
21
|
+
*/
|
|
22
|
+
function shouldIgnoreNode(node) {
|
|
23
|
+
return (node.nodeType === TEXT_NODE ||
|
|
24
|
+
node.nodeType === COMMENT_NODE ||
|
|
25
|
+
node.nodeType === CDATA_NODE);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if the node is empty. Some plist file has such node:
|
|
29
|
+
* <key />
|
|
30
|
+
* this node should be ignored.
|
|
31
|
+
*
|
|
32
|
+
* @see https://github.com/TooTallNate/plist.js/issues/66
|
|
33
|
+
*/
|
|
34
|
+
function isEmptyNode(node) {
|
|
35
|
+
if (!node.childNodes || node.childNodes.length === 0) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function invariant(test, message) {
|
|
43
|
+
if (!test) {
|
|
44
|
+
throw new Error(message);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parses a Plist XML string. Returns an Object.
|
|
49
|
+
*
|
|
50
|
+
* @param xml - the XML String to decode
|
|
51
|
+
* @returns the decoded value from the Plist XML
|
|
52
|
+
*/
|
|
53
|
+
export function parse(xml) {
|
|
54
|
+
// Handle binary plist input
|
|
55
|
+
if (xml instanceof ArrayBuffer) {
|
|
56
|
+
return parseBinary(new Uint8Array(xml));
|
|
57
|
+
}
|
|
58
|
+
if (xml instanceof Uint8Array) {
|
|
59
|
+
return parseBinary(xml);
|
|
60
|
+
}
|
|
61
|
+
if (typeof xml === 'string' && xml.startsWith('bplist')) {
|
|
62
|
+
const encoder = new TextEncoder();
|
|
63
|
+
return parseBinary(encoder.encode(xml));
|
|
64
|
+
}
|
|
65
|
+
// Detect OpenStep/ASCII plist format
|
|
66
|
+
if (typeof xml === 'string') {
|
|
67
|
+
const trimmed = xml.trimStart();
|
|
68
|
+
if ((trimmed[0] === '{' || trimmed[0] === '(') &&
|
|
69
|
+
!trimmed.startsWith('<?xml') &&
|
|
70
|
+
!trimmed.startsWith('<!DOCTYPE') &&
|
|
71
|
+
!trimmed.startsWith('<plist')) {
|
|
72
|
+
return parseOpenStep(xml);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const doc = new DOMParser().parseFromString(xml, "text/xml");
|
|
76
|
+
const root = doc.documentElement;
|
|
77
|
+
invariant(root !== null && root.nodeName === "plist", "malformed document. First element should be <plist>");
|
|
78
|
+
let plist = parsePlistXML(root);
|
|
79
|
+
// the root <plist> node gets interpreted as an Array,
|
|
80
|
+
// so pull out the inner data first
|
|
81
|
+
if (Array.isArray(plist) && plist.length == 1)
|
|
82
|
+
plist = plist[0];
|
|
83
|
+
return plist;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Convert an XML based plist document into a JSON representation.
|
|
87
|
+
*/
|
|
88
|
+
function parsePlistXML(node) {
|
|
89
|
+
if (!node)
|
|
90
|
+
return null;
|
|
91
|
+
if (node.nodeName === "plist") {
|
|
92
|
+
const new_arr = [];
|
|
93
|
+
if (isEmptyNode(node)) {
|
|
94
|
+
return new_arr;
|
|
95
|
+
}
|
|
96
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
97
|
+
if (!shouldIgnoreNode(node.childNodes[i])) {
|
|
98
|
+
new_arr.push(parsePlistXML(node.childNodes[i]));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return new_arr;
|
|
102
|
+
}
|
|
103
|
+
else if (node.nodeName === "dict") {
|
|
104
|
+
const new_obj = {};
|
|
105
|
+
let key = null;
|
|
106
|
+
let counter = 0;
|
|
107
|
+
if (isEmptyNode(node)) {
|
|
108
|
+
return new_obj;
|
|
109
|
+
}
|
|
110
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
111
|
+
if (shouldIgnoreNode(node.childNodes[i]))
|
|
112
|
+
continue;
|
|
113
|
+
if (counter % 2 === 0) {
|
|
114
|
+
invariant(node.childNodes[i].nodeName === "key", "Missing key while parsing <dict/>.");
|
|
115
|
+
key = parsePlistXML(node.childNodes[i]);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
invariant(node.childNodes[i].nodeName !== "key", "Unexpected <key> while parsing <dict/>. Keys and values must alternate.");
|
|
119
|
+
new_obj[key] = parsePlistXML(node.childNodes[i]);
|
|
120
|
+
}
|
|
121
|
+
counter += 1;
|
|
122
|
+
}
|
|
123
|
+
if (counter % 2 === 1) {
|
|
124
|
+
new_obj[key] = "";
|
|
125
|
+
}
|
|
126
|
+
return new_obj;
|
|
127
|
+
}
|
|
128
|
+
else if (node.nodeName === "array") {
|
|
129
|
+
const new_arr = [];
|
|
130
|
+
if (isEmptyNode(node)) {
|
|
131
|
+
return new_arr;
|
|
132
|
+
}
|
|
133
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
134
|
+
if (!shouldIgnoreNode(node.childNodes[i])) {
|
|
135
|
+
const res = parsePlistXML(node.childNodes[i]);
|
|
136
|
+
if (null != res)
|
|
137
|
+
new_arr.push(res);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return new_arr;
|
|
141
|
+
}
|
|
142
|
+
else if (node.nodeName === "#text") {
|
|
143
|
+
// TODO: what should we do with text types? (CDATA sections)
|
|
144
|
+
}
|
|
145
|
+
else if (node.nodeName === "key") {
|
|
146
|
+
if (isEmptyNode(node)) {
|
|
147
|
+
return "";
|
|
148
|
+
}
|
|
149
|
+
invariant(node.childNodes[0].nodeValue !== "__proto__", "__proto__ keys can lead to prototype pollution. More details on CVE-2022-22912");
|
|
150
|
+
return node.childNodes[0].nodeValue;
|
|
151
|
+
}
|
|
152
|
+
else if (node.nodeName === "string") {
|
|
153
|
+
let res = "";
|
|
154
|
+
if (isEmptyNode(node)) {
|
|
155
|
+
return res;
|
|
156
|
+
}
|
|
157
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
158
|
+
const type = node.childNodes[i].nodeType;
|
|
159
|
+
if (type === TEXT_NODE || type === CDATA_NODE) {
|
|
160
|
+
res += node.childNodes[i].nodeValue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return res;
|
|
164
|
+
}
|
|
165
|
+
else if (node.nodeName === "integer") {
|
|
166
|
+
invariant(!isEmptyNode(node), 'Cannot parse "" as integer.');
|
|
167
|
+
return parseInt(node.childNodes[0].nodeValue, 10);
|
|
168
|
+
}
|
|
169
|
+
else if (node.nodeName === "real") {
|
|
170
|
+
invariant(!isEmptyNode(node), 'Cannot parse "" as real.');
|
|
171
|
+
let res = "";
|
|
172
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
173
|
+
if (node.childNodes[i].nodeType === TEXT_NODE) {
|
|
174
|
+
res += node.childNodes[i].nodeValue;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return parseFloat(res);
|
|
178
|
+
}
|
|
179
|
+
else if (node.nodeName === "data") {
|
|
180
|
+
let res = "";
|
|
181
|
+
if (isEmptyNode(node)) {
|
|
182
|
+
return base64ToUint8Array(res);
|
|
183
|
+
}
|
|
184
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
185
|
+
if (node.childNodes[i].nodeType === TEXT_NODE) {
|
|
186
|
+
res += node.childNodes[i].nodeValue.replace(/\s+/g, "");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return base64ToUint8Array(res);
|
|
190
|
+
}
|
|
191
|
+
else if (node.nodeName === "date") {
|
|
192
|
+
invariant(!isEmptyNode(node), 'Cannot parse "" as Date.');
|
|
193
|
+
return new Date(node.childNodes[0].nodeValue);
|
|
194
|
+
}
|
|
195
|
+
else if (node.nodeName === "null") {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
else if (node.nodeName === "true") {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
else if (node.nodeName === "false") {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
throw new Error("Invalid PLIST tag " + node.nodeName);
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=parse.js.map
|