Package: XMLParser$Token

XMLParser$Token

nameinstructionbranchcomplexitylinemethod
XMLParser.Token(String, int, String)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 136 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
toString()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * #%~
3: * org.overture.ide.debug
4: * %%
5: * Copyright (C) 2008 - 2014 Overture
6: * %%
7: * This program is free software: you can redistribute it and/or modify
8: * it under the terms of the GNU General Public License as
9: * published by the Free Software Foundation, either version 3 of the
10: * License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public
18: * License along with this program. If not, see
19: * <http://www.gnu.org/licenses/gpl-3.0.html>.
20: * #~%
21: */
22: package org.overture.ide.debug.utils.xml;
23:
24: import java.io.IOException;
25: import java.util.List;
26: import java.util.Properties;
27: import java.util.Vector;
28:
29: public class XMLParser
30: {
31:         private StringBuilder buffer;
32:         private int end;
33:         private int pos;
34:         private char ch;
35:         private Token token;
36:         private String value; // Tag and quoted tokens have values
37:
38:         private enum Token
39:         {
40:                 OPEN("<"), CLOSE(">"), QOPEN("<?"), QCLOSE("?>"), COMPLETE("/>"), STOP(
41:                                 "</"), TAG("tag"), EQUALS("="), QUOTED("quoted value"), CDATA(
42:                                 "<![CDATA["), CDEND("]]>"), EOF("EOF");
43:
44:                 private String value;
45:
46:                 Token(String s)
47:                 {
48:                         value = s;
49:                 }
50:
51:                 @Override
52:                 public String toString()
53:                 {
54:                         return value;
55:                 }
56:         }
57:
58:         public XMLParser(byte[] xml) throws IOException
59:         {
60:                 if (xml[0] == '<' && xml[1] == '?')
61:                 {
62:                         String ascii = new String(xml, "ASCII"); // header is ASCII
63:                         buffer = new StringBuilder(ascii);
64:                         end = ascii.length();
65:                         pos = 0;
66:                         rdCh();
67:                         rdToken();
68:
69:                         checkFor(Token.QOPEN);
70:
71:                         // Check header, like <?xml version="1.0" encoding="UTF-8"?>
72:
73:                         if (token != Token.TAG || !value.equals("xml"))
74:                         {
75:                                 throw new IOException("Expecting '<?xml' at " + pos);
76:                         }
77:
78:                         rdToken();
79:                         Properties p = readAttributes();
80:                         checkFor(Token.QCLOSE);
81:
82:                         String version = p.getProperty("version");
83:                         String encoding = p.getProperty("encoding");
84:
85:                         if (version == null || !version.equals("1.0"))
86:                         {
87:                                 throw new IOException("Expecting XML version 1.0 at " + pos);
88:                         }
89:
90:                         // Re-encode the remainder using the header encoding
91:
92:                         String body = new String(ascii.substring(pos - 2).getBytes("ASCII"), encoding);
93:                         buffer = new StringBuilder(body);
94:                         end = body.length();
95:                         pos = 0;
96:                         rdCh();
97:                         rdToken();
98:                 } else
99:                 {
100:                         String s = new String(xml); // default platform encoding
101:                         buffer = new StringBuilder(s);
102:                         end = s.length();
103:                         pos = 0;
104:                         rdCh();
105:                         rdToken();
106:                 }
107:         }
108:
109:         private char rdCh()
110:         {
111:                 if (pos == end)
112:                 {
113:                         ch = 0; // EOF
114:                 } else
115:                 {
116:                         ch = buffer.charAt(pos);
117:                         pos++;
118:                 }
119:
120:                 return ch;
121:         }
122:
123:         private void checkFor(char c) throws IOException
124:         {
125:                 if (ch == c)
126:                 {
127:                         rdCh();
128:                         return;
129:                 }
130:
131:                 throw new IOException("Expecting '" + c + "' at pos " + pos);
132:         }
133:
134:         private void checkFor(Token tok) throws IOException
135:         {
136:                 if (token == tok)
137:                 {
138:                         rdToken();
139:                         return;
140:                 }
141:
142:                 throw new IOException("Expecting '" + tok + "' at pos " + pos);
143:         }
144:
145:         private boolean isStart(char c)
146:         {
147:                 return Character.isLetter(c) || c == '_';
148:         }
149:
150:         private String rdTag()
151:         {
152:                 StringBuilder tag = new StringBuilder();
153:
154:                 while (isStart(ch) || Character.isDigit(ch))
155:                 {
156:                         tag.append(ch);
157:                         rdCh();
158:                 }
159:
160:                 return tag.toString();
161:         }
162:
163:         private String rdQuoted() throws IOException
164:         {
165:                 StringBuilder sb = new StringBuilder();
166:                 rdCh();
167:
168:                 while (ch != '"')
169:                 {
170:                         sb.append(ch);
171:                         rdCh();
172:                 }
173:
174:                 checkFor('"');
175:
176:                 return sb.toString();
177:         }
178:
179:         private Token rdToken() throws IOException
180:         {
181:                 boolean rdch = true;
182:                 value = null;
183:
184:                 while (Character.isWhitespace(ch))
185:                 {
186:                         rdCh();
187:                 }
188:
189:                 switch (ch)
190:                 {
191:                         case '<':
192:                                 if (rdCh() == '!')
193:                                 {
194:                                         rdCh();
195:                                         checkFor('[');
196:                                         checkFor('C');
197:                                         checkFor('D');
198:                                         checkFor('A');
199:                                         checkFor('T');
200:                                         checkFor('A');
201:                                         checkFor('[');
202:                                         token = Token.CDATA;
203:                                         rdch = false;
204:                                 } else if (ch == '?')
205:                                 {
206:                                         token = Token.QOPEN;
207:                                 } else if (ch == '/')
208:                                 {
209:                                         token = Token.STOP;
210:                                 } else
211:                                 {
212:                                         token = Token.OPEN;
213:                                         rdch = false;
214:                                 }
215:                                 break;
216:
217:                         case '/':
218:                                 rdCh();
219:                                 checkFor('>');
220:                                 token = Token.COMPLETE;
221:                                 rdch = false;
222:                                 break;
223:
224:                         case '?':
225:                                 rdCh();
226:                                 checkFor('>');
227:                                 token = Token.QCLOSE;
228:                                 rdch = false;
229:                                 break;
230:
231:                         case '>':
232:                                 token = Token.CLOSE;
233:                                 break;
234:
235:                         case ']':
236:                                 rdCh();
237:                                 checkFor(']');
238:                                 checkFor('>');
239:                                 token = Token.CDEND;
240:                                 rdch = false;
241:                                 break;
242:
243:                         case '=':
244:                                 token = Token.EQUALS;
245:                                 break;
246:
247:                         case '"':
248:                                 value = rdQuoted();
249:                                 token = Token.QUOTED;
250:                                 rdch = false;
251:                                 break;
252:
253:                         case 0:
254:                                 token = Token.EOF;
255:                                 break;
256:
257:                         default:
258:                                 if (isStart(ch))
259:                                 {
260:                                         value = rdTag();
261:                                         token = Token.TAG;
262:                                         rdch = false;
263:                                 } else
264:                                 {
265:                                         throw new IOException("Unexpected char '" + ch
266:                                                         + "' at pos " + pos);
267:                                 }
268:                                 break;
269:                 }
270:
271:                 if (rdch)
272:                 {
273:                         rdCh();
274:                 }
275:                 return token;
276:         }
277:
278:         public XMLNode readNode() throws IOException
279:         {
280:                 switch (token)
281:                 {
282:                         case OPEN:
283:                                 return readTagNode();
284:
285:                         case CDATA:
286:                                 return readDataNode();
287:
288:                         default:
289:                                 throw new IOException("Expecting <tag or <![CDATA[ at " + pos);
290:                 }
291:         }
292:
293:         private XMLNode readTagNode() throws IOException
294:         {
295:                 checkFor(Token.OPEN);
296:                 String tag = value;
297:                 checkFor(Token.TAG);
298:
299:                 Properties attr = null;
300:                 List<XMLNode> children = new Vector<XMLNode>();
301:
302:                 if (token == Token.TAG)
303:                 {
304:                         attr = readAttributes();
305:                 } else
306:                 {
307:                         attr = new Properties();
308:                 }
309:
310:                 switch (token)
311:                 {
312:                         case CLOSE:
313:                                 if (ch != '<')
314:                                 {
315:                                         children.add(new XMLTextNode(rdQuotedData()));
316:                                         rdToken();
317:                                 } else
318:                                 {
319:                                         rdToken();
320:
321:                                         while (token == Token.OPEN || token == Token.CDATA)
322:                                         {
323:                                                 XMLNode node = readNode();
324:                                                 children.add(node);
325:                                         }
326:                                 }
327:
328:                                 String finish = readStop();
329:
330:                                 if (!finish.equals(tag))
331:                                 {
332:                                         throw new IOException("Expecting </" + tag + "> at " + pos);
333:                                 }
334:
335:                                 return new XMLOpenTagNode(tag, attr, children);
336:
337:                         case COMPLETE:
338:                                 rdToken();
339:                                 return new XMLTagNode(tag, attr);
340:
341:                         default:
342:                                 throw new IOException("Expecting </" + tag + "> at " + pos);
343:                 }
344:         }
345:
346:         private String rdQuotedData()
347:         {
348:                 StringBuilder sb = new StringBuilder();
349:
350:                 while (ch != '<' && ch != 0)
351:                 {
352:                         sb.append(ch);
353:                         rdCh();
354:                 }
355:
356:                 // De-quote the text...
357:
358:                 return sb.toString();
359:         }
360:
361:         private XMLDataNode readDataNode() throws IOException
362:         {
363:                 StringBuilder sb = new StringBuilder();
364:
365:                 while (true)
366:                 {
367:                         if (ch == ']')
368:                         {
369:                                 if (buffer.substring(pos - 1, pos + 2).equals("]]>"))
370:                                 {
371:                                         rdCh();
372:                                         rdCh();
373:                                         rdCh();
374:                                         break;
375:                                 }
376:                         }
377:
378:                         sb.append(ch);
379:                         rdCh();
380:                 }
381:
382:                 rdToken();
383:                 return new XMLDataNode(sb.toString());
384:         }
385:
386:         private String readStop() throws IOException
387:         {
388:                 checkFor(Token.STOP);
389:                 String tag = value;
390:                 checkFor(Token.TAG);
391:                 checkFor(Token.CLOSE);
392:                 return tag;
393:         }
394:
395:         private Properties readAttributes() throws IOException
396:         {
397:                 Properties p = new Properties();
398:
399:                 while (token == Token.TAG)
400:                 {
401:                         String attr = value;
402:                         rdToken();
403:                         checkFor(Token.EQUALS);
404:                         String aval = value;
405:                         checkFor(Token.QUOTED);
406:
407:                         p.put(attr, aval);
408:                 }
409:
410:                 return p;
411:         }
412:
413:         public static void main(String[] args) throws IOException
414:         {
415:                 XMLParser p = new XMLParser("<![CDATA[]]]>".getBytes());
416:                 System.out.println(p.readNode());
417:         }
418: }