~ubuntu-branches/ubuntu/jaunty/psi/jaunty

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

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<qptrlist.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
                QPtrList<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
}