~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to iris/xmpp-core/parser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * parser.cpp - parse an XMPP "document"
3
 
 * Copyright (C) 2003  Justin Karneges
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 *
19
 
 */
20
 
 
21
 
/*
22
 
  TODO:
23
 
 
24
 
  For XMPP::Parser to be "perfect", some things must be solved/changed in the
25
 
  Qt library:
26
 
 
27
 
  - Fix weird QDomElement::haveAttributeNS() bug (patch submitted to
28
 
    Trolltech on Aug 31st, 2003).
29
 
  - Fix weird behavior in QXmlSimpleReader of reporting endElement() when
30
 
    the '/' character of a self-closing tag is reached, instead of when
31
 
    the final '>' is reached.
32
 
  - Fix incremental parsing bugs in QXmlSimpleReader.  At the moment, the
33
 
    only bug I've found is related to attribute parsing, but there might
34
 
    be more (search for '###' in $QTDIR/src/xml/qxml.cpp).
35
 
 
36
 
  We have workarounds for all of the above problems in the code below.
37
 
 
38
 
  - Deal with the <?xml?> processing instruction as an event type, so that we
39
 
    can feed it back to the application properly.  Right now it is completely
40
 
    untrackable and is simply tacked into the first event's actualString.  We
41
 
    can't easily do this because QXmlSimpleReader eats an extra byte beyond
42
 
    the processing instruction before reporting it.
43
 
 
44
 
  - Make QXmlInputSource capable of accepting data incrementally, to ensure
45
 
    proper text encoding detection and processing over a network.  This is
46
 
    technically not a bug, as we have our own subclass below to do it, but
47
 
    it would be nice if Qt had this already.
48
 
*/
49
 
 
50
 
#include "parser.h"
51
 
 
52
 
#include <qtextcodec.h>
53
 
#include <q3ptrlist.h>
54
 
#include <string.h>
55
 
 
56
 
using namespace XMPP;
57
 
 
58
 
static bool qt_bug_check = false;
59
 
static bool qt_bug_have;
60
 
 
61
 
//----------------------------------------------------------------------------
62
 
// StreamInput
63
 
//----------------------------------------------------------------------------
64
 
class StreamInput : public QXmlInputSource
65
 
{
66
 
public:
67
 
        StreamInput()
68
 
        {
69
 
                dec = 0;
70
 
                reset();
71
 
        }
72
 
 
73
 
        ~StreamInput()
74
 
        {
75
 
                delete dec;
76
 
        }
77
 
 
78
 
        void reset()
79
 
        {
80
 
                delete dec;
81
 
                dec = 0;
82
 
                in.resize(0);
83
 
                out = "";
84
 
                at = 0;
85
 
                paused = false;
86
 
                mightChangeEncoding = true;
87
 
                checkBad = true;
88
 
                last = QChar();
89
 
                v_encoding = "";
90
 
                resetLastData();
91
 
        }
92
 
 
93
 
        void resetLastData()
94
 
        {
95
 
                last_string = "";
96
 
        }
97
 
 
98
 
        QString lastString() const
99
 
        {
100
 
                return last_string;
101
 
        }
102
 
 
103
 
        void appendData(const QByteArray &a)
104
 
        {
105
 
                int oldsize = in.size();
106
 
                in.resize(oldsize + a.size());
107
 
                memcpy(in.data() + oldsize, a.data(), a.size());
108
 
                processBuf();
109
 
        }
110
 
 
111
 
        QChar lastRead()
112
 
        {
113
 
                return last;
114
 
        }
115
 
 
116
 
        QChar next()
117
 
        {
118
 
                if(paused)
119
 
                        return EndOfData;
120
 
                else
121
 
                        return readNext();
122
 
        }
123
 
 
124
 
        // NOTE: setting 'peek' to true allows the same char to be read again,
125
 
        //       however this still advances the internal byte processing.
126
 
        QChar readNext(bool peek=false)
127
 
        {
128
 
                QChar c;
129
 
                if(mightChangeEncoding)
130
 
                        c = EndOfData;
131
 
                else {
132
 
                        if(out.isEmpty()) {
133
 
                                QString s;
134
 
                                if(!tryExtractPart(&s))
135
 
                                        c = EndOfData;
136
 
                                else {
137
 
                                        out = s;
138
 
                                        c = out[0];
139
 
                                }
140
 
                        }
141
 
                        else
142
 
                                c = out[0];
143
 
                        if(!peek)
144
 
                                out.remove(0, 1);
145
 
                }
146
 
                if(c == EndOfData) {
147
 
#ifdef XMPP_PARSER_DEBUG
148
 
                        printf("next() = EOD\n");
149
 
#endif
150
 
                }
151
 
                else {
152
 
#ifdef XMPP_PARSER_DEBUG
153
 
                        printf("next() = [%c]\n", c.latin1());
154
 
#endif
155
 
                        last = c;
156
 
                }
157
 
 
158
 
                return c;
159
 
        }
160
 
 
161
 
        QByteArray unprocessed() const
162
 
        {
163
 
                QByteArray a(in.size() - at);
164
 
                memcpy(a.data(), in.data() + at, a.size());
165
 
                return a;
166
 
        }
167
 
 
168
 
        void pause(bool b)
169
 
        {
170
 
                paused = b;
171
 
        }
172
 
 
173
 
        bool isPaused()
174
 
        {
175
 
                return paused;
176
 
        }
177
 
 
178
 
        QString encoding() const
179
 
        {
180
 
                return v_encoding;
181
 
        }
182
 
 
183
 
private:
184
 
        QTextDecoder *dec;
185
 
        QByteArray in;
186
 
        QString out;
187
 
        int at;
188
 
        bool paused;
189
 
        bool mightChangeEncoding;
190
 
        QChar last;
191
 
        QString v_encoding;
192
 
        QString last_string;
193
 
        bool checkBad;
194
 
 
195
 
        void processBuf()
196
 
        {
197
 
#ifdef XMPP_PARSER_DEBUG
198
 
                printf("processing.  size=%d, at=%d\n", in.size(), at);
199
 
#endif
200
 
                if(!dec) {
201
 
                        QTextCodec *codec = 0;
202
 
                        uchar *p = (uchar *)in.data() + at;
203
 
                        int size = in.size() - at;
204
 
 
205
 
                        // do we have enough information to determine the encoding?
206
 
                        if(size == 0)
207
 
                                return;
208
 
                        bool utf16 = false;
209
 
                        if(p[0] == 0xfe || p[0] == 0xff) {
210
 
                                // probably going to be a UTF-16 byte order mark
211
 
                                if(size < 2)
212
 
                                        return;
213
 
                                if((p[0] == 0xfe && p[1] == 0xff) || (p[0] == 0xff && p[1] == 0xfe)) {
214
 
                                        // ok it is UTF-16
215
 
                                        utf16 = true;
216
 
                                }
217
 
                        }
218
 
                        if(utf16)
219
 
                                codec = QTextCodec::codecForMib(1000); // UTF-16
220
 
                        else
221
 
                                codec = QTextCodec::codecForMib(106); // UTF-8
222
 
 
223
 
                        v_encoding = codec->name();
224
 
                        dec = codec->makeDecoder();
225
 
 
226
 
                        // for utf16, put in the byte order mark
227
 
                        if(utf16) {
228
 
                                out += dec->toUnicode((const char *)p, 2);
229
 
                                at += 2;
230
 
                        }
231
 
                }
232
 
 
233
 
                if(mightChangeEncoding) {
234
 
                        while(1) {
235
 
                                int n = out.find('<');
236
 
                                if(n != -1) {
237
 
                                        // we need a closing bracket
238
 
                                        int n2 = out.find('>', n);
239
 
                                        if(n2 != -1) {
240
 
                                                ++n2;
241
 
                                                QString h = out.mid(n, n2-n);
242
 
                                                QString enc = processXmlHeader(h);
243
 
                                                QTextCodec *codec = 0;
244
 
                                                if(!enc.isEmpty())
245
 
                                                        codec = QTextCodec::codecForName(enc.latin1());
246
 
 
247
 
                                                // changing codecs
248
 
                                                if(codec) {
249
 
                                                        v_encoding = codec->name();
250
 
                                                        delete dec;
251
 
                                                        dec = codec->makeDecoder();
252
 
                                                }
253
 
                                                mightChangeEncoding = false;
254
 
                                                out.truncate(0);
255
 
                                                at = 0;
256
 
                                                resetLastData();
257
 
                                                break;
258
 
                                        }
259
 
                                }
260
 
                                QString s;
261
 
                                if(!tryExtractPart(&s))
262
 
                                        break;
263
 
                                if(checkBad && checkForBadChars(s)) {
264
 
                                        // go to the parser
265
 
                                        mightChangeEncoding = false;
266
 
                                        out.truncate(0);
267
 
                                        at = 0;
268
 
                                        resetLastData();
269
 
                                        break;
270
 
                                }
271
 
                                out += s;
272
 
                        }
273
 
                }
274
 
        }
275
 
 
276
 
        QString processXmlHeader(const QString &h)
277
 
        {
278
 
                if(h.left(5) != "<?xml")
279
 
                        return "";
280
 
 
281
 
                int endPos = h.find(">");
282
 
                int startPos = h.find("encoding");
283
 
                if(startPos < endPos && startPos != -1) {
284
 
                        QString encoding;
285
 
                        do {
286
 
                                startPos++;
287
 
                                if(startPos > endPos) {
288
 
                                        return "";
289
 
                                }
290
 
                        } while(h[startPos] != '"' && h[startPos] != '\'');
291
 
                        startPos++;
292
 
                        while(h[startPos] != '"' && h[startPos] != '\'') {
293
 
                                encoding += h[startPos];
294
 
                                startPos++;
295
 
                                if(startPos > endPos) {
296
 
                                        return "";
297
 
                                }
298
 
                        }
299
 
                        return encoding;
300
 
                }
301
 
                else
302
 
                        return "";
303
 
        }
304
 
 
305
 
        bool tryExtractPart(QString *s)
306
 
        {
307
 
                int size = in.size() - at;
308
 
                if(size == 0)
309
 
                        return false;
310
 
                uchar *p = (uchar *)in.data() + at;
311
 
                QString nextChars;
312
 
                while(1) {
313
 
                        nextChars = dec->toUnicode((const char *)p, 1);
314
 
                        ++p;
315
 
                        ++at;
316
 
                        if(!nextChars.isEmpty())
317
 
                                break;
318
 
                        if(at == (int)in.size())
319
 
                                return false;
320
 
                }
321
 
                last_string += nextChars;
322
 
                *s = nextChars;
323
 
 
324
 
                // free processed data?
325
 
                if(at >= 1024) {
326
 
                        char *p = in.data();
327
 
                        int size = in.size() - at;
328
 
                        memmove(p, p + at, size);
329
 
                        in.resize(size);
330
 
                        at = 0;
331
 
                }
332
 
 
333
 
                return true;
334
 
        }
335
 
 
336
 
        bool checkForBadChars(const QString &s)
337
 
        {
338
 
                int len = s.find('<');
339
 
                if(len == -1)
340
 
                        len = s.length();
341
 
                else
342
 
                        checkBad = false;
343
 
                for(int n = 0; n < len; ++n) {
344
 
                        if(!s.at(n).isSpace())
345
 
                                return true;
346
 
                }
347
 
                return false;
348
 
        }
349
 
};
350
 
 
351
 
 
352
 
//----------------------------------------------------------------------------
353
 
// ParserHandler
354
 
//----------------------------------------------------------------------------
355
 
namespace XMPP
356
 
{
357
 
        class ParserHandler : public QXmlDefaultHandler
358
 
        {
359
 
        public:
360
 
                ParserHandler(StreamInput *_in, QDomDocument *_doc)
361
 
                {
362
 
                        in = _in;
363
 
                        doc = _doc;
364
 
                        needMore = false;
365
 
                }
366
 
 
367
 
                ~ParserHandler()
368
 
                {
369
 
                        eventList.setAutoDelete(true);
370
 
                        eventList.clear();
371
 
                }
372
 
 
373
 
                bool startDocument()
374
 
                {
375
 
                        depth = 0;
376
 
                        return true;
377
 
                }
378
 
 
379
 
                bool endDocument()
380
 
                {
381
 
                        return true;
382
 
                }
383
 
 
384
 
                bool startPrefixMapping(const QString &prefix, const QString &uri)
385
 
                {
386
 
                        if(depth == 0) {
387
 
                                nsnames += prefix;
388
 
                                nsvalues += uri;
389
 
                        }
390
 
                        return true;
391
 
                }
392
 
 
393
 
                bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
394
 
                {
395
 
                        if(depth == 0) {
396
 
                                Parser::Event *e = new Parser::Event;
397
 
                                QXmlAttributes a;
398
 
                                for(int n = 0; n < atts.length(); ++n) {
399
 
                                        QString uri = atts.uri(n);
400
 
                                        QString ln = atts.localName(n);
401
 
                                        if(a.index(uri, ln) == -1)
402
 
                                                a.append(atts.qName(n), uri, ln, atts.value(n));
403
 
                                }
404
 
                                e->setDocumentOpen(namespaceURI, localName, qName, a, nsnames, nsvalues);
405
 
                                nsnames.clear();
406
 
                                nsvalues.clear();
407
 
                                e->setActualString(in->lastString());
408
 
 
409
 
                                in->resetLastData();
410
 
                                eventList.append(e);
411
 
                                in->pause(true);
412
 
                        }
413
 
                        else {
414
 
                                QDomElement e = doc->createElementNS(namespaceURI, qName);
415
 
                                for(int n = 0; n < atts.length(); ++n) {
416
 
                                        QString uri = atts.uri(n);
417
 
                                        QString ln = atts.localName(n);
418
 
                                        bool have;
419
 
                                        if(!uri.isEmpty()) {
420
 
                                                have = e.hasAttributeNS(uri, ln);
421
 
                                                if(qt_bug_have)
422
 
                                                        have = !have;
423
 
                                        }
424
 
                                        else
425
 
                                                have = e.hasAttribute(ln);
426
 
                                        if(!have)
427
 
                                                e.setAttributeNS(uri, atts.qName(n), atts.value(n));
428
 
                                }
429
 
 
430
 
                                if(depth == 1) {
431
 
                                        elem = e;
432
 
                                        current = e;
433
 
                                }
434
 
                                else {
435
 
                                        current.appendChild(e);
436
 
                                        current = e;
437
 
                                }
438
 
                        }
439
 
                        ++depth;
440
 
                        return true;
441
 
                }
442
 
 
443
 
                bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
444
 
                {
445
 
                        --depth;
446
 
                        if(depth == 0) {
447
 
                                Parser::Event *e = new Parser::Event;
448
 
                                e->setDocumentClose(namespaceURI, localName, qName);
449
 
                                e->setActualString(in->lastString());
450
 
                                in->resetLastData();
451
 
                                eventList.append(e);
452
 
                                in->pause(true);
453
 
                        }
454
 
                        else {
455
 
                                // done with a depth 1 element?
456
 
                                if(depth == 1) {
457
 
                                        Parser::Event *e = new Parser::Event;
458
 
                                        e->setElement(elem);
459
 
                                        e->setActualString(in->lastString());
460
 
                                        in->resetLastData();
461
 
                                        eventList.append(e);
462
 
                                        in->pause(true);
463
 
 
464
 
                                        elem = QDomElement();
465
 
                                        current = QDomElement();
466
 
                                }
467
 
                                else
468
 
                                        current = current.parentNode().toElement();
469
 
                        }
470
 
 
471
 
                        if(in->lastRead() == '/')
472
 
                                checkNeedMore();
473
 
 
474
 
                        return true;
475
 
                }
476
 
 
477
 
                bool characters(const QString &str)
478
 
                {
479
 
                        if(depth >= 1) {
480
 
                                QString content = str;
481
 
                                if(content.isEmpty())
482
 
                                        return true;
483
 
 
484
 
                                if(!current.isNull()) {
485
 
                                        QDomText text = doc->createTextNode(content);
486
 
                                        current.appendChild(text);
487
 
                                }
488
 
                        }
489
 
                        return true;
490
 
                }
491
 
 
492
 
                /*bool processingInstruction(const QString &target, const QString &data)
493
 
                {
494
 
                        printf("Processing: [%s], [%s]\n", target.latin1(), data.latin1());
495
 
                        in->resetLastData();
496
 
                        return true;
497
 
                }*/
498
 
 
499
 
                void checkNeedMore()
500
 
                {
501
 
                        // Here we will work around QXmlSimpleReader strangeness and self-closing tags.
502
 
                        // The problem is that endElement() is called when the '/' is read, not when
503
 
                        // the final '>' is read.  This is a potential problem when obtaining unprocessed
504
 
                        // bytes from StreamInput after this event, as the '>' character will end up
505
 
                        // in the unprocessed chunk.  To work around this, we need to advance StreamInput's
506
 
                        // internal byte processing, but not the xml character data.  This way, the '>'
507
 
                        // will get processed and will no longer be in the unprocessed return, but
508
 
                        // QXmlSimpleReader can still read it.  To do this, we call StreamInput::readNext
509
 
                        // with 'peek' mode.
510
 
                        QChar c = in->readNext(true); // peek
511
 
                        if(c == QXmlInputSource::EndOfData) {
512
 
                                needMore = true;
513
 
                        }
514
 
                        else {
515
 
                                // We'll assume the next char is a '>'.  If it isn't, then
516
 
                                // QXmlSimpleReader will deal with that problem on the next
517
 
                                // parse.  We don't need to take any action here.
518
 
                                needMore = false;
519
 
 
520
 
                                // there should have been a pending event
521
 
                                Parser::Event *e = eventList.getFirst();
522
 
                                if(e) {
523
 
                                        e->setActualString(e->actualString() + '>');
524
 
                                        in->resetLastData();
525
 
                                }
526
 
                        }
527
 
                }
528
 
 
529
 
                Parser::Event *takeEvent()
530
 
                {
531
 
                        if(needMore)
532
 
                                return 0;
533
 
                        if(eventList.isEmpty())
534
 
                                return 0;
535
 
 
536
 
                        Parser::Event *e = eventList.getFirst();
537
 
                        eventList.removeRef(e);
538
 
                        in->pause(false);
539
 
                        return e;
540
 
                }
541
 
 
542
 
                StreamInput *in;
543
 
                QDomDocument *doc;
544
 
                int depth;
545
 
                QStringList nsnames, nsvalues;
546
 
                QDomElement elem, current;
547
 
                Q3PtrList<Parser::Event> eventList;
548
 
                bool needMore;
549
 
        };
550
 
};
551
 
 
552
 
 
553
 
//----------------------------------------------------------------------------
554
 
// Event
555
 
//----------------------------------------------------------------------------
556
 
class Parser::Event::Private
557
 
{
558
 
public:
559
 
        int type;
560
 
        QString ns, ln, qn;
561
 
        QXmlAttributes a;
562
 
        QDomElement e;
563
 
        QString str;
564
 
        QStringList nsnames, nsvalues;
565
 
};
566
 
 
567
 
Parser::Event::Event()
568
 
{
569
 
        d = 0;
570
 
}
571
 
 
572
 
Parser::Event::Event(const Event &from)
573
 
{
574
 
        d = 0;
575
 
        *this = from;
576
 
}
577
 
 
578
 
Parser::Event & Parser::Event::operator=(const Event &from)
579
 
{
580
 
        delete d;
581
 
        d = 0;
582
 
        if(from.d)
583
 
                d = new Private(*from.d);
584
 
        return *this;
585
 
}
586
 
 
587
 
Parser::Event::~Event()
588
 
{
589
 
        delete d;
590
 
}
591
 
 
592
 
bool Parser::Event::isNull() const
593
 
{
594
 
        return (d ? false: true);
595
 
}
596
 
 
597
 
int Parser::Event::type() const
598
 
{
599
 
        if(isNull())
600
 
                return -1;
601
 
        return d->type;
602
 
}
603
 
 
604
 
QString Parser::Event::nsprefix(const QString &s) const
605
 
{
606
 
        QStringList::ConstIterator it = d->nsnames.begin();
607
 
        QStringList::ConstIterator it2 = d->nsvalues.begin();
608
 
        for(; it != d->nsnames.end(); ++it) {
609
 
                if((*it) == s)
610
 
                        return (*it2);
611
 
                ++it2;
612
 
        }
613
 
        return QString::null;
614
 
}
615
 
 
616
 
QString Parser::Event::namespaceURI() const
617
 
{
618
 
        return d->ns;
619
 
}
620
 
 
621
 
QString Parser::Event::localName() const
622
 
{
623
 
        return d->ln;
624
 
}
625
 
 
626
 
QString Parser::Event::qName() const
627
 
{
628
 
        return d->qn;
629
 
}
630
 
 
631
 
QXmlAttributes Parser::Event::atts() const
632
 
{
633
 
        return d->a;
634
 
}
635
 
 
636
 
QString Parser::Event::actualString() const
637
 
{
638
 
        return d->str;
639
 
}
640
 
 
641
 
QDomElement Parser::Event::element() const
642
 
{
643
 
        return d->e;
644
 
}
645
 
 
646
 
void Parser::Event::setDocumentOpen(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts, const QStringList &nsnames, const QStringList &nsvalues)
647
 
{
648
 
        if(!d)
649
 
                d = new Private;
650
 
        d->type = DocumentOpen;
651
 
        d->ns = namespaceURI;
652
 
        d->ln = localName;
653
 
        d->qn = qName;
654
 
        d->a = atts;
655
 
        d->nsnames = nsnames;
656
 
        d->nsvalues = nsvalues;
657
 
}
658
 
 
659
 
void Parser::Event::setDocumentClose(const QString &namespaceURI, const QString &localName, const QString &qName)
660
 
{
661
 
        if(!d)
662
 
                d = new Private;
663
 
        d->type = DocumentClose;
664
 
        d->ns = namespaceURI;
665
 
        d->ln = localName;
666
 
        d->qn = qName;
667
 
}
668
 
 
669
 
void Parser::Event::setElement(const QDomElement &elem)
670
 
{
671
 
        if(!d)
672
 
                d = new Private;
673
 
        d->type = Element;
674
 
        d->e = elem;
675
 
}
676
 
 
677
 
void Parser::Event::setError()
678
 
{
679
 
        if(!d)
680
 
                d = new Private;
681
 
        d->type = Error;
682
 
}
683
 
 
684
 
void Parser::Event::setActualString(const QString &str)
685
 
{
686
 
        d->str = str;
687
 
}
688
 
 
689
 
//----------------------------------------------------------------------------
690
 
// Parser
691
 
//----------------------------------------------------------------------------
692
 
class Parser::Private
693
 
{
694
 
public:
695
 
        Private()
696
 
        {
697
 
                doc = 0;
698
 
                in = 0;
699
 
                handler = 0;
700
 
                reader = 0;
701
 
                reset();
702
 
        }
703
 
 
704
 
        ~Private()
705
 
        {
706
 
                reset(false);
707
 
        }
708
 
 
709
 
        void reset(bool create=true)
710
 
        {
711
 
                delete reader;
712
 
                delete handler;
713
 
                delete in;
714
 
                delete doc;
715
 
 
716
 
                if(create) {
717
 
                        doc = new QDomDocument;
718
 
                        in = new StreamInput;
719
 
                        handler = new ParserHandler(in, doc);
720
 
                        reader = new QXmlSimpleReader;
721
 
                        reader->setContentHandler(handler);
722
 
 
723
 
                        // initialize the reader
724
 
                        in->pause(true);
725
 
                        reader->parse(in, true);
726
 
                        in->pause(false);
727
 
                }
728
 
        }
729
 
 
730
 
        QDomDocument *doc;
731
 
        StreamInput *in;
732
 
        ParserHandler *handler;
733
 
        QXmlSimpleReader *reader;
734
 
};
735
 
 
736
 
Parser::Parser()
737
 
{
738
 
        d = new Private;
739
 
 
740
 
        // check for evil bug in Qt <= 3.2.1
741
 
        if(!qt_bug_check) {
742
 
                qt_bug_check = true;
743
 
                QDomElement e = d->doc->createElementNS("someuri", "somename");
744
 
                if(e.hasAttributeNS("someuri", "somename"))
745
 
                        qt_bug_have = true;
746
 
                else
747
 
                        qt_bug_have = false;
748
 
        }
749
 
}
750
 
 
751
 
Parser::~Parser()
752
 
{
753
 
        delete d;
754
 
}
755
 
 
756
 
void Parser::reset()
757
 
{
758
 
        d->reset();
759
 
}
760
 
 
761
 
void Parser::appendData(const QByteArray &a)
762
 
{
763
 
        d->in->appendData(a);
764
 
 
765
 
        // if handler was waiting for more, give it a kick
766
 
        if(d->handler->needMore)
767
 
                d->handler->checkNeedMore();
768
 
}
769
 
 
770
 
Parser::Event Parser::readNext()
771
 
{
772
 
        Event e;
773
 
        if(d->handler->needMore)
774
 
                return e;
775
 
        Event *ep = d->handler->takeEvent();
776
 
        if(!ep) {
777
 
                if(!d->reader->parseContinue()) {
778
 
                        e.setError();
779
 
                        return e;
780
 
                }
781
 
                ep = d->handler->takeEvent();
782
 
                if(!ep)
783
 
                        return e;
784
 
        }
785
 
        e = *ep;
786
 
        delete ep;
787
 
        return e;
788
 
}
789
 
 
790
 
QByteArray Parser::unprocessed() const
791
 
{
792
 
        return d->in->unprocessed();
793
 
}
794
 
 
795
 
QString Parser::encoding() const
796
 
{
797
 
        return d->in->encoding();
798
 
}