001: // Copyright (c) 2000, 2001 The Wilson Partnership.
002: // All Rights Reserved.
003: // @(#)MinML.java, 1.7, 18th November 2001
004: // Author: John Wilson - tug@wilson.co.uk
005:
006: package uk.co.wilson.xml;
007:
008: /*
009: Copyright (c) 2000, 2001 John Wilson (tug@wilson.co.uk).
010: All rights reserved.
011: Redistribution and use in source and binary forms,
012: with or without modification, are permitted provided
013: that the following conditions are met:
014:
015: Redistributions of source code must retain the above
016: copyright notice, this list of conditions and the
017: following disclaimer.
018:
019: Redistributions in binary form must reproduce the
020: above copyright notice, this list of conditions and
021: the following disclaimer in the documentation and/or
022: other materials provided with the distribution.
023:
024: All advertising materials mentioning features or use
025: of this software must display the following acknowledgement:
026:
027: This product includes software developed by John Wilson.
028: The name of John Wilson may not be used to endorse or promote
029: products derived from this software without specific prior
030: written permission.
031:
032: THIS SOFTWARE IS PROVIDED BY JOHN WILSON ``AS IS'' AND ANY
033: EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
034: THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
035: PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOHN WILSON
036: BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
037: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
038: TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
039: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
040: ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
041: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
042: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE
044: */
045:
046: import java.io.IOException;
047: import java.io.InputStreamReader;
048: import java.io.Reader;
049: import java.io.Writer;
050: import java.net.URL;
051: import java.util.EmptyStackException;
052: import java.util.Locale;
053: import java.util.Stack;
054: import java.util.Vector;
055:
056: import org.xml.sax.AttributeList;
057: import org.xml.sax.DTDHandler;
058: import org.xml.sax.EntityResolver;
059: import org.xml.sax.ErrorHandler;
060: import org.xml.sax.InputSource;
061: import org.xml.sax.Locator;
062: import org.xml.sax.SAXException;
063: import org.xml.sax.SAXParseException;
064:
065: import uk.org.xml.sax.DocumentHandler;
066: import uk.org.xml.sax.Parser;
067:
068: public class MinML implements Parser, Locator, DocumentHandler,
069: ErrorHandler {
070: public static final int endStartName = 0;
071: public static final int emitStartElement = 1;
072: public static final int emitEndElement = 2;
073: public static final int possiblyEmitCharacters = 3;
074: public static final int emitCharacters = 4;
075: public static final int emitCharactersSave = 5;
076: public static final int saveAttributeName = 6;
077: public static final int saveAttributeValue = 7;
078: public static final int startComment = 8;
079: public static final int endComment = 9;
080: public static final int incLevel = 10;
081: public static final int decLevel = 11;
082: public static final int startCDATA = 12;
083: public static final int endCDATA = 13;
084: public static final int processCharRef = 14;
085: public static final int writeCdata = 15;
086: public static final int exitParser = 16;
087: public static final int parseError = 17;
088: public static final int discardAndChange = 18;
089: public static final int discardSaveAndChange = 19;
090: public static final int saveAndChange = 20;
091: public static final int change = 21;
092:
093: public static final int inSkipping = 0;
094: public static final int inSTag = 1;
095: public static final int inPossiblyAttribute = 2;
096: public static final int inNextAttribute = 3;
097: public static final int inAttribute = 4;
098: public static final int inAttribute1 = 5;
099: public static final int inAttributeValue = 6;
100: public static final int inAttributeQuoteValue = 7;
101: public static final int inAttributeQuotesValue = 8;
102: public static final int inETag = 9;
103: public static final int inETag1 = 10;
104: public static final int inMTTag = 11;
105: public static final int inTag = 12;
106: public static final int inTag1 = 13;
107: public static final int inPI = 14;
108: public static final int inPI1 = 15;
109: public static final int inPossiblySkipping = 16;
110: public static final int inCharData = 17;
111: public static final int inCDATA = 18;
112: public static final int inCDATA1 = 19;
113: public static final int inComment = 20;
114: public static final int inDTD = 21;
115:
116: public MinML(final int initialBufferSize, final int bufferIncrement) {
117: this .initialBufferSize = initialBufferSize;
118: this .bufferIncrement = bufferIncrement;
119: }
120:
121: public MinML() {
122: this (256, 128);
123: }
124:
125: public void parse(final Reader in) throws SAXException, IOException {
126: final Vector attributeNames = new Vector();
127: final Vector attributeValues = new Vector();
128:
129: final AttributeList attrs = new AttributeList() {
130: public int getLength() {
131: return attributeNames.size();
132: }
133:
134: public String getName(final int i) {
135: return (String) attributeNames.elementAt(i);
136: }
137:
138: public String getType(final int i) {
139: return "CDATA";
140: }
141:
142: public String getValue(final int i) {
143: return (String) attributeValues.elementAt(i);
144: }
145:
146: public String getType(final String name) {
147: return "CDATA";
148: }
149:
150: public String getValue(final String name) {
151: final int index = attributeNames.indexOf(name);
152:
153: return (index == -1) ? null : (String) attributeValues
154: .elementAt(index);
155: }
156: };
157:
158: final MinMLBuffer buffer = new MinMLBuffer(in);
159: int currentChar = 0, charCount = 0;
160: int level = 0;
161: int mixedContentLevel = -1;
162: String elementName = null;
163: String state = operands[inSkipping];
164:
165: this .lineNumber = 1;
166: this .columnNumber = 0;
167:
168: try {
169: while (true) {
170: charCount++;
171:
172: //
173: // this is to try and make the loop a bit faster
174: // currentChar = buffer.read(); is simpler but is a bit slower.
175: //
176: currentChar = (buffer.nextIn == buffer.lastIn) ? buffer
177: .read() : buffer.chars[buffer.nextIn++];
178:
179: final int transition;
180:
181: if (currentChar > ']') {
182: transition = state.charAt(14);
183: } else {
184: final int charClass = charClasses[currentChar + 1];
185:
186: if (charClass == -1)
187: fatalError(
188: "Document contains illegal control character with value "
189: + currentChar, this .lineNumber,
190: this .columnNumber);
191:
192: if (charClass == 12) {
193: if (currentChar == '\r') {
194: currentChar = '\n';
195: charCount = -1;
196: }
197:
198: if (currentChar == '\n') {
199: if (charCount == 0)
200: continue; // preceeded by '\r' so ignore
201:
202: if (charCount != -1)
203: charCount = 0;
204:
205: this .lineNumber++;
206: this .columnNumber = 0;
207: }
208: }
209:
210: transition = state.charAt(charClass);
211: }
212:
213: this .columnNumber++;
214:
215: final String operand = operands[transition >>> 8];
216:
217: switch (transition & 0XFF) {
218: case endStartName:
219: // end of start element name
220: elementName = buffer.getString();
221: if (currentChar != '>' && currentChar != '/')
222: break; // change state to operand
223: // drop through to emit start element (we have no attributes)
224:
225: case emitStartElement:
226: // emit start element
227:
228: final Writer newWriter = this .extDocumentHandler
229: .startElement(
230: elementName,
231: attrs,
232: (this .tags.empty()) ? this .extDocumentHandler
233: .startDocument(buffer)
234: : buffer.getWriter());
235:
236: buffer.pushWriter(newWriter);
237: this .tags.push(elementName);
238:
239: attributeValues.removeAllElements();
240: attributeNames.removeAllElements();
241:
242: if (mixedContentLevel != -1)
243: mixedContentLevel++;
244:
245: if (currentChar != '/')
246: break; // change state to operand
247:
248: // <element/> drop through
249:
250: case emitEndElement:
251: // emit end element
252:
253: try {
254: final String begin = (String) this .tags.pop();
255:
256: buffer.popWriter();
257: elementName = buffer.getString();
258:
259: if (currentChar != '/'
260: && !elementName.equals(begin)) {
261: fatalError("end tag </" + elementName
262: + "> does not match begin tag <"
263: + begin + ">", this .lineNumber,
264: this .columnNumber);
265: } else {
266: this .documentHandler.endElement(begin);
267:
268: if (this .tags.empty()) {
269: this .documentHandler.endDocument();
270: return;
271: }
272: }
273: } catch (final EmptyStackException e) {
274: fatalError("end tag at begining of document",
275: this .lineNumber, this .columnNumber);
276: }
277:
278: if (mixedContentLevel != -1)
279: --mixedContentLevel;
280:
281: break; // change state to operand
282:
283: case emitCharacters:
284: // emit characters
285:
286: buffer.flush();
287: break; // change state to operand
288:
289: case emitCharactersSave:
290: // emit characters and save current character
291:
292: if (mixedContentLevel == -1)
293: mixedContentLevel = 0;
294:
295: buffer.flush();
296:
297: buffer.saveChar((char) currentChar);
298:
299: break; // change state to operand
300:
301: case possiblyEmitCharacters:
302: // write any skipped whitespace if in mixed content
303:
304: if (mixedContentLevel != -1)
305: buffer.flush();
306: break; // change state to operand
307:
308: case saveAttributeName:
309: // save attribute name
310:
311: attributeNames.addElement(buffer.getString());
312: break; // change state to operand
313:
314: case saveAttributeValue:
315: // save attribute value
316:
317: attributeValues.addElement(buffer.getString());
318: break; // change state to operand
319:
320: case startComment:
321: // change state if we have found "<!--"
322:
323: if (buffer.read() != '-')
324: continue; // not "<!--"
325:
326: break; // change state to operand
327:
328: case endComment:
329: // change state if we find "-->"
330:
331: if ((currentChar = buffer.read()) == '-') {
332: // deal with the case where we might have "------->"
333: while ((currentChar = buffer.read()) == '-')
334: ;
335:
336: if (currentChar == '>')
337: break; // end of comment, change state to operand
338: }
339:
340: continue; // not end of comment, don't change state
341:
342: case incLevel:
343:
344: level++;
345:
346: break;
347:
348: case decLevel:
349:
350: if (level == 0)
351: break; // outer level <> change state
352:
353: level--;
354:
355: continue; // in nested <>, don't change state
356:
357: case startCDATA:
358: // change state if we have found "<![CDATA["
359:
360: if (buffer.read() != 'C')
361: continue; // don't change state
362: if (buffer.read() != 'D')
363: continue; // don't change state
364: if (buffer.read() != 'A')
365: continue; // don't change state
366: if (buffer.read() != 'T')
367: continue; // don't change state
368: if (buffer.read() != 'A')
369: continue; // don't change state
370: if (buffer.read() != '[')
371: continue; // don't change state
372: break; // change state to operand
373:
374: case endCDATA:
375: // change state if we find "]]>"
376:
377: if ((currentChar = buffer.read()) == ']') {
378: // deal with the case where we might have "]]]]]]]>"
379: while ((currentChar = buffer.read()) == ']')
380: buffer.write(']');
381:
382: if (currentChar == '>')
383: break; // end of CDATA section, change state to operand
384:
385: buffer.write(']');
386: }
387:
388: buffer.write(']');
389: buffer.write(currentChar);
390: continue; // not end of CDATA section, don't change state
391:
392: case processCharRef:
393: // process character entity
394:
395: int crefState = 0;
396:
397: currentChar = buffer.read();
398:
399: while (true) {
400: if ("#amp;&pos;'quot;\"gt;>lt;<"
401: .charAt(crefState) == currentChar) {
402: crefState++;
403:
404: if (currentChar == ';') {
405: buffer
406: .write("#amp;&pos;'quot;\"gt;>lt;<"
407: .charAt(crefState));
408: break;
409:
410: } else if (currentChar == '#') {
411: final int radix;
412:
413: currentChar = buffer.read();
414:
415: if (currentChar == 'x') {
416: radix = 16;
417: currentChar = buffer.read();
418: } else {
419: radix = 10;
420: }
421:
422: int charRef = Character.digit(
423: (char) currentChar, radix);
424:
425: while (true) {
426: currentChar = buffer.read();
427:
428: final int digit = Character.digit(
429: (char) currentChar, radix);
430:
431: if (digit == -1)
432: break;
433:
434: charRef = (char) ((charRef * radix) + digit);
435: }
436:
437: if (currentChar == ';' && charRef != -1) {
438: buffer.write(charRef);
439: break;
440: }
441:
442: fatalError("invalid Character Entitiy",
443: this .lineNumber,
444: this .columnNumber);
445: } else {
446: currentChar = buffer.read();
447: }
448: } else {
449: crefState = ("\u0001\u000b\u0006\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff"
450: +
451: // # a m p ; & p o s ; '
452: // 0 1 2 3 4 5 6 7 8 9 a
453: "\u0011\u00ff\u00ff\u00ff\u00ff\u00ff\u0015\u00ff\u00ff\u00ff"
454: +
455: // q u o t ; " g t ; >
456: // b b d e f 10 11 12 13 14
457: "\u00ff\u00ff\u00ff")
458: .charAt(crefState);
459: // l t ;
460: // 15 16 17
461:
462: if (crefState == 255)
463: fatalError("invalid Character Entitiy",
464: this .lineNumber,
465: this .columnNumber);
466: }
467: }
468:
469: break;
470:
471: case parseError:
472: // report fatal error
473:
474: fatalError(operand, this .lineNumber,
475: this .columnNumber);
476: // drop through to exit parser
477:
478: case exitParser:
479: // exit parser
480:
481: return;
482:
483: case writeCdata:
484: // write character data
485: // this will also write any skipped whitespace
486:
487: buffer.write(currentChar);
488: break; // change state to operand
489:
490: case discardAndChange:
491: // throw saved characters away and change state
492:
493: buffer.reset();
494: break; // change state to operand
495:
496: case discardSaveAndChange:
497: // throw saved characters away, save character and change state
498:
499: buffer.reset();
500: // drop through to save character and change state
501:
502: case saveAndChange:
503: // save character and change state
504:
505: buffer.saveChar((char) currentChar);
506: break; // change state to operand
507:
508: case change:
509: // change state to operand
510:
511: break; // change state to operand
512: }
513:
514: state = operand;
515: }
516: } catch (final IOException e) {
517: this .errorHandler.fatalError(new SAXParseException(e
518: .toString(), null, null, this .lineNumber,
519: this .columnNumber, e));
520: } finally {
521: this .errorHandler = this ;
522: this .documentHandler = this .extDocumentHandler = this ;
523: this .tags.removeAllElements();
524: }
525: }
526:
527: public void parse(final InputSource source) throws SAXException,
528: IOException {
529: if (source.getCharacterStream() != null)
530: parse(source.getCharacterStream());
531: else if (source.getByteStream() != null)
532: parse(new InputStreamReader(source.getByteStream()));
533: else
534: parse(new InputStreamReader(new URL(source.getSystemId())
535: .openStream()));
536: }
537:
538: public void parse(final String systemId) throws SAXException,
539: IOException {
540: parse(new InputSource(systemId));
541: }
542:
543: public void setLocale(final Locale locale) throws SAXException {
544: throw new SAXException("Not supported");
545: }
546:
547: public void setEntityResolver(final EntityResolver resolver) {
548: // not supported
549: }
550:
551: public void setDTDHandler(final DTDHandler handler) {
552: // not supported
553: }
554:
555: public void setDocumentHandler(
556: final org.xml.sax.DocumentHandler handler) {
557: this .documentHandler = (handler == null) ? this : handler;
558: this .extDocumentHandler = this ;
559: }
560:
561: public void setDocumentHandler(final DocumentHandler handler) {
562: this .documentHandler = this .extDocumentHandler = (handler == null) ? this
563: : handler;
564: this .documentHandler.setDocumentLocator(this );
565: }
566:
567: public void setErrorHandler(final ErrorHandler handler) {
568: this .errorHandler = (handler == null) ? this : handler;
569: }
570:
571: public void setDocumentLocator(final Locator locator) {
572: }
573:
574: public void startDocument() throws SAXException {
575: }
576:
577: public Writer startDocument(final Writer writer)
578: throws SAXException {
579: this .documentHandler.startDocument();
580: return writer;
581: }
582:
583: public void endDocument() throws SAXException {
584: }
585:
586: public void startElement(final String name,
587: final AttributeList attributes) throws SAXException {
588: }
589:
590: public Writer startElement(final String name,
591: final AttributeList attributes, final Writer writer)
592: throws SAXException {
593: this .documentHandler.startElement(name, attributes);
594: return writer;
595: }
596:
597: public void endElement(final String name) throws SAXException {
598: }
599:
600: public void characters(final char ch[], final int start,
601: final int length) throws SAXException {
602: }
603:
604: public void ignorableWhitespace(final char ch[], final int start,
605: final int length) throws SAXException {
606: }
607:
608: public void processingInstruction(final String target,
609: final String data) throws SAXException {
610: }
611:
612: public void warning(final SAXParseException e) throws SAXException {
613: }
614:
615: public void error(final SAXParseException e) throws SAXException {
616: }
617:
618: public void fatalError(final SAXParseException e)
619: throws SAXException {
620: throw e;
621: }
622:
623: public String getPublicId() {
624: return "";
625: }
626:
627: public String getSystemId() {
628: return "";
629: }
630:
631: public int getLineNumber() {
632: return this .lineNumber;
633: }
634:
635: public int getColumnNumber() {
636: return this .columnNumber;
637: }
638:
639: private void fatalError(final String msg, final int lineNumber,
640: final int columnNumber) throws SAXException {
641: this .errorHandler.fatalError(new SAXParseException(msg, null,
642: null, lineNumber, columnNumber));
643: }
644:
645: private class MinMLBuffer extends Writer {
646: public MinMLBuffer(final Reader in) {
647: this .in = in;
648: }
649:
650: public void close() throws IOException {
651: flush();
652: }
653:
654: public void flush() throws IOException {
655: try {
656: _flush();
657: if (writer != this )
658: writer.flush();
659: } finally {
660: flushed = true;
661: }
662: }
663:
664: public void write(final int c) throws IOException {
665: written = true;
666: chars[count++] = (char) c;
667: }
668:
669: public void write(final char[] cbuf, final int off,
670: final int len) throws IOException {
671: written = true;
672: System.arraycopy(cbuf, off, chars, count, len);
673: count += len;
674: }
675:
676: public void saveChar(final char c) {
677: written = false;
678: chars[count++] = c;
679: }
680:
681: public void pushWriter(final Writer writer) {
682: MinML.this .tags.push(this .writer);
683:
684: this .writer = (writer == null) ? this : writer;
685:
686: flushed = written = false;
687: }
688:
689: public Writer getWriter() {
690: return writer;
691: }
692:
693: public void popWriter() throws IOException {
694: try {
695: if (!flushed && writer != this )
696: writer.flush();
697: } finally {
698: writer = (Writer) MinML.this .tags.pop();
699: flushed = written = false;
700: }
701: }
702:
703: public String getString() {
704: final String result = new String(chars, 0, count);
705:
706: count = 0;
707: return result;
708: }
709:
710: public void reset() {
711: count = 0;
712: }
713:
714: public int read() throws IOException {
715: if (nextIn == lastIn) {
716: if (count != 0) {
717: if (written) {
718: _flush();
719: } else if (count >= (chars.length - MinML.this .bufferIncrement)) {
720: final char[] newChars = new char[chars.length
721: + MinML.this .bufferIncrement];
722:
723: System.arraycopy(chars, 0, newChars, 0, count);
724: chars = newChars;
725: }
726: }
727:
728: final int numRead = in.read(chars, count, chars.length
729: - count);
730:
731: if (numRead == -1)
732: return -1;
733:
734: nextIn = count;
735: lastIn = count + numRead;
736: }
737:
738: return chars[nextIn++];
739: }
740:
741: private void _flush() throws IOException {
742: if (count != 0) {
743: try {
744: if (writer == this ) {
745: try {
746: MinML.this .documentHandler.characters(
747: chars, 0, count);
748: } catch (final SAXException e) {
749: throw new IOException(e.toString());
750: }
751: } else {
752: writer.write(chars, 0, count);
753: }
754: } finally {
755: count = 0;
756: }
757: }
758: }
759:
760: private int nextIn = 0, lastIn = 0;
761: private char[] chars = new char[MinML.this .initialBufferSize];
762: private final Reader in;
763: private int count = 0;
764: private Writer writer = this ;
765: private boolean flushed = false;
766: private boolean written = false;
767: }
768:
769: private DocumentHandler extDocumentHandler = this ;
770: private org.xml.sax.DocumentHandler documentHandler = this ;
771: private ErrorHandler errorHandler = this ;
772: private final Stack tags = new Stack();
773: private int lineNumber = 1;
774: private int columnNumber = 0;
775: private final int initialBufferSize;
776: private final int bufferIncrement;
777:
778: private static final byte[] charClasses = {
779: // EOF
780: 13,
781: // \t \n \r
782: -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, -1, -1, 12,
783: -1,
784: -1,
785: //
786: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
787: -1,
788: // SP ! " # $ % & ' ( ) * + , - . /
789: 12, 8, 7, 14, 14, 14, 3, 6, 14, 14, 14, 14, 14, 11, 14, 2,
790: // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
791: 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 5, 1, 4,
792: //
793: 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
794: 14,
795: // [ \ ]
796: 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 10 };
797:
798: private static final String[] operands = {
799: "\u0d15\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u0015\u0010\u1611",
800: "\u1711\u1000\u0b00\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0114\u0200\u1811\u0114",
801: "\u1711\u1001\u0b01\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0215\u1811\u0414",
802: "\u1711\u1001\u0b01\u1711\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u0315\u1811\u0414",
803: "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u0414\u0515\u1811\u0414",
804: "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u1911\u0515\u1811\u1911",
805: "\u1a11\u1a11\u1a11\u1a11\u1a11\u1a11\u0715\u0815\u1a11\u1a11\u1a11\u1a11\u0615\u1811\u1a11",
806: "\u0714\u0714\u0714\u070e\u0714\u0714\u0307\u0714\u0714\u0714\u0714\u0714\u0714\u1811\u0714",
807: "\u0814\u0814\u0814\u080e\u0814\u0814\u0814\u0307\u0814\u0814\u0814\u0814\u0814\u1811\u0814",
808: "\u1711\u1002\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0914\u0915\u1811\u0914",
809: "\u1b11\u1b11\u0904\u1b11\u1b11\u1b11\u1b11\u1b11\u1215\u1b11\u1b11\u1b11\u1b11\u1811\u0105",
810: "\u1711\u1012\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1811\u1711",
811: "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
812: "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
813: "\u0e15\u0e15\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
814: "\u0e15\u0015\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
815: "\u0c03\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1014\u1811\u110f",
816: "\u0a15\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1811\u110f",
817: "\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u130c\u1d11\u1408\u1d11\u1811\u1515",
818: "\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u110d\u130f\u130f\u1811\u130f",
819: "\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u0009\u1415\u1811\u1415",
820: "\u150a\u000b\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1811\u1515",
821: "expected Element", "unexpected character in tag",
822: "unexpected end of file found",
823: "attribute name not followed by '='",
824: "invalid attribute value", "expecting end tag",
825: "empty tag", "unexpected character after <!" };
826: }
|