072997e14c869aed206f86914eccdfd82f63272e
[platform/upstream/doxygen.git] / qtools / qxml.cpp
1 /****************************************************************************
2 ** 
3 **
4 ** Implementation of QXmlSimpleReader and related classes.
5 **
6 ** Created : 000518
7 **
8 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
9 **
10 ** This file is part of the XML module of the Qt GUI Toolkit.
11 **
12 ** This file may be distributed under the terms of the Q Public License
13 ** as defined by Trolltech AS of Norway and appearing in the file
14 ** LICENSE.QPL included in the packaging of this file.
15 **
16 ** This file may be distributed and/or modified under the terms of the
17 ** GNU General Public License version 2 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.GPL included in the
19 ** packaging of this file.
20 **
21 ** Licensees holding valid Qt Enterprise Edition licenses may use this
22 ** file in accordance with the Qt Commercial License Agreement provided
23 ** with the Software.
24 **
25 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 **
28 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29 **   information about Qt Commercial License Agreements.
30 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
31 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
32 **
33 ** Contact info@trolltech.com if any conditions of this licensing are
34 ** not clear to you.
35 **
36 **********************************************************************/
37
38 #define QT_XML_CPP
39 #include "qxml.h"
40 #include "qtextcodec.h"
41 #include "qbuffer.h"
42
43 #ifndef QT_NO_XML
44 // NOT REVISED
45
46 // Error strings for the XML reader
47 #define XMLERR_OK                         "no error occurred"
48 #define XMLERR_TAGMISMATCH                "tag mismatch"
49 #define XMLERR_UNEXPECTEDEOF              "unexpected end of file"
50 #define XMLERR_FINISHEDPARSINGWHILENOTEOF "parsing is finished but end of file is not reached"
51 #define XMLERR_LETTEREXPECTED             "letter is expected"
52 #define XMLERR_ERRORPARSINGELEMENT        "error while parsing element"
53 #define XMLERR_ERRORPARSINGPROLOG         "error while parsing prolog"
54 #define XMLERR_ERRORPARSINGMAINELEMENT    "error while parsing main element"
55 #define XMLERR_ERRORPARSINGCONTENT        "error while parsing content"
56 #define XMLERR_ERRORPARSINGNAME           "error while parsing name"
57 #define XMLERR_ERRORPARSINGNMTOKEN        "error while parsing Nmtoken"
58 #define XMLERR_ERRORPARSINGATTRIBUTE      "error while parsing attribute"
59 #define XMLERR_ERRORPARSINGMISC           "error while parsing misc"
60 #define XMLERR_ERRORPARSINGCHOICE         "error while parsing choice or seq"
61 #define XMLERR_ERRORBYCONSUMER            "error triggered by consumer"
62 #define XMLERR_UNEXPECTEDCHARACTER        "unexpected character"
63 #define XMLERR_EQUALSIGNEXPECTED          "expected '=' but not found"
64 #define XMLERR_QUOTATIONEXPECTED          "expected \" or ' but not found"
65 #define XMLERR_ERRORPARSINGREFERENCE      "error while parsing reference"
66 #define XMLERR_ERRORPARSINGPI             "error while parsing processing instruction"
67 #define XMLERR_ERRORPARSINGATTLISTDECL    "error while parsing attribute list declaration"
68 #define XMLERR_ERRORPARSINGATTTYPE        "error while parsing attribute type declaration"
69 #define XMLERR_ERRORPARSINGATTVALUE       "error while parsing attribute value declaration"
70 #define XMLERR_ERRORPARSINGELEMENTDECL    "error while parsing element declaration"
71 #define XMLERR_ERRORPARSINGENTITYDECL     "error while parsing entity declaration"
72 #define XMLERR_ERRORPARSINGNOTATIONDECL   "error while parsing notation declaration"
73 #define XMLERR_ERRORPARSINGEXTERNALID     "error while parsing external id"
74 #define XMLERR_ERRORPARSINGCOMMENT        "error while parsing comment"
75 #define XMLERR_ERRORPARSINGENTITYVALUE    "error while parsing entity value declaration"
76 #define XMLERR_CDSECTHEADEREXPECTED       "expected the header for a cdata section"
77 #define XMLERR_MORETHANONEDOCTYPE         "more than one document type definition"
78 #define XMLERR_ERRORPARSINGDOCTYPE        "error while parsing document type definition"
79 #define XMLERR_INVALIDNAMEFORPI           "invalid name for processing instruction"
80 #define XMLERR_VERSIONEXPECTED            "version expected while reading the XML declaration"
81 #define XMLERR_EDECLORSDDECLEXPECTED      "EDecl or SDDecl expected while reading the XML declaration"
82 #define XMLERR_SDDECLEXPECTED             "SDDecl expected while reading the XML declaration"
83 #define XMLERR_WRONGVALUEFORSDECL         "wrong value for standalone declaration"
84 #define XMLERR_UNPARSEDENTITYREFERENCE    "unparsed entity reference in wrong context"
85 #define XMLERR_INTERNALGENERALENTITYINDTD "internal general entity reference not allowed in DTD"
86 #define XMLERR_EXTERNALGENERALENTITYINDTD "external parsed general entity reference not allowed in DTD"
87 #define XMLERR_EXTERNALGENERALENTITYINAV  "external parsed general entity reference not allowed in attribute value"
88
89
90 // the constants for the lookup table
91 static const signed char cltWS      =  0; // white space
92 static const signed char cltPer     =  1; // %
93 static const signed char cltAmp     =  2; // &
94 static const signed char cltGt      =  3; // >
95 static const signed char cltLt      =  4; // <
96 static const signed char cltSlash   =  5; // /
97 static const signed char cltQm      =  6; // ?
98 static const signed char cltEm      =  7; // !
99 static const signed char cltDash    =  8; // -
100 static const signed char cltCB      =  9; // ]
101 static const signed char cltOB      = 10; // [
102 static const signed char cltEq      = 11; // =
103 static const signed char cltDq      = 12; // "
104 static const signed char cltSq      = 13; // '
105 static const signed char cltUnknown = 14;
106
107 // character lookup table
108 static const signed char charLookupTable[256]={
109     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x00 - 0x07
110     cltUnknown, // 0x08
111     cltWS,      // 0x09 \t
112     cltWS,      // 0x0A \n
113     cltUnknown, // 0x0B
114     cltUnknown, // 0x0C
115     cltWS,      // 0x0D \r
116     cltUnknown, // 0x0E
117     cltUnknown, // 0x0F
118     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x17 - 0x16
119     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x18 - 0x1F
120     cltWS,      // 0x20 Space
121     cltEm,      // 0x21 !
122     cltDq,      // 0x22 "
123     cltUnknown, // 0x23
124     cltUnknown, // 0x24
125     cltPer,     // 0x25 %
126     cltAmp,     // 0x26 &
127     cltSq,      // 0x27 '
128     cltUnknown, // 0x28
129     cltUnknown, // 0x29
130     cltUnknown, // 0x2A
131     cltUnknown, // 0x2B
132     cltUnknown, // 0x2C
133     cltDash,    // 0x2D -
134     cltUnknown, // 0x2E
135     cltSlash,   // 0x2F /
136     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x30 - 0x37
137     cltUnknown, // 0x38
138     cltUnknown, // 0x39
139     cltUnknown, // 0x3A
140     cltUnknown, // 0x3B
141     cltLt,      // 0x3C <
142     cltEq,      // 0x3D =
143     cltGt,      // 0x3E >
144     cltQm,      // 0x3F ?
145     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x40 - 0x47
146     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x48 - 0x4F
147     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x50 - 0x57
148     cltUnknown, // 0x58
149     cltUnknown, // 0x59
150     cltUnknown, // 0x5A
151     cltOB,      // 0x5B [
152     cltUnknown, // 0x5C
153     cltCB,      // 0x5D ]
154     cltUnknown, // 0x5E
155     cltUnknown, // 0x5F
156     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x60 - 0x67
157     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x68 - 0x6F
158     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x70 - 0x77
159     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x78 - 0x7F
160     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x80 - 0x87
161     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x88 - 0x8F
162     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x90 - 0x97
163     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x98 - 0x9F
164     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA0 - 0xA7
165     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA8 - 0xAF
166     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB0 - 0xB7
167     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB8 - 0xBF
168     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC0 - 0xC7
169     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC8 - 0xCF
170     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD0 - 0xD7
171     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD8 - 0xDF
172     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE0 - 0xE7
173     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE8 - 0xEF
174     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xF0 - 0xF7
175     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown  // 0xF8 - 0xFF
176 };
177
178
179 class QXmlNamespaceSupportPrivate
180 {
181 };
182 class QXmlAttributesPrivate
183 {
184 };
185 class QXmlInputSourcePrivate
186 {
187 };
188 class QXmlParseExceptionPrivate
189 {
190 };
191 class QXmlLocatorPrivate
192 {
193 };
194 class QXmlDefaultHandlerPrivate
195 {
196 };
197
198 #if defined(Q_FULL_TEMPLATE_INSTANTIATION)
199 bool operator==( const QMap<QString, QString>, const QMap<QString, QString> )
200 {
201     return FALSE;
202 }
203 #endif
204
205 /*!
206   \class QXmlParseException qxml.h
207   \brief The QXmlParseException class is used to report errors with the
208   QXmlErrorHandler interface.
209
210   \module XML
211
212   \sa QXmlErrorHandler
213 */
214 /*!
215   \fn QXmlParseException::QXmlParseException( const QString& name, int c, int l, const QString& p, const QString& s )
216
217   Constructs a parse exception with the error string \a name in the column
218   \a c and line \a l for the public identifier \a p and the system identifier
219   \a s.
220 */
221 /*!
222   Returns the error message.
223 */
224 QString QXmlParseException::message() const
225 {
226     return msg;
227 }
228 /*!
229   Returns the column number the error occurred.
230 */
231 int QXmlParseException::columnNumber() const
232 {
233     return column;
234 }
235 /*!
236   Returns the line number the error occurred.
237 */
238 int QXmlParseException::lineNumber() const
239 {
240     return line;
241 }
242 /*!
243   Returns the public identifier the error occurred.
244 */
245 QString QXmlParseException::publicId() const
246 {
247     return pub;
248 }
249 /*!
250   Returns the system identifier the error occurred.
251 */
252 QString QXmlParseException::systemId() const
253 {
254     return sys;
255 }
256
257
258 /*!
259   \class QXmlLocator qxml.h
260   \brief The QXmlLocator class provides the XML handler classes with
261   information about the actual parsing position.
262
263   \module XML
264
265   The reader reports a QXmlLocator to the content handler before he starts to
266   parse the document. This is done with the
267   QXmlContentHandler::setDocumentLocator() function. The handler classes can
268   now use this locator to get the actual position the reader is at.
269 */
270 /*!
271     \fn QXmlLocator::QXmlLocator( QXmlSimpleReader* parent )
272
273     Constructor.
274 */
275 /*!
276     \fn QXmlLocator::~QXmlLocator()
277
278     Destructor.
279 */
280 /*!
281     Gets the column number (starting with 1) or -1 if there is no column number
282     available.
283 */
284 int QXmlLocator::columnNumber()
285 {
286     return ( reader->columnNr == -1 ? -1 : reader->columnNr + 1 );
287 }
288 /*!
289     Gets the line number (starting with 1) or -1 if there is no line number
290     available.
291 */
292 int QXmlLocator::lineNumber()
293 {
294     return ( reader->lineNr == -1 ? -1 : reader->lineNr + 1 );
295 }
296
297
298 /*********************************************
299  *
300  * QXmlNamespaceSupport
301  *
302  *********************************************/
303
304 /*!
305   \class QXmlNamespaceSupport qxml.h
306   \brief The QXmlNamespaceSupport class is a helper class for XML readers which
307   want to include namespace support.
308
309   \module XML
310
311   It provides some functions that makes it easy to handle namespaces. Its main
312   use is for subclasses of QXmlReader which want to provide namespace
313   support.
314
315   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
316 */
317
318 /*!
319   Constructs a QXmlNamespaceSupport.
320 */
321 QXmlNamespaceSupport::QXmlNamespaceSupport()
322 {
323     reset();
324 }
325
326 /*!
327   Destructs a QXmlNamespaceSupport.
328 */
329 QXmlNamespaceSupport::~QXmlNamespaceSupport()
330 {
331 }
332
333 /*!
334   This function declares a prefix in the current namespace context; the prefix
335   will remain in force until this context is popped, unless it is shadowed in a
336   descendant context.
337
338   Note that there is an asymmetry in this library: while prefix() will not
339   return the default "" prefix, even if you have declared one; to check for a
340   default prefix, you have to look it up explicitly using uri(). This
341   asymmetry exists to make it easier to look up prefixes for attribute names,
342   where the default prefix is not allowed.
343 */
344 void QXmlNamespaceSupport::setPrefix( const QString& pre, const QString& uri )
345 {
346     if( pre.isNull() ) {
347         ns.insert( "", uri );
348     } else {
349         ns.insert( pre, uri );
350     }
351 }
352
353 /*!
354   Returns one of the prefixes mapped to a namespace URI.
355
356   If more than one prefix is currently mapped to the same URI, this function
357   will make an arbitrary selection; if you want all of the prefixes, use the
358   prefixes() function instead.
359
360   Note: this will never return the empty (default) prefix; to check for a
361   default prefix, use the uri() function with an argument of "".
362 */
363 QString QXmlNamespaceSupport::prefix( const QString& uri ) const
364 {
365     QMap<QString, QString>::ConstIterator itc, it = ns.begin();
366     while ( (itc=it) != ns.end() ) {
367         ++it;
368         if ( itc.data() == uri && !itc.key().isEmpty() )
369             return itc.key();
370     }
371     return "";
372 }
373
374 /*!
375   Looks up a prefix in the current context and returns the currently-mapped
376   namespace URI. Use the empty string ("") for the default namespace.
377 */
378 QString QXmlNamespaceSupport::uri( const QString& prefix ) const
379 {
380     const QString& returi = ns[ prefix ];
381     return returi;
382 }
383
384 /*!
385   Splits the name at the ':' and returns the prefix and the local name.
386 */
387 void QXmlNamespaceSupport::splitName( const QString& qname,
388         QString& prefix, QString& localname ) const
389 {
390     uint pos;
391     // search the ':'
392     for( pos=0; pos<qname.length(); pos++ ) {
393         if ( qname.at(pos) == ':' )
394             break;
395     }
396     // and split
397     prefix = qname.left( pos );
398     localname = qname.mid( pos+1 );
399 }
400
401 /*!
402   Processes a raw XML 1.0 name in the current context by removing the prefix
403   and looking it up among the prefixes currently declared.
404
405   First parameter is the raw XML 1.0 name to be processed. The second parameter
406   is a flag whether the name is the name of an attribute (TRUE) or not (FALSE).
407
408   The return values will be stored in the last two parameters as follows:
409   <ul>
410   <li> The namespace URI, or an empty string if none is in use.
411   <li> The local name (without prefix).
412   </ul>
413
414   If the raw name has a prefix that has not been declared, then the return
415   value will be empty.
416
417   Note that attribute names are processed differently than element names: an
418   unprefixed element name will received the default namespace (if any), while
419   an unprefixed element name will not
420 */
421 void QXmlNamespaceSupport::processName( const QString& qname,
422         bool isAttribute,
423         QString& nsuri, QString& localname ) const
424 {
425     uint pos;
426     // search the ':'
427     for( pos=0; pos<qname.length(); pos++ ) {
428         if ( qname.at(pos) == ':' )
429             break;
430     }
431     if ( pos < qname.length() ) {
432         // there was a ':'
433         nsuri = uri( qname.left( pos ) );
434         localname = qname.mid( pos+1 );
435     } else {
436         // there was no ':'
437         if ( isAttribute ) {
438             nsuri = ""; // attributes don't take default namespace
439         } else {
440             nsuri = uri( "" ); // get default namespace
441         }
442         localname = qname;
443     }
444 }
445
446 /*!
447   Returns an enumeration of all prefixes currently declared.
448
449   Note: if there is a default prefix, it will not be returned in this
450   enumeration; check for the default prefix using uri() with an argument
451   of "".
452 */
453 QStringList QXmlNamespaceSupport::prefixes() const
454 {
455     QStringList list;
456
457     QMap<QString, QString>::ConstIterator itc, it = ns.begin();
458     while ( (itc=it) != ns.end() ) {
459         ++it;
460         if ( !itc.key().isEmpty() )
461             list.append( itc.key() );
462     }
463     return list;
464 }
465
466 /*!
467   Returns a list of all prefixes currently declared for a URI.
468
469   The xml: prefix will be included. If you want only one prefix that's
470   mapped to the namespace URI, and you don't care which one you get, use the
471   prefix() function instead.
472
473   Note: the empty (default) prefix is never included in this enumeration; to
474   check for the presence of a default namespace, use uri() with an
475   argument of "".
476 */
477 QStringList QXmlNamespaceSupport::prefixes( const QString& uri ) const
478 {
479     QStringList list;
480
481     QMap<QString, QString>::ConstIterator itc, it = ns.begin();
482     while ( (itc=it) != ns.end() ) {
483         ++it;
484         if ( itc.data() == uri && !itc.key().isEmpty() )
485             list.append( itc.key() );
486     }
487     return list;
488 }
489
490 /*!
491   Starts a new namespace context.
492
493   Normally, you should push a new context at the beginning of each XML element:
494   the new context will automatically inherit the declarations of its parent
495   context, but it will also keep track of which declarations were made within
496   this context.
497 */
498 void QXmlNamespaceSupport::pushContext()
499 {
500     nsStack.push( ns );
501 }
502
503 /*!
504   Reverts to the previous namespace context.
505
506   Normally, you should pop the context at the end of each XML element.  After
507   popping the context, all namespace prefix mappings that were previously in
508   force are restored.
509 */
510 void QXmlNamespaceSupport::popContext()
511 {
512     if( !nsStack.isEmpty() )
513         ns = nsStack.pop();
514 }
515
516 /*!
517   Resets this namespace support object for reuse.
518 */
519 void QXmlNamespaceSupport::reset()
520 {
521     nsStack.clear();
522     ns.clear();
523     ns.insert( "xml", "http://www.w3.org/XML/1998/namespace" ); // the XML namespace
524 }
525
526
527
528 /*********************************************
529  *
530  * QXmlAttributes
531  *
532  *********************************************/
533
534 /*!
535   \class QXmlAttributes qxml.h
536   \brief The QXmlAttributes class provides XML attributes.
537
538   \module XML
539
540   If attributes are reported by QXmlContentHandler::startElement() this
541   class is used to pass the attribute values. It provides you with different
542   functions to access the attribute names and values.
543 */
544 /*!
545   \fn QXmlAttributes::QXmlAttributes()
546
547   Constructs an empty attribute list.
548 */
549 /*!
550   \fn QXmlAttributes::~QXmlAttributes()
551
552   Destructs attributes.
553 */
554
555 /*!
556   Look up the index of an attribute by an XML 1.0 qualified name.
557
558   Returns the index of the attribute (starting with 0) or -1 if it wasn't
559   found.
560
561   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
562 */
563 int QXmlAttributes::index( const QString& qName ) const
564 {
565     return qnameList.findIndex( qName );
566 }
567
568 /*!
569   Looks up the index of an attribute by a namespace name.
570
571   \a uri specifies the namespace URI, or the empty string if the name has no
572   namespace URI. \a localPart specifies the attribute's local name.
573
574   Returns the index of the attribute (starting with 0) or -1 if it wasn't
575   found.
576
577   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
578 */
579 int QXmlAttributes::index( const QString& uri, const QString& localPart ) const
580 {
581     uint count = uriList.count();
582     for ( uint i=0; i<count; i++ ) {
583         if ( uriList[i] == uri && localnameList[i] == localPart )
584             return i;
585     }
586     return -1;
587 }
588
589 /*!
590   Returns the number of attributes in the list.
591 */
592 int QXmlAttributes::length() const
593 {
594     return valueList.count();
595 }
596
597 /*!
598   Looks up an attribute's local name by index (starting with 0).
599
600   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
601 */
602 QString QXmlAttributes::localName( int index ) const
603 {
604     return localnameList[index];
605 }
606
607 /*!
608   Looks up an attribute's XML 1.0 qualified name by index (starting with 0).
609
610   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
611 */
612 QString QXmlAttributes::qName( int index ) const
613 {
614     return qnameList[index];
615 }
616
617 /*!
618   Looks up an attribute's namespace URI by index (starting with 0).
619
620   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
621 */
622 QString QXmlAttributes::uri( int index ) const
623 {
624     return uriList[index];
625 }
626
627 /*!
628   Looks up an attribute's type by index (starting with 0).
629
630   At the moment only 'CDATA' is returned.
631 */
632 QString QXmlAttributes::type( int ) const
633 {
634     return "CDATA";
635 }
636
637 /*!
638   Looks up an attribute's type by XML 1.0 qualified name.
639
640   At the moment only 'CDATA' is returned.
641 */
642 QString QXmlAttributes::type( const QString& ) const
643 {
644     return "CDATA";
645 }
646
647 /*!
648   Looks up an attribute's type by namespace name.
649
650   The first parameter specifies the namespace URI, or the empty string if
651   the name has no namespace URI. The second parameter specifies the
652   attribute's local name.
653
654   At the moment only 'CDATA' is returned.
655 */
656 QString QXmlAttributes::type( const QString&, const QString& ) const
657 {
658     return "CDATA";
659 }
660
661 /*!
662   Looks up an attribute's value by index (starting with 0).
663 */
664 QString QXmlAttributes::value( int index ) const
665 {
666     return valueList[index];
667 }
668
669 /*!
670   Looks up an attribute's value by XML 1.0 qualified name.
671
672   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
673 */
674 QString QXmlAttributes::value( const QString& qName ) const
675 {
676     int i = index( qName );
677     if ( i == -1 )
678         return QString::null;
679     return valueList[ i ];
680 }
681
682 /*!
683   Looks up an attribute's value by namespace name.
684
685   \a uri specifies the namespace URI, or the empty string if the name has no
686   namespace URI. \a localName specifies the attribute's local name.
687
688   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
689 */
690 QString QXmlAttributes::value( const QString& uri, const QString& localName ) const
691 {
692     int i = index( uri, localName );
693     if ( i == -1 )
694         return QString::null;
695     return valueList[ i ];
696 }
697
698
699 /*********************************************
700  *
701  * QXmlInputSource
702  *
703  *********************************************/
704
705 /*!
706   \class QXmlInputSource qxml.h
707   \brief The QXmlInputSource class is the source where XML data is read from.
708
709   \module XML
710
711   All subclasses of QXmlReader read the input from this class.
712 */
713
714 /*!
715   Returns all the data this input source contains.
716 */
717 const QString& QXmlInputSource::data() const
718 {
719     return input;
720 }
721
722 /*!
723   Constructs a input source which contains no data.
724 */
725 QXmlInputSource::QXmlInputSource( )
726 {
727     input = "";
728 }
729
730 /*!
731   Constructs a input source and get the data from the text stream.
732 */
733 QXmlInputSource::QXmlInputSource( QTextStream& stream )
734 {
735     QByteArray rawData;
736     if ( stream.device()->isDirectAccess() ) {
737         rawData = stream.device()->readAll();
738     } else {
739         int nread = 0;
740         const int bufsize = 512;
741         while ( !stream.device()->atEnd() ) {
742             rawData.resize( nread + bufsize );
743             nread += stream.device()->readBlock( rawData.data()+nread, bufsize );
744         }
745         rawData.resize( nread );
746     }
747     readInput( rawData );
748 }
749
750 /*!
751   Constructs a input source and get the data from a file. If the file cannot be
752   read the input source is empty.
753 */
754 QXmlInputSource::QXmlInputSource( QFile& file )
755 {
756     if ( !file.open(IO_ReadOnly) ) {
757         input = "";
758         return;
759     }
760     QByteArray rawData = file.readAll();
761     readInput( rawData );
762     file.close();
763 }
764
765 /*!
766   Destructor.
767 */
768 QXmlInputSource::~QXmlInputSource()
769 {
770 }
771
772 /*!
773   Sets the data of the input source to \a dat.
774 */
775 void QXmlInputSource::setData( const QString& dat )
776 {
777     input = dat;
778 }
779
780 /*!
781   Read the XML file from the byte array; try to recoginize the encoding.
782 */
783 // ### The input source should not do the encoding detection!
784 void QXmlInputSource::readInput( QByteArray& rawData )
785 {
786     QBuffer buf( rawData );
787     buf.open( IO_ReadOnly );
788     QTextStream *stream = new QTextStream( &buf );
789     QChar tmp;
790     // assume UTF8 or UTF16 at first
791     stream->setEncoding( QTextStream::UnicodeUTF8 );
792     input = "";
793     // read the first 5 characters
794     for ( int i=0; i<5; i++ ) {
795         *stream >> tmp;
796         input += tmp;
797     }
798     // starts the document with an XML declaration?
799     if ( input == "<?xml" ) {
800         // read the whole XML declaration
801         do {
802             *stream >> tmp;
803             input += tmp;
804         } while( tmp != '>' );
805         // and try to find out if there is an encoding
806         int pos = input.find( "encoding" );
807         if ( pos != -1 ) {
808             QString encoding;
809             do {
810                 pos++;
811                 if ( pos > (int)input.length() )
812                     goto finished;
813             } while( input[pos] != '"' && input[pos] != '\'' );
814             pos++;
815             while( input[pos] != '"' && input[pos] != '\'' ) {
816                 encoding += input[pos];
817                 pos++;
818                 if ( pos > (int)input.length() )
819                     goto finished;
820             }
821             delete stream;
822             stream = new QTextStream( &buf );
823             stream->setCodec( QTextCodec::codecForName( encoding.utf8() ) );
824             buf.reset();
825             input = "";
826         }
827     }
828 finished:
829     input += stream->read();
830     delete stream;
831     buf.close();
832 }
833
834
835 /*********************************************
836  *
837  * QXmlDefaultHandler
838  *
839  *********************************************/
840
841 /*!
842   \class QXmlContentHandler qxml.h
843   \brief The QXmlContentHandler class provides an interface to report logical
844   content of XML data.
845
846   \module XML
847
848   If the application needs to be informed of basic parsing events, it
849   implements this interface and sets it with QXmlReader::setContentHandler().
850   The reader reports basic document-related events like the start and end of
851   elements and character data through this interface.
852
853   The order of events in this interface is very important, and mirrors the
854   order of information in the document itself. For example, all of an element's
855   content (character data, processing instructions, and/or subelements) will
856   appear, in order, between the startElement() event and the corresponding
857   endElement() event.
858
859   The class QXmlDefaultHandler gives a default implementation for this
860   interface; subclassing from this class is very convenient if you want only be
861   informed of some parsing events.
862
863   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
864
865   \sa QXmlDTDHandler QXmlDeclHandler QXmlEntityResolver QXmlErrorHandler
866   QXmlLexicalHandler
867 */
868 /*!
869   \fn void QXmlContentHandler::setDocumentLocator( QXmlLocator* locator )
870
871   The reader calls this function before he starts parsing the document. The
872   argument \a locator is a pointer to a QXmlLocator which allows the
873   application to get the actual position of the parsing in the document.
874
875   Do not destroy the \a locator; it is destroyed when the reader is destroyed
876   (do not use the \a locator after the reader got destroyed).
877 */
878 /*!
879   \fn bool QXmlContentHandler::startDocument()
880
881   The reader calls this function when he starts parsing the document.
882   The reader will call this function only once before any other functions in
883   this class or in the QXmlDTDHandler class are called (except
884   QXmlContentHandler::setDocumentLocator()).
885
886   If this function returns FALSE the reader will stop parsing and will report
887   an error. The reader will use the function errorString() to get the error
888   message that will be used for reporting the error.
889
890   \sa endDocument()
891 */
892 /*!
893   \fn bool QXmlContentHandler::endDocument()
894
895   The reader calls this function after he has finished the parsing. It
896   is only called once. It is the last function of all handler functions that is
897   called. It is called after the reader has read all input or has abandoned
898   parsing because of a fatal error.
899
900   If this function returns FALSE the reader will stop parsing and will report
901   an error. The reader will use the function errorString() to get the error
902   message that will be used for reporting the error.
903
904   \sa startDocument()
905 */
906 /*!
907   \fn bool QXmlContentHandler::startPrefixMapping( const QString& prefix, const QString& uri )
908
909   The reader calls this function to signal the begin of a prefix-URI
910   namespace mapping scope. This information is not necessary for normal
911   namespace processing since the reader automatically replaces prefixes for
912   element and attribute names.
913
914   Note that startPrefixMapping and endPrefixMapping calls are not guaranteed to
915   be properly nested relative to each-other: all startPrefixMapping events will
916   occur before the corresponding startElement event, and all endPrefixMapping
917   events will occur after the corresponding endElement event, but their order
918   is not otherwise guaranteed.
919
920   The argument \a prefix is the namespace prefix being declared and the
921   argument \a uri is the namespace URI the prefix is mapped to.
922
923   If this function returns FALSE the reader will stop parsing and will report
924   an error. The reader will use the function errorString() to get the error
925   message that will be used for reporting the error.
926
927   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
928
929   \sa endPrefixMapping()
930 */
931 /*!
932   \fn bool QXmlContentHandler::endPrefixMapping( const QString& prefix )
933
934   The reader calls this function to signal the end of a prefix mapping.
935
936   If this function returns FALSE the reader will stop parsing and will report
937   an error. The reader will use the function errorString() to get the error
938   message that will be used for reporting the error.
939
940   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
941
942   \sa startPrefixMapping()
943 */
944 /*!
945   \fn bool QXmlContentHandler::startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts )
946
947   The reader calls this function when he has parsed a start element tag.
948
949   There will be a corresponding endElement() call when the corresponding end
950   element tag was read. The startElement() and endElement() calls are always
951   nested correctly. Empty element tags (e.g. &lt;a/&gt;) are reported by
952   startElement() directly followed by a call to endElement().
953
954   The attribute list provided will contain only attributes with explicit
955   values. The attribute list will contain attributes used for namespace
956   declaration (i.e. attributes starting with xmlns) only if the
957   namespace-prefix property of the reader is TRUE.
958
959   The argument \a uri is the namespace URI, or the empty string if the element
960   has no namespace URI or if namespace processing is not being performed, \a
961   localName is the local name (without prefix), or the empty string if
962   namespace processing is not being performed, \a qName is the qualified name
963   (with prefix), or the empty string if qualified names are not available and
964   \a atts are the attributes attached to the element. If there are no
965   attributes, \a atts is an empty attributes object
966
967   If this function returns FALSE the reader will stop parsing and will report
968   an error. The reader will use the function errorString() to get the error
969   message that will be used for reporting the error.
970
971   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
972
973   \sa endElement()
974 */
975 /*!
976   \fn bool QXmlContentHandler::endElement( const QString& namespaceURI, const QString& localName, const QString& qName )
977
978   The reader calls this function when he has parsed an end element tag.
979
980   If this function returns FALSE the reader will stop parsing and will report
981   an error. The reader will use the function errorString() to get the error
982   message that will be used for reporting the error.
983
984   See also the <a href="xml-sax.html#namespaces">namespace description</a>.
985
986   \sa startElement()
987 */
988 /*!
989   \fn bool QXmlContentHandler::characters( const QString& ch )
990
991   The reader calls this function when he has parsed a chunk of character
992   data (either normal character data or character data inside a CDATA section;
993   if you have to distinguish between those two types you have to use
994   QXmlLexicalHandler::startCDATA() and QXmlLexicalHandler::endCDATA() in
995   addition).
996
997   Some readers will report whitespace in element content using the
998   ignorableWhitespace() function rather than this one (QXmlSimpleReader will
999   do it not though).
1000
1001   A reader is allowed to report the character data of an element in more than
1002   one chunk; e.g. a reader might want to report "a &amp;lt; b" in three
1003   characters() events ("a ", "<" and " b").
1004
1005   If this function returns FALSE the reader will stop parsing and will report
1006   an error. The reader will use the function errorString() to get the error
1007   message that will be used for reporting the error.
1008 */
1009 /*!
1010   \fn bool QXmlContentHandler::ignorableWhitespace( const QString& ch )
1011
1012   Some readers may use this function to report each chunk of whitespace in
1013   element content (QXmlSimpleReader does not though).
1014
1015   If this function returns FALSE the reader will stop parsing and will report
1016   an error. The reader will use the function errorString() to get the error
1017   message that will be used for reporting the error.
1018 */
1019 /*!
1020   \fn bool QXmlContentHandler::processingInstruction( const QString& target, const QString& data )
1021
1022   The reader calls this function when he has parsed a processing
1023   instruction.
1024
1025   \a target is the target name of the processing instruction and \a data is the
1026   data of the processing instruction.
1027
1028   If this function returns FALSE the reader will stop parsing and will report
1029   an error. The reader will use the function errorString() to get the error
1030   message that will be used for reporting the error.
1031 */
1032 /*!
1033   \fn bool QXmlContentHandler::skippedEntity( const QString& name )
1034
1035   Some readers may skip entities if they have not seen the declarations (e.g.
1036   because they are in an external DTD). If they do so they will report it by
1037   calling this function.
1038
1039   If this function returns FALSE the reader will stop parsing and will report
1040   an error. The reader will use the function errorString() to get the error
1041   message that will be used for reporting the error.
1042 */
1043 /*!
1044   \fn QString QXmlContentHandler::errorString()
1045
1046   The reader calls this function to get an error string if any of the handler
1047   functions returns FALSE to him.
1048 */
1049
1050
1051 /*!
1052   \class QXmlErrorHandler qxml.h
1053   \brief The QXmlErrorHandler class provides an interface to report errors in
1054   XML data.
1055
1056   \module XML
1057
1058   If the application is interested in reporting errors to the user or any other
1059   customized error handling, you should subclass this class.
1060
1061   You can set the error handler with QXmlReader::setErrorHandler().
1062
1063   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
1064
1065   \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver
1066   QXmlLexicalHandler
1067 */
1068 /*!
1069   \fn bool QXmlErrorHandler::warning( const QXmlParseException& exception )
1070
1071   A reader might use this function to report a warning. Warnings are conditions
1072   that are not errors or fatal errors as defined by the XML 1.0 specification.
1073
1074   If this function returns FALSE the reader will stop parsing and will report
1075   an error. The reader will use the function errorString() to get the error
1076   message that will be used for reporting the error.
1077 */
1078 /*!
1079   \fn bool QXmlErrorHandler::error( const QXmlParseException& exception )
1080
1081   A reader might use this function to report a recoverable error. A recoverable
1082   error corresponds to the definition of "error" in section 1.2 of the XML 1.0
1083   specification.
1084
1085   The reader must continue to provide normal parsing events after invoking this
1086   function.
1087
1088   If this function returns FALSE the reader will stop parsing and will report
1089   an error. The reader will use the function errorString() to get the error
1090   message that will be used for reporting the error.
1091 */
1092 /*!
1093   \fn bool QXmlErrorHandler::fatalError( const QXmlParseException& exception )
1094
1095   A reader must use this function to report a non-recoverable error.
1096
1097   If this function returns TRUE the reader might try to go on parsing and
1098   reporting further errors; but no regular parsing events are reported.
1099 */
1100 /*!
1101   \fn QString QXmlErrorHandler::errorString()
1102
1103   The reader calls this function to get an error string if any of the handler
1104   functions returns FALSE to him.
1105 */
1106
1107
1108 /*!
1109   \class QXmlDTDHandler qxml.h
1110   \brief The QXmlDTDHandler class provides an interface to report DTD content
1111   of XML data.
1112
1113   \module XML
1114
1115   If an application needs information about notations and unparsed entities,
1116   then the application implements this interface and registers an instance with
1117   QXmlReader::setDTDHandler().
1118
1119   Note that this interface includes only those DTD events that the XML
1120   recommendation requires processors to report: notation and unparsed entity
1121   declarations.
1122
1123   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
1124
1125   \sa QXmlDeclHandler QXmlContentHandler QXmlEntityResolver QXmlErrorHandler
1126   QXmlLexicalHandler
1127 */
1128 /*!
1129   \fn bool QXmlDTDHandler::notationDecl( const QString& name, const QString& publicId, const QString& systemId )
1130
1131   The reader calls this function when he has parsed a notation
1132   declaration.
1133
1134   The argument \a name is the notation name, \a publicId is the notations's
1135   public identifier and \a systemId is the notations's system identifier.
1136
1137   If this function returns FALSE the reader will stop parsing and will report
1138   an error. The reader will use the function errorString() to get the error
1139   message that will be used for reporting the error.
1140 */
1141 /*!
1142   \fn bool QXmlDTDHandler::unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName )
1143
1144   The reader calls this function when he finds an unparsed entity declaration.
1145
1146   The argument \a name is the unparsed entity's name, \a publicId is the
1147   entity's public identifier, \a systemId is the entity's system identifier and
1148   \a notation is the name of the associated notation.
1149
1150   If this function returns FALSE the reader will stop parsing and will report
1151   an error. The reader will use the function errorString() to get the error
1152   message that will be used for reporting the error.
1153 */
1154 /*!
1155   \fn QString QXmlDTDHandler::errorString()
1156
1157   The reader calls this function to get an error string if any of the handler
1158   functions returns FALSE to him.
1159 */
1160
1161
1162 /*!
1163   \class QXmlEntityResolver qxml.h
1164   \brief The QXmlEntityResolver class provides an interface to resolve extern
1165   entities contained in XML data.
1166
1167   \module XML
1168
1169   If an application needs to implement customized handling for external
1170   entities, it must implement this interface and register it with
1171   QXmlReader::setEntityResolver().
1172
1173   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
1174
1175   \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlErrorHandler
1176   QXmlLexicalHandler
1177 */
1178 /*!
1179   \fn bool QXmlEntityResolver::resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* ret )
1180
1181   The reader will call this function before he opens any external entity,
1182   except the top-level document entity. The application may request the reader
1183   to resolve the entity itself (\a ret is 0) or to use an entirely different
1184   input source (\a ret points to the input source).
1185
1186   The reader will delete the input source \a ret when he no longer needs it. So
1187   you should allocate it on the heap with \c new.
1188
1189   The argument \a publicId is the public identifier of the external entity, \a
1190   systemId is the system identifier of the external entity and \a ret is the
1191   return value of this function: if it is 0 the reader should resolve the
1192   entity itself, if it is non-zero it must point to an input source which the
1193   reader will use instead.
1194
1195   If this function returns FALSE the reader will stop parsing and will report
1196   an error. The reader will use the function errorString() to get the error
1197   message that will be used for reporting the error.
1198 */
1199 /*!
1200   \fn QString QXmlEntityResolver::errorString()
1201
1202   The reader calls this function to get an error string if any of the handler
1203   functions returns FALSE to him.
1204 */
1205
1206
1207 /*!
1208   \class QXmlLexicalHandler qxml.h
1209   \brief The QXmlLexicalHandler class provides an interface to report lexical
1210   content of XML data.
1211
1212   \module XML
1213
1214   The events in the lexical handler apply to the entire document, not just to
1215   the document element, and all lexical handler events appear between the
1216   content handler's startDocument and endDocument events.
1217
1218   You can set the lexical handler with QXmlReader::setLexicalHandler().
1219
1220   This interface is designed after the SAX2 extension LexicalHandler. The
1221   functions startEntity() and endEntity() are not included though.
1222
1223   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
1224
1225   \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver
1226   QXmlErrorHandler
1227 */
1228 /*!
1229   \fn bool QXmlLexicalHandler::startDTD( const QString& name, const QString& publicId, const QString& systemId )
1230
1231   The reader calls this function to report the start of a DTD declaration, if
1232   any.
1233
1234   All declarations reported through QXmlDTDHandler or QXmlDeclHandler appear
1235   between the startDTD() and endDTD() calls.
1236
1237   If this function returns FALSE the reader will stop parsing and will report
1238   an error. The reader will use the function errorString() to get the error
1239   message that will be used for reporting the error.
1240
1241   \sa endDTD()
1242 */
1243 /*!
1244   \fn bool QXmlLexicalHandler::endDTD()
1245
1246   The reader calls this function to report the end of a DTD declaration, if
1247   any.
1248
1249   If this function returns FALSE the reader will stop parsing and will report
1250   an error. The reader will use the function errorString() to get the error
1251   message that will be used for reporting the error.
1252
1253   \sa startDTD()
1254 */
1255 /*!
1256   \fn bool QXmlLexicalHandler::startCDATA()
1257
1258   The reader calls this function to report the start of a CDATA section. The
1259   content of the CDATA section will be reported through the regular
1260   QXmlContentHandler::characters(). This function is intended only to report
1261   the boundary.
1262
1263   If this function returns FALSE the reader will stop parsing and will report
1264   an error. The reader will use the function errorString() to get the error
1265   message that will be used for reporting the error.
1266
1267   \sa endCDATA()
1268 */
1269 /*!
1270   \fn bool QXmlLexicalHandler::endCDATA()
1271
1272   The reader calls this function to report the end of a CDATA section.
1273
1274   If this function returns FALSE the reader will stop parsing and will report
1275   an error. The reader will use the function errorString() to get the error
1276   message that will be used for reporting the error.
1277
1278   \sa startCDATA()
1279 */
1280 /*!
1281   \fn bool QXmlLexicalHandler::comment( const QString& ch )
1282
1283   The reader calls this function to report an XML comment anywhere in the
1284   document.
1285
1286   If this function returns FALSE the reader will stop parsing and will report
1287   an error. The reader will use the function errorString() to get the error
1288   message that will be used for reporting the error.
1289 */
1290 /*!
1291   \fn QString QXmlLexicalHandler::errorString()
1292
1293   The reader calls this function to get an error string if any of the handler
1294   functions returns FALSE to him.
1295 */
1296
1297
1298 /*!
1299   \class QXmlDeclHandler qxml.h
1300   \brief The QXmlDeclHandler class provides an interface to report declaration
1301   content of XML data.
1302
1303   \module XML
1304
1305   You can set the declaration handler with QXmlReader::setDeclHandler().
1306
1307   This interface is designed after the SAX2 extension DeclHandler.
1308
1309   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
1310
1311   \sa QXmlDTDHandler QXmlContentHandler QXmlEntityResolver QXmlErrorHandler
1312   QXmlLexicalHandler
1313 */
1314 /*!
1315   \fn bool QXmlDeclHandler::attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value )
1316
1317   The reader calls this function to report an attribute type declaration. Only
1318   the effective (first) declaration for an attribute will be reported.
1319
1320   If this function returns FALSE the reader will stop parsing and will report
1321   an error. The reader will use the function errorString() to get the error
1322   message that will be used for reporting the error.
1323 */
1324 /*!
1325   \fn bool QXmlDeclHandler::internalEntityDecl( const QString& name, const QString& value )
1326
1327   The reader calls this function to report an internal entity declaration. Only
1328   the effective (first) declaration will be reported.
1329
1330   If this function returns FALSE the reader will stop parsing and will report
1331   an error. The reader will use the function errorString() to get the error
1332   message that will be used for reporting the error.
1333 */
1334 /*!
1335   \fn bool QXmlDeclHandler::externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId )
1336
1337   The reader calls this function to report a parsed external entity
1338   declaration. Only the effective (first) declaration for each entity will be
1339   reported.
1340
1341   If this function returns FALSE the reader will stop parsing and will report
1342   an error. The reader will use the function errorString() to get the error
1343   message that will be used for reporting the error.
1344 */
1345 /*!
1346   \fn QString QXmlDeclHandler::errorString()
1347
1348   The reader calls this function to get an error string if any of the handler
1349   functions returns FALSE to him.
1350 */
1351
1352
1353 /*!
1354   \class QXmlDefaultHandler qxml.h
1355   \brief The QXmlDefaultHandler class provides a default implementation of all
1356   XML handler classes.
1357
1358   \module XML
1359
1360   Very often you are only interested in parts of the things that that the
1361   reader reports to you. This class simply implements a default behaviour of
1362   the handler classes (most of the time: do nothing). Normally this is the
1363   class you subclass for implementing your customized handler.
1364
1365   See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>.
1366
1367   \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver
1368   QXmlErrorHandler QXmlLexicalHandler
1369 */
1370 /*!
1371   \fn QXmlDefaultHandler::QXmlDefaultHandler()
1372
1373   Constructor.
1374 */
1375 /*!
1376   \fn QXmlDefaultHandler::~QXmlDefaultHandler()
1377
1378   Destructor.
1379 */
1380
1381 /*!
1382   Does nothing.
1383 */
1384 void QXmlDefaultHandler::setDocumentLocator( QXmlLocator* )
1385 {
1386 }
1387
1388 /*!
1389   Does nothing.
1390 */
1391 bool QXmlDefaultHandler::startDocument()
1392 {
1393     return TRUE;
1394 }
1395
1396 /*!
1397   Does nothing.
1398 */
1399 bool QXmlDefaultHandler::endDocument()
1400 {
1401     return TRUE;
1402 }
1403
1404 /*!
1405   Does nothing.
1406 */
1407 bool QXmlDefaultHandler::startPrefixMapping( const QString&, const QString& )
1408 {
1409     return TRUE;
1410 }
1411
1412 /*!
1413   Does nothing.
1414 */
1415 bool QXmlDefaultHandler::endPrefixMapping( const QString& )
1416 {
1417     return TRUE;
1418 }
1419
1420 /*!
1421   Does nothing.
1422 */
1423 bool QXmlDefaultHandler::startElement( const QString&, const QString&,
1424         const QString&, const QXmlAttributes& )
1425 {
1426     return TRUE;
1427 }
1428
1429 /*!
1430   Does nothing.
1431 */
1432 bool QXmlDefaultHandler::endElement( const QString&, const QString&,
1433         const QString& )
1434 {
1435     return TRUE;
1436 }
1437
1438 /*!
1439   Does nothing.
1440 */
1441 bool QXmlDefaultHandler::characters( const QString& )
1442 {
1443     return TRUE;
1444 }
1445
1446 /*!
1447   Does nothing.
1448 */
1449 bool QXmlDefaultHandler::ignorableWhitespace( const QString& )
1450 {
1451     return TRUE;
1452 }
1453
1454 /*!
1455   Does nothing.
1456 */
1457 bool QXmlDefaultHandler::processingInstruction( const QString&,
1458         const QString& )
1459 {
1460     return TRUE;
1461 }
1462
1463 /*!
1464   Does nothing.
1465 */
1466 bool QXmlDefaultHandler::skippedEntity( const QString& )
1467 {
1468     return TRUE;
1469 }
1470
1471 /*!
1472   Does nothing.
1473 */
1474 bool QXmlDefaultHandler::warning( const QXmlParseException& )
1475 {
1476     return TRUE;
1477 }
1478
1479 /*!
1480   Does nothing.
1481 */
1482 bool QXmlDefaultHandler::error( const QXmlParseException& )
1483 {
1484     return TRUE;
1485 }
1486
1487 /*!
1488   Does nothing.
1489 */
1490 bool QXmlDefaultHandler::fatalError( const QXmlParseException& )
1491 {
1492     return TRUE;
1493 }
1494
1495 /*!
1496   Does nothing.
1497 */
1498 bool QXmlDefaultHandler::notationDecl( const QString&, const QString&,
1499         const QString& )
1500 {
1501     return TRUE;
1502 }
1503
1504 /*!
1505   Does nothing.
1506 */
1507 bool QXmlDefaultHandler::unparsedEntityDecl( const QString&, const QString&,
1508         const QString&, const QString& )
1509 {
1510     return TRUE;
1511 }
1512
1513 /*!
1514   Always sets \a ret to 0, so that the reader will use the system identifier
1515   provided in the XML document.
1516 */
1517 bool QXmlDefaultHandler::resolveEntity( const QString&, const QString&,
1518         QXmlInputSource* &ret )
1519 {
1520     ret = 0;
1521     return TRUE;
1522 }
1523
1524 /*!
1525   Returns the default error string.
1526 */
1527 QString QXmlDefaultHandler::errorString()
1528 {
1529     return QString( XMLERR_ERRORBYCONSUMER );
1530 }
1531
1532 /*!
1533   Does nothing.
1534 */
1535 bool QXmlDefaultHandler::startDTD( const QString&, const QString&, const QString& )
1536 {
1537     return TRUE;
1538 }
1539
1540 /*!
1541   Does nothing.
1542 */
1543 bool QXmlDefaultHandler::endDTD()
1544 {
1545     return TRUE;
1546 }
1547
1548 #if 0
1549 /*!
1550   Does nothing.
1551 */
1552 bool QXmlDefaultHandler::startEntity( const QString& )
1553 {
1554     return TRUE;
1555 }
1556
1557 /*!
1558   Does nothing.
1559 */
1560 bool QXmlDefaultHandler::endEntity( const QString& )
1561 {
1562     return TRUE;
1563 }
1564 #endif
1565
1566 /*!
1567   Does nothing.
1568 */
1569 bool QXmlDefaultHandler::startCDATA()
1570 {
1571     return TRUE;
1572 }
1573
1574 /*!
1575   Does nothing.
1576 */
1577 bool QXmlDefaultHandler::endCDATA()
1578 {
1579     return TRUE;
1580 }
1581
1582 /*!
1583   Does nothing.
1584 */
1585 bool QXmlDefaultHandler::comment( const QString& )
1586 {
1587     return TRUE;
1588 }
1589
1590 /*!
1591   Does nothing.
1592 */
1593 bool QXmlDefaultHandler::attributeDecl( const QString&, const QString&, const QString&, const QString&, const QString& )
1594 {
1595     return TRUE;
1596 }
1597
1598 /*!
1599   Does nothing.
1600 */
1601 bool QXmlDefaultHandler::internalEntityDecl( const QString&, const QString& )
1602 {
1603     return TRUE;
1604 }
1605
1606 /*!
1607   Does nothing.
1608 */
1609 bool QXmlDefaultHandler::externalEntityDecl( const QString&, const QString&, const QString& )
1610 {
1611     return TRUE;
1612 }
1613
1614
1615 /*********************************************
1616  *
1617  * QXmlSimpleReaderPrivate
1618  *
1619  *********************************************/
1620
1621 class QXmlSimpleReaderPrivate
1622 {
1623 private:
1624     // constructor
1625     QXmlSimpleReaderPrivate()
1626     { }
1627
1628
1629     // used for entity declarations
1630     struct ExternParameterEntity
1631     {
1632         ExternParameterEntity( ) {}
1633         ExternParameterEntity( const QString &p, const QString &s )
1634             : publicId(p), systemId(s) {}
1635         QString publicId;
1636         QString systemId;
1637     };
1638     struct ExternEntity
1639     {
1640         ExternEntity( ) {}
1641         ExternEntity( const QString &p, const QString &s, const QString &n )
1642             : publicId(p), systemId(s), notation(n) {}
1643         QString publicId;
1644         QString systemId;
1645         QString notation;
1646     };
1647     QMap<QString,ExternParameterEntity> externParameterEntities;
1648     QMap<QString,QString> parameterEntities;
1649     QMap<QString,ExternEntity> externEntities;
1650     QMap<QString,QString> entities;
1651
1652     // used for standalone declaration
1653     enum Standalone { Yes, No, Unknown };
1654
1655     QString doctype; // only used for the doctype
1656     QString xmlVersion; // only used to store the version information
1657     QString encoding; // only used to store the encoding
1658     Standalone standalone; // used to store the value of the standalone declaration
1659
1660     QString publicId; // used by parseExternalID() to store the public ID
1661     QString systemId; // used by parseExternalID() to store the system ID
1662     QString attDeclEName; // use by parseAttlistDecl()
1663     QString attDeclAName; // use by parseAttlistDecl()
1664
1665     // flags for some features support
1666     bool useNamespaces;
1667     bool useNamespacePrefixes;
1668     bool reportWhitespaceCharData;
1669
1670     // used to build the attribute list
1671     QXmlAttributes attList;
1672
1673     // helper classes
1674     QXmlLocator *locator;
1675     QXmlNamespaceSupport namespaceSupport;
1676
1677     // error string
1678     QString error;
1679
1680     // friend declarations
1681     friend class QXmlSimpleReader;
1682 };
1683
1684
1685 /*********************************************
1686  *
1687  * QXmlSimpleReader
1688  *
1689  *********************************************/
1690
1691 /*!
1692   \class QXmlReader qxml.h
1693   \brief The QXmlReader class provides an interface for XML readers (i.e.
1694   parsers).
1695
1696   \module XML
1697
1698   This abstract class describes an interface for all XML readers in Qt. At the
1699   moment there is only one implementation of a reader included in the XML
1700   module of Qt (QXmlSimpleReader). In future releases there might be more
1701   readers with different properties available (e.g. a validating parser).
1702
1703   The design of the XML classes follow the
1704   <a href="http://www.megginson.com/SAX/">SAX2 java interface</a>.
1705   It was adopted to fit into the Qt naming conventions; so it should be very
1706   easy for anybody who has worked with SAX2 to get started with the Qt XML
1707   classes.
1708
1709   All readers use the class QXmlInputSource to read the input document from.
1710   Since you are normally interested in certain contents of the XML document,
1711   the reader reports those contents through special handler classes
1712   (QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
1713   QXmlErrorHandler and QXmlLexicalHandler).
1714
1715   You have to subclass these classes. Since the handler classes describe only
1716   interfaces you must implement all functions; there is a class
1717   (QXmlDefaultHandler) to make this easier; it implements a default behaviour
1718   (do nothing) for all functions.
1719
1720   For getting started see also the
1721   <a href="xml-sax.html#quickStart">Quick start</a>.
1722
1723   \sa QXmlSimpleReader
1724 */
1725 /*!
1726   \fn bool QXmlReader::feature( const QString& name, bool *ok ) const
1727
1728   If the reader has the feature \a name, this function returns the value of the
1729   feature.
1730
1731   If the reader has not the feature \a name, the return value may be anything.
1732
1733   If \a ok is not 0, then \a ok  is set to TRUE if the reader has the feature
1734   \a name, otherwise \a ok is set to FALSE.
1735
1736   \sa setFeature() hasFeature()
1737 */
1738 /*!
1739   \fn void QXmlReader::setFeature( const QString& name, bool value )
1740
1741   Sets the feature \a name to \a value. If the reader has not the feature \a
1742   name, this value is ignored.
1743
1744   \sa feature() hasFeature()
1745 */
1746 /*!
1747   \fn bool QXmlReader::hasFeature( const QString& name ) const
1748
1749   Returns \c TRUE if the reader has the feature \a name, otherwise FALSE.
1750
1751   \sa feature() setFeature()
1752 */
1753 /*!
1754   \fn void* QXmlReader::property( const QString& name, bool *ok ) const
1755
1756   If the reader has the property \a name, this function returns the value of
1757   the property.
1758
1759   If the reader has not the property \a name, the return value is 0.
1760
1761   If \a ok is not 0, then \a ok  is set to TRUE if the reader has the property
1762   \a name, otherwise \a ok is set to FALSE.
1763
1764   \sa setProperty() hasProperty()
1765 */
1766 /*!
1767   \fn void QXmlReader::setProperty( const QString& name, void* value )
1768
1769   Sets the property \a name to \a value. If the reader has not the property \a
1770   name, this value is ignored.
1771
1772   \sa property() hasProperty()
1773 */
1774 /*!
1775   \fn bool QXmlReader::hasProperty( const QString& name ) const
1776
1777   Returns TRUE if the reader has the property \a name, otherwise FALSE.
1778
1779   \sa property() setProperty()
1780 */
1781 /*!
1782   \fn void QXmlReader::setEntityResolver( QXmlEntityResolver* handler )
1783
1784   Sets the entity resolver to \a handler.
1785
1786   \sa entityResolver()
1787 */
1788 /*!
1789   \fn QXmlEntityResolver* QXmlReader::entityResolver() const
1790
1791   Returns the entity resolver or 0 if none was set.
1792
1793   \sa setEntityResolver()
1794 */
1795 /*!
1796   \fn void QXmlReader::setDTDHandler( QXmlDTDHandler* handler )
1797
1798   Sets the DTD handler to \a handler.
1799
1800   \sa DTDHandler()
1801 */
1802 /*!
1803   \fn QXmlDTDHandler* QXmlReader::DTDHandler() const
1804
1805   Returns the DTD handler or 0 if none was set.
1806
1807   \sa setDTDHandler()
1808 */
1809 /*!
1810   \fn void QXmlReader::setContentHandler( QXmlContentHandler* handler )
1811
1812   Sets the content handler to \a handler.
1813
1814   \sa contentHandler()
1815 */
1816 /*!
1817   \fn QXmlContentHandler* QXmlReader::contentHandler() const
1818
1819   Returns the content handler or 0 if none was set.
1820
1821   \sa setContentHandler()
1822 */
1823 /*!
1824   \fn void QXmlReader::setErrorHandler( QXmlErrorHandler* handler )
1825
1826   Sets the error handler to \a handler.
1827
1828   \sa errorHandler()
1829 */
1830 /*!
1831   \fn QXmlErrorHandler* QXmlReader::errorHandler() const
1832
1833   Returns the error handler or 0 if none was set
1834
1835   \sa setErrorHandler()
1836 */
1837 /*!
1838   \fn void QXmlReader::setLexicalHandler( QXmlLexicalHandler* handler )
1839
1840   Sets the lexical handler to \a handler.
1841
1842   \sa lexicalHandler()
1843 */
1844 /*!
1845   \fn QXmlLexicalHandler* QXmlReader::lexicalHandler() const
1846
1847   Returns the lexical handler or 0 if none was set.
1848
1849   \sa setLexicalHandler()
1850 */
1851 /*!
1852   \fn void QXmlReader::setDeclHandler( QXmlDeclHandler* handler )
1853
1854   Sets the declaration handler to \a handler.
1855
1856   \sa declHandler()
1857 */
1858 /*!
1859   \fn QXmlDeclHandler* QXmlReader::declHandler() const
1860
1861   Returns the declaration handler or 0 if none was set.
1862
1863   \sa setDeclHandler()
1864 */
1865 /*!
1866   \fn bool QXmlReader::parse( const QXmlInputSource& input )
1867
1868   Parses the XML document \a input. Returns TRUE if the parsing was successful,
1869   otherwise FALSE.
1870 */
1871 /*!
1872   \fn bool QXmlReader::parse( const QString& systemId )
1873
1874   Parses the XML document at the location \a systemId. Returns TRUE if the
1875   parsing was successful, otherwise FALSE.
1876 */
1877
1878
1879 /*!
1880   \class QXmlSimpleReader qxml.h
1881   \brief The QXmlSimpleReader class provides an implementation of a simple XML
1882   reader (i.e. parser).
1883
1884   \module XML
1885
1886   This XML reader is sufficient for simple parsing tasks. Here is a short list
1887   of the properties of this reader:
1888   <ul>
1889   <li> well-formed parser
1890   <li> does not parse any external entities
1891   <li> can do namespace processing
1892   </ul>
1893
1894   For getting started see also the
1895   <a href="xml-sax.html#quickStart">Quick start</a>.
1896 */
1897
1898 //guaranteed not to be a characater
1899 const QChar QXmlSimpleReader::QEOF = QChar((ushort)0xffff);
1900
1901 /*!
1902   Constructs a simple XML reader.
1903 */
1904 QXmlSimpleReader::QXmlSimpleReader()
1905 {
1906     d = new QXmlSimpleReaderPrivate();
1907     d->locator = new QXmlLocator( this );
1908
1909     entityRes  = 0;
1910     dtdHnd     = 0;
1911     contentHnd = 0;
1912     errorHnd   = 0;
1913     lexicalHnd = 0;
1914     declHnd    = 0;
1915
1916     // default feature settings
1917     d->useNamespaces = TRUE;
1918     d->useNamespacePrefixes = FALSE;
1919     d->reportWhitespaceCharData = TRUE;
1920 }
1921
1922 /*!
1923   Destroys a simple XML reader.
1924 */
1925 QXmlSimpleReader::~QXmlSimpleReader()
1926 {
1927     delete d->locator;
1928     delete d;
1929 }
1930
1931 /*!
1932   Gets the state of a feature.
1933
1934   \sa setFeature() hasFeature()
1935 */
1936 bool QXmlSimpleReader::feature( const QString& name, bool *ok ) const
1937 {
1938     if ( ok != 0 )
1939         *ok = TRUE;
1940     if        ( name == "http://xml.org/sax/features/namespaces" ) {
1941         return d->useNamespaces;
1942     } else if ( name == "http://xml.org/sax/features/namespace-prefixes" ) {
1943         return d->useNamespacePrefixes;
1944     } else if ( name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) {
1945         return d->reportWhitespaceCharData;
1946     } else {
1947         qWarning( "Unknown feature %s", name.ascii() );
1948         if ( ok != 0 )
1949             *ok = FALSE;
1950     }
1951     return FALSE;
1952 }
1953
1954 /*!
1955   Sets the state of a feature.
1956
1957   Supported features are:
1958   <ul>
1959   <li> http://xml.org/sax/features/namespaces:
1960        if this feature is TRUE, namespace processing is performed
1961   <li> http://xml.org/sax/features/namespace-prefixes:
1962        if this feature is TRUE, the the original prefixed names and attributes
1963        used for namespace declarations are reported
1964   <li> http://trolltech.com/xml/features/report-whitespace-only-CharData:
1965        if this feature is TRUE, CharData that consists only of whitespace (and
1966        no other characters) is not reported via
1967        QXmlContentHandler::characters()
1968   </ul>
1969
1970   \sa feature() hasFeature()
1971 */
1972 void QXmlSimpleReader::setFeature( const QString& name, bool value )
1973 {
1974     if        ( name == "http://xml.org/sax/features/namespaces" ) {
1975         d->useNamespaces = value;
1976     } else if ( name == "http://xml.org/sax/features/namespace-prefixes" ) {
1977         d->useNamespacePrefixes = value;
1978     } else if ( name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) {
1979         d->reportWhitespaceCharData = value;
1980     } else {
1981         qWarning( "Unknown feature %s", name.ascii() );
1982     }
1983 }
1984
1985 /*!
1986   Returns TRUE if the class has a feature named \a feature, otherwise FALSE.
1987
1988   \sa setFeature() feature()
1989 */
1990 bool QXmlSimpleReader::hasFeature( const QString& name ) const
1991 {
1992     if (    name == "http://xml.org/sax/features/namespaces" ||
1993             name == "http://xml.org/sax/features/namespace-prefixes" ||
1994             name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) {
1995         return TRUE;
1996     } else {
1997         return FALSE;
1998     }
1999 }
2000
2001 /*!
2002   Returns 0 since this class does not support any properties.
2003 */
2004 void* QXmlSimpleReader::property( const QString&, bool *ok ) const
2005 {
2006     if ( ok != 0 )
2007         *ok = FALSE;
2008     return 0;
2009 }
2010
2011 /*!
2012   Does nothing since this class does not support any properties.
2013 */
2014 void QXmlSimpleReader::setProperty( const QString&, void* )
2015 {
2016 }
2017
2018 /*!
2019   Returns FALSE since this class does not support any properties.
2020 */
2021 bool QXmlSimpleReader::hasProperty( const QString& ) const
2022 {
2023     return FALSE;
2024 }
2025
2026 /*! \reimp */
2027 void QXmlSimpleReader::setEntityResolver( QXmlEntityResolver* handler )
2028 { entityRes = handler; }
2029
2030 /*! \reimp */
2031 QXmlEntityResolver* QXmlSimpleReader::entityResolver() const
2032 { return entityRes; }
2033
2034 /*! \reimp */
2035 void QXmlSimpleReader::setDTDHandler( QXmlDTDHandler* handler )
2036 { dtdHnd = handler; }
2037
2038 /*! \reimp */
2039 QXmlDTDHandler* QXmlSimpleReader::DTDHandler() const
2040 { return dtdHnd; }
2041
2042 /*! \reimp */
2043 void QXmlSimpleReader::setContentHandler( QXmlContentHandler* handler )
2044 { contentHnd = handler; }
2045
2046 /*! \reimp */
2047 QXmlContentHandler* QXmlSimpleReader::contentHandler() const
2048 { return contentHnd; }
2049
2050 /*! \reimp */
2051 void QXmlSimpleReader::setErrorHandler( QXmlErrorHandler* handler )
2052 { errorHnd = handler; }
2053
2054 /*! \reimp */
2055 QXmlErrorHandler* QXmlSimpleReader::errorHandler() const
2056 { return errorHnd; }
2057
2058 /*! \reimp */
2059 void QXmlSimpleReader::setLexicalHandler( QXmlLexicalHandler* handler )
2060 { lexicalHnd = handler; }
2061
2062 /*! \reimp */
2063 QXmlLexicalHandler* QXmlSimpleReader::lexicalHandler() const
2064 { return lexicalHnd; }
2065
2066 /*! \reimp */
2067 void QXmlSimpleReader::setDeclHandler( QXmlDeclHandler* handler )
2068 { declHnd = handler; }
2069
2070 /*! \reimp */
2071 QXmlDeclHandler* QXmlSimpleReader::declHandler() const
2072 { return declHnd; }
2073
2074
2075
2076 /*! \reimp */
2077 bool QXmlSimpleReader::parse( const QXmlInputSource& input )
2078 {
2079     init( input );
2080     // call the handler
2081     if ( contentHnd ) {
2082         contentHnd->setDocumentLocator( d->locator );
2083         if ( !contentHnd->startDocument() ) {
2084             d->error = contentHnd->errorString();
2085             goto parseError;
2086         }
2087     }
2088     // parse prolog
2089     if ( !parseProlog() ) {
2090         d->error = XMLERR_ERRORPARSINGPROLOG;
2091         goto parseError;
2092     }
2093     // parse element
2094     if ( !parseElement() ) {
2095         d->error = XMLERR_ERRORPARSINGMAINELEMENT;
2096         goto parseError;
2097     }
2098     // parse Misc*
2099     while ( !atEnd() ) {
2100         if ( !parseMisc() ) {
2101             d->error = XMLERR_ERRORPARSINGMISC;
2102             goto parseError;
2103         }
2104     }
2105     // is stack empty?
2106     if ( !tags.isEmpty() ) {
2107         d->error = XMLERR_UNEXPECTEDEOF;
2108         goto parseError;
2109     }
2110     // call the handler
2111     if ( contentHnd ) {
2112         if ( !contentHnd->endDocument() ) {
2113             d->error = contentHnd->errorString();
2114             goto parseError;
2115         }
2116     }
2117
2118     return TRUE;
2119
2120     // error handling
2121
2122 parseError:
2123     reportParseError();
2124     tags.clear();
2125     return FALSE;
2126 }
2127
2128 /*!
2129   Parses the prolog [22].
2130 */
2131 bool QXmlSimpleReader::parseProlog()
2132 {
2133     bool xmldecl_possible = TRUE;
2134     bool doctype_read = FALSE;
2135
2136     const signed char Init             = 0;
2137     const signed char EatWS            = 1; // eat white spaces
2138     const signed char Lt               = 2; // '<' read
2139     const signed char Em               = 3; // '!' read
2140     const signed char DocType          = 4; // read doctype
2141     const signed char Comment          = 5; // read comment
2142     const signed char PI               = 6; // read PI
2143     const signed char Done             = 7;
2144
2145     const signed char InpWs            = 0;
2146     const signed char InpLt            = 1; // <
2147     const signed char InpQm            = 2; // ?
2148     const signed char InpEm            = 3; // !
2149     const signed char InpD             = 4; // D
2150     const signed char InpDash          = 5; // -
2151     const signed char InpUnknown       = 6;
2152
2153     // use some kind of state machine for parsing
2154     static signed char table[7][7] = {
2155      /*  InpWs   InpLt  InpQm  InpEm  InpD      InpDash  InpUnknown */
2156         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // Init
2157         { -1,     Lt,    -1,    -1,    -1,       -1,       -1      }, // EatWS
2158         { -1,     -1,    PI,    Em,    Done,     -1,       Done    }, // Lt
2159         { -1,     -1,    -1,    -1,    DocType,  Comment,  -1      }, // Em
2160         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // DocType
2161         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // Comment
2162         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }  // PI
2163     };
2164     signed char state = Init;
2165     signed char input;
2166     bool parseOk = TRUE;
2167
2168     while ( TRUE ) {
2169
2170         // read input
2171         if ( atEnd() ) {
2172             d->error = XMLERR_UNEXPECTEDEOF;
2173             goto parseError;
2174         }
2175         if        ( is_S(c) ) {
2176             input = InpWs;
2177         } else if ( c == '<' ) {
2178             input = InpLt;
2179         } else if ( c == '?' ) {
2180             input = InpQm;
2181         } else if ( c == '!' ) {
2182             input = InpEm;
2183         } else if ( c == 'D' ) {
2184             input = InpD;
2185         } else if ( c == '-' ) {
2186             input = InpDash;
2187         } else {
2188             input = InpUnknown;
2189         }
2190         // get new state
2191         state = table[state][input];
2192
2193         // in some cases do special actions depending on state
2194         switch ( state ) {
2195             case EatWS:
2196                 // XML declaration only on first position possible
2197                 xmldecl_possible = FALSE;
2198                 // eat white spaces
2199                 eat_ws();
2200                 break;
2201             case Lt:
2202                 // next character
2203                 next();
2204                 break;
2205             case Em:
2206                 // XML declaration only on first position possible
2207                 xmldecl_possible = FALSE;
2208                 // next character
2209                 next();
2210                 break;
2211             case DocType:
2212                 parseOk = parseDoctype();
2213                 break;
2214             case Comment:
2215                 parseOk = parseComment();
2216                 break;
2217             case PI:
2218                 parseOk = parsePI( xmldecl_possible );
2219                 break;
2220         }
2221         // no input is read after this
2222         switch ( state ) {
2223             case DocType:
2224                 if ( !parseOk ) {
2225                     d->error = XMLERR_ERRORPARSINGPROLOG;
2226                     goto parseError;
2227                 }
2228                 if ( doctype_read ) {
2229                     d->error = XMLERR_MORETHANONEDOCTYPE;
2230                     goto parseError;
2231                 } else {
2232                     doctype_read = FALSE;
2233                 }
2234                 break;
2235             case Comment:
2236                 if ( !parseOk ) {
2237                     d->error = XMLERR_ERRORPARSINGPROLOG;
2238                     goto parseError;
2239                 }
2240                 if ( lexicalHnd ) {
2241                     if ( !lexicalHnd->comment( string() ) ) {
2242                         d->error = lexicalHnd->errorString();
2243                         goto parseError;
2244                     }
2245                 }
2246                 break;
2247             case PI:
2248                 if ( !parseOk ) {
2249                     d->error = XMLERR_ERRORPARSINGPROLOG;
2250                     goto parseError;
2251                 }
2252                 // call the handler
2253                 if ( contentHnd ) {
2254                     if ( xmldecl_possible && !d->xmlVersion.isEmpty() ) {
2255                         QString value( "version = '" );
2256                         value += d->xmlVersion;
2257                         value += "'";
2258                         if ( !d->encoding.isEmpty() ) {
2259                             value += " encoding = '";
2260                             value += d->encoding;
2261                             value += "'";
2262                         }
2263                         if ( d->standalone == QXmlSimpleReaderPrivate::Yes ) {
2264                             value += " standalone = 'yes'";
2265                         } else if ( d->standalone == QXmlSimpleReaderPrivate::No ) {
2266                             value += " standalone = 'no'";
2267                         }
2268                         if ( !contentHnd->processingInstruction( "xml", value ) ) {
2269                             d->error = contentHnd->errorString();
2270                             goto parseError;
2271                         }
2272                     } else {
2273                         if ( !contentHnd->processingInstruction( name(), string() ) ) {
2274                             d->error = contentHnd->errorString();
2275                             goto parseError;
2276                         }
2277                     }
2278                 }
2279                 // XML declaration only on first position possible
2280                 xmldecl_possible = FALSE;
2281                 break;
2282             case Done:
2283                 return TRUE;
2284             case -1:
2285                 d->error = XMLERR_ERRORPARSINGELEMENT;
2286                 goto parseError;
2287         }
2288
2289     }
2290
2291     return TRUE;
2292
2293 parseError:
2294     reportParseError();
2295     return FALSE;
2296 }
2297
2298 /*!
2299   Parse an element [39].
2300
2301   Precondition: the opening '<' is already read.
2302 */
2303 bool QXmlSimpleReader::parseElement()
2304 {
2305     static QString uri, lname, prefix;
2306     static bool t;
2307
2308     const signed char Init             =  0;
2309     const signed char ReadName         =  1;
2310     const signed char Ws1              =  2;
2311     const signed char STagEnd          =  3;
2312     const signed char STagEnd2         =  4;
2313     const signed char ETagBegin        =  5;
2314     const signed char ETagBegin2       =  6;
2315     const signed char Ws2              =  7;
2316     const signed char EmptyTag         =  8;
2317     const signed char Attribute        =  9;
2318     const signed char Ws3              = 10;
2319     const signed char Done             = 11;
2320
2321     const signed char InpWs            = 0; // whitespace
2322     const signed char InpNameBe        = 1; // is_NameBeginning()
2323     const signed char InpGt            = 2; // >
2324     const signed char InpSlash         = 3; // /
2325     const signed char InpUnknown       = 4;
2326
2327     // use some kind of state machine for parsing
2328     static signed char table[11][5] = {
2329      /*  InpWs      InpNameBe    InpGt        InpSlash     InpUnknown */
2330         { -1,        ReadName,    -1,          -1,          -1        }, // Init
2331         { Ws1,       Attribute,   STagEnd,     EmptyTag,    -1        }, // ReadName
2332         { -1,        Attribute,   STagEnd,     EmptyTag,    -1        }, // Ws1
2333         { STagEnd2,  STagEnd2,    STagEnd2,    STagEnd2,    STagEnd2  }, // STagEnd
2334         { -1,        -1,          -1,          ETagBegin,   -1        }, // STagEnd2
2335         { -1,        ETagBegin2,  -1,          -1,          -1        }, // ETagBegin
2336         { Ws2,       -1,          Done,        -1,          -1        }, // ETagBegin2
2337         { -1,        -1,          Done,        -1,          -1        }, // Ws2
2338         { -1,        -1,          Done,        -1,          -1        }, // EmptyTag
2339         { Ws3,       Attribute,   STagEnd,     EmptyTag,    -1        }, // Attribute
2340         { -1,        Attribute,   STagEnd,     EmptyTag,    -1        }  // Ws3
2341     };
2342     signed char state = Init;
2343     signed char input;
2344     bool parseOk = TRUE;
2345
2346     while ( TRUE ) {
2347
2348         // read input
2349         if ( atEnd() ) {
2350             d->error = XMLERR_UNEXPECTEDEOF;
2351             goto parseError;
2352         }
2353         if        ( is_S(c) ) {
2354             input = InpWs;
2355         } else if ( is_NameBeginning(c) ) {
2356             input = InpNameBe;
2357         } else if ( c == '>' ) {
2358             input = InpGt;
2359         } else if ( c == '/' ) {
2360             input = InpSlash;
2361         } else {
2362             input = InpUnknown;
2363         }
2364         // get new state
2365 //qDebug( "%d -%d(%c)-> %d", state, input, c.latin1(), table[state][input] );
2366         state = table[state][input];
2367
2368         // in some cases do special actions depending on state
2369         switch ( state ) {
2370             case ReadName:
2371                 parseOk = parseName();
2372                 break;
2373             case Ws1:
2374             case Ws2:
2375             case Ws3:
2376                 eat_ws();
2377                 break;
2378             case STagEnd:
2379                 // call the handler
2380                 if ( contentHnd ) {
2381                     if ( d->useNamespaces ) {
2382                         d->namespaceSupport.processName( tags.top(), FALSE, uri, lname );
2383                         t = contentHnd->startElement( uri, lname, tags.top(), d->attList );
2384                     } else {
2385                         t = contentHnd->startElement( "", "", tags.top(), d->attList );
2386                     }
2387                     if ( !t ) {
2388                         d->error = contentHnd->errorString();
2389                         goto parseError;
2390                     }
2391                 }
2392                 next();
2393                 break;
2394             case STagEnd2:
2395                 parseOk = parseContent();
2396                 break;
2397             case ETagBegin:
2398                 next();
2399                 break;
2400             case ETagBegin2:
2401                 // get the name of the tag
2402                 parseOk = parseName();
2403                 break;
2404             case EmptyTag:
2405                 if  ( tags.isEmpty() ) {
2406                     d->error = XMLERR_TAGMISMATCH;
2407                     goto parseError;
2408                 }
2409                 if ( !parseElementEmptyTag( t, uri, lname ) )
2410                     goto parseError;
2411                 // next character
2412                 next();
2413                 break;
2414             case Attribute:
2415                 // get name and value of attribute
2416                 parseOk = parseAttribute();
2417                 break;
2418             case Done:
2419                 next();
2420                 break;
2421         }
2422         // no input is read after this
2423         switch ( state ) {
2424             case ReadName:
2425                 if ( !parseOk ) {
2426                     d->error = XMLERR_ERRORPARSINGNAME;
2427                     goto parseError;
2428                 }
2429                 // store it on the stack
2430                 tags.push( name() );
2431                 // empty the attributes
2432                 d->attList.qnameList.clear();
2433                 d->attList.uriList.clear();
2434                 d->attList.localnameList.clear();
2435                 d->attList.valueList.clear();
2436                 // namespace support?
2437                 if ( d->useNamespaces ) {
2438                     d->namespaceSupport.pushContext();
2439                 }
2440                 break;
2441             case STagEnd2:
2442                 if ( !parseOk ) {
2443                     d->error = XMLERR_ERRORPARSINGCONTENT;
2444                     goto parseError;
2445                 }
2446                 break;
2447             case ETagBegin2:
2448                 if ( !parseOk ) {
2449                     d->error = XMLERR_ERRORPARSINGNAME;
2450                     goto parseError;
2451                 }
2452                 if ( !parseElementETagBegin2( uri, lname ) )
2453                     goto parseError;
2454                 break;
2455             case Attribute:
2456                 if ( !parseOk ) {
2457                     d->error = XMLERR_ERRORPARSINGATTRIBUTE;
2458                     goto parseError;
2459                 }
2460                 if ( !parseElementAttribute( prefix, uri, lname ) )
2461                     goto parseError;
2462                 break;
2463             case Done:
2464                 return TRUE;
2465             case -1:
2466                 d->error = XMLERR_ERRORPARSINGELEMENT;
2467                 goto parseError;
2468         }
2469
2470     }
2471
2472     return TRUE;
2473
2474 parseError:
2475     reportParseError();
2476     return FALSE;
2477 }
2478 /*!
2479   Helper to break down the size of the code in the case statement.
2480   Return FALSE on error, otherwise TRUE.
2481 */
2482 bool QXmlSimpleReader::parseElementEmptyTag( bool &t, QString &uri, QString &lname )
2483 {
2484     // pop the stack and call the handler
2485     if ( contentHnd ) {
2486         // report startElement first...
2487         if ( d->useNamespaces ) {
2488             d->namespaceSupport.processName( tags.top(), FALSE, uri, lname );
2489             t = contentHnd->startElement( uri, lname, tags.top(), d->attList );
2490         } else {
2491             t = contentHnd->startElement( "", "", tags.top(), d->attList );
2492         }
2493         if ( !t ) {
2494             d->error = contentHnd->errorString();
2495             return FALSE;
2496         }
2497         // ... followed by endElement
2498         if ( d->useNamespaces ) {
2499             if ( !contentHnd->endElement( uri, lname,tags.pop() ) ) {
2500                 d->error = contentHnd->errorString();
2501                 return FALSE;
2502             }
2503         }
2504         else {
2505             if ( !contentHnd->endElement( "","",tags.pop() ) ) {
2506                 d->error = contentHnd->errorString();
2507                 return FALSE;
2508             }
2509         }
2510         // namespace support?
2511         if ( d->useNamespaces ) {
2512             QStringList prefixesBefore, prefixesAfter;
2513             if ( contentHnd ) {
2514                 prefixesBefore = d->namespaceSupport.prefixes();
2515             }
2516             d->namespaceSupport.popContext();
2517             // call the handler for prefix mapping
2518             if ( contentHnd ) {
2519                 prefixesAfter = d->namespaceSupport.prefixes();
2520                 for ( QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it ) {
2521                     if ( prefixesAfter.contains(*it) == 0 ) {
2522                         if ( !contentHnd->endPrefixMapping( *it ) ) {
2523                             d->error = contentHnd->errorString();
2524                             return FALSE;
2525                         }
2526                     }
2527                 }
2528             }
2529         }
2530     } else {
2531         tags.pop();
2532     }
2533     return TRUE;
2534 }
2535 /*!
2536   Helper to break down the size of the code in the case statement.
2537   Return FALSE on error, otherwise TRUE.
2538 */
2539 bool QXmlSimpleReader::parseElementETagBegin2( QString &uri, QString &lname )
2540 {
2541
2542     // pop the stack and compare it with the name
2543     if ( tags.pop() != name() ) {
2544         d->error = XMLERR_TAGMISMATCH;
2545         return FALSE;
2546     }
2547     // call the handler
2548     if ( contentHnd ) {
2549         if ( d->useNamespaces ) {
2550                 d->namespaceSupport.processName( name(), FALSE, uri, lname );
2551                 if ( !contentHnd->endElement(uri,lname,name()) ) {
2552                     d->error = contentHnd->errorString();
2553                     return FALSE;
2554                 }
2555         }
2556         else {
2557                 if ( !contentHnd->endElement("","",name()) ) {
2558                     d->error = contentHnd->errorString();
2559                     return FALSE;
2560                 }
2561         }
2562     }
2563     // namespace support?
2564     if ( d->useNamespaces ) {
2565         QStringList prefixesBefore, prefixesAfter;
2566         if ( contentHnd ) {
2567             prefixesBefore = d->namespaceSupport.prefixes();
2568         }
2569         d->namespaceSupport.popContext();
2570         // call the handler for prefix mapping
2571         if ( contentHnd ) {
2572             prefixesAfter = d->namespaceSupport.prefixes();
2573             for ( QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it ) {
2574                 if ( prefixesAfter.contains(*it) == 0 ) {
2575                     if ( !contentHnd->endPrefixMapping( *it ) ) {
2576                         d->error = contentHnd->errorString();
2577                         return FALSE;
2578                     }
2579                 }
2580             }
2581         }
2582     }
2583     return TRUE;
2584 }
2585 /*!
2586   Helper to break down the size of the code in the case statement.
2587   Return FALSE on error, otherwise TRUE.
2588 */
2589 bool QXmlSimpleReader::parseElementAttribute( QString &prefix, QString &uri, QString &lname )
2590 {
2591     // add the attribute to the list
2592     if ( d->useNamespaces ) {
2593         // is it a namespace declaration?
2594         d->namespaceSupport.splitName( name(), prefix, lname );
2595         if ( prefix == "xmlns" ) {
2596             // namespace declaration
2597             d->namespaceSupport.setPrefix( lname, string() );
2598             if ( d->useNamespacePrefixes ) {
2599                 d->attList.qnameList.append( name() );
2600                 d->attList.uriList.append( "" );
2601                 d->attList.localnameList.append( "" );
2602                 d->attList.valueList.append( string() );
2603             }
2604             // call the handler for prefix mapping
2605             if ( contentHnd ) {
2606                 if ( !contentHnd->startPrefixMapping( lname, string() ) ) {
2607                     d->error = contentHnd->errorString();
2608                     return FALSE;
2609                 }
2610             }
2611         } else {
2612             // no namespace delcaration
2613             d->namespaceSupport.processName( name(), TRUE, uri, lname );
2614             d->attList.qnameList.append( name() );
2615             d->attList.uriList.append( uri );
2616             d->attList.localnameList.append( lname );
2617             d->attList.valueList.append( string() );
2618         }
2619     } else {
2620         // no namespace support
2621         d->attList.qnameList.append( name() );
2622         d->attList.uriList.append( "" );
2623         d->attList.localnameList.append( "" );
2624         d->attList.valueList.append( string() );
2625     }
2626     return TRUE;
2627 }
2628
2629 /*!
2630   Parse a content [43].
2631
2632   A content is only used between tags. If a end tag is found the < is already
2633   read and the head stand on the '/' of the end tag '</name>'.
2634 */
2635 bool QXmlSimpleReader::parseContent()
2636 {
2637     bool charDataRead = FALSE;
2638
2639     const signed char Init             =  0;
2640     const signed char ChD              =  1; // CharData
2641     const signed char ChD1             =  2; // CharData help state
2642     const signed char ChD2             =  3; // CharData help state
2643     const signed char Ref              =  4; // Reference
2644     const signed char Lt               =  5; // '<' read
2645     const signed char PI               =  6; // PI
2646     const signed char Elem             =  7; // Element
2647     const signed char Em               =  8; // '!' read
2648     const signed char Com              =  9; // Comment
2649     const signed char CDS              = 10; // CDSect
2650     const signed char CDS1             = 11; // read a CDSect
2651     const signed char CDS2             = 12; // read a CDSect (help state)
2652     const signed char CDS3             = 13; // read a CDSect (help state)
2653     const signed char Done             = 14; // finished reading content
2654
2655     const signed char InpLt            = 0; // <
2656     const signed char InpGt            = 1; // >
2657     const signed char InpSlash         = 2; // /
2658     const signed char InpQMark         = 3; // ?
2659     const signed char InpEMark         = 4; // !
2660     const signed char InpAmp           = 5; // &
2661     const signed char InpDash          = 6; // -
2662     const signed char InpOpenB         = 7; // [
2663     const signed char InpCloseB        = 8; // ]
2664     const signed char InpUnknown       = 9;
2665
2666     static signed char mapCLT2FSMChar[] = {
2667         InpUnknown, // white space
2668         InpUnknown, // %
2669         InpAmp,     // &
2670         InpGt,      // >
2671         InpLt,      // <
2672         InpSlash,   // /
2673         InpQMark,   // ?
2674         InpEMark,   // !
2675         InpDash,    // -
2676         InpCloseB,  // ]
2677         InpOpenB,   // [
2678         InpUnknown, // =
2679         InpUnknown, // "
2680         InpUnknown, // '
2681         InpUnknown  // unknown
2682     };
2683
2684     // use some kind of state machine for parsing
2685     static signed char const table[14][10] = {
2686      /*  InpLt  InpGt  InpSlash  InpQMark  InpEMark  InpAmp  InpDash  InpOpenB  InpCloseB  InpUnknown */
2687         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD1,      ChD  }, // Init
2688         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD1,      ChD  }, // ChD
2689         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD2,      ChD  }, // ChD1
2690         { Lt,    -1,    ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD2,      ChD  }, // ChD2
2691         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // Ref (same as Init)
2692         { -1,    -1,    Done,     PI,       Em,       -1,     -1,      -1,       -1,        Elem }, // Lt
2693         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // PI (same as Init)
2694         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // Elem (same as Init)
2695         { -1,    -1,    -1,       -1,       -1,       -1,     Com,     CDS,      -1,        -1   }, // Em
2696         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // Com (same as Init)
2697         { CDS1,  CDS1,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS2,      CDS1 }, // CDS
2698         { CDS1,  CDS1,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS2,      CDS1 }, // CDS1
2699         { CDS1,  CDS1,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS3,      CDS1 }, // CDS2
2700         { CDS1,  Init,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS3,      CDS1 }  // CDS3
2701     };
2702     signed char state = Init;
2703     signed char input;
2704     bool parseOk = TRUE;
2705
2706     while ( TRUE ) {
2707
2708         // get input (use lookup-table instead of nested ifs for performance
2709         // reasons)
2710         if ( atEnd() ) {
2711             d->error = XMLERR_UNEXPECTEDEOF;
2712             goto parseError;
2713         }
2714         if ( c.row() ) {
2715             input = InpUnknown;
2716         } else {
2717             input = mapCLT2FSMChar[ charLookupTable[ c.cell() ] ];
2718         }
2719
2720         // set state according to input
2721         state = table[state][input];
2722
2723         // do some actions according to state
2724         switch ( state ) {
2725             case Init:
2726                 // next character
2727                 next();
2728                 break;
2729             case ChD:
2730                 // on first call: clear string
2731                 if ( !charDataRead ) {
2732                     charDataRead = TRUE;
2733                     stringClear();
2734                 }
2735                 stringAddC();
2736                 next();
2737                 break;
2738             case ChD1:
2739                 // on first call: clear string
2740                 if ( !charDataRead ) {
2741                     charDataRead = TRUE;
2742                     stringClear();
2743                 }
2744                 stringAddC();
2745                 next();
2746                 break;
2747             case ChD2:
2748                 stringAddC();
2749                 next();
2750                 break;
2751             case Ref:
2752                 if ( !charDataRead) {
2753                     // reference may be CharData; so clear string to be safe
2754                     stringClear();
2755                     parseOk = parseReference( charDataRead, InContent );
2756                 } else {
2757                     bool tmp;
2758                     parseOk = parseReference( tmp, InContent );
2759                 }
2760                 break;
2761             case Lt:
2762                 // call the handler for CharData
2763                 if ( contentHnd ) {
2764                     if ( charDataRead ) {
2765                         if ( d->reportWhitespaceCharData || !string().simplifyWhiteSpace().isEmpty() ) {
2766                             if ( !contentHnd->characters( string() ) ) {
2767                                 d->error = contentHnd->errorString();
2768                                 goto parseError;
2769                             }
2770                         }
2771                     }
2772                 }
2773                 charDataRead = FALSE;
2774                 // next character
2775                 next();
2776                 break;
2777             case PI:
2778                 parseOk = parsePI();
2779                 break;
2780             case Elem:
2781                 parseOk = parseElement();
2782                 break;
2783             case Em:
2784                 // next character
2785                 next();
2786                 break;
2787             case Com:
2788                 parseOk = parseComment();
2789                 break;
2790             case CDS:
2791                 parseOk = parseString( "[CDATA[" );
2792                 break;
2793             case CDS1:
2794                 // read one character and add it
2795                 stringAddC();
2796                 next();
2797                 break;
2798             case CDS2:
2799                 // skip ']'
2800                 next();
2801                 break;
2802             case CDS3:
2803                 // skip ']'...
2804                 next();
2805                 break;
2806         }
2807         // no input is read after this
2808         switch ( state ) {
2809             case Ref:
2810                 if ( !parseOk ) {
2811                     d->error = XMLERR_ERRORPARSINGREFERENCE;
2812                     goto parseError;
2813                 }
2814                 break;
2815             case PI:
2816                 if ( !parseOk ) {
2817                     d->error = XMLERR_ERRORPARSINGPI;
2818                     goto parseError;
2819                 }
2820                 // call the handler
2821                 if ( contentHnd ) {
2822                     if ( !contentHnd->processingInstruction(name(),string()) ) {
2823                         d->error = contentHnd->errorString();
2824                         goto parseError;
2825                     }
2826                 }
2827                 break;
2828             case Elem:
2829                 if ( !parseOk ) {
2830                     d->error = XMLERR_ERRORPARSINGELEMENT;
2831                     goto parseError;
2832                 }
2833                 break;
2834             case Com:
2835                 if ( !parseOk ) {
2836                     d->error = XMLERR_ERRORPARSINGCOMMENT;
2837                     goto parseError;
2838                 }
2839                 if ( lexicalHnd ) {
2840                     if ( !lexicalHnd->comment( string() ) ) {
2841                         d->error = lexicalHnd->errorString();
2842                         goto parseError;
2843                     }
2844                 }
2845                 break;
2846             case CDS:
2847                 if( !parseOk ) {
2848                     d->error = XMLERR_CDSECTHEADEREXPECTED;
2849                     goto parseError;
2850                 }
2851                 // empty string
2852                 stringClear();
2853                 break;
2854             case CDS2:
2855                 if (c != ']') {
2856                     stringAddC( ']' );
2857                 }
2858                 break;
2859             case CDS3:
2860                 // test if this skipping was legal
2861                 if        ( c == '>' ) {
2862                     // the end of the CDSect
2863                     if ( lexicalHnd ) {
2864                         if ( !lexicalHnd->startCDATA() ) {
2865                             d->error = lexicalHnd->errorString();
2866                             goto parseError;
2867                         }
2868                     }
2869                     if ( contentHnd ) {
2870                         if ( !contentHnd->characters( string() ) ) {
2871                             d->error = contentHnd->errorString();
2872                             goto parseError;
2873                         }
2874                     }
2875                     if ( lexicalHnd ) {
2876                         if ( !lexicalHnd->endCDATA() ) {
2877                             d->error = lexicalHnd->errorString();
2878                             goto parseError;
2879                         }
2880                     }
2881                 } else if (c == ']') {
2882                     // three or more ']'
2883                     stringAddC( ']' );
2884                 } else {
2885                     // after ']]' comes another character
2886                     stringAddC( ']' );
2887                     stringAddC( ']' );
2888                 }
2889                 break;
2890             case Done:
2891                 // call the handler for CharData
2892                 if ( contentHnd ) {
2893                     if ( charDataRead ) {
2894                         if ( d->reportWhitespaceCharData || !string().simplifyWhiteSpace().isEmpty() ) {
2895                             if ( !contentHnd->characters( string() ) ) {
2896                                 d->error = contentHnd->errorString();
2897                                 goto parseError;
2898                             }
2899                         }
2900                     }
2901                 }
2902                 // Done
2903                 return TRUE;
2904             case -1:
2905                 // Error
2906                 d->error = XMLERR_ERRORPARSINGCONTENT;
2907                 goto parseError;
2908         }
2909
2910     }
2911
2912     return TRUE;
2913
2914 parseError:
2915     reportParseError();
2916     return FALSE;
2917 }
2918
2919 /*!
2920   Parse Misc [27].
2921 */
2922 bool QXmlSimpleReader::parseMisc()
2923 {
2924     const signed char Init             = 0;
2925     const signed char Lt               = 1; // '<' was read
2926     const signed char Comment          = 2; // read comment
2927     const signed char eatWS            = 3; // eat whitespaces
2928     const signed char PI               = 4; // read PI
2929     const signed char Comment2         = 5; // read comment
2930
2931     const signed char InpWs            = 0; // S
2932     const signed char InpLt            = 1; // <
2933     const signed char InpQm            = 2; // ?
2934     const signed char InpEm            = 3; // !
2935     const signed char InpUnknown       = 4;
2936
2937     // use some kind of state machine for parsing
2938     static signed char table[3][5] = {
2939      /*  InpWs   InpLt  InpQm  InpEm     InpUnknown */
2940         { eatWS,  Lt,    -1,    -1,       -1        }, // Init
2941         { -1,     -1,    PI,    Comment,  -1        }, // Lt
2942         { -1,     -1,    -1,    -1,       Comment2  }  // Comment
2943     };
2944     signed char state = Init;
2945     signed char input;
2946     bool parseOk = TRUE;
2947
2948     while ( TRUE ) {
2949
2950         // get input
2951         if ( atEnd() ) {
2952             d->error = XMLERR_UNEXPECTEDEOF;
2953             goto parseError;
2954         }
2955         if        ( is_S(c) ) {
2956             input = InpWs;
2957         } else if ( c == '<' ) {
2958             input = InpLt;
2959         } else if ( c == '?' ) {
2960             input = InpQm;
2961         } else if ( c == '!' ) {
2962             input = InpEm;
2963         } else {
2964             input = InpUnknown;
2965         }
2966
2967         // set state according to input
2968         state = table[state][input];
2969
2970         // do some actions according to state
2971         switch ( state ) {
2972             case eatWS:
2973                 eat_ws();
2974                 break;
2975             case Lt:
2976                 next();
2977                 break;
2978             case PI:
2979                 parseOk = parsePI();
2980                 break;
2981             case Comment:
2982                 next();
2983                 break;
2984             case Comment2:
2985                 parseOk = parseComment();
2986                 break;
2987         }
2988         // no input is read after this
2989         switch ( state ) {
2990             case eatWS:
2991                 return TRUE;
2992             case PI:
2993                 if ( !parseOk ) {
2994                     d->error = XMLERR_ERRORPARSINGPI;
2995                     goto parseError;
2996                 }
2997                 if ( contentHnd ) {
2998                     if ( !contentHnd->processingInstruction(name(),string()) ) {
2999                         d->error = contentHnd->errorString();
3000                         goto parseError;
3001                     }
3002                 }
3003                 return TRUE;
3004             case Comment2:
3005                 if ( !parseOk ) {
3006                     d->error = XMLERR_ERRORPARSINGCOMMENT;
3007                     goto parseError;
3008                 }
3009                 if ( lexicalHnd ) {
3010                     if ( !lexicalHnd->comment( string() ) ) {
3011                         d->error = lexicalHnd->errorString();
3012                         goto parseError;
3013                     }
3014                 }
3015                 return TRUE;
3016             case -1:
3017                 // Error
3018                 d->error = XMLERR_UNEXPECTEDCHARACTER;
3019                 goto parseError;
3020         }
3021
3022     }
3023
3024     return TRUE;
3025
3026 parseError:
3027     reportParseError();
3028     return FALSE;
3029 }
3030
3031 /*!
3032   Parse a processing instruction [16].
3033
3034   If xmldec is TRUE, it tries to parse a PI or a XML declaration [23].
3035
3036   Precondition: the beginning '<' of the PI is already read and the head stand
3037   on the '?' of '<?'.
3038
3039   If this funktion was successful, the head-position is on the first
3040   character after the PI.
3041 */
3042 bool QXmlSimpleReader::parsePI( bool xmldecl )
3043 {
3044     const signed char Init             =  0;
3045     const signed char QmI              =  1; // ? was read
3046     const signed char Name             =  2; // read Name
3047     const signed char XMLDecl          =  3; // read XMLDecl
3048     const signed char Ws1              =  4; // eat ws after "xml" of XMLDecl
3049     const signed char PI               =  5; // read PI
3050     const signed char Ws2              =  6; // eat ws after Name of PI
3051     const signed char Version          =  7; // read versionInfo
3052     const signed char Ws3              =  8; // eat ws after versionInfo
3053     const signed char EorSD            =  9; // read EDecl or SDDecl
3054     const signed char Ws4              = 10; // eat ws after EDecl or SDDecl
3055     const signed char SD               = 11; // read SDDecl
3056     const signed char Ws5              = 12; // eat ws after SDDecl
3057     const signed char ADone            = 13; // almost done
3058     const signed char Char             = 14; // Char was read
3059     const signed char Qm               = 15; // Qm was read
3060     const signed char Done             = 16; // finished reading content
3061
3062     const signed char InpWs            = 0; // whitespace
3063     const signed char InpNameBe        = 1; // is_nameBeginning()
3064     const signed char InpGt            = 2; // >
3065     const signed char InpQm            = 3; // ?
3066     const signed char InpUnknown       = 4;
3067
3068     // use some kind of state machine for parsing
3069     static signed char table[16][5] = {
3070      /*  InpWs,  InpNameBe  InpGt  InpQm   InpUnknown  */
3071         { -1,     -1,        -1,    QmI,    -1     }, // Init
3072         { -1,     Name,      -1,    -1,     -1     }, // QmI
3073         { -1,     -1,        -1,    -1,     -1     }, // Name (this state is left not through input)
3074         { Ws1,    -1,        -1,    -1,     -1     }, // XMLDecl
3075         { -1,     Version,   -1,    -1,     -1     }, // Ws1
3076         { Ws2,    -1,        -1,    Qm,     -1     }, // PI
3077         { Char,   Char,      Char,  Qm,     Char   }, // Ws2
3078         { Ws3,    -1,        -1,    ADone,  -1     }, // Version
3079         { -1,     EorSD,     -1,    ADone,  -1     }, // Ws3
3080         { Ws4,    -1,        -1,    ADone,  -1     }, // EorSD
3081         { -1,     SD,        -1,    ADone,  -1     }, // Ws4
3082         { Ws5,    -1,        -1,    ADone,  -1     }, // SD
3083         { -1,     -1,        -1,    ADone,  -1     }, // Ws5
3084         { -1,     -1,        Done,  -1,     -1     }, // ADone
3085         { Char,   Char,      Char,  Qm,     Char   }, // Char
3086         { Char,   Char,      Done,  Qm,     Char   }, // Qm
3087     };
3088     signed char state = Init;
3089     signed char input;
3090     bool parseOk = TRUE;
3091
3092     while ( TRUE ) {
3093
3094         // get input
3095         if ( atEnd() ) {
3096             d->error = XMLERR_UNEXPECTEDEOF;
3097             goto parseError;
3098         }
3099         if        ( is_S(c) ) {
3100             input = InpWs;
3101         } else if ( is_NameBeginning(c) ) {
3102             input = InpNameBe;
3103         } else if ( c == '>' ) {
3104             input = InpGt;
3105         } else if ( c == '?' ) {
3106             input = InpQm;
3107         } else {
3108             input = InpUnknown;
3109         }
3110
3111         // set state according to input
3112         state = table[state][input];
3113
3114         // do some actions according to state
3115         switch ( state ) {
3116             case QmI:
3117                 next();
3118                 break;
3119             case Name:
3120                 parseOk = parseName();
3121                 break;
3122             case Ws1:
3123             case Ws2:
3124             case Ws3:
3125             case Ws4:
3126             case Ws5:
3127                 eat_ws();
3128                 break;
3129             case Version:
3130                 parseOk = parseAttribute();
3131                 break;
3132             case EorSD:
3133                 parseOk = parseAttribute();
3134                 break;
3135             case SD:
3136                 // get the SDDecl (syntax like an attribute)
3137                 if ( d->standalone != QXmlSimpleReaderPrivate::Unknown ) {
3138                     // already parsed the standalone declaration
3139                     d->error = XMLERR_UNEXPECTEDCHARACTER;
3140                     goto parseError;
3141                 }
3142                 parseOk = parseAttribute();
3143                 break;
3144             case ADone:
3145                 next();
3146                 break;
3147             case Char:
3148                 stringAddC();
3149                 next();
3150                 break;
3151             case Qm:
3152                 // skip the '?'
3153                 next();
3154                 break;
3155             case Done:
3156                 next();
3157                 break;
3158         }
3159         // no input is read after this
3160         switch ( state ) {
3161             case Name:
3162                 if ( !parseOk ) {
3163                     d->error = XMLERR_ERRORPARSINGNAME;
3164                     goto parseError;
3165                 }
3166                 // test what name was read and determine the next state
3167                 // (not very beautiful, I admit)
3168                 if ( name().lower() == "xml" ) {
3169                     if ( xmldecl && name()=="xml" ) {
3170                         state = XMLDecl;
3171                     } else {
3172                         d->error = XMLERR_INVALIDNAMEFORPI;
3173                         goto parseError;
3174                     }
3175                 } else {
3176                     state = PI;
3177                     stringClear();
3178                 }
3179                 break;
3180             case Version:
3181                 // get version (syntax like an attribute)
3182                 if ( !parseOk ) {
3183                     d->error = XMLERR_VERSIONEXPECTED;
3184                     goto parseError;
3185                 }
3186                 if ( name() != "version" ) {
3187                     d->error = XMLERR_VERSIONEXPECTED;
3188                     goto parseError;
3189                 }
3190                 d->xmlVersion = string();
3191                 break;
3192             case EorSD:
3193                 // get the EDecl or SDDecl (syntax like an attribute)
3194                 if ( !parseOk ) {
3195                     d->error = XMLERR_EDECLORSDDECLEXPECTED;
3196                     goto parseError;
3197                 }
3198                 if        ( name() == "standalone" ) {
3199                     if ( string()=="yes" ) {
3200                         d->standalone = QXmlSimpleReaderPrivate::Yes;
3201                     } else if ( string()=="no" ) {
3202                         d->standalone = QXmlSimpleReaderPrivate::No;
3203                     } else {
3204                         d->error = XMLERR_WRONGVALUEFORSDECL;
3205                         goto parseError;
3206                     }
3207                 } else if ( name() == "encoding" ) {
3208                     d->encoding = string();
3209                 } else {
3210                     d->error = XMLERR_EDECLORSDDECLEXPECTED;
3211                     goto parseError;
3212                 }
3213                 break;
3214             case SD:
3215                 if ( !parseOk ) {
3216                     d->error = XMLERR_SDDECLEXPECTED;
3217                     goto parseError;
3218                 }
3219                 if ( name() != "standalone" ) {
3220                     d->error = XMLERR_SDDECLEXPECTED;
3221                     goto parseError;
3222                 }
3223                 if ( string()=="yes" ) {
3224                     d->standalone = QXmlSimpleReaderPrivate::Yes;
3225                 } else if ( string()=="no" ) {
3226                     d->standalone = QXmlSimpleReaderPrivate::No;
3227                 } else {
3228                     d->error = XMLERR_WRONGVALUEFORSDECL;
3229                     goto parseError;
3230                 }
3231                 break;
3232             case Qm:
3233                 // test if the skipping was legal
3234                 if ( c != '>' ) {
3235                     stringAddC( '?' );
3236                 }
3237                 break;
3238             case Done:
3239                 return TRUE;
3240             case -1:
3241                 // Error
3242                 d->error = XMLERR_UNEXPECTEDCHARACTER;
3243                 goto parseError;
3244         }
3245
3246     }
3247
3248     return TRUE;
3249
3250 parseError:
3251     reportParseError();
3252     return FALSE;
3253 }
3254
3255 /*!
3256   Parse a document type definition (doctypedecl [28]).
3257
3258   Precondition: the beginning '<!' of the doctype is already read the head
3259   stands on the 'D' of '<!DOCTYPE'.
3260
3261   If this funktion was successful, the head-position is on the first
3262   character after the document type definition.
3263 */
3264 bool QXmlSimpleReader::parseDoctype()
3265 {
3266     // some init-stuff
3267     d->systemId = QString::null;
3268     d->publicId = QString::null;
3269
3270     const signed char Init             =  0;
3271     const signed char Doctype          =  1; // read the doctype
3272     const signed char Ws1              =  2; // eat_ws
3273     const signed char Doctype2         =  3; // read the doctype, part 2
3274     const signed char Ws2              =  4; // eat_ws
3275     const signed char Sys              =  5; // read SYSTEM
3276     const signed char Ws3              =  6; // eat_ws
3277     const signed char MP               =  7; // markupdecl or PEReference
3278     const signed char PER              =  8; // PERReference
3279     const signed char Mup              =  9; // markupdecl
3280     const signed char Ws4              = 10; // eat_ws
3281     const signed char MPE              = 11; // end of markupdecl or PEReference
3282     const signed char Done             = 12;
3283
3284     const signed char InpWs            = 0;
3285     const signed char InpD             = 1; // 'D'
3286     const signed char InpS             = 2; // 'S' or 'P'
3287     const signed char InpOB            = 3; // [
3288     const signed char InpCB            = 4; // ]
3289     const signed char InpPer           = 5; // %
3290     const signed char InpGt            = 6; // >
3291     const signed char InpUnknown       = 7;
3292
3293     // use some kind of state machine for parsing
3294     static signed char table[12][8] = {
3295      /*  InpWs,  InpD       InpS       InpOB  InpCB  InpPer InpGt  InpUnknown */
3296         { -1,     Doctype,   -1,        -1,    -1,    -1,    -1,    -1        }, // Init
3297         { Ws1,    Doctype2,  Doctype2,  -1,    -1,    -1,    -1,    Doctype2  }, // Doctype
3298         { -1,     Doctype2,  Doctype2,  -1,    -1,    -1,    -1,    Doctype2  }, // Ws1
3299         { Ws2,    -1,        Sys,       MP,    -1,    -1,    Done,  -1        }, // Doctype2
3300         { -1,     -1,        Sys,       MP,    -1,    -1,    Done,  -1        }, // Ws2
3301         { Ws3,    -1,        -1,        MP,    -1,    -1,    Done,  -1        }, // Sys
3302         { -1,     -1,        -1,        MP,    -1,    -1,    Done,  -1        }, // Ws3
3303         { -1,     -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // MP
3304         { Ws4,    -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // PER
3305         { Ws4,    -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // Mup
3306         { -1,     -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // Ws4
3307         { -1,     -1,        -1,        -1,    -1,    -1,    Done,  -1        }  // MPE
3308     };
3309     signed char state = Init;
3310     signed char input;
3311     bool parseOk = TRUE;
3312
3313     while ( TRUE ) {
3314
3315         // get input
3316         if ( atEnd() ) {
3317             d->error = XMLERR_UNEXPECTEDEOF;
3318             goto parseError;
3319         }
3320         if        ( is_S(c) ) {
3321             input = InpWs;
3322         } else if ( c == 'D' ) {
3323             input = InpD;
3324         } else if ( c == 'S' ) {
3325             input = InpS;
3326         } else if ( c == 'P' ) {
3327             input = InpS;
3328         } else if ( c == '[' ) {
3329             input = InpOB;
3330         } else if ( c == ']' ) {
3331             input = InpCB;
3332         } else if ( c == '%' ) {
3333             input = InpPer;
3334         } else if ( c == '>' ) {
3335             input = InpGt;
3336         } else {
3337             input = InpUnknown;
3338         }
3339
3340         // set state according to input
3341         state = table[state][input];
3342
3343         // do some actions according to state
3344         switch ( state ) {
3345             case Doctype:
3346                 parseOk = parseString( "DOCTYPE" );
3347                 break;
3348             case Ws1:
3349             case Ws2:
3350             case Ws3:
3351             case Ws4:
3352                 eat_ws();
3353                 break;
3354             case Doctype2:
3355                 parseName();
3356                 break;
3357             case Sys:
3358                 parseOk = parseExternalID();
3359                 break;
3360             case MP:
3361                 next_eat_ws();
3362                 break;
3363             case PER:
3364                 parseOk = parsePEReference( InDTD );
3365                 break;
3366             case Mup:
3367                 parseOk = parseMarkupdecl();
3368                 break;
3369             case MPE:
3370                 next_eat_ws();
3371                 break;
3372             case Done:
3373                 if ( lexicalHnd ) {
3374                     if ( !lexicalHnd->endDTD() ) {
3375                         d->error = lexicalHnd->errorString();
3376                         goto parseError;
3377                     }
3378                 }
3379                 next();
3380                 break;
3381         }
3382         // no input is read after this
3383         switch ( state ) {
3384             case Doctype:
3385                 if ( !parseOk ) {
3386                     d->error = XMLERR_ERRORPARSINGDOCTYPE;
3387                     goto parseError;
3388                 }
3389                 if ( !is_S(c) ) {
3390                     d->error = XMLERR_ERRORPARSINGDOCTYPE;
3391                     goto parseError;
3392                 }
3393                 break;
3394             case Doctype2:
3395                 d->doctype = name();
3396                 if ( lexicalHnd ) {
3397                     if ( !lexicalHnd->startDTD( d->doctype, d->publicId, d->systemId ) ) {
3398                         d->error = lexicalHnd->errorString();
3399                         goto parseError;
3400                     }
3401                 }
3402                 break;
3403             case Sys:
3404                 if ( !parseOk ) {
3405                     d->error = XMLERR_ERRORPARSINGDOCTYPE;
3406                     goto parseError;
3407                 }
3408                 break;
3409             case PER:
3410                 if ( !parseOk ) {
3411                     d->error = XMLERR_ERRORPARSINGDOCTYPE;
3412                     goto parseError;
3413                 }
3414                 break;
3415             case Mup:
3416                 if ( !parseOk ) {
3417                     d->error = XMLERR_ERRORPARSINGDOCTYPE;
3418                     goto parseError;
3419                 }
3420                 break;
3421             case Done:
3422                 return TRUE;
3423             case -1:
3424                 // Error
3425                 d->error = XMLERR_ERRORPARSINGDOCTYPE;
3426                 goto parseError;
3427         }
3428
3429     }
3430
3431     return TRUE;
3432
3433 parseError:
3434     reportParseError();
3435     return FALSE;
3436 }
3437
3438 /*!
3439   Parse a ExternalID [75].
3440
3441   If allowPublicID is TRUE parse ExternalID [75] or PublicID [83].
3442 */
3443 bool QXmlSimpleReader::parseExternalID( bool allowPublicID )
3444 {
3445     // some init-stuff
3446     d->systemId = QString::null;
3447     d->publicId = QString::null;
3448
3449     const signed char Init             =  0;
3450     const signed char Sys              =  1; // parse 'SYSTEM'
3451     const signed char SysWS            =  2; // parse the whitespace after 'SYSTEM'
3452     const signed char SysSQ            =  3; // parse SystemLiteral with '
3453     const signed char SysSQ2           =  4; // parse SystemLiteral with '
3454     const signed char SysDQ            =  5; // parse SystemLiteral with "
3455     const signed char SysDQ2           =  6; // parse SystemLiteral with "
3456     const signed char Pub              =  7; // parse 'PUBLIC'
3457     const signed char PubWS            =  8; // parse the whitespace after 'PUBLIC'
3458     const signed char PubSQ            =  9; // parse PubidLiteral with '
3459     const signed char PubSQ2           = 10; // parse PubidLiteral with '
3460     const signed char PubDQ            = 11; // parse PubidLiteral with "
3461     const signed char PubDQ2           = 12; // parse PubidLiteral with "
3462     const signed char PubE             = 13; // finished parsing the PubidLiteral
3463     const signed char PubWS2           = 14; // parse the whitespace after the PubidLiteral
3464     const signed char PDone            = 15; // done if allowPublicID is TRUE
3465     const signed char Done             = 16;
3466
3467     const signed char InpSQ            = 0; // '
3468     const signed char InpDQ            = 1; // "
3469     const signed char InpS             = 2; // S
3470     const signed char InpP             = 3; // P
3471     const signed char InpWs            = 4; // white space
3472     const signed char InpUnknown       = 5;
3473
3474     // use some kind of state machine for parsing
3475     static signed char table[15][6] = {
3476      /*  InpSQ    InpDQ    InpS     InpP     InpWs     InpUnknown */
3477         { -1,      -1,      Sys,     Pub,     -1,       -1      }, // Init
3478         { -1,      -1,      -1,      -1,      SysWS,    -1      }, // Sys
3479         { SysSQ,   SysDQ,   -1,      -1,      -1,       -1      }, // SysWS
3480         { Done,    SysSQ2,  SysSQ2,  SysSQ2,  SysSQ2,   SysSQ2  }, // SysSQ
3481         { Done,    SysSQ2,  SysSQ2,  SysSQ2,  SysSQ2,   SysSQ2  }, // SysSQ2
3482         { SysDQ2,  Done,    SysDQ2,  SysDQ2,  SysDQ2,   SysDQ2  }, // SysDQ
3483         { SysDQ2,  Done,    SysDQ2,  SysDQ2,  SysDQ2,   SysDQ2  }, // SysDQ2
3484         { -1,      -1,      -1,      -1,      PubWS,    -1      }, // Pub
3485         { PubSQ,   PubDQ,   -1,      -1,      -1,       -1      }, // PubWS
3486         { PubE,    -1,      PubSQ2,  PubSQ2,  PubSQ2,   PubSQ2  }, // PubSQ
3487         { PubE,    -1,      PubSQ2,  PubSQ2,  PubSQ2,   PubSQ2  }, // PubSQ2
3488         { -1,      PubE,    PubDQ2,  PubDQ2,  PubDQ2,   PubDQ2  }, // PubDQ
3489         { -1,      PubE,    PubDQ2,  PubDQ2,  PubDQ2,   PubDQ2  }, // PubDQ2
3490         { PDone,   PDone,   PDone,   PDone,   PubWS2,   PDone   }, // PubE
3491         { SysSQ,   SysDQ,   PDone,   PDone,   PDone,    PDone   }  // PubWS2
3492     };
3493     signed char state = Init;
3494     signed char input;
3495     bool parseOk = TRUE;
3496
3497     while ( TRUE ) {
3498
3499         // get input
3500         if ( atEnd() ) {
3501             d->error = XMLERR_UNEXPECTEDEOF;
3502             goto parseError;
3503         }
3504         if        ( is_S(c) ) {
3505             input = InpWs;
3506         } else if ( c == '\'' ) {
3507             input = InpSQ;
3508         } else if ( c == '"' ) {
3509             input = InpDQ;
3510         } else if ( c == 'S' ) {
3511             input = InpS;
3512         } else if ( c == 'P' ) {
3513             input = InpP;
3514         } else {
3515             input = InpUnknown;
3516         }
3517
3518         // set state according to input
3519         state = table[state][input];
3520
3521         // do some actions according to state
3522         switch ( state ) {
3523             case Sys:
3524                 parseOk = parseString( "SYSTEM" );
3525                 break;
3526             case SysWS:
3527                 eat_ws();
3528                 break;
3529             case SysSQ:
3530             case SysDQ:
3531                 stringClear();
3532                 next();
3533                 break;
3534             case SysSQ2:
3535             case SysDQ2:
3536                 stringAddC();
3537                 next();
3538                 break;
3539             case Pub:
3540                 parseOk = parseString( "PUBLIC" );
3541                 break;
3542             case PubWS:
3543                 eat_ws();
3544                 break;
3545             case PubSQ:
3546             case PubDQ:
3547                 stringClear();
3548                 next();
3549                 break;
3550             case PubSQ2:
3551             case PubDQ2:
3552                 stringAddC();
3553                 next();
3554                 break;
3555             case PubE:
3556                 next();
3557                 break;
3558             case PubWS2:
3559                 d->publicId = string();
3560                 eat_ws();
3561                 break;
3562             case Done:
3563                 d->systemId = string();
3564                 next();
3565                 break;
3566         }
3567         // no input is read after this
3568         switch ( state ) {
3569             case Sys:
3570                 if( !parseOk ) {
3571                     d->error = XMLERR_UNEXPECTEDCHARACTER;
3572                     goto parseError;
3573                 }
3574                 break;
3575             case Pub:
3576                 if( !parseOk ) {
3577                     d->error = XMLERR_UNEXPECTEDCHARACTER;
3578                     goto parseError;
3579                 }
3580                 break;
3581             case PDone:
3582                 if ( allowPublicID ) {
3583                     d->publicId = string();
3584                     return TRUE;
3585                 } else {
3586                     d->error = XMLERR_UNEXPECTEDCHARACTER;
3587                     goto parseError;
3588                 }
3589                 break;
3590             case Done:
3591                 return TRUE;
3592             case -1:
3593                 // Error
3594                 d->error = XMLERR_UNEXPECTEDCHARACTER;
3595                 goto parseError;
3596         }
3597
3598     }
3599
3600     return TRUE;
3601
3602 parseError:
3603     reportParseError();
3604     return FALSE;
3605 }
3606
3607 /*!
3608   Parse a markupdecl [29].
3609 */
3610 bool QXmlSimpleReader::parseMarkupdecl()
3611 {
3612     const signed char Init             = 0;
3613     const signed char Lt               = 1; // < was read
3614     const signed char Em               = 2; // ! was read
3615     const signed char CE               = 3; // E was read
3616     const signed char Qm               = 4; // ? was read
3617     const signed char Dash             = 5; // - was read
3618     const signed char CA               = 6; // A was read
3619     const signed char CEL              = 7; // EL was read
3620     const signed char CEN              = 8; // EN was read
3621     const signed char CN               = 9; // N was read
3622     const signed char Done             = 10;
3623
3624     const signed char InpLt            = 0; // <
3625     const signed char InpQm            = 1; // ?
3626     const signed char InpEm            = 2; // !
3627     const signed char InpDash          = 3; // -
3628     const signed char InpA             = 4; // A
3629     const signed char InpE             = 5; // E
3630     const signed char InpL             = 6; // L
3631     const signed char InpN             = 7; // N
3632     const signed char InpUnknown       = 8;
3633
3634     // use some kind of state machine for parsing
3635     static signed char table[4][9] = {
3636      /*  InpLt  InpQm  InpEm  InpDash  InpA   InpE   InpL   InpN   InpUnknown */
3637         { Lt,    -1,    -1,    -1,      -1,    -1,    -1,    -1,    -1     }, // Init
3638         { -1,    Qm,    Em,    -1,      -1,    -1,    -1,    -1,    -1     }, // Lt
3639         { -1,    -1,    -1,    Dash,    CA,    CE,    -1,    CN,    -1     }, // Em
3640         { -1,    -1,    -1,    -1,      -1,    -1,    CEL,   CEN,   -1     }  // CE
3641     };
3642     signed char state = Init;
3643     signed char input;
3644     bool parseOk = TRUE;
3645
3646     while ( TRUE ) {
3647
3648         // get input
3649         if ( atEnd() ) {
3650             d->error = XMLERR_UNEXPECTEDEOF;
3651             goto parseError;
3652         }
3653         if        ( c == '<' ) {
3654             input = InpLt;
3655         } else if ( c == '?' ) {
3656             input = InpQm;
3657         } else if ( c == '!' ) {
3658             input = InpEm;
3659         } else if ( c == '-' ) {
3660             input = InpDash;
3661         } else if ( c == 'A' ) {
3662             input = InpA;
3663         } else if ( c == 'E' ) {
3664             input = InpE;
3665         } else if ( c == 'L' ) {
3666             input = InpL;
3667         } else if ( c == 'N' ) {
3668             input = InpN;
3669         } else {
3670             input = InpUnknown;
3671         }
3672
3673         // set state according to input
3674         state = table[state][input];
3675
3676         // do some actions according to state
3677         switch ( state ) {
3678             case Lt:
3679                 next();
3680                 break;
3681             case Em:
3682                 next();
3683                 break;
3684             case CE:
3685                 next();
3686                 break;
3687             case Qm:
3688                 parseOk = parsePI();
3689                 break;
3690             case Dash:
3691                 parseOk = parseComment();
3692                 break;
3693             case CA:
3694                 parseOk = parseAttlistDecl();
3695                 break;
3696             case CEL:
3697                 parseOk = parseElementDecl();
3698                 break;
3699             case CEN:
3700                 parseOk = parseEntityDecl();
3701                 break;
3702             case CN:
3703                 parseOk = parseNotationDecl();
3704                 break;
3705         }
3706         // no input is read after this
3707         switch ( state ) {
3708             case Qm:
3709                 if ( !parseOk ) {
3710                     d->error = XMLERR_ERRORPARSINGPI;
3711                     goto parseError;
3712                 }
3713                 if ( contentHnd ) {
3714                     if ( !contentHnd->processingInstruction(name(),string()) ) {
3715                         d->error = contentHnd->errorString();
3716                         goto parseError;
3717                     }
3718                 }
3719                 return TRUE;
3720             case Dash:
3721                 if ( !parseOk ) {
3722                     d->error = XMLERR_ERRORPARSINGCOMMENT;
3723                     goto parseError;
3724                 }
3725                 if ( lexicalHnd ) {
3726                     if ( !lexicalHnd->comment( string() ) ) {
3727                         d->error = lexicalHnd->errorString();
3728                         goto parseError;
3729                     }
3730                 }
3731                 return TRUE;
3732             case CA:
3733                 if ( !parseOk ) {
3734                     d->error = XMLERR_ERRORPARSINGATTLISTDECL;
3735                     goto parseError;
3736                 }
3737                 return TRUE;
3738             case CEL:
3739                 if ( !parseOk ) {
3740                     d->error = XMLERR_ERRORPARSINGELEMENTDECL;
3741                     goto parseError;
3742                 }
3743                 return TRUE;
3744             case CEN:
3745                 if ( !parseOk ) {
3746                     d->error = XMLERR_ERRORPARSINGENTITYDECL;
3747                     goto parseError;
3748                 }
3749                 return TRUE;
3750             case CN:
3751                 if ( !parseOk ) {
3752                     d->error = XMLERR_ERRORPARSINGNOTATIONDECL;
3753                     goto parseError;
3754                 }
3755                 return TRUE;
3756             case Done:
3757                 return TRUE;
3758             case -1:
3759                 // Error
3760                 d->error = XMLERR_LETTEREXPECTED;
3761                 goto parseError;
3762         }
3763
3764     }
3765
3766     return TRUE;
3767
3768 parseError:
3769     reportParseError();
3770     return FALSE;
3771 }
3772
3773 /*!
3774   Parse a PEReference [69]
3775 */
3776 bool QXmlSimpleReader::parsePEReference( EntityRecognitionContext context )
3777 {
3778     const signed char Init             = 0;
3779     const signed char Next             = 1;
3780     const signed char Name             = 2;
3781     const signed char Done             = 3;
3782
3783     const signed char InpSemi          = 0; // ;
3784     const signed char InpPer           = 1; // %
3785     const signed char InpUnknown       = 2;
3786
3787     // use some kind of state machine for parsing
3788     static signed char table[3][3] = {
3789      /*  InpSemi  InpPer  InpUnknown */
3790         { -1,      Next,   -1    }, // Init
3791         { -1,      -1,     Name  }, // Next
3792         { Done,    -1,     -1    }  // Name
3793     };
3794     signed char state = Init;
3795     signed char input;
3796     bool parseOk = TRUE;
3797
3798     while ( TRUE ) {
3799
3800         // get input
3801         if ( atEnd() ) {
3802             d->error = XMLERR_UNEXPECTEDEOF;
3803             goto parseError;
3804         }
3805         if        ( c == ';' ) {
3806             input = InpSemi;
3807         } else if ( c == '%' ) {
3808             input = InpPer;
3809         } else {
3810             input = InpUnknown;
3811         }
3812
3813         // set state according to input
3814         state = table[state][input];
3815
3816         // do some actions according to state
3817         switch ( state ) {
3818             case Next:
3819                 next();
3820                 break;
3821             case Name:
3822                 parseOk = parseName( TRUE );
3823                 break;
3824             case Done:
3825                 next();
3826                 break;
3827         }
3828         // no input is read after this
3829         switch ( state ) {
3830             case Name:
3831                 if ( !parseOk ) {
3832                     d->error = XMLERR_ERRORPARSINGNAME;
3833                     goto parseError;
3834                 }
3835                 if ( d->parameterEntities.find( ref() ) == d->parameterEntities.end() ) {
3836                     // ### skip it???
3837                     if ( contentHnd ) {
3838                         if ( !contentHnd->skippedEntity( QString("%") + ref() ) ) {
3839                             d->error = contentHnd->errorString();
3840                             goto parseError;
3841                         }
3842                     }
3843                 } else {
3844                     if ( context == InEntityValue ) {
3845                         // Included in literal
3846                         xmlRef = d->parameterEntities.find( ref() )
3847                             .data().replace( QRegExp("\""), "&quot;" ).replace( QRegExp("'"), "&apos;" )
3848                             + xmlRef;
3849                     } else if ( context == InDTD ) {
3850                         // Included as PE
3851                         xmlRef = QString(" ") +
3852                             d->parameterEntities.find( ref() ).data() +
3853                             QString(" ") + xmlRef;
3854                     }
3855                 }
3856                 break;
3857             case Done:
3858                 return TRUE;
3859             case -1:
3860                 // Error
3861                 d->error = XMLERR_LETTEREXPECTED;
3862                 goto parseError;
3863         }
3864
3865     }
3866
3867     return TRUE;
3868
3869 parseError:
3870     reportParseError();
3871     return FALSE;
3872 }
3873
3874 /*!
3875   Parse a AttlistDecl [52].
3876
3877   Precondition: the beginning '<!' is already read and the head
3878   stands on the 'A' of '<!ATTLIST'
3879 */
3880 bool QXmlSimpleReader::parseAttlistDecl()
3881 {
3882     const signed char Init             =  0;
3883     const signed char Attlist          =  1; // parse the string "ATTLIST"
3884     const signed char Ws               =  2; // whitespace read
3885     const signed char Name             =  3; // parse name
3886     const signed char Ws1              =  4; // whitespace read
3887     const signed char Attdef           =  5; // parse the AttDef
3888     const signed char Ws2              =  6; // whitespace read
3889     const signed char Atttype          =  7; // parse the AttType
3890     const signed char Ws3              =  8; // whitespace read
3891     const signed char DDecH            =  9; // DefaultDecl with #
3892     const signed char DefReq           = 10; // parse the string "REQUIRED"
3893     const signed char DefImp           = 11; // parse the string "IMPLIED"
3894     const signed char DefFix           = 12; // parse the string "FIXED"
3895     const signed char Attval           = 13; // parse the AttValue
3896     const signed char Ws4              = 14; // whitespace read
3897     const signed char Done             = 15;
3898
3899     const signed char InpWs            = 0; // white space
3900     const signed char InpGt            = 1; // >
3901     const signed char InpHash          = 2; // #
3902     const signed char InpA             = 3; // A
3903     const signed char InpI             = 4; // I
3904     const signed char InpF             = 5; // F
3905     const signed char InpR             = 6; // R
3906     const signed char InpUnknown       = 7;
3907
3908     // use some kind of state machine for parsing
3909     static signed char table[15][8] = {
3910      /*  InpWs    InpGt    InpHash  InpA      InpI     InpF     InpR     InpUnknown */
3911         { -1,      -1,      -1,      Attlist,  -1,      -1,      -1,      -1      }, // Init
3912         { Ws,      -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // Attlist
3913         { -1,      -1,      -1,      Name,     Name,    Name,    Name,    Name    }, // Ws
3914         { Ws1,     Done,    Attdef,  Attdef,   Attdef,  Attdef,  Attdef,  Attdef  }, // Name
3915         { -1,      Done,    Attdef,  Attdef,   Attdef,  Attdef,  Attdef,  Attdef  }, // Ws1
3916         { Ws2,     -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // Attdef
3917         { -1,      Atttype, Atttype, Atttype,  Atttype, Atttype, Atttype, Atttype }, // Ws2
3918         { Ws3,     -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // Attype
3919         { -1,      Attval,  DDecH,   Attval,   Attval,  Attval,  Attval,  Attval  }, // Ws3
3920         { -1,      -1,      -1,      -1,       DefImp,  DefFix,  DefReq,  -1      }, // DDecH
3921         { Ws4,     Ws4,     -1,      -1,       -1,      -1,      -1,      -1      }, // DefReq
3922         { Ws4,     Ws4,     -1,      -1,       -1,      -1,      -1,      -1      }, // DefImp
3923         { Ws3,     -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // DefFix
3924         { Ws4,     Ws4,     -1,      -1,       -1,      -1,      -1,      -1      }, // Attval
3925         { -1,      Done,    Attdef,  Attdef,   Attdef,  Attdef,  Attdef,  Attdef  }  // Ws4
3926     };
3927     signed char state = Init;
3928     signed char input;
3929     bool parseOk = TRUE;
3930
3931     while ( TRUE ) {
3932
3933         // get input
3934         if ( atEnd() ) {
3935             d->error = XMLERR_UNEXPECTEDEOF;
3936             goto parseError;
3937         }
3938         if        ( is_S(c) ) {
3939             input = InpWs;
3940         } else if ( c == '>' ) {
3941             input = InpGt;
3942         } else if ( c == '#' ) {
3943             input = InpHash;
3944         } else if ( c == 'A' ) {
3945             input = InpA;
3946         } else if ( c == 'I' ) {
3947             input = InpI;
3948         } else if ( c == 'F' ) {
3949             input = InpF;
3950         } else if ( c == 'R' ) {
3951             input = InpR;
3952         } else {
3953             input = InpUnknown;
3954         }
3955
3956         // set state according to input
3957         state = table[state][input];
3958
3959         // do some actions according to state
3960         switch ( state ) {
3961             case Attlist:
3962                 parseOk = parseString( "ATTLIST" );
3963                 break;
3964             case Ws:
3965             case Ws1:
3966             case Ws2:
3967             case Ws3:
3968                 eat_ws();
3969                 break;
3970             case Name:
3971                 parseOk = parseName();
3972                 break;
3973             case Attdef:
3974                 parseOk = parseName();
3975                 break;
3976             case Atttype:
3977                 parseOk = parseAttType();
3978                 break;
3979             case DDecH:
3980                 next();
3981                 break;
3982             case DefReq:
3983                 parseOk = parseString( "REQUIRED" );
3984                 break;
3985             case DefImp:
3986                 parseOk = parseString( "IMPLIED" );
3987                 break;
3988             case DefFix:
3989                 parseOk = parseString( "FIXED" );
3990                 break;
3991             case Attval:
3992                 parseOk = parseAttValue();
3993                 break;
3994             case Ws4:
3995                 if ( declHnd ) {
3996                     // TODO: not all values are computed yet...
3997                     if ( !declHnd->attributeDecl( d->attDeclEName, d->attDeclAName, "", "", "" ) ) {
3998                         d->error = declHnd->errorString();
3999                         goto parseError;
4000                     }
4001                 }
4002                 eat_ws();
4003                 break;
4004             case Done:
4005                 next();
4006                 break;
4007         }
4008         // no input is read after this
4009         switch ( state ) {
4010             case Attlist:
4011                 if( !parseOk ) {
4012                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4013                     goto parseError;
4014                 }
4015                 break;
4016             case Name:
4017                 if ( !parseOk ) {
4018                     d->error = XMLERR_ERRORPARSINGNAME;
4019                     goto parseError;
4020                 }
4021                 d->attDeclEName = name();
4022                 break;
4023             case Attdef:
4024                 if ( !parseOk ) {
4025                     d->error = XMLERR_ERRORPARSINGNAME;
4026                     goto parseError;
4027                 }
4028                 d->attDeclAName = name();
4029                 break;
4030             case Atttype:
4031                 if ( !parseOk ) {
4032                     d->error = XMLERR_ERRORPARSINGATTTYPE;
4033                     goto parseError;
4034                 }
4035                 break;
4036             case DefReq:
4037                 if( !parseOk ) {
4038                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4039                     goto parseError;
4040                 }
4041                 break;
4042             case DefImp:
4043                 if( !parseOk ) {
4044                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4045                     goto parseError;
4046                 }
4047                 break;
4048             case DefFix:
4049                 if( !parseOk ) {
4050                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4051                     goto parseError;
4052                 }
4053                 break;
4054             case Attval:
4055                 if ( !parseOk ) {
4056                     d->error = XMLERR_ERRORPARSINGATTVALUE;
4057                     goto parseError;
4058                 }
4059                 break;
4060             case Done:
4061                 return TRUE;
4062             case -1:
4063                 // Error
4064                 d->error = XMLERR_LETTEREXPECTED;
4065                 goto parseError;
4066         }
4067
4068     }
4069
4070     return TRUE;
4071
4072 parseError:
4073     reportParseError();
4074     return FALSE;
4075 }
4076
4077 /*!
4078   Parse a AttType [54]
4079 */
4080 bool QXmlSimpleReader::parseAttType()
4081 {
4082     const signed char Init             =  0;
4083     const signed char ST               =  1; // StringType
4084     const signed char TTI              =  2; // TokenizedType starting with 'I'
4085     const signed char TTI2             =  3; // TokenizedType helpstate
4086     const signed char TTI3             =  4; // TokenizedType helpstate
4087     const signed char TTE              =  5; // TokenizedType starting with 'E'
4088     const signed char TTEY             =  6; // TokenizedType starting with 'ENTITY'
4089     const signed char TTEI             =  7; // TokenizedType starting with 'ENTITI'
4090     const signed char N                =  8; // N read (TokenizedType or Notation)
4091     const signed char TTNM             =  9; // TokenizedType starting with 'NM'
4092     const signed char TTNM2            = 10; // TokenizedType helpstate
4093     const signed char NO               = 11; // Notation
4094     const signed char NO2              = 12; // Notation helpstate
4095     const signed char NO3              = 13; // Notation helpstate
4096     const signed char NOName           = 14; // Notation, read name
4097     const signed char NO4              = 15; // Notation helpstate
4098     const signed char EN               = 16; // Enumeration
4099     const signed char ENNmt            = 17; // Enumeration, read Nmtoken
4100     const signed char EN2              = 18; // Enumeration helpstate
4101     const signed char ADone            = 19; // almost done (make next and accept)
4102     const signed char Done             = 20;
4103
4104     const signed char InpWs            =  0; // whitespace
4105     const signed char InpOp            =  1; // (
4106     const signed char InpCp            =  2; // )
4107     const signed char InpPipe          =  3; // |
4108     const signed char InpC             =  4; // C
4109     const signed char InpE             =  5; // E
4110     const signed char InpI             =  6; // I
4111     const signed char InpM             =  7; // M
4112     const signed char InpN             =  8; // N
4113     const signed char InpO             =  9; // O
4114     const signed char InpR             = 10; // R
4115     const signed char InpS             = 11; // S
4116     const signed char InpY             = 12; // Y
4117     const signed char InpUnknown       = 13;
4118
4119     // use some kind of state machine for parsing
4120     static signed char table[19][14] = {
4121      /*  InpWs    InpOp    InpCp    InpPipe  InpC     InpE     InpI     InpM     InpN     InpO     InpR     InpS     InpY     InpUnknown */
4122         { -1,      EN,      -1,      -1,      ST,      TTE,     TTI,     -1,      N,       -1,      -1,      -1,      -1,      -1     }, // Init
4123         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // ST
4124         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    TTI2,    Done,    Done,    Done   }, // TTI
4125         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    TTI3,    Done,    Done   }, // TTI2
4126         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTI3
4127         { -1,      -1,      -1,      -1,      -1,      -1,      TTEI,    -1,      -1,      -1,      -1,      -1,      TTEY,    -1     }, // TTE
4128         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTEY
4129         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTEI
4130         { -1,      -1,      -1,      -1,      -1,      -1,      -1,      TTNM,    -1,      NO,      -1,      -1,      -1,      -1     }, // N
4131         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    TTNM2,   Done,    Done   }, // TTNM
4132         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTNM2
4133         { NO2,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NO
4134         { -1,      NO3,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NO2
4135         { NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName }, // NO3
4136         { NO4,     -1,      ADone,   NO3,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NOName
4137         { -1,      -1,      ADone,   NO3,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NO4
4138         { -1,      -1,      ENNmt,   -1,      ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt  }, // EN
4139         { EN2,     -1,      ADone,   EN,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // ENNmt
4140         { -1,      -1,      ADone,   EN,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }  // EN2
4141     };
4142     signed char state = Init;
4143     signed char input;
4144     bool parseOk = TRUE;
4145
4146     while ( TRUE ) {
4147
4148         // get input
4149         if ( atEnd() ) {
4150             d->error = XMLERR_UNEXPECTEDEOF;
4151             goto parseError;
4152         }
4153         if        ( is_S(c) ) {
4154             input = InpWs;
4155         } else if ( c == '(' ) {
4156             input = InpOp;
4157         } else if ( c == ')' ) {
4158             input = InpCp;
4159         } else if ( c == '|' ) {
4160             input = InpPipe;
4161         } else if ( c == 'C' ) {
4162             input = InpC;
4163         } else if ( c == 'E' ) {
4164             input = InpE;
4165         } else if ( c == 'I' ) {
4166             input = InpI;
4167         } else if ( c == 'M' ) {
4168             input = InpM;
4169         } else if ( c == 'N' ) {
4170             input = InpN;
4171         } else if ( c == 'O' ) {
4172             input = InpO;
4173         } else if ( c == 'R' ) {
4174             input = InpR;
4175         } else if ( c == 'S' ) {
4176             input = InpS;
4177         } else if ( c == 'Y' ) {
4178             input = InpY;
4179         } else {
4180             input = InpUnknown;
4181         }
4182
4183         // set state according to input
4184         state = table[state][input];
4185
4186         // do some actions according to state
4187         switch ( state ) {
4188             case ST:
4189                 parseOk = parseString( "CDATA" );
4190                 break;
4191             case TTI:
4192                 parseOk = parseString( "ID" );
4193                 break;
4194             case TTI2:
4195                 parseOk = parseString( "REF" );
4196                 break;
4197             case TTI3:
4198                 next(); // S
4199                 break;
4200             case TTE:
4201                 parseOk = parseString( "ENTIT" );
4202                 break;
4203             case TTEY:
4204                 next(); // Y
4205                 break;
4206             case TTEI:
4207                 parseOk = parseString( "IES" );
4208                 break;
4209             case N:
4210                 next(); // N
4211                 break;
4212             case TTNM:
4213                 parseOk = parseString( "MTOKEN" );
4214                 break;
4215             case TTNM2:
4216                 next(); // S
4217                 break;
4218             case NO:
4219                 parseOk = parseString( "OTATION" );
4220                 break;
4221             case NO2:
4222                 eat_ws();
4223                 break;
4224             case NO3:
4225                 next_eat_ws();
4226                 break;
4227             case NOName:
4228                 parseOk = parseName();
4229                 break;
4230             case NO4:
4231                 eat_ws();
4232                 break;
4233             case EN:
4234                 next_eat_ws();
4235                 break;
4236             case ENNmt:
4237                 parseOk = parseNmtoken();
4238                 break;
4239             case EN2:
4240                 eat_ws();
4241                 break;
4242             case ADone:
4243                 next();
4244                 break;
4245         }
4246         // no input is read after this
4247         switch ( state ) {
4248             case ST:
4249                 if( !parseOk ) {
4250                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4251                     goto parseError;
4252                 }
4253                 break;
4254             case TTI:
4255                 if( !parseOk ) {
4256                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4257                     goto parseError;
4258                 }
4259                 break;
4260             case TTI2:
4261                 if( !parseOk ) {
4262                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4263                     goto parseError;
4264                 }
4265                 break;
4266             case TTE:
4267                 if( !parseOk ) {
4268                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4269                     goto parseError;
4270                 }
4271                 break;
4272             case TTEI:
4273                 if( !parseOk ) {
4274                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4275                     goto parseError;
4276                 }
4277                 break;
4278             case TTNM:
4279                 if( !parseOk ) {
4280                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4281                     goto parseError;
4282                 }
4283                 break;
4284             case NO:
4285                 if( !parseOk ) {
4286                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4287                     goto parseError;
4288                 }
4289                 break;
4290             case NOName:
4291                 if ( !parseOk ) {
4292                     d->error = XMLERR_ERRORPARSINGNAME;
4293                     goto parseError;
4294                 }
4295                 break;
4296             case ENNmt:
4297                 if ( !parseOk ) {
4298                     d->error = XMLERR_ERRORPARSINGNMTOKEN;
4299                     goto parseError;
4300                 }
4301                 break;
4302             case ADone:
4303                 return TRUE;
4304             case Done:
4305                 return TRUE;
4306             case -1:
4307                 // Error
4308                 d->error = XMLERR_LETTEREXPECTED;
4309                 goto parseError;
4310         }
4311
4312     }
4313
4314     return TRUE;
4315
4316 parseError:
4317     reportParseError();
4318     return FALSE;
4319 }
4320
4321 /*!
4322   Parse a AttValue [10]
4323
4324   Precondition: the head stands on the beginning " or '
4325
4326   If this function was successful, the head stands on the first
4327   character after the closing " or ' and the value of the attribute
4328   is in string().
4329 */
4330 bool QXmlSimpleReader::parseAttValue()
4331 {
4332     bool tmp;
4333
4334     const signed char Init             = 0;
4335     const signed char Dq               = 1; // double quotes were read
4336     const signed char DqRef            = 2; // read references in double quotes
4337     const signed char DqC              = 3; // signed character read in double quotes
4338     const signed char Sq               = 4; // single quotes were read
4339     const signed char SqRef            = 5; // read references in single quotes
4340     const signed char SqC              = 6; // signed character read in single quotes
4341     const signed char Done             = 7;
4342
4343     const signed char InpDq            = 0; // "
4344     const signed char InpSq            = 1; // '
4345     const signed char InpAmp           = 2; // &
4346     const signed char InpLt            = 3; // <
4347     const signed char InpUnknown       = 4;
4348
4349     // use some kind of state machine for parsing
4350     static signed char table[7][5] = {
4351      /*  InpDq  InpSq  InpAmp  InpLt InpUnknown */
4352         { Dq,    Sq,    -1,     -1,   -1    }, // Init
4353         { Done,  DqC,   DqRef,  -1,   DqC   }, // Dq
4354         { Done,  DqC,   DqRef,  -1,   DqC   }, // DqRef
4355         { Done,  DqC,   DqRef,  -1,   DqC   }, // DqC
4356         { SqC,   Done,  SqRef,  -1,   SqC   }, // Sq
4357         { SqC,   Done,  SqRef,  -1,   SqC   }, // SqRef
4358         { SqC,   Done,  SqRef,  -1,   SqC   }  // SqRef
4359     };
4360     signed char state = Init;
4361     signed char input;
4362     bool parseOk = TRUE;
4363
4364     while ( TRUE ) {
4365
4366         // get input
4367         if ( atEnd() ) {
4368             d->error = XMLERR_UNEXPECTEDEOF;
4369             goto parseError;
4370         }
4371         if        ( c == '"' ) {
4372             input = InpDq;
4373         } else if ( c == '\'' ) {
4374             input = InpSq;
4375         } else if ( c == '&' ) {
4376             input = InpAmp;
4377         } else if ( c == '<' ) {
4378             input = InpLt;
4379         } else {
4380             input = InpUnknown;
4381         }
4382
4383         // set state according to input
4384         state = table[state][input];
4385
4386         // do some actions according to state
4387         switch ( state ) {
4388             case Dq:
4389             case Sq:
4390                 stringClear();
4391                 next();
4392                 break;
4393             case DqRef:
4394             case SqRef:
4395                 parseOk = parseReference( tmp, InAttributeValue );
4396                 break;
4397             case DqC:
4398             case SqC:
4399                 stringAddC();
4400                 next();
4401                 break;
4402             case Done:
4403                 next();
4404                 break;
4405         }
4406         // no input is read after this
4407         switch ( state ) {
4408             case DqRef:
4409             case SqRef:
4410                 if ( !parseOk ) {
4411                     d->error = XMLERR_ERRORPARSINGREFERENCE;
4412                     goto parseError;
4413                 }
4414                 break;
4415             case Done:
4416                 return TRUE;
4417             case -1:
4418                 // Error
4419                 d->error = XMLERR_UNEXPECTEDCHARACTER;
4420                 goto parseError;
4421         }
4422
4423     }
4424
4425     return TRUE;
4426
4427 parseError:
4428     reportParseError();
4429     return FALSE;
4430 }
4431
4432 /*!
4433   Parse a elementdecl [45].
4434
4435   Precondition: the beginning '<!E' is already read and the head
4436   stands on the 'L' of '<!ELEMENT'
4437 */
4438 bool QXmlSimpleReader::parseElementDecl()
4439 {
4440     const signed char Init             =  0;
4441     const signed char Elem             =  1; // parse the beginning string
4442     const signed char Ws1              =  2; // whitespace required
4443     const signed char Nam              =  3; // parse Name
4444     const signed char Ws2              =  4; // whitespace required
4445     const signed char Empty            =  5; // read EMPTY
4446     const signed char Any              =  6; // read ANY
4447     const signed char Cont             =  7; // read contentspec (except ANY or EMPTY)
4448     const signed char Mix              =  8; // read Mixed
4449     const signed char Mix2             =  9; //
4450     const signed char Mix3             = 10; //
4451     const signed char MixN1            = 11; //
4452     const signed char MixN2            = 12; //
4453     const signed char MixN3            = 13; //
4454     const signed char MixN4            = 14; //
4455     const signed char Cp               = 15; // parse cp
4456     const signed char Cp2              = 16; //
4457     const signed char WsD              = 17; // eat whitespace before Done
4458     const signed char Done             = 18;
4459
4460     const signed char InpWs            =  0;
4461     const signed char InpGt            =  1; // >
4462     const signed char InpPipe          =  2; // |
4463     const signed char InpOp            =  3; // (
4464     const signed char InpCp            =  4; // )
4465     const signed char InpHash          =  5; // #
4466     const signed char InpQm            =  6; // ?
4467     const signed char InpAst           =  7; // *
4468     const signed char InpPlus          =  8; // +
4469     const signed char InpA             =  9; // A
4470     const signed char InpE             = 10; // E
4471     const signed char InpL             = 11; // L
4472     const signed char InpUnknown       = 12;
4473
4474     // use some kind of state machine for parsing
4475     static signed char table[18][13] = {
4476      /*  InpWs   InpGt  InpPipe  InpOp  InpCp   InpHash  InpQm  InpAst  InpPlus  InpA    InpE    InpL    InpUnknown */
4477         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     Elem,   -1     }, // Init
4478         { Ws1,    -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Elem
4479         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      Nam,    Nam,    Nam,    Nam    }, // Ws1
4480         { Ws2,    -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Nam
4481         { -1,     -1,    -1,      Cont,  -1,     -1,      -1,    -1,     -1,      Any,    Empty,  -1,     -1     }, // Ws2
4482         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Empty
4483         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Any
4484         { -1,     -1,    -1,      Cp,    Cp,     Mix,     -1,    -1,     -1,      Cp,     Cp,     Cp,     Cp     }, // Cont
4485         { Mix2,   -1,    MixN1,   -1,    Mix3,   -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Mix
4486         { -1,     -1,    MixN1,   -1,    Mix3,   -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Mix2
4487         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    WsD,    -1,      -1,     -1,     -1,     -1     }, // Mix3
4488         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      MixN2,  MixN2,  MixN2,  MixN2  }, // MixN1
4489         { MixN3,  -1,    MixN1,   -1,    MixN4,  -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // MixN2
4490         { -1,     -1,    MixN1,   -1,    MixN4,  -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // MixN3
4491         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    WsD,    -1,      -1,     -1,     -1,     -1     }, // MixN4
4492         { WsD,    Done,  -1,      -1,    -1,     -1,      Cp2,   Cp2,    Cp2,     -1,     -1,     -1,     -1     }, // Cp
4493         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Cp2
4494         { -1,     Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }  // WsD
4495     };
4496     signed char state = Init;
4497     signed char input;
4498     bool parseOk = TRUE;
4499
4500     while ( TRUE ) {
4501
4502         // read input
4503         if ( atEnd() ) {
4504             d->error = XMLERR_UNEXPECTEDEOF;
4505             goto parseError;
4506         }
4507         if        ( is_S(c) ) {
4508             input = InpWs;
4509         } else if ( c == '>' ) {
4510             input = InpGt;
4511         } else if ( c == '|' ) {
4512             input = InpPipe;
4513         } else if ( c == '(' ) {
4514             input = InpOp;
4515         } else if ( c == ')' ) {
4516             input = InpCp;
4517         } else if ( c == '#' ) {
4518             input = InpHash;
4519         } else if ( c == '?' ) {
4520             input = InpQm;
4521         } else if ( c == '*' ) {
4522             input = InpAst;
4523         } else if ( c == '+' ) {
4524             input = InpPlus;
4525         } else if ( c == 'A' ) {
4526             input = InpA;
4527         } else if ( c == 'E' ) {
4528             input = InpE;
4529         } else if ( c == 'L' ) {
4530             input = InpL;
4531         } else {
4532             input = InpUnknown;
4533         }
4534         // get new state
4535 //qDebug( "%d -%d(%c)-> %d", state, input, c.latin1(), table[state][input] );
4536         state = table[state][input];
4537
4538         // in some cases do special actions depending on state
4539         switch ( state ) {
4540             case Elem:
4541                 parseOk = parseString( "LEMENT" );
4542                 break;
4543             case Ws1:
4544                 eat_ws();
4545                 break;
4546             case Nam:
4547                 parseOk = parseName();
4548                 break;
4549             case Ws2:
4550                 eat_ws();
4551                 break;
4552             case Empty:
4553                 parseOk = parseString( "EMPTY" );
4554                 break;
4555             case Any:
4556                 parseOk = parseString( "ANY" );
4557                 break;
4558             case Cont:
4559                 next_eat_ws();
4560                 break;
4561             case Mix:
4562                 parseOk = parseString( "#PCDATA" );
4563                 break;
4564             case Mix2:
4565                 eat_ws();
4566                 break;
4567             case Mix3:
4568                 next();
4569                 break;
4570             case MixN1:
4571                 next_eat_ws();
4572                 break;
4573             case MixN2:
4574                 parseOk = parseName();
4575                 break;
4576             case MixN3:
4577                 eat_ws();
4578                 break;
4579             case MixN4:
4580                 next();
4581                 break;
4582             case Cp:
4583                 parseOk = parseChoiceSeq();
4584                 break;
4585             case Cp2:
4586                 next();
4587                 break;
4588             case WsD:
4589                 next_eat_ws();
4590                 break;
4591             case Done:
4592                 next();
4593                 break;
4594         }
4595         // no input is read after this
4596         switch ( state ) {
4597             case Elem:
4598                 if( !parseOk ) {
4599                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4600                     goto parseError;
4601                 }
4602                 break;
4603             case Nam:
4604                 if ( !parseOk ) {
4605                     d->error = XMLERR_ERRORPARSINGNAME;
4606                     goto parseError;
4607                 }
4608                 break;
4609             case Empty:
4610                 if( !parseOk ) {
4611                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4612                     goto parseError;
4613                 }
4614                 break;
4615             case Any:
4616                 if( !parseOk ) {
4617                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4618                     goto parseError;
4619                 }
4620                 break;
4621             case Mix:
4622                 if( !parseOk ) {
4623                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4624                     goto parseError;
4625                 }
4626                 break;
4627             case MixN2:
4628                 if ( !parseOk ) {
4629                     d->error = XMLERR_ERRORPARSINGNAME;
4630                     goto parseError;
4631                 }
4632                 break;
4633             case Cp:
4634                 if ( !parseOk ) {
4635                     d->error = XMLERR_ERRORPARSINGCHOICE;
4636                     goto parseError;
4637                 }
4638                 break;
4639             case Done:
4640                 return TRUE;
4641             case -1:
4642                 d->error = XMLERR_UNEXPECTEDCHARACTER;
4643                 goto parseError;
4644         }
4645
4646     }
4647
4648     return TRUE;
4649
4650 parseError:
4651     reportParseError();
4652     return FALSE;
4653 }
4654
4655 /*!
4656   Parse a NotationDecl [82].
4657
4658   Precondition: the beginning '<!' is already read and the head
4659   stands on the 'N' of '<!NOTATION'
4660 */
4661 bool QXmlSimpleReader::parseNotationDecl()
4662 {
4663     const signed char Init             = 0;
4664     const signed char Not              = 1; // read NOTATION
4665     const signed char Ws1              = 2; // eat whitespaces
4666     const signed char Nam              = 3; // read Name
4667     const signed char Ws2              = 4; // eat whitespaces
4668     const signed char ExtID            = 5; // parse ExternalID
4669     const signed char Ws3              = 6; // eat whitespaces
4670     const signed char Done             = 7;
4671
4672     const signed char InpWs            = 0;
4673     const signed char InpGt            = 1; // >
4674     const signed char InpN             = 2; // N
4675     const signed char InpUnknown       = 3;
4676
4677     // use some kind of state machine for parsing
4678     static signed char table[7][4] = {
4679      /*  InpWs   InpGt  InpN    InpUnknown */
4680         { -1,     -1,    Not,    -1     }, // Init
4681         { Ws1,    -1,    -1,     -1     }, // Not
4682         { -1,     -1,    Nam,    Nam    }, // Ws1
4683         { Ws2,    Done,  -1,     -1     }, // Nam
4684         { -1,     Done,  ExtID,  ExtID  }, // Ws2
4685         { Ws3,    Done,  -1,     -1     }, // ExtID
4686         { -1,     Done,  -1,     -1     }  // Ws3
4687     };
4688     signed char state = Init;
4689     signed char input;
4690     bool parseOk = TRUE;
4691
4692     while ( TRUE ) {
4693
4694         // get input
4695         if ( atEnd() ) {
4696             d->error = XMLERR_UNEXPECTEDEOF;
4697             goto parseError;
4698         }
4699         if        ( is_S(c) ) {
4700             input = InpWs;
4701         } else if ( c == '>' ) {
4702             input = InpGt;
4703         } else if ( c == 'N' ) {
4704             input = InpN;
4705         } else {
4706             input = InpUnknown;
4707         }
4708
4709         // set state according to input
4710         state = table[state][input];
4711
4712         // do some actions according to state
4713         switch ( state ) {
4714             case Not:
4715                 parseOk = parseString( "NOTATION" );
4716                 break;
4717             case Ws1:
4718                 eat_ws();
4719                 break;
4720             case Nam:
4721                 parseOk = parseName();
4722                 break;
4723             case Ws2:
4724                 eat_ws();
4725                 break;
4726             case ExtID:
4727                 parseOk = parseExternalID( TRUE );
4728                 break;
4729             case Ws3:
4730                 eat_ws();
4731                 break;
4732             case Done:
4733                 next();
4734                 break;
4735         }
4736         // no input is read after this
4737         switch ( state ) {
4738             case Not:
4739                 if ( !parseOk ) {
4740                     d->error = XMLERR_UNEXPECTEDCHARACTER;
4741                     goto parseError;
4742                 }
4743                 break;
4744             case Nam:
4745                 if ( !parseOk ) {
4746                     d->error = XMLERR_ERRORPARSINGNAME;
4747                     goto parseError;
4748                 }
4749                 break;
4750             case ExtID:
4751                 if ( !parseOk ) {
4752                     d->error = XMLERR_ERRORPARSINGEXTERNALID;
4753                     goto parseError;
4754                 }
4755                 // call the handler
4756                 if ( dtdHnd ) {
4757                     if ( !dtdHnd->notationDecl( name(), d->publicId, d->systemId ) ) {
4758                         d->error = dtdHnd->errorString();
4759                         goto parseError;
4760                     }
4761                 }
4762                 break;
4763             case Done:
4764                 return TRUE;
4765             case -1:
4766                 // Error
4767                 d->error = XMLERR_UNEXPECTEDCHARACTER;
4768                 goto parseError;
4769         }
4770
4771     }
4772
4773     return TRUE;
4774
4775 parseError:
4776     reportParseError();
4777     return FALSE;
4778 }
4779
4780 /*!
4781   Parse choice [49] or seq [50].
4782
4783   Precondition: the beginning '('S? is already read and the head
4784   stands on the first non-whitespace character after it.
4785 */
4786 bool QXmlSimpleReader::parseChoiceSeq()
4787 {
4788     const signed char Init             = 0;
4789     const signed char Ws1              = 1; // eat whitespace
4790     const signed char CS_              = 2; // choice or set
4791     const signed char Ws2              = 3; // eat whitespace
4792     const signed char More             = 4; // more cp to read
4793     const signed char Name             = 5; // read name
4794     const signed char Done             = 6; //
4795
4796     const signed char InpWs            = 0; // S
4797     const signed char InpOp            = 1; // (
4798     const signed char InpCp            = 2; // )
4799     const signed char InpQm            = 3; // ?
4800     const signed char InpAst           = 4; // *
4801     const signed char InpPlus          = 5; // +
4802     const signed char InpPipe          = 6; // |
4803     const signed char InpComm          = 7; // ,
4804     const signed char InpUnknown       = 8;
4805
4806     // use some kind of state machine for parsing
4807     static signed char table[6][9] = {
4808      /*  InpWs   InpOp  InpCp  InpQm  InpAst  InpPlus  InpPipe  InpComm  InpUnknown */
4809         { -1,     Ws1,   -1,    -1,    -1,     -1,      -1,      -1,      Name  }, // Init
4810         { -1,     CS_,   -1,    -1,    -1,     -1,      -1,      -1,      CS_    }, // Ws1
4811         { Ws2,    -1,    Done,  Ws2,   Ws2,    Ws2,     More,    More,    -1    }, // CS_
4812         { -1,     -1,    Done,  -1,    -1,     -1,      More,    More,    -1    }, // Ws2
4813         { -1,     Ws1,   -1,    -1,    -1,     -1,      -1,      -1,      Name  }, // More (same as Init)
4814         { Ws2,    -1,    Done,  Ws2,   Ws2,    Ws2,     More,    More,    -1    }  // Name (same as CS_)
4815     };
4816     signed char state = Init;
4817     signed char input;
4818     bool parseOk = TRUE;
4819
4820     while ( TRUE ) {
4821
4822         // get input
4823         if ( atEnd() ) {
4824             d->error = XMLERR_UNEXPECTEDEOF;
4825             goto parseError;
4826         }
4827         if        ( is_S(c) ) {
4828             input = InpWs;
4829         } else if ( c == '(' ) {
4830             input = InpOp;
4831         } else if ( c == ')' ) {
4832             input = InpCp;
4833         } else if ( c == '?' ) {
4834             input = InpQm;
4835         } else if ( c == '*' ) {
4836             input = InpAst;
4837         } else if ( c == '+' ) {
4838             input = InpPlus;
4839         } else if ( c == '|' ) {
4840             input = InpPipe;
4841         } else if ( c == ',' ) {
4842             input = InpComm;
4843         } else {
4844             input = InpUnknown;
4845         }
4846
4847         // set state according to input
4848         state = table[state][input];
4849
4850         // do some actions according to state
4851         switch ( state ) {
4852             case Ws1:
4853                 next_eat_ws();
4854                 break;
4855             case CS_:
4856                 parseOk = parseChoiceSeq();
4857                 break;
4858             case Ws2:
4859                 next_eat_ws();
4860                 break;
4861             case More:
4862                 next_eat_ws();
4863                 break;
4864             case Name:
4865                 parseOk = parseName();
4866                 break;
4867             case Done:
4868                 next();
4869                 break;
4870         }
4871         // no input is read after this
4872         switch ( state ) {
4873             case CS_:
4874                 if ( !parseOk ) {
4875                     d->error = XMLERR_ERRORPARSINGCHOICE;
4876                     goto parseError;
4877                 }
4878                 break;
4879             case Name:
4880                 if ( !parseOk ) {
4881                     d->error = XMLERR_ERRORPARSINGNAME;
4882                     goto parseError;
4883                 }
4884                 break;
4885             case Done:
4886                 return TRUE;
4887             case -1:
4888                 // Error
4889                 d->error = XMLERR_UNEXPECTEDCHARACTER;
4890                 goto parseError;
4891         }
4892
4893     }
4894
4895     return TRUE;
4896
4897 parseError:
4898     reportParseError();
4899     return FALSE;
4900 }
4901
4902 /*!
4903   Parse a EntityDecl [70].
4904
4905   Precondition: the beginning '<!E' is already read and the head
4906   stand on the 'N' of '<!ENTITY'
4907 */
4908 bool QXmlSimpleReader::parseEntityDecl()
4909 {
4910     const signed char Init             =  0;
4911     const signed char Ent              =  1; // parse "ENTITY"
4912     const signed char Ws1              =  2; // white space read
4913     const signed char Name             =  3; // parse name
4914     const signed char Ws2              =  4; // white space read
4915     const signed char EValue           =  5; // parse entity value
4916     const signed char ExtID            =  6; // parse ExternalID
4917     const signed char Ws3              =  7; // white space read
4918     const signed char Ndata            =  8; // parse "NDATA"
4919     const signed char Ws4              =  9; // white space read
4920     const signed char NNam             = 10; // parse name
4921     const signed char PEDec            = 11; // parse PEDecl
4922     const signed char Ws6              = 12; // white space read
4923     const signed char PENam            = 13; // parse name
4924     const signed char Ws7              = 14; // white space read
4925     const signed char PEVal            = 15; // parse entity value
4926     const signed char PEEID            = 16; // parse ExternalID
4927     const signed char WsE              = 17; // white space read
4928     const signed char EDDone           = 19; // done, but also report an external, unparsed entity decl
4929     const signed char Done             = 18;
4930
4931     const signed char InpWs            = 0; // white space
4932     const signed char InpPer           = 1; // %
4933     const signed char InpQuot          = 2; // " or '
4934     const signed char InpGt            = 3; // >
4935     const signed char InpN             = 4; // N
4936     const signed char InpUnknown       = 5;
4937
4938     // use some kind of state machine for parsing
4939     static signed char table[18][6] = {
4940      /*  InpWs  InpPer  InpQuot  InpGt  InpN    InpUnknown */
4941         { -1,    -1,     -1,      -1,    Ent,    -1      }, // Init
4942         { Ws1,   -1,     -1,      -1,    -1,     -1      }, // Ent
4943         { -1,    PEDec,  -1,      -1,    Name,   Name    }, // Ws1
4944         { Ws2,   -1,     -1,      -1,    -1,     -1      }, // Name
4945         { -1,    -1,     EValue,  -1,    -1,     ExtID   }, // Ws2
4946         { WsE,   -1,     -1,      Done,  -1,     -1      }, // EValue
4947         { Ws3,   -1,     -1,      EDDone,-1,     -1      }, // ExtID
4948         { -1,    -1,     -1,      EDDone,Ndata,  -1      }, // Ws3
4949         { Ws4,   -1,     -1,      -1,    -1,     -1      }, // Ndata
4950         { -1,    -1,     -1,      -1,    NNam,   NNam    }, // Ws4
4951         { WsE,   -1,     -1,      Done,  -1,     -1      }, // NNam
4952         { Ws6,   -1,     -1,      -1,    -1,     -1      }, // PEDec
4953         { -1,    -1,     -1,      -1,    PENam,  PENam   }, // Ws6
4954         { Ws7,   -1,     -1,      -1,    -1,     -1      }, // PENam
4955         { -1,    -1,     PEVal,   -1,    -1,     PEEID   }, // Ws7
4956         { WsE,   -1,     -1,      Done,  -1,     -1      }, // PEVal
4957         { WsE,   -1,     -1,      Done,  -1,     -1      }, // PEEID
4958         { -1,    -1,     -1,      Done,  -1,     -1      }  // WsE
4959     };
4960     signed char state = Init;
4961     signed char input;
4962     bool parseOk = TRUE;
4963
4964     while ( TRUE ) {
4965
4966         // get input
4967         if ( atEnd() ) {
4968             d->error = XMLERR_UNEXPECTEDEOF;
4969             goto parseError;
4970         }
4971         if        ( is_S(c) ) {
4972             input = InpWs;
4973         } else if ( c == '%' ) {
4974             input = InpPer;
4975         } else if ( c == '"' || c == '\'' ) {
4976             input = InpQuot;
4977         } else if ( c == '>' ) {
4978             input = InpGt;
4979         } else if ( c == 'N' ) {
4980             input = InpN;
4981         } else {
4982             input = InpUnknown;
4983         }
4984
4985         // set state according to input
4986         state = table[state][input];
4987
4988         // do some actions according to state
4989         switch ( state ) {
4990             case Ent:
4991                 parseOk = parseString( "NTITY" );
4992                 break;
4993             case Ws1:
4994                 eat_ws();
4995                 break;
4996             case Name:
4997                 parseOk = parseName();
4998                 break;
4999             case Ws2:
5000                 eat_ws();
5001                 break;
5002             case EValue:
5003                 parseOk = parseEntityValue();
5004                 break;
5005             case ExtID:
5006                 parseOk = parseExternalID();
5007                 break;
5008             case Ws3:
5009                 eat_ws();
5010                 break;
5011             case Ndata:
5012                 parseOk = parseString( "NDATA" );
5013                 break;
5014             case Ws4:
5015                 eat_ws();
5016                 break;
5017             case NNam:
5018                 parseOk = parseName( TRUE );
5019                 break;
5020             case PEDec:
5021                 next();
5022                 break;
5023             case Ws6:
5024                 eat_ws();
5025                 break;
5026             case PENam:
5027                 parseOk = parseName();
5028                 break;
5029             case Ws7:
5030                 eat_ws();
5031                 break;
5032             case PEVal:
5033                 parseOk = parseEntityValue();
5034                 break;
5035             case PEEID:
5036                 parseOk = parseExternalID();
5037                 break;
5038             case WsE:
5039                 eat_ws();
5040                 break;
5041             case EDDone:
5042                 next();
5043                 break;
5044             case Done:
5045                 next();
5046                 break;
5047         }
5048         // no input is read after this
5049         switch ( state ) {
5050             case Ent:
5051                 if ( !parseOk ) {
5052                     d->error = XMLERR_UNEXPECTEDCHARACTER;
5053                     goto parseError;
5054                 }
5055                 break;
5056             case Name:
5057                 if ( !parseOk ) {
5058                     d->error = XMLERR_ERRORPARSINGNAME;
5059                     goto parseError;
5060                 }
5061                 break;
5062             case EValue:
5063                 if ( !parseOk ) {
5064                     d->error = XMLERR_ERRORPARSINGENTITYVALUE;
5065                     goto parseError;
5066                 }
5067                 if (  !entityExist( name() ) ) {
5068                     d->entities.insert( name(), string() );
5069                     if ( declHnd ) {
5070                         if ( !declHnd->internalEntityDecl( name(), string() ) ) {
5071                             d->error = declHnd->errorString();
5072                             goto parseError;
5073                         }
5074                     }
5075                 }
5076                 break;
5077             case ExtID:
5078                 if ( !parseOk ) {
5079                     d->error = XMLERR_ERRORPARSINGEXTERNALID;
5080                     goto parseError;
5081                 }
5082                 break;
5083             case Ndata:
5084                 if ( !parseOk ) {
5085                     d->error = XMLERR_UNEXPECTEDCHARACTER;
5086                     goto parseError;
5087                 }
5088                 break;
5089             case NNam:
5090                 if ( !parseOk ) {
5091                     d->error = XMLERR_ERRORPARSINGNAME;
5092                     goto parseError;
5093                 }
5094                 if (  !entityExist( name() ) ) {
5095                     d->externEntities.insert( name(), QXmlSimpleReaderPrivate::ExternEntity( d->publicId, d->systemId, ref() ) );
5096                     if ( dtdHnd ) {
5097                         if ( !dtdHnd->unparsedEntityDecl( name(), d->publicId, d->systemId, ref() ) ) {
5098                             d->error = declHnd->errorString();
5099                             goto parseError;
5100                         }
5101                     }
5102                 }
5103                 break;
5104             case PENam:
5105                 if ( !parseOk ) {
5106                     d->error = XMLERR_ERRORPARSINGNAME;
5107                     goto parseError;
5108                 }
5109                 break;
5110             case PEVal:
5111                 if ( !parseOk ) {
5112                     d->error = XMLERR_ERRORPARSINGENTITYVALUE;
5113                     goto parseError;
5114                 }
5115                 if (  !entityExist( name() ) ) {
5116                     d->parameterEntities.insert( name(), string() );
5117                     if ( declHnd ) {
5118                         if ( !declHnd->internalEntityDecl( QString("%")+name(), string() ) ) {
5119                             d->error = declHnd->errorString();
5120                             goto parseError;
5121                         }
5122                     }
5123                 }
5124                 break;
5125             case PEEID:
5126                 if ( !parseOk ) {
5127                     d->error = XMLERR_ERRORPARSINGEXTERNALID;
5128                     goto parseError;
5129                 }
5130                 if (  !entityExist( name() ) ) {
5131                     d->externParameterEntities.insert( name(), QXmlSimpleReaderPrivate::ExternParameterEntity( d->publicId, d->systemId ) );
5132                     if ( declHnd ) {
5133                         if ( !declHnd->externalEntityDecl( QString("%")+name(), d->publicId, d->systemId ) ) {
5134                             d->error = declHnd->errorString();
5135                             goto parseError;
5136                         }
5137                     }
5138                 }
5139                 break;
5140             case EDDone:
5141                 if (  !entityExist( name() ) ) {
5142                     d->externEntities.insert( name(), QXmlSimpleReaderPrivate::ExternEntity( d->publicId, d->systemId, QString::null ) );
5143                     if ( declHnd ) {
5144                         if ( !declHnd->externalEntityDecl( name(), d->publicId, d->systemId ) ) {
5145                             d->error = declHnd->errorString();
5146                             goto parseError;
5147                         }
5148                     }
5149                 }
5150                 return TRUE;
5151             case Done:
5152                 return TRUE;
5153             case -1:
5154                 // Error
5155                 d->error = XMLERR_LETTEREXPECTED;
5156                 goto parseError;
5157         }
5158
5159     }
5160
5161     return TRUE;
5162
5163 parseError:
5164     reportParseError();
5165     return FALSE;
5166 }
5167
5168 /*!
5169   Parse a EntityValue [9]
5170 */
5171 bool QXmlSimpleReader::parseEntityValue()
5172 {
5173     bool tmp;
5174
5175     const signed char Init             = 0;
5176     const signed char Dq               = 1; // EntityValue is double quoted
5177     const signed char DqC              = 2; // signed character
5178     const signed char DqPER            = 3; // PERefence
5179     const signed char DqRef            = 4; // Reference
5180     const signed char Sq               = 5; // EntityValue is double quoted
5181     const signed char SqC              = 6; // signed character
5182     const signed char SqPER            = 7; // PERefence
5183     const signed char SqRef            = 8; // Reference
5184     const signed char Done             = 9;
5185
5186     const signed char InpDq            = 0; // "
5187     const signed char InpSq            = 1; // '
5188     const signed char InpAmp           = 2; // &
5189     const signed char InpPer           = 3; // %
5190     const signed char InpUnknown       = 4;
5191
5192     // use some kind of state machine for parsing
5193     static signed char table[9][5] = {
5194      /*  InpDq  InpSq  InpAmp  InpPer  InpUnknown */
5195         { Dq,    Sq,    -1,     -1,     -1    }, // Init
5196         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // Dq
5197         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // DqC
5198         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // DqPER
5199         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // DqRef
5200         { SqC,   Done,  SqRef,  SqPER,  SqC   }, // Sq
5201         { SqC,   Done,  SqRef,  SqPER,  SqC   }, // SqC
5202         { SqC,   Done,  SqRef,  SqPER,  SqC   }, // SqPER
5203         { SqC,   Done,  SqRef,  SqPER,  SqC   }  // SqRef
5204     };
5205     signed char state = Init;
5206     signed char input;
5207     bool parseOk = TRUE;
5208
5209     while ( TRUE ) {
5210
5211         // get input
5212         if ( atEnd() ) {
5213             d->error = XMLERR_UNEXPECTEDEOF;
5214             goto parseError;
5215         }
5216         if        ( c == '"' ) {
5217             input = InpDq;
5218         } else if ( c == '\'' ) {
5219             input = InpSq;
5220         } else if ( c == '&' ) {
5221             input = InpAmp;
5222         } else if ( c == '%' ) {
5223             input = InpPer;
5224         } else {
5225             input = InpUnknown;
5226         }
5227
5228         // set state according to input
5229         state = table[state][input];
5230
5231         // do some actions according to state
5232         switch ( state ) {
5233             case Dq:
5234             case Sq:
5235                 stringClear();
5236                 next();
5237                 break;
5238             case DqC:
5239             case SqC:
5240                 stringAddC();
5241                 next();
5242                 break;
5243             case DqPER:
5244             case SqPER:
5245                 parseOk = parsePEReference( InEntityValue );
5246                 break;
5247             case DqRef:
5248             case SqRef:
5249                 parseOk = parseReference( tmp, InEntityValue );
5250                 break;
5251             case Done:
5252                 next();
5253                 break;
5254         }
5255         // no input is read after this
5256         switch ( state ) {
5257             case DqPER:
5258             case SqPER:
5259                 if ( !parseOk ) {
5260                     d->error = XMLERR_ERRORPARSINGDOCTYPE;
5261                     goto parseError;
5262                 }
5263                 break;
5264             case DqRef:
5265             case SqRef:
5266                 if ( !parseOk ) {
5267                     d->error = XMLERR_ERRORPARSINGREFERENCE;
5268                     goto parseError;
5269                 }
5270                 break;
5271             case Done:
5272                 return TRUE;
5273             case -1:
5274                 // Error
5275                 d->error = XMLERR_LETTEREXPECTED;
5276                 goto parseError;
5277         }
5278
5279     }
5280
5281     return TRUE;
5282
5283 parseError:
5284     reportParseError();
5285     return FALSE;
5286 }
5287
5288 /*!
5289   Parse a comment [15].
5290
5291   Precondition: the beginning '<!' of the comment is already read and the head
5292   stands on the first '-' of '<!--'.
5293
5294   If this funktion was successful, the head-position is on the first
5295   character after the comment.
5296 */
5297 bool QXmlSimpleReader::parseComment()
5298 {
5299     const signed char Init             = 0;
5300     const signed char Dash1            = 1; // the first dash was read
5301     const signed char Dash2            = 2; // the second dash was read
5302     const signed char Com              = 3; // read comment
5303     const signed char Com2             = 4; // read comment (help state)
5304     const signed char ComE             = 5; // finished reading comment
5305     const signed char Done             = 6;
5306
5307     const signed char InpDash          = 0; // -
5308     const signed char InpGt            = 1; // >
5309     const signed char InpUnknown       = 2;
5310
5311     // use some kind of state machine for parsing
5312     static signed char table[6][3] = {
5313      /*  InpDash  InpGt  InpUnknown */
5314         { Dash1,   -1,    -1  }, // Init
5315         { Dash2,   -1,    -1  }, // Dash1
5316         { Com2,    Com,   Com }, // Dash2
5317         { Com2,    Com,   Com }, // Com
5318         { ComE,    Com,   Com }, // Com2
5319         { -1,      Done,  -1  }  // ComE
5320     };
5321     signed char state = Init;
5322     signed char input;
5323
5324     while ( TRUE ) {
5325
5326         // get input
5327         if ( atEnd() ) {
5328             d->error = XMLERR_UNEXPECTEDEOF;
5329             goto parseError;
5330         }
5331         if        ( c == '-' ) {
5332             input = InpDash;
5333         } else if ( c == '>' ) {
5334             input = InpGt;
5335         } else {
5336             input = InpUnknown;
5337         }
5338
5339         // set state according to input
5340         state = table[state][input];
5341
5342         // do some actions according to state
5343         switch ( state ) {
5344             case Dash1:
5345                 next();
5346                 break;
5347             case Dash2:
5348                 next();
5349                 break;
5350             case Com:
5351                 stringAddC();
5352                 next();
5353                 break;
5354             case Com2:
5355                 next();
5356                 break;
5357             case ComE:
5358                 next();
5359                 break;
5360             case Done:
5361                 next();
5362                 break;
5363         }
5364         // no input is read after this
5365         switch ( state ) {
5366             case Dash2:
5367                 stringClear();
5368                 break;
5369             case Com2:
5370                 // if next character is not a dash than don't skip it
5371                 if ( c != '-' ) {
5372                     stringAddC( '-' );
5373                 }
5374                 break;
5375             case Done:
5376                 return TRUE;
5377             case -1:
5378                 // Error
5379                 d->error = XMLERR_ERRORPARSINGCOMMENT;
5380                 goto parseError;
5381         }
5382
5383     }
5384
5385     return TRUE;
5386
5387 parseError:
5388     reportParseError();
5389     return FALSE;
5390 }
5391
5392 /*!
5393   Parse a Attribute [41].
5394
5395   Precondition: the head stands on the first character of the name of the
5396   attribute (i.e. all whitespaces are already parsed).
5397
5398   The head stand on the next character after the end quotes. The variable name
5399   contains the name of the attribute and the variable string contains the value
5400   of the attribute.
5401 */
5402 bool QXmlSimpleReader::parseAttribute()
5403 {
5404     const signed char Init             = 0;
5405     const signed char PName            = 1; // parse name
5406     const signed char Ws               = 2; // eat ws
5407     const signed char Eq               = 3; // the '=' was read
5408     const signed char Quotes           = 4; // " or ' were read
5409
5410     const signed char InpNameBe        = 0;
5411     const signed char InpEq            = 1; // =
5412     const signed char InpDq            = 2; // "
5413     const signed char InpSq            = 3; // '
5414     const signed char InpUnknown       = 4;
5415
5416     // use some kind of state machine for parsing
5417     static signed char table[4][5] = {
5418      /*  InpNameBe  InpEq  InpDq    InpSq    InpUnknown */
5419         { PName,     -1,    -1,      -1,      -1    }, // Init
5420         { -1,        Eq,    -1,      -1,      Ws    }, // PName
5421         { -1,        Eq,    -1,      -1,      -1    }, // Ws
5422         { -1,        -1,    Quotes,  Quotes,  -1    }  // Eq
5423     };
5424     signed char state = Init;
5425     signed char input;
5426     bool parseOk = TRUE;
5427
5428     while ( TRUE ) {
5429
5430         // get input
5431         if ( atEnd() ) {
5432             d->error = XMLERR_UNEXPECTEDEOF;
5433             goto parseError;
5434         }
5435         if        ( is_NameBeginning(c) ) {
5436             input = InpNameBe;
5437         } else if ( c == '=' ) {
5438             input = InpEq;
5439         } else if ( c == '"' ) {
5440             input = InpDq;
5441         } else if ( c == '\'' ) {
5442             input = InpSq;
5443         } else {
5444             input = InpUnknown;
5445         }
5446
5447         // set state according to input
5448         state = table[state][input];
5449
5450         // do some actions according to state
5451         switch ( state ) {
5452             case PName:
5453                 parseOk = parseName();
5454                 break;
5455             case Ws:
5456                 eat_ws();
5457                 break;
5458             case Eq:
5459                 next_eat_ws();
5460                 break;
5461             case Quotes:
5462                 parseOk = parseAttValue();
5463                 break;
5464         }
5465         // no input is read after this
5466         switch ( state ) {
5467             case PName:
5468                 if ( !parseOk ) {
5469                     d->error = XMLERR_ERRORPARSINGNAME;
5470                     goto parseError;
5471                 }
5472                 break;
5473             case Quotes:
5474                 if ( !parseOk ) {
5475                     d->error = XMLERR_ERRORPARSINGATTVALUE;
5476                     goto parseError;
5477                 }
5478                 // Done
5479                 return TRUE;
5480             case -1:
5481                 // Error
5482                 d->error = XMLERR_UNEXPECTEDCHARACTER;
5483                 goto parseError;
5484         }
5485
5486     }
5487
5488     return TRUE;
5489
5490 parseError:
5491     reportParseError();
5492     return FALSE;
5493 }
5494
5495 /*!
5496   Parse a Name [5] and store the name in name or ref (if useRef is TRUE).
5497 */
5498 bool QXmlSimpleReader::parseName( bool useRef )
5499 {
5500     const signed char Init             = 0;
5501     const signed char Name1            = 1; // parse first signed character of the name
5502     const signed char Name             = 2; // parse name
5503     const signed char Done             = 3;
5504
5505     const signed char InpNameBe        = 0; // name beginning signed characters
5506     const signed char InpNameCh        = 1; // NameChar without InpNameBe
5507     const signed char InpUnknown       = 2;
5508
5509     // use some kind of state machine for parsing
5510     static signed char table[3][3] = {
5511      /*  InpNameBe  InpNameCh  InpUnknown */
5512         { Name1,     -1,        -1    }, // Init
5513         { Name,      Name,      Done  }, // Name1
5514         { Name,      Name,      Done  }  // Name
5515     };
5516     signed char state = Init;
5517     signed char input;
5518
5519     while ( TRUE ) {
5520
5521         // get input
5522         if ( atEnd() ) {
5523             d->error = XMLERR_UNEXPECTEDEOF;
5524             goto parseError;
5525         }
5526         if        ( is_NameBeginning(c) ) {
5527             input = InpNameBe;
5528         } else if ( is_NameChar(c) ) {
5529             input = InpNameCh;
5530         } else {
5531             input = InpUnknown;
5532         }
5533
5534         // set state according to input
5535         state = table[state][input];
5536
5537         // do some actions according to state
5538         switch ( state ) {
5539             case Name1:
5540                 if ( useRef ) {
5541                     refClear();
5542                     refAddC();
5543                 } else {
5544                     nameClear();
5545                     nameAddC();
5546                 }
5547                 next();
5548                 break;
5549             case Name:
5550                 if ( useRef ) {
5551                     refAddC();
5552                 } else {
5553                     nameAddC();
5554                 }
5555                 next();
5556                 break;
5557         }
5558         // no input is read after this
5559         switch ( state ) {
5560             case Done:
5561                 return TRUE;
5562             case -1:
5563                 // Error
5564                 d->error = XMLERR_LETTEREXPECTED;
5565                 goto parseError;
5566         }
5567
5568     }
5569
5570     return TRUE;
5571
5572 parseError:
5573     reportParseError();
5574     return FALSE;
5575 }
5576
5577 /*!
5578   Parse a Nmtoken [7] and store the name in name.
5579 */
5580 bool QXmlSimpleReader::parseNmtoken()
5581 {
5582     const signed char Init             = 0;
5583     const signed char NameF            = 1;
5584     const signed char Name             = 2;
5585     const signed char Done             = 3;
5586
5587     const signed char InpNameCh        = 0; // NameChar without InpNameBe
5588     const signed char InpUnknown       = 1;
5589
5590     // use some kind of state machine for parsing
5591     static signed char table[3][2] = {
5592      /*  InpNameCh  InpUnknown */
5593         { NameF,     -1    }, // Init
5594         { Name,      Done  }, // NameF
5595         { Name,      Done  }  // Name
5596     };
5597     signed char state = Init;
5598     signed char input;
5599
5600     while ( TRUE ) {
5601
5602         // get input
5603         if ( atEnd() ) {
5604             d->error = XMLERR_UNEXPECTEDEOF;
5605             goto parseError;
5606         }
5607         if ( is_NameChar(c) ) {
5608             input = InpNameCh;
5609         } else {
5610             input = InpUnknown;
5611         }
5612
5613         // set state according to input
5614         state = table[state][input];
5615
5616         // do some actions according to state
5617         switch ( state ) {
5618             case NameF:
5619                 nameClear();
5620                 nameAddC();
5621                 next();
5622                 break;
5623             case Name:
5624                 nameAddC();
5625                 next();
5626                 break;
5627         }
5628         // no input is read after this
5629         switch ( state ) {
5630             case Done:
5631                 return TRUE;
5632             case -1:
5633                 // Error
5634                 d->error = XMLERR_LETTEREXPECTED;
5635                 goto parseError;
5636         }
5637
5638     }
5639
5640     return TRUE;
5641
5642 parseError:
5643     reportParseError();
5644     return FALSE;
5645 }
5646
5647 /*!
5648   Parse a Reference [67].
5649
5650   charDataRead is set to TRUE if the reference must not be parsed. The
5651   character(s) which the reference mapped to are appended to string. The
5652   head stands on the first character after the reference.
5653
5654   charDataRead is set to FALSE if the reference must be parsed. The
5655   character(s) which the reference mapped to are inserted at the reference
5656   position. The head stands on the first character of the replacement).
5657 */
5658 bool QXmlSimpleReader::parseReference( bool &charDataRead, EntityRecognitionContext context )
5659 {
5660     // temporary variables
5661     uint tmp;
5662     bool ok;
5663
5664     const signed char Init             =  0;
5665     const signed char SRef             =  1; // start of a reference
5666     const signed char ChRef            =  2; // parse CharRef
5667     const signed char ChDec            =  3; // parse CharRef decimal
5668     const signed char ChHexS           =  4; // start CharRef hexadecimal
5669     const signed char ChHex            =  5; // parse CharRef hexadecimal
5670     const signed char Name             =  6; // parse name
5671     const signed char DoneD            =  7; // done CharRef decimal
5672     const signed char DoneH            =  8; // done CharRef hexadecimal
5673     const signed char DoneN            =  9; // done EntityRef
5674
5675     const signed char InpAmp           = 0; // &
5676     const signed char InpSemi          = 1; // ;
5677     const signed char InpHash          = 2; // #
5678     const signed char InpX             = 3; // x
5679     const signed char InpNum           = 4; // 0-9
5680     const signed char InpHex           = 5; // a-f A-F
5681     const signed char InpUnknown       = 6;
5682
5683     // use some kind of state machine for parsing
5684     static signed char table[8][7] = {
5685      /*  InpAmp  InpSemi  InpHash  InpX     InpNum  InpHex  InpUnknown */
5686         { SRef,   -1,      -1,      -1,      -1,     -1,     -1    }, // Init
5687         { -1,     -1,      ChRef,   Name,    Name,   Name,   Name  }, // SRef
5688         { -1,     -1,      -1,      ChHexS,  ChDec,  -1,     -1    }, // ChRef
5689         { -1,     DoneD,   -1,      -1,      ChDec,  -1,     -1    }, // ChDec
5690         { -1,     -1,      -1,      -1,      ChHex,  ChHex,  -1    }, // ChHexS
5691         { -1,     DoneH,   -1,      -1,      ChHex,  ChHex,  -1    }, // ChHex
5692         { -1,     DoneN,   -1,      -1,      -1,     -1,     -1    }  // Name
5693     };
5694     signed char state = Init;
5695     signed char input;
5696
5697     while ( TRUE ) {
5698
5699         // get input
5700         if ( atEnd() ) {
5701             d->error = XMLERR_UNEXPECTEDEOF;
5702             goto parseError;
5703         }
5704         if        ( c.row() ) {
5705             input = InpUnknown;
5706         } else if ( c.cell() == '&' ) {
5707             input = InpAmp;
5708         } else if ( c.cell() == ';' ) {
5709             input = InpSemi;
5710         } else if ( c.cell() == '#' ) {
5711             input = InpHash;
5712         } else if ( c.cell() == 'x' ) {
5713             input = InpX;
5714         } else if ( '0' <= c.cell() && c.cell() <= '9' ) {
5715             input = InpNum;
5716         } else if ( 'a' <= c.cell() && c.cell() <= 'f' ) {
5717             input = InpHex;
5718         } else if ( 'A' <= c.cell() && c.cell() <= 'F' ) {
5719             input = InpHex;
5720         } else {
5721             input = InpUnknown;
5722         }
5723
5724         // set state according to input
5725         state = table[state][input];
5726
5727         // do some actions according to state
5728         switch ( state ) {
5729             case SRef:
5730                 refClear();
5731                 next();
5732                 break;
5733             case ChRef:
5734                 next();
5735                 break;
5736             case ChDec:
5737                 refAddC();
5738                 next();
5739                 break;
5740             case ChHexS:
5741                 next();
5742                 break;
5743             case ChHex:
5744                 refAddC();
5745                 next();
5746                 break;
5747             case Name:
5748                 // read the name into the ref
5749                 parseName( TRUE );
5750                 break;
5751             case DoneD:
5752                 tmp = ref().toUInt( &ok, 10 );
5753                 if ( ok ) {
5754                     stringAddC( QChar(tmp) );
5755                 } else {
5756                     d->error = XMLERR_ERRORPARSINGREFERENCE;
5757                     goto parseError;
5758                 }
5759                 charDataRead = TRUE;
5760                 next();
5761                 break;
5762             case DoneH:
5763                 tmp = ref().toUInt( &ok, 16 );
5764                 if ( ok ) {
5765                     stringAddC( QChar(tmp) );
5766                 } else {
5767                     d->error = XMLERR_ERRORPARSINGREFERENCE;
5768                     goto parseError;
5769                 }
5770                 charDataRead = TRUE;
5771                 next();
5772                 break;
5773             case DoneN:
5774                 if ( !processReference( charDataRead, context ) )
5775                     goto parseError;
5776                 next();
5777                 break;
5778         }
5779         // no input is read after this
5780         switch ( state ) {
5781             case DoneD:
5782                 return TRUE;
5783             case DoneH:
5784                 return TRUE;
5785             case DoneN:
5786                 return TRUE;
5787             case -1:
5788                 // Error
5789                 d->error = XMLERR_ERRORPARSINGREFERENCE;
5790                 goto parseError;
5791         }
5792
5793     }
5794
5795     return TRUE;
5796
5797 parseError:
5798     reportParseError();
5799     return FALSE;
5800 }
5801
5802 /*!
5803   Helper function for parseReference()
5804 */
5805 bool QXmlSimpleReader::processReference( bool &charDataRead, EntityRecognitionContext context )
5806 {
5807     QString reference = ref();
5808     if ( reference == "amp" ) {
5809         if ( context == InEntityValue ) {
5810             // Bypassed
5811             stringAddC( '&' ); stringAddC( 'a' ); stringAddC( 'm' ); stringAddC( 'p' ); stringAddC( ';' );
5812         } else {
5813             // Included or Included in literal
5814             stringAddC( '&' );
5815         }
5816         charDataRead = TRUE;
5817     } else if ( reference == "lt" ) {
5818         if ( context == InEntityValue ) {
5819             // Bypassed
5820             stringAddC( '&' ); stringAddC( 'l' ); stringAddC( 't' ); stringAddC( ';' );
5821         } else {
5822             // Included or Included in literal
5823             stringAddC( '<' );
5824         }
5825         charDataRead = TRUE;
5826     } else if ( reference == "gt" ) {
5827         if ( context == InEntityValue ) {
5828             // Bypassed
5829             stringAddC( '&' ); stringAddC( 'g' ); stringAddC( 't' ); stringAddC( ';' );
5830         } else {
5831             // Included or Included in literal
5832             stringAddC( '>' );
5833         }
5834         charDataRead = TRUE;
5835     } else if ( reference == "apos" ) {
5836         if ( context == InEntityValue ) {
5837             // Bypassed
5838             stringAddC( '&' ); stringAddC( 'a' ); stringAddC( 'p' ); stringAddC( 'o' ); stringAddC( 's' ); stringAddC( ';' );
5839         } else {
5840             // Included or Included in literal
5841             stringAddC( '\'' );
5842         }
5843         charDataRead = TRUE;
5844     } else if ( reference == "quot" ) {
5845         if ( context == InEntityValue ) {
5846             // Bypassed
5847             stringAddC( '&' ); stringAddC( 'q' ); stringAddC( 'u' ); stringAddC( 'o' ); stringAddC( 't' ); stringAddC( ';' );
5848         } else {
5849             // Included or Included in literal
5850             stringAddC( '"' );
5851         }
5852         charDataRead = TRUE;
5853     } else {
5854         QMap<QString,QString>::Iterator it;
5855         it = d->entities.find( reference );
5856         if ( it != d->entities.end() ) {
5857             // "Internal General"
5858             switch ( context ) {
5859                 case InContent:
5860                     // Included
5861                     xmlRef = it.data() + xmlRef;
5862                     charDataRead = FALSE;
5863                     break;
5864                 case InAttributeValue:
5865                     // Included in literal
5866                     xmlRef = it.data().replace( QRegExp("\""), "&quot;" ).replace( QRegExp("'"), "&apos;" )
5867                         + xmlRef;
5868                     charDataRead = FALSE;
5869                     break;
5870                 case InEntityValue:
5871                     {
5872                         // Bypassed
5873                         stringAddC( '&' );
5874                         for ( int i=0; i<(int)reference.length(); i++ ) {
5875                             stringAddC( reference[i] );
5876                         }
5877                         stringAddC( ';');
5878                         charDataRead = TRUE;
5879                     }
5880                     break;
5881                 case InDTD:
5882                     // Forbidden
5883                     d->error = XMLERR_INTERNALGENERALENTITYINDTD;
5884                     charDataRead = FALSE;
5885                     break;
5886             }
5887         } else {
5888             QMap<QString,QXmlSimpleReaderPrivate::ExternEntity>::Iterator itExtern;
5889             itExtern = d->externEntities.find( reference );
5890             if ( itExtern == d->externEntities.end() ) {
5891                 // entity not declared
5892                 // ### check this case for conformance
5893                 if ( context == InEntityValue ) {
5894                     // Bypassed
5895                     stringAddC( '&' );
5896                     for ( int i=0; i<(int)reference.length(); i++ ) {
5897                         stringAddC( reference[i] );
5898                     }
5899                     stringAddC( ';');
5900                     charDataRead = TRUE;
5901                 } else {
5902                     if ( contentHnd ) {
5903                         if ( !contentHnd->skippedEntity( reference ) ) {
5904                             d->error = contentHnd->errorString();
5905                             return FALSE; // error
5906                         }
5907                     }
5908                 }
5909             } else if ( (*itExtern).notation.isNull() ) {
5910                 // "External Parsed General"
5911                 switch ( context ) {
5912                     case InContent:
5913                         // Included if validating
5914                         if ( contentHnd ) {
5915                             if ( !contentHnd->skippedEntity( reference ) ) {
5916                                 d->error = contentHnd->errorString();
5917                                 return FALSE; // error
5918                             }
5919                         }
5920                         charDataRead = FALSE;
5921                         break;
5922                     case InAttributeValue:
5923                         // Forbidden
5924                         d->error = XMLERR_EXTERNALGENERALENTITYINAV;
5925                         charDataRead = FALSE;
5926                         break;
5927                     case InEntityValue:
5928                         {
5929                             // Bypassed
5930                             stringAddC( '&' );
5931                             for ( int i=0; i<(int)reference.length(); i++ ) {
5932                                 stringAddC( reference[i] );
5933                             }
5934                             stringAddC( ';');
5935                             charDataRead = TRUE;
5936                         }
5937                         break;
5938                     case InDTD:
5939                         // Forbidden
5940                         d->error = XMLERR_EXTERNALGENERALENTITYINDTD;
5941                         charDataRead = FALSE;
5942                         break;
5943                 }
5944             } else {
5945                 // "Unparsed"
5946                 // ### notify for "Occurs as Attribute Value" missing (but this is no reference, anyway)
5947                 // Forbidden
5948                 d->error = XMLERR_UNPARSEDENTITYREFERENCE;
5949                 charDataRead = FALSE;
5950                 return FALSE; // error
5951             }
5952         }
5953     }
5954     return TRUE; // no error
5955 }
5956
5957
5958 /*!
5959   Parse over a simple string.
5960
5961   After the string was successfully parsed, the head is on the first
5962   character after the string.
5963 */
5964 bool QXmlSimpleReader::parseString( const QString& s )
5965 {
5966     signed char Done                   = s.length();
5967
5968     const signed char InpCharExpected  = 0; // the character that was expected
5969     const signed char InpUnknown       = 1;
5970
5971     signed char state = 0; // state in this function is the position in the string s
5972     signed char input;
5973
5974     while ( TRUE ) {
5975
5976         // get input
5977         if ( atEnd() ) {
5978             d->error = XMLERR_UNEXPECTEDEOF;
5979             goto parseError;
5980         }
5981         if ( c == s[(int)state] ) {
5982             input = InpCharExpected;
5983         } else {
5984             input = InpUnknown;
5985         }
5986
5987         // set state according to input
5988         if ( input == InpCharExpected ) {
5989             state++;
5990         } else {
5991             // Error
5992             d->error = XMLERR_UNEXPECTEDCHARACTER;
5993             goto parseError;
5994         }
5995
5996         // do some actions according to state
5997         next();
5998         // no input is read after this
5999         if ( state == Done ) {
6000             return TRUE;
6001         }
6002
6003     }
6004
6005     return TRUE;
6006
6007 parseError:
6008     reportParseError();
6009     return FALSE;
6010 }
6011
6012
6013 /*!
6014   Inits the data values.
6015 */
6016 void QXmlSimpleReader::init( const QXmlInputSource& i )
6017 {
6018     xml = i.data();
6019     xmlLength = xml.length();
6020     xmlRef = "";
6021
6022     d->externParameterEntities.clear();
6023     d->parameterEntities.clear();
6024     d->externEntities.clear();
6025     d->entities.clear();
6026
6027     tags.clear();
6028
6029     d->doctype = "";
6030     d->xmlVersion = "";
6031     d->encoding = "";
6032     d->standalone = QXmlSimpleReaderPrivate::Unknown;
6033
6034     lineNr = 0;
6035     columnNr = -1;
6036     pos = 0;
6037     next();
6038     d->error = XMLERR_OK;
6039 }
6040
6041 /*!
6042   Returns TRUE if a entity with the name \a e exists,
6043   otherwise returns FALSE.
6044 */
6045 bool QXmlSimpleReader::entityExist( const QString& e ) const
6046 {
6047     if (  d->parameterEntities.find(e) == d->parameterEntities.end() &&
6048             d->externParameterEntities.find(e) == d->externParameterEntities.end() ) {
6049         return FALSE;
6050     } else {
6051         return TRUE;
6052     }
6053 }
6054
6055 void QXmlSimpleReader::reportParseError()
6056 {
6057     if ( errorHnd )
6058         errorHnd->fatalError( QXmlParseException( d->error, columnNr+1, lineNr+1 ) );
6059 }
6060
6061 #endif //QT_NO_XML