Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/sourcetools/com.ibm.jpp.preprocessor/com/ibm/jpp/xml/XMLParser.java
6004 views
1
/*******************************************************************************
2
* Copyright (c) 1999, 2017 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
package com.ibm.jpp.xml;
23
24
import java.io.IOException;
25
import java.io.InputStream;
26
import java.util.HashMap;
27
import java.util.Map;
28
29
public class XMLParser {
30
static final boolean THROW_ON_EOF = true;
31
static final boolean EOF_ENCOUNTERED = true;
32
static final boolean VERBOSE = false;
33
34
private String _fURI;
35
private InputStream _fInput;
36
private char _fScan;
37
private boolean _fSuccess;
38
private int _fLine = 1;
39
private int _fColumn = 1;
40
private int _fLevel;
41
private IXMLDocumentHandler _fDocumentHandler;
42
private final byte[] _fbuf = new byte[256];
43
private int _fcount;
44
private int _fpos;
45
46
void assertCondition(boolean condition, String detail) throws XMLException {
47
if (!condition) {
48
parseError(detail);
49
}
50
}
51
52
void parseError(String detail) throws XMLException {
53
throw new XMLException(_fURI + "(line " + _fLine + "): Column " + _fColumn + ": " + detail);
54
}
55
56
boolean scan_char() throws XMLException {
57
return scan_char(THROW_ON_EOF);
58
}
59
60
// Read a single character
61
boolean scan_char(boolean throwOnEOF) throws XMLException {
62
try {
63
int i = read();
64
if (i == -1) {
65
if (throwOnEOF) {
66
parseError("Unexpected EOF");
67
} else {
68
return false;
69
}
70
}
71
_fScan = (char) i;
72
} catch (IOException e) {
73
throw new XMLException(e);
74
}
75
76
if (XMLSpec.isLineDelimiter(_fScan)) {
77
_fLine++;
78
_fColumn = 1;
79
} else {
80
_fColumn++;
81
}
82
83
if (VERBOSE) {
84
System.out.print(String.valueOf(_fScan));
85
}
86
return true;
87
}
88
89
void _scan_for_all(String expected) throws XMLException {
90
int length = expected.length();
91
for (int i = 0; i < length; i++) {
92
char expectedChar = expected.charAt(i);
93
if (_fScan != expectedChar) {
94
parseError("Expected '" + expectedChar + "'");
95
}
96
scan_char();
97
}
98
}
99
100
// Eat and discard whitespace
101
private void _skip_whitespace() throws XMLException {
102
while (XMLSpec.isWhitespace(_fScan)) {
103
scan_char();
104
}
105
}
106
107
// Primitive: Scan a name, current scan position is the first char
108
private String _scan_name() throws XMLException {
109
assertCondition(XMLSpec.isNameStartChar(_fScan), "Expected beginning of a name");
110
XMLStringBuffer buffer = new XMLStringBuffer();
111
112
do {
113
buffer.append(_fScan);
114
scan_char();
115
} while (XMLSpec.isNameChar(_fScan));
116
117
return buffer.toString();
118
}
119
120
// Primitive: Scan escaped character reference
121
// We have read a &
122
private String _scan_escaped_char() throws XMLException {
123
assertCondition(_fScan == '&', "Expected beginning of an escaped character");
124
scan_char(); // advance past the ampersand
125
126
boolean scanningDigits = (_fScan == '#');
127
128
if (scanningDigits) {
129
scan_char(); // advance past the sharp
130
}
131
132
XMLStringBuffer buffer = new XMLStringBuffer();
133
while (XMLSpec.isNameChar(_fScan)) {
134
buffer.append(_fScan);
135
scan_char();
136
}
137
138
String escape = buffer.toString();
139
140
if (scanningDigits) {
141
int i = decode(escape);
142
return String.valueOf((char) i);
143
} else {
144
String equivalent = XMLSpec.namedEscapeToString(escape);
145
assertCondition(equivalent != null, "Unrecognized escape -->" + escape);
146
return equivalent;
147
}
148
}
149
150
int read() throws IOException {
151
if (_fbuf == null) {
152
throw new IOException();
153
} else if (_fpos >= _fcount && fillbuf() == -1) {
154
/* Are there buffered bytes available? */
155
return -1; /* no, fill buffer */
156
} else if (_fcount - _fpos <= 0) {
157
/* Did filling the buffer fail with -1 (EOF)? */
158
return -1;
159
} else {
160
return _fbuf[_fpos++] & 0xFF;
161
}
162
}
163
164
private int fillbuf() throws IOException {
165
_fpos = 0;
166
int result = _fInput.read(_fbuf);
167
_fcount = result == -1 ? 0 : result;
168
return result;
169
}
170
171
static int decode(String string) throws NumberFormatException {
172
int length = string.length();
173
int i = 0;
174
if (length == 0) {
175
throw new NumberFormatException();
176
}
177
178
char firstDigit = string.charAt(i++);
179
boolean negative = firstDigit == '-';
180
if (negative) {
181
if (length == 1) {
182
throw new NumberFormatException(string);
183
}
184
firstDigit = string.charAt(i++);
185
}
186
187
int base = 10;
188
if (firstDigit == '0') {
189
if (i == length) {
190
return 0;
191
}
192
193
if ((firstDigit = string.charAt(i++)) == 'x' || firstDigit == 'X') {
194
if (i == length) {
195
throw new NumberFormatException(string);
196
}
197
firstDigit = string.charAt(i++);
198
base = 16;
199
} else {
200
base = 8;
201
}
202
} else if (firstDigit == '#') {
203
if (i == length) {
204
throw new NumberFormatException(string);
205
}
206
firstDigit = string.charAt(i++);
207
base = 16;
208
}
209
210
int result = Character.digit(firstDigit, base);
211
if (result == -1) {
212
throw new NumberFormatException(string);
213
}
214
215
result = -result;
216
while (i < length) {
217
int digit = Character.digit(string.charAt(i++), base);
218
if (digit == -1) {
219
throw new NumberFormatException(string);
220
}
221
222
int next = result * base - digit;
223
if (next > result) {
224
throw new NumberFormatException(string);
225
}
226
result = next;
227
}
228
if (!negative) {
229
result = -result;
230
if (result < 0) {
231
throw new NumberFormatException(string);
232
}
233
}
234
return result;
235
}
236
237
// Primitive: Scan character data
238
private boolean _scan_cdata_or_eof() throws XMLException {
239
XMLStringBuffer buffer = new XMLStringBuffer();
240
241
while (_fScan != '<') {
242
if (_fScan == '&') {
243
buffer.append(_scan_escaped_char());
244
} else {
245
if (!XMLSpec.isWhitespace(_fScan)) {
246
buffer.append(_fScan);
247
} else {
248
buffer.append(" "); // convert to a regular space
249
}
250
}
251
252
if (!scan_char(!THROW_ON_EOF)) {
253
// Failed to read
254
if (_fLevel == 0) {
255
return EOF_ENCOUNTERED;
256
} else {
257
parseError("Character data ended prematurely");
258
}
259
}
260
}
261
262
_fDocumentHandler.xmlCharacters(buffer.toString());
263
return !EOF_ENCOUNTERED;
264
}
265
266
// Primitive: Scan a name, current scan position is the open quote
267
private String _scan_attribute_value() throws XMLException {
268
assertCondition(_fScan == '"', "Expected quoted attribute value");
269
scan_char();
270
271
XMLStringBuffer buffer = new XMLStringBuffer();
272
/*[PR 120136] flags="" in jpp_configuration causes problems*/
273
if (_fScan != '"') {
274
do {
275
buffer.append(_fScan);
276
scan_char();
277
} while (_fScan != '"');
278
}
279
// Advance past the final quote
280
scan_char();
281
282
return buffer.toString();
283
}
284
285
// Scan attributes into a hashtable
286
private Map<String, String> _scan_attributes() throws XMLException {
287
Map<String, String> attributes = new HashMap<>();
288
289
_skip_whitespace();
290
291
while (XMLSpec.isNameStartChar(_fScan)) {
292
String key = _scan_name();
293
_scan_for_all("=");
294
String val = _scan_attribute_value();
295
_skip_whitespace();
296
297
// Store the key-value pair in the hashtable
298
attributes.put(key, val);
299
}
300
301
return attributes;
302
}
303
304
// Perform very cursory verification
305
private void _scan_xml_header() throws XMLException {
306
_scan_for_all("<?xml");
307
Map<String, String> attributes = _scan_attributes();
308
309
String encoding = attributes.get("encoding");
310
assertCondition("UTF-8".equals(encoding), "Unsupported encoding");
311
_scan_for_all("?>");
312
313
// Notify the content handler
314
_fDocumentHandler.xmlStartDocument();
315
}
316
317
// <? already scanned, continue ==> <?xml:stylesheet type="text/xsl"
318
// href="excludes.xsl" ?>
319
private void _scan_processing_instruction() throws XMLException {
320
scan_char(); // advance past '?'
321
_scan_name();
322
_skip_whitespace();
323
_scan_attributes();
324
325
while (_fScan != '>') {
326
scan_char();
327
}
328
}
329
330
// <!- already scanned, continue
331
private void _scan_comment() throws XMLException {
332
_scan_for_all("-"); // get the second '-'
333
334
XMLStringBuffer comment = new XMLStringBuffer();
335
do {
336
scan_char();
337
comment.append(_fScan);
338
} while (!comment.endsWith("-->"));
339
}
340
341
// <!D already scanned, continue
342
// '<!DOCTYPE' S Name (S ExternalID)? S? ('[' (markupdecl | DeclSep)* ']'
343
// S?)? '>'
344
private void _scan_doctype() throws XMLException {
345
_scan_for_all("DOCTYPE");
346
_skip_whitespace();
347
_scan_name();
348
349
while (_fScan != '>') {
350
scan_char();
351
}
352
}
353
354
// <! already scanned, continue
355
private void _scan_doctype_or_comment() throws XMLException {
356
scan_char(); // advance past '!'
357
358
switch (_fScan) {
359
case 'D':
360
_scan_doctype();
361
break;
362
case '-':
363
_scan_comment();
364
break;
365
default:
366
parseError("Unknown <! type -->" + _fScan);
367
break;
368
}
369
}
370
371
// </ already scanned,
372
private void _scan_element_close() throws XMLException {
373
scan_char(); // advance past '/'
374
String closedTag = _scan_name();
375
while (_fScan != '>') {
376
scan_char();
377
}
378
379
// Notify the content handler
380
_fDocumentHandler.xmlEndElement(closedTag);
381
_fLevel--;
382
}
383
384
// Perform very cursory verification
385
private void _scan_element_or_instruction() throws XMLException {
386
assertCondition(_fScan == '<', "Expected entity or directive");
387
scan_char();
388
389
if (_fScan == '?') {
390
_scan_processing_instruction();
391
return;
392
}
393
394
if (_fScan == '!') {
395
_scan_doctype_or_comment();
396
return;
397
}
398
399
if (_fScan == '/') {
400
_scan_element_close();
401
return;
402
}
403
404
String elementName = _scan_name();
405
Map<String, String> attributes = _scan_attributes();
406
407
// Notify the content handler
408
_fDocumentHandler.xmlStartElement(elementName, attributes);
409
_fLevel++;
410
411
_skip_whitespace();
412
if (_fScan == '/') {
413
// Special case for empty elements
414
_fDocumentHandler.xmlEndElement(elementName);
415
_fLevel--;
416
}
417
418
while (_fScan != '>') {
419
scan_char();
420
}
421
scan_char(); // eat the element close
422
}
423
424
boolean checkForCompletion() throws XMLException {
425
while (true) {
426
if (!scan_char(!THROW_ON_EOF)) {
427
return false; // out of data
428
} else if (!XMLSpec.isWhitespace(_fScan)) {
429
return true;
430
}
431
}
432
}
433
434
void parseXML() throws XMLException {
435
_fLevel = 0;
436
437
// Fetch the first character
438
scan_char();
439
440
// Consume any leading whitespace
441
_skip_whitespace();
442
_scan_xml_header();
443
444
// Begin scanning body
445
do {
446
if (_fScan == '<') {
447
_scan_element_or_instruction();
448
}
449
} while (_scan_cdata_or_eof() != EOF_ENCOUNTERED);
450
451
// Notify the content handler
452
_fDocumentHandler.xmlEndDocument();
453
}
454
455
public boolean parse(InputStream uriStream, IXMLDocumentHandler handler) throws XMLException {
456
_fSuccess = false;
457
_fDocumentHandler = handler;
458
459
_fInput = uriStream;
460
parseXML();
461
462
return _fSuccess;
463
}
464
465
}
466
467