1 /*******************************************************************************
\r
2 * ============LICENSE_START==================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
25 import java.util.HashMap;
\r
26 import java.util.Map;
\r
31 public class XMLTokener extends JSONTokener {
\r
34 /** The table of entity values. It initially contains Character values for
\r
35 * amp, apos, gt, lt, quot.
\r
37 public static final Map<String,Character> entity;
\r
40 entity = new HashMap<String,Character>(8);
\r
41 entity.put("amp", XML.AMP);
\r
42 entity.put("apos", XML.APOS);
\r
43 entity.put("gt", XML.GT);
\r
44 entity.put("lt", XML.LT);
\r
45 entity.put("quot", XML.QUOT);
\r
49 * Construct an XMLTokener from a string.
\r
50 * @param s A source string.
\r
52 public XMLTokener(String s) {
\r
57 * Get the text in the CDATA block.
\r
58 * @return The string up to the <code>]]></code>.
\r
59 * @throws JSONException If the <code>]]></code> is not found.
\r
61 public String nextCDATA() throws JSONException {
\r
64 StringBuffer sb = new StringBuffer();
\r
68 throw syntaxError("Unclosed CDATA");
\r
71 i = sb.length() - 3;
\r
72 if (i >= 0 && sb.charAt(i) == ']' &&
\r
73 sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
\r
75 return sb.toString();
\r
82 * Get the next XML outer token, trimming whitespace. There are two kinds
\r
83 * of tokens: the '<' character which begins a markup tag, and the content
\r
84 * text between markup tags.
\r
86 * @return A string, or a '<' Character, or null if there is no more
\r
88 * @throws JSONException
\r
90 public Object nextContent() throws JSONException {
\r
95 } while (Character.isWhitespace(c));
\r
102 sb = new StringBuffer();
\r
104 if (c == '<' || c == 0) {
\r
106 return sb.toString().trim();
\r
109 sb.append(nextEntity(c));
\r
119 * Return the next entity. These entities are translated to Characters:
\r
120 * <code>& ' > < "</code>.
\r
121 * @param ampersand An ampersand character.
\r
122 * @return A Character or an entity String if the entity is not recognized.
\r
123 * @throws JSONException If missing ';' in XML entity.
\r
125 public Object nextEntity(char ampersand) throws JSONException {
\r
126 StringBuffer sb = new StringBuffer();
\r
129 if (Character.isLetterOrDigit(c) || c == '#') {
\r
130 sb.append(Character.toLowerCase(c));
\r
131 } else if (c == ';') {
\r
134 throw syntaxError("Missing ';' in XML entity: &" + sb);
\r
137 String string = sb.toString();
\r
138 Object object = entity.get(string);
\r
139 return object != null ? object : ampersand + string + ";";
\r
144 * Returns the next XML meta token. This is used for skipping over <!...>
\r
145 * and <?...?> structures.
\r
146 * @return Syntax characters (<code>< > / = ! ?</code>) are returned as
\r
147 * Character, and strings and names are returned as Boolean. We don't care
\r
148 * what the values actually are.
\r
149 * @throws JSONException If a string is not properly closed or if the XML
\r
150 * is badly structured.
\r
152 public Object nextMeta() throws JSONException {
\r
157 } while (Character.isWhitespace(c));
\r
160 throw syntaxError("Misshaped meta tag");
\r
179 throw syntaxError("Unterminated string");
\r
182 return Boolean.TRUE;
\r
188 if (Character.isWhitespace(c)) {
\r
189 return Boolean.TRUE;
\r
202 return Boolean.TRUE;
\r
210 * Get the next XML Token. These tokens are found inside of angle
\r
211 * brackets. It may be one of these characters: <code>/ > = ! ?</code> or it
\r
212 * may be a string wrapped in single quotes or double quotes, or it may be a
\r
214 * @return a String or a Character.
\r
215 * @throws JSONException If the XML is not well formed.
\r
217 public Object nextToken() throws JSONException {
\r
223 } while (Character.isWhitespace(c));
\r
226 throw syntaxError("Misshaped element");
\r
228 throw syntaxError("Misplaced '<'");
\r
245 sb = new StringBuffer();
\r
249 throw syntaxError("Unterminated string");
\r
252 return sb.toString();
\r
255 sb.append(nextEntity(c));
\r
264 sb = new StringBuffer();
\r
268 if (Character.isWhitespace(c)) {
\r
269 return sb.toString();
\r
273 return sb.toString();
\r
282 return sb.toString();
\r
286 throw syntaxError("Bad character in a name");
\r
294 * Skip characters until past the requested string.
\r
295 * If it is not found, we are left at the end of the source with a result of false.
\r
296 * @param to A string to skip past.
\r
297 * @throws JSONException
\r
299 public boolean skipPast(String to) throws JSONException {
\r
305 int length = to.length();
\r
306 char[] circle = new char[length];
\r
309 * First fill the circle buffer with as many characters as are in the
\r
310 * to string. If we reach an early end, bail.
\r
313 for (i = 0; i < length; i += 1) {
\r
321 /* We will loop, possibly for all of the remaining characters. */
\r
327 /* Compare the circle buffer with the to string. */
\r
329 for (i = 0; i < length; i += 1) {
\r
330 if (circle[j] != to.charAt(i)) {
\r
340 /* If we exit the loop with b intact, then victory is ours. */
\r
346 /* Get the next character. If there isn't one, then defeat is ours. */
\r
353 * Shove the character in the circle buffer and advance the
\r
354 * circle offset. The offset is mod n.
\r
356 circle[offset] = c;
\r
358 if (offset >= length) {
\r