Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members  

ElementStream.cpp

00001 //============================================================================
00002 // Project:       Jabber Universal Document Objects (Judo)
00003 // Filename:      ElementStream.cpp
00004 // Description:   Expat parsing wrapper
00005 // Created at:    Fri Jun 29 13:13:09 2001
00006 // Modified at:   Mon Jul 30 18:10:20 2001
00007 // 
00008 //   License:
00009 // 
00010 // The contents of this file are subject to the Jabber Open Source License
00011 // Version 1.0 (the "License").  You may not copy or use this file, in either
00012 // source code or executable form, except in compliance with the License.  You
00013 // may obtain a copy of the License at http://www.jabber.com/license/ or at
00014 // http://www.opensource.org/.  
00015 //
00016 // Software distributed under the License is distributed on an "AS IS" basis,
00017 // WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
00018 // for the specific language governing rights and limitations under the
00019 // License.
00020 //
00021 //   Copyrights
00022 //
00023 // Portions created by or assigned to Jabber.com, Inc. are 
00024 // Copyright (c) 1999-2001 Jabber.com, Inc.  All Rights Reserved.  
00025 // 
00026 // $Id: ElementStream.cpp,v 1.2 2002/07/13 19:30:19 temas Exp $
00027 //============================================================================
00028 
00029 #include "judo.hpp"
00030 using namespace judo;
00031 using namespace std;
00032 
00033 
00034 ElementStream::ElementStream(ElementStreamEventListener* l)
00035     : _parser_ready(false), _event_listener(l)
00036 {
00037     reset();
00038 }
00039 
00040 ElementStream::~ElementStream()
00041 {
00042     XML_ParserFree(_parser);
00043 }
00044 
00050 void ElementStream::push(const char* data, int datasz)
00051 {
00052     assert(_document_ended != true);
00053     if (!XML_Parse(_parser, data, datasz, 0))
00054     {
00055         throw exception::ParserError(XML_GetErrorCode(_parser));
00056     }
00057 }
00058 
00062 void ElementStream::reset()
00063 {
00064     // Reset status flags
00065     _document_started = false;
00066     _document_ended = false;
00067 
00068     // Release the current parser and create
00069     // a new one
00070     if (_parser_ready)
00071         XML_ParserFree(_parser);
00072     _parser = XML_ParserCreate(NULL);
00073     _parser_ready = true;
00074     
00075     // Setup callbacks
00076     XML_SetUserData(_parser, this);
00077     XML_SetElementHandler(_parser, &ElementStream::onStartElement, 
00078                           &ElementStream::onEndElement);
00079     XML_SetCharacterDataHandler(_parser, &ElementStream::onCDATA);
00080 }
00081 
00082 void ElementStream::onStartElement(void* userdata, const char* name, const char** attribs)
00083 {
00084     ElementStream* ts = (ElementStream*)userdata;
00085 
00086     // If the document has started..
00087     if (ts->_document_started)
00088     {
00089         if (!ts->_element_stack.empty())
00090             ts->_element_stack.push_back(ts->_element_stack.back()->addElement(name, attribs));
00091         else
00092             ts->_element_stack.push_back(new Element(name, attribs));
00093     }
00094     // Document hasn't started; we need to generate a document start
00095     // event
00096     else
00097     {
00098         Element* root = new Element(name, attribs);
00099         ts->_document_started = true;
00100         ts->_event_listener->onDocumentStart(root);     
00101     }
00102 }
00103 
00104 void ElementStream::onEndElement(void* userdata, const char* name)
00105 {
00106     ElementStream* ts = (ElementStream*)userdata;
00107 
00108     switch (ts->_element_stack.size())
00109     {
00110         // Only one remaining element on the stack; thus we must be
00111         // closing the packet-level element
00112     case 1:
00113         ts->_event_listener->onElement(ts->_element_stack.back());
00114         ts->_element_stack.pop_back();
00115         break;
00116         // No packet-level elements currently being built; thus the
00117         // document must be closing
00118     case 0:
00119         ts->_event_listener->onDocumentEnd();
00120         ts->_document_ended = true;
00121         break;
00122     default:
00123         ts->_element_stack.pop_back();
00124     }
00125 }
00126 
00127 void ElementStream::onCDATA(void* userdata, const char* cdata, int cdatasz)
00128 {
00129     ElementStream* ts = (ElementStream*)userdata;
00130 
00131     if (!ts->_element_stack.empty())
00132         ts->_element_stack.back()->addCDATA(cdata, cdatasz, true);
00133     else
00134         ts->_event_listener->onCDATA(new CDATA(cdata, cdatasz, true));
00135 }
00136 
00137 
00138 class BufferParser
00139     : public ElementStreamEventListener
00140 {
00141 public:
00142     BufferParser()
00143         : _finished(false), _root(NULL), _stream(this)
00144         {}
00145     ~BufferParser()
00146         { 
00147             if (!_finished && _root != NULL)
00148                 delete _root;
00149         }
00150     Element* process(const char* data)
00151         {
00152             _stream.push(data, strlen(data));
00153             if (!_finished)
00154                 throw ElementStream::exception::IncompleteParse();
00155             return _root;
00156         }
00157     void onDocumentStart(Element* t)
00158         { _root = t; }
00159     void onElement(Element* t)
00160         { _root->appendChild(t); }
00161     void onCDATA(CDATA* c)
00162         { _root->appendChild(c); }
00163     void onDocumentEnd()
00164         { _finished = true; }
00165     bool isFinished()
00166         { return _finished; }
00167 private:
00168     bool _finished;
00169     Element* _root;
00170     ElementStream _stream;
00171 };
00172 
00176 Element* ElementStream::parseAtOnce(const char* data)
00177 {
00178     BufferParser p;
00179     return p.process(data);
00180 }
00181 

Generated on Thu Jul 24 13:31:50 2003 for jabberoo by doxygen1.3-rc3