~ubuntu-branches/debian/stretch/openbabel/stretch

« back to all changes in this revision

Viewing changes to src/formats/xml/xml.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Banck
  • Date: 2008-07-22 23:54:58 UTC
  • mfrom: (3.1.10 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080722235458-3o606czluviz4akx
Tags: 2.2.0-2
* Upload to unstable.
* debian/control: Updated descriptions.
* debian/patches/gauss_cube_format.patch: New patch, makes the 
  gaussian cube format available again.
* debian/rules (DEB_DH_MAKESHLIBS_ARGS_libopenbabel3): Removed.
* debian/rules (DEB_CONFIGURE_EXTRA_FLAGS): Likewise.
* debian/libopenbabel3.install: Adjust formats directory to single 
  version hierarchy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
GNU General Public License for more details.
13
13
***********************************************************************/
14
 
 
15
 
#include "xml.h"
 
14
#include <openbabel/babelconfig.h>
 
15
#include <openbabel/xml.h>
16
16
 
17
17
using namespace std;
18
18
namespace OpenBabel
19
19
{
20
20
 
21
 
//static variable
22
 
XMLBaseFormat* XMLConversion::_pDefault=NULL;
23
 
 
24
 
XMLConversion::XMLConversion(OBConversion* pConv)
25
 
                : OBConversion(*pConv), _reader(NULL), _writer(NULL),
26
 
                _LookingForNamespace(false),_SkipNextRead(false),
27
 
                  _lastpos(0), _requestedpos(0)
28
 
{
29
 
        _pConv = pConv;
30
 
        pConv->SetAuxConv(this);//marks original OBConversion object as having been extended 
31
 
        SetAuxConv(this);//marks this new object as extended (for use with OBConversion pointer)
32
 
}
33
 
 
34
 
bool XMLConversion::SetupReader()
35
 
{
36
 
        if(_reader)
37
 
                return true; //do not need to make a new reader
38
 
 
39
 
        //If the inputstream is not at the start (probably arising in fastsearch),
40
 
        //save its position and rewind so that the reader initialization is ok.
41
 
        //(Getting the requested object is handled in ReadXML(), when the format is known.) 
42
 
        _requestedpos = GetInStream()->tellg();
43
 
        if(_requestedpos)
44
 
                GetInStream()->seekg(0);
45
 
 
46
 
        //Set up a parser from an input stream 
47
 
        _reader = xmlReaderForIO(
48
 
                        ReadStream, //xmlInputReadCallback (static member function)
49
 
                        NULL,//xmlInputCloseCallback (static member function)
50
 
                        this,       //context
51
 
                        "",         //URL
52
 
                        NULL,       //encoding
53
 
                        0);         //options
54
 
 
55
 
        if (_reader == NULL)
56
 
        {
57
 
                cerr << "Cannot set up libxml2 reader" << endl;
58
 
                return false;
59
 
        }
60
 
        //A new reader immediately reads 4 bytes (presumably to determine
61
 
        //the encoding).
62
 
                _lastpos = GetInStream()->tellg();
63
 
        return true;
64
 
}
65
 
 
66
 
bool XMLConversion::SetupWriter()
67
 
{
68
 
  //Set up XML writer if one does not already exist
69
 
        if(_writer)
70
 
                return true;
 
21
  //static variable
 
22
  XMLBaseFormat* XMLConversion::_pDefault=NULL;
 
23
 
 
24
  XMLConversion::XMLConversion(OBConversion* pConv)
 
25
    : OBConversion(*pConv),
 
26
      _requestedpos(0), _lastpos(0),
 
27
      _reader(NULL), _writer(NULL),
 
28
      _LookingForNamespace(false), _SkipNextRead(false)
 
29
  {
 
30
    _pConv = pConv;
 
31
    pConv->SetAuxConv(this);//marks original OBConversion object as having been extended 
 
32
    SetAuxConv(this);//marks this new object as extended (for use with OBConversion pointer)
 
33
  }
 
34
 
 
35
  bool XMLConversion::SetupReader()
 
36
  {
 
37
    if(_reader)
 
38
      return true; //do not need to make a new reader
 
39
 
 
40
    //If the inputstream is not at the start (probably arising in fastsearch),
 
41
    //save its position and rewind so that the reader initialization is ok.
 
42
    //(Getting the requested object is handled in ReadXML(), when the format is known.) 
 
43
    _requestedpos = GetInStream()->tellg();
 
44
    if(_requestedpos)
 
45
      GetInStream()->seekg(0);
 
46
 
 
47
    //Set up a parser from an input stream 
 
48
    _reader = xmlReaderForIO(
 
49
                             ReadStream, //xmlInputReadCallback (static member function)
 
50
                             NULL,//xmlInputCloseCallback (static member function)
 
51
                             this,       //context
 
52
                             "",         //URL
 
53
                             NULL,       //encoding
 
54
                             0);         //options
 
55
 
 
56
    if (_reader == NULL)
 
57
      {
 
58
        cerr << "Cannot set up libxml2 reader" << endl;
 
59
        return false;
 
60
      }
 
61
    //A new reader immediately reads 4 bytes (presumably to determine
 
62
    //the encoding).
 
63
    _lastpos = GetInStream()->tellg();
 
64
    return true;
 
65
  }
 
66
 
 
67
  bool XMLConversion::SetupWriter()
 
68
  {
 
69
    //Set up XML writer if one does not already exist
 
70
    if(_writer)
 
71
      return true;
71
72
  
72
 
        _buf = xmlOutputBufferCreateIO  (
73
 
                        WriteStream, //xmlOutputWriteCallback 
74
 
                        NULL,                      //xmlOutputCloseCallback
75
 
                        this,        //context
76
 
                        NULL);        //xmlCharEncodingHandlerPtr
77
 
        _writer = xmlNewTextWriter(_buf);
78
 
 
79
 
/*
80
 
        _buf = xmlBufferCreate();
81
 
  _writer = xmlNewTextWriterMemory(_buf, 0);
82
 
*/ 
 
73
    _buf = xmlOutputBufferCreateIO  (
 
74
                                     WriteStream, //xmlOutputWriteCallback 
 
75
                                     NULL,         //xmlOutputCloseCallback
 
76
                                     this,        //context
 
77
                                     NULL);        //xmlCharEncodingHandlerPtr
 
78
    _writer = xmlNewTextWriter(_buf);
 
79
 
 
80
    if(!_buf || !_writer)
 
81
      {
 
82
        cerr << "Error setting up xml writer\n" << endl;
 
83
        return false;
 
84
      }
 
85
 
 
86
    int ret;
 
87
    if(IsOption("c"))
 
88
      ret = xmlTextWriterSetIndent(_writer,0);
 
89
    else
 
90
      {
 
91
        ret = xmlTextWriterSetIndent(_writer,1);
 
92
        ret = xmlTextWriterSetIndentString(_writer, BAD_CAST " "); 
 
93
      }
 
94
    return ret==0;
 
95
  }
 
96
 
 
97
  XMLConversion::~XMLConversion()
 
98
  {
 
99
    if(_reader)
 
100
      xmlFreeTextReader(_reader);
 
101
    if(_writer)
 
102
//      xmlTextWriterEndDocument(_writer); //if hasn't been called ealier
 
103
        xmlFreeTextWriter(_writer);// was crashing
 
104
    //xmlBufferFree(_buf);
 
105
  }
 
106
 
 
107
  ///Called from each XML class during its construction
 
108
  void XMLConversion::RegisterXMLFormat(XMLBaseFormat* pFormat, bool IsDefault, const char* uri)
 
109
  {
 
110
    if(IsDefault || Namespaces().empty())
 
111
      _pDefault=pFormat;
 
112
    if(uri)
 
113
      Namespaces()[uri] = pFormat;
 
114
    else
 
115
      Namespaces()[pFormat->NamespaceURI()] = pFormat;
 
116
  }
 
117
 
 
118
  ///Returns the extended form of the OBConversion object with an xml reader or writer,
 
119
  /// if this has not already been done.
 
120
  XMLConversion* XMLConversion::GetDerived(OBConversion* pConv, bool ForReading)
 
121
  {
 
122
    XMLConversion* pxmlConv;
 
123
    if(!pConv->GetAuxConv())
 
124
      //Need to make an extended copy. It will be deleted by pConv's destructor
 
125
      pxmlConv =  new XMLConversion(pConv);
 
126
    else
 
127
      {
 
128
        //pConv has already had an extended copy made 
 
129
        pxmlConv = dynamic_cast<XMLConversion*>(pConv->GetAuxConv());
 
130
        if (!pxmlConv)
 
131
          return NULL;
 
132
      }
 
133
 
 
134
    if(ForReading)
 
135
      {
 
136
        pxmlConv->SetupReader();
 
137
        if(pConv->GetInStream()->tellg() < pxmlConv->_lastpos)
 
138
          {
 
139
            //Probably a new file; copy some member vars and renew the current reader
 
140
            pxmlConv->InFilename = pConv->GetInFilename();
 
141
            pxmlConv->pInFormat = pConv->GetInFormat();
 
142
 
 
143
            if(xmlReaderNewIO( pxmlConv->_reader, ReadStream, NULL, pxmlConv, "", NULL, 0)==-1)
 
144
              return false;
 
145
          }
 
146
      }
 
147
    else
 
148
    {
 
149
      pxmlConv->SetupWriter();
 
150
      pxmlConv->SetLast(pConv->IsLast()); //Copy IsLast flag to the extended object
 
151
    }
 
152
    return pxmlConv;
 
153
  }
 
154
 
 
155
 
 
156
  bool XMLConversion::ReadXML(XMLBaseFormat* pFormat, OBBase* pOb)
 
157
  { 
 
158
    if(_requestedpos)
 
159
      {
 
160
        //The initial stream position was not at the start, probably because of fastsearch
 
161
        //Read and discard the first object to synchronize the reader,
 
162
        //then continue getting the requested object.
 
163
        //Assumes the objects are all at the same level in the DOM tree.
 
164
        SetOneObjectOnly(); //probably already set
 
165
        streampos SavedReqestedPos = _requestedpos; 
 
166
        _requestedpos=0;//don't do this again
 
167
        ReadXML(pFormat,pOb);
 
168
        GetInStream()->seekg(SavedReqestedPos);
 
169
      }
 
170
 
 
171
    //**Parse
 
172
    int result=1;
 
173
    while(GetInStream()->good() && (_SkipNextRead || (result=xmlTextReaderRead(_reader))==1)) //read may not be called
 
174
    {
 
175
      _SkipNextRead=false;
 
176
      if(_LookingForNamespace)
 
177
      {
 
178
        const xmlChar* puri = xmlTextReaderConstNamespaceUri(_reader);
 
179
        if(puri)
 
180
          {
 
181
            string uri((const char*)puri);
 
182
            //Look up appropriate format class from the namespace URI
 
183
            NsMapType::iterator nsiter;
 
184
            nsiter = Namespaces().find(uri);
 
185
            if(nsiter!=Namespaces().end())
 
186
              {
 
187
                XMLBaseFormat* pNewFormat = nsiter->second;
 
188
                //Must have same target, e.g. OBMol, as current format 
 
189
                if(pNewFormat->GetType() == pFormat->GetType())
 
190
                  {
 
191
                    _LookingForNamespace=false;
 
192
                    _SkipNextRead=true;
 
193
                    SetInFormat(pNewFormat);
 
194
                    pNewFormat->ReadMolecule(pOb,this);
 
195
                    return true;
 
196
                  }
 
197
              }
 
198
          }
 
199
      }
 
200
 
 
201
      const xmlChar* pname = xmlTextReaderConstLocalName(_reader);
 
202
      int typ = xmlTextReaderNodeType(_reader);
 
203
      if(typ==XML_READER_TYPE_SIGNIFICANT_WHITESPACE || !pname)
 
204
        continue; //Text nodes handled in format class
 
205
      string ElName((const char*)pname);
 
206
 
 
207
      //Pass the node on to the appropriate format class
 
208
      bool ret;
 
209
      if(typ==XML_READER_TYPE_ELEMENT)
 
210
        ret= pFormat->DoElement(ElName);
 
211
      else if(typ==XML_READER_TYPE_END_ELEMENT)
 
212
        ret= pFormat->EndElement(ElName);
 
213
      else 
 
214
        continue;
 
215
      _lastpos = GetInStream()->tellg();
 
216
 
 
217
      if(!ret)
 
218
        //derived format callback has stopped processing by returning false;
 
219
        //leave reader intact so it can be continued to be used.
 
220
        if(!IsOption("n",OBConversion::INOPTIONS))
 
221
          {
 
222
            _LookingForNamespace = true;
 
223
            return true;
 
224
          }
 
225
      }
 
226
 
 
227
    if(result==-1)
 
228
    {
 
229
      xmlError* perr = xmlGetLastError();
 
230
      if(perr && perr->level!=XML_ERR_NONE)
 
231
        {
 
232
          obErrorLog.ThrowError("XML Parser " + GetInFilename(),
 
233
                                perr->message, obError);
 
234
        }
 
235
      xmlResetError(perr);
 
236
      GetInStream()->setstate(ios::eofbit);
 
237
      return false;
 
238
    }
 
239
    return GetInStream()->good() && result!=0;
 
240
  }
 
241
 
 
242
  /////////////////////////////////////////////////////////
 
243
  ///Read and discard XML text up to the next occurrence of the tag e.g."/molecule>"
 
244
  ///This is left as the current node. Returns 1 on success, 0 if not found, -1 if failed.
 
245
  int XMLConversion::SkipXML(const char* ctag)
 
246
  {
 
247
    string tag(ctag);
 
248
    tag.erase(--tag.end()); //remove >
 
249
    int targettyp = XML_READER_TYPE_ELEMENT;
 
250
    if(tag[0]=='/')
 
251
      {
 
252
        tag.erase(0,1);
 
253
        targettyp = XML_READER_TYPE_END_ELEMENT;
 
254
      }
 
255
 
 
256
    int result;
 
257
    while((result = xmlTextReaderRead(_reader))==1)
 
258
      {
 
259
        if(xmlTextReaderNodeType(_reader)==targettyp
 
260
           && !xmlStrcmp(xmlTextReaderConstLocalName(_reader), BAD_CAST tag.c_str()))
 
261
          break;
 
262
      }
 
263
    return result;
 
264
  }
 
265
  /////////////////////////////////////////////////////////
 
266
  string XMLConversion::GetAttribute(const char* attrname)
 
267
  {
 
268
    string AttributeValue;
 
269
    xmlChar* pvalue  = xmlTextReaderGetAttribute(_reader, BAD_CAST attrname);
 
270
    if(pvalue)
 
271
    {
 
272
      AttributeValue = (const char*)pvalue;
 
273
      xmlFree(pvalue);
 
274
    }
 
275
    return AttributeValue;
 
276
  }
 
277
 
 
278
  ////////////////////////////////////////////////////////
 
279
  string XMLConversion::GetContent()
 
280
  {
 
281
    xmlTextReaderRead(_reader);
 
282
    const xmlChar* pvalue = xmlTextReaderConstValue(_reader);
 
283
    string value((const char*)pvalue);
 
284
    return Trim(value);
 
285
  }
 
286
 
 
287
  ////////////////////////////////////////////////////////
 
288
  bool XMLConversion::GetContentInt(int& value)
 
289
  {
 
290
    xmlTextReaderRead(_reader);
 
291
    const xmlChar* pvalue = xmlTextReaderConstValue(_reader);
 
292
    if(!pvalue)
 
293
      return false;
 
294
    value = atoi((const char*)pvalue);
 
295
    return true;
 
296
  }
 
297
 
 
298
  ////////////////////////////////////////////////////////
 
299
  bool XMLConversion::GetContentDouble(double& value)
 
300
  {
 
301
    xmlTextReaderRead(_reader);
 
302
    const xmlChar* pvalue = xmlTextReaderConstValue(_reader);
 
303
    if(!pvalue)
 
304
      return false;
 
305
    value = strtod((const char*)pvalue,NULL);
 
306
    return true;
 
307
  }
 
308
 
 
309
  ////////////////////////////////////////////////////////
 
310
  ///Static callback function for xmlReaderForIO(). Reads up to the next '>', or len chars.
 
311
 
 
312
  int XMLConversion::ReadStream(void * context, char * buffer, int len)
 
313
  {
 
314
    //TODO worry about non-ascii coding
 
315
    XMLConversion* pConv = static_cast<XMLConversion*>(context);
 
316
    istream* ifs = pConv->GetInStream();
 
317
    if(!ifs->good() || ifs->eof())
 
318
      return 0;
83
319
        
84
 
        if(!_buf || !_writer)
85
 
        {
86
 
                cerr << "Error setting up xml writer\n" << endl;
87
 
    return false;
88
 
        }
89
 
 
90
 
        int ret = xmlTextWriterSetIndent(_writer,1);
91
 
        ret = xmlTextWriterSetIndentString(_writer, BAD_CAST " "); 
92
 
        return ret==0;
93
 
}
94
 
 
95
 
XMLConversion::~XMLConversion()
96
 
{
97
 
        if(_reader)
98
 
                xmlFreeTextReader(_reader);
99
 
//      if(_writer)
100
 
//              xmlFreeTextWriter(_writer); was crashing
101
 
                //xmlBufferFree(_buf);
102
 
}
103
 
 
104
 
///Called from each XML class during its construction
105
 
void XMLConversion::RegisterXMLFormat(XMLBaseFormat* pFormat, bool IsDefault, const char* uri)
106
 
{
107
 
        if(IsDefault || Namespaces().empty())
108
 
                _pDefault=pFormat;
109
 
        if(uri)
110
 
                Namespaces()[uri] = pFormat;
111
 
        else
112
 
                Namespaces()[pFormat->NamespaceURI()] = pFormat;
113
 
}
114
 
 
115
 
XMLConversion* XMLConversion::GetDerived(OBConversion* pConv, bool ForReading)
116
 
{
117
 
        XMLConversion* pxmlConv;
118
 
        if(!pConv->GetAuxConv())
119
 
                //Need to make an extended copy. It will be deleted by pConv's destructor
120
 
                pxmlConv =  new XMLConversion(pConv);
121
 
        else
122
 
        {
123
 
                //pConv has already had an extended copy made   
124
 
                pxmlConv = dynamic_cast<XMLConversion*>(pConv->GetAuxConv());
125
 
                if (!pxmlConv)
126
 
                        return NULL;
127
 
        }
128
 
 
129
 
        if(ForReading)
130
 
        {
131
 
                pxmlConv->SetupReader();
132
 
                if(pConv->GetInStream()->tellg() < pxmlConv->_lastpos)
133
 
                {
134
 
                        //Probably a new file; copy some member vars and renew the current reader
135
 
                        pxmlConv->InFilename = pConv->GetInFilename();
136
 
                        pxmlConv->pInFormat = pConv->GetInFormat();
137
 
 
138
 
                        if(xmlReaderNewIO( pxmlConv->_reader, ReadStream, NULL, pxmlConv, "", NULL, 0)==-1)
139
 
                                return false;
140
 
                }
141
 
        }
142
 
        else
143
 
                pxmlConv->SetupWriter();
144
 
 
145
 
        return pxmlConv;
146
 
}
147
 
 
148
 
 
149
 
bool XMLConversion::ReadXML(XMLBaseFormat* pFormat, OBBase* pOb)
150
 
{       
151
 
        if(_requestedpos)
152
 
        {
153
 
                //The initial stream position was not at the start, probably because of fastsearch
154
 
                //Read and discard the first object to synchronize the reader,
155
 
                //then continue getting the requested object.
156
 
                //Assumes the objects are all at the same level in the DOM tree.
157
 
                SetOneObjectOnly(); //probably already set
158
 
                streampos SavedReqestedPos = _requestedpos; 
159
 
                _requestedpos=0;//don't do this again
160
 
                ReadXML(pFormat,pOb);
161
 
                GetInStream()->seekg(SavedReqestedPos);
162
 
        }
163
 
 
164
 
        //**Parse
165
 
        int result=1;
166
 
        while(GetInStream()->good() && 
167
 
              (_SkipNextRead || (result=xmlTextReaderRead(_reader))==1)) //read may not be called
168
 
        {
169
 
                _SkipNextRead=false;
170
 
                if(_LookingForNamespace)
171
 
                {
172
 
                        const xmlChar* puri = xmlTextReaderConstNamespaceUri(_reader);
173
 
                        if(puri)
174
 
                        {
175
 
                                string uri((const char*)puri);
176
 
                                //Look up appropriate format class from the namespace URI
177
 
                                NsMapType::iterator nsiter;
178
 
                                nsiter = Namespaces().find(uri);
179
 
                                if(nsiter!=Namespaces().end())
180
 
                                {
181
 
                                        XMLBaseFormat* pNewFormat = nsiter->second;
182
 
                                        //Must have same target, e.g. OBMol, as current format 
183
 
                                        if(pNewFormat->GetType() == pFormat->GetType())
184
 
                                        {
185
 
                                                _LookingForNamespace=false;
186
 
                                                _SkipNextRead=true;
187
 
                                                SetInFormat(pNewFormat);
188
 
                                                pNewFormat->ReadMolecule(pOb,this);
189
 
                                                return true;
190
 
                                        }
191
 
                                }
192
 
                        }
193
 
                }
194
 
 
195
 
                const xmlChar* pname = xmlTextReaderConstLocalName(_reader);
196
 
                int typ = xmlTextReaderNodeType(_reader);
197
 
                if(typ==XML_READER_TYPE_SIGNIFICANT_WHITESPACE || !pname)
198
 
                        continue; //Text nodes handled in format class
199
 
                string ElName((const char*)pname);
200
 
 
201
 
                //Pass the node on to the appropriate format class
202
 
                bool ret;
203
 
                if(typ==XML_READER_TYPE_ELEMENT)
204
 
                        ret= pFormat->DoElement(ElName);
205
 
                else if(typ==XML_READER_TYPE_END_ELEMENT)
206
 
                        ret= pFormat->EndElement(ElName);
207
 
                
208
 
                _lastpos = GetInStream()->tellg();
209
 
 
210
 
                if(!ret)
211
 
                        //derived format callback has stopped processing by returning false;
212
 
                        //leave reader intact so it can be continued to be used.
213
 
                        if(!IsOption("n",OBConversion::INOPTIONS))
214
 
                        {
215
 
                                _LookingForNamespace = true;
216
 
                                return true;
217
 
                        }
218
 
        }
219
 
 
220
 
        if(result==-1)
221
 
        {
222
 
                cerr << "XML Parser failed in " << GetInFilename() << endl;
223
 
                GetInStream()->setstate(ios::eofbit);
224
 
        }
225
 
        return (result==0);// was result==0;
226
 
}
227
 
 
228
 
/////////////////////////////////////////////////////////
229
 
string XMLConversion::GetAttribute(const char* attrname)
230
 
{
231
 
        string AttributeValue;
232
 
        const xmlChar* pvalue  = xmlTextReaderGetAttribute(_reader, BAD_CAST attrname);
233
 
        if(pvalue)
234
 
                AttributeValue = (const char*)pvalue;
235
 
        return AttributeValue;
236
 
}
237
 
 
238
 
////////////////////////////////////////////////////////
239
 
string XMLConversion::GetContent()
240
 
{
241
 
        xmlTextReaderRead(_reader);
242
 
        const xmlChar* pvalue = xmlTextReaderConstValue(_reader);
243
 
        string value((const char*)pvalue);
244
 
        return value;
245
 
}
246
 
 
247
 
////////////////////////////////////////////////////////
248
 
bool XMLConversion::GetContentInt(int& value)
249
 
{
250
 
        xmlTextReaderRead(_reader);
251
 
        const xmlChar* pvalue = xmlTextReaderConstValue(_reader);
252
 
        if(!pvalue)
253
 
                return false;
254
 
        value = atoi((const char*)pvalue);
255
 
        return true;
256
 
}
257
 
 
258
 
////////////////////////////////////////////////////////
259
 
bool XMLConversion::GetContentDouble(double& value)
260
 
{
261
 
        xmlTextReaderRead(_reader);
262
 
        const xmlChar* pvalue = xmlTextReaderConstValue(_reader);
263
 
        if(!pvalue)
264
 
                return false;
265
 
        value = strtod((const char*)pvalue,NULL);
266
 
        return true;
267
 
}
268
 
 
269
 
//**********************************************
270
 
/// Utility function to read an input stream until a specified string is found 
271
 
streamsize gettomatch(istream& is, char* buf, streamsize count, const char* match) 
272
 
{
273
 
        //Reads chars from input stream into a buffer until either: 
274
 
        //  count chars have been read or
275
 
        //  the string match has been input.
276
 
        //The buffer is NOT terminated by a '\0' char.
277
 
        //The number of characters stored in buf is returned.  
278
 
 
279
 
        int matchlength = 0;
280
 
        char lastchar = EOF; //value if no vaild match provided
281
 
        if(match)
282
 
        {
283
 
                matchlength = strlen(match);
284
 
                lastchar = match[matchlength-1];
285
 
        }
286
 
        char* p = buf;
287
 
        streambuf* prb = is.rdbuf();
288
 
        int i;
289
 
        for(i=0;i<count;++i)
290
 
        {
291
 
                *p = prb->sbumpc();
292
 
                if(*p==EOF)
293
 
                        break;
294
 
                if(*p++==lastchar)
295
 
                {
296
 
                        const char* mptr = match + matchlength-2; //last char is already matched
297
 
                        const char* bptr = p-2;
298
 
                        while((*mptr-- == *bptr--) && (mptr >= match));
299
 
 
300
 
                        if(mptr<match)
301
 
                        {
302
 
                                i++;
303
 
                                break;//have found match
304
 
                        }
305
 
                }
306
 
        }
307
 
        return i;
308
 
}
309
 
//***********************************************
310
 
 
311
 
///Static callback function for xmlReaderForIO()
312
 
int XMLConversion::ReadStream(void * context, char * buffer, int len)
313
 
{
314
 
        //Reads up to the next '>'
315
 
        XMLConversion* pConv = static_cast<XMLConversion*>(context);
316
 
        istream* ifs = pConv->GetInStream();
317
 
        if(ifs->eof())
318
 
                return 0;
319
 
        const char* endtag = NULL;
320
 
        OBFormat* pFormat = pConv->GetInFormat();
321
 
        XMLBaseFormat* pxmlFormat = static_cast<XMLBaseFormat*>(pFormat);
322
 
        if(pxmlFormat)
323
 
                endtag = pxmlFormat->EndTag();
324
 
 
325
 
//      static char* OrigBuffer;
326
 
//      if(len==4)
327
 
//              OrigBuffer = buffer;
328
 
 
329
 
        return gettomatch(*ifs, buffer, len , endtag);//was + OrigBuffer - buffer
330
 
}
331
 
 
332
 
int XMLConversion::WriteStream(void * context, const char * buffer, int len)
333
 
{
334
 
        XMLConversion* pxmlConv = static_cast<XMLConversion*>(context);
335
 
        ostream* ofs = pxmlConv->GetOutStream();
336
 
        ofs->write(buffer,len);
337
 
        if(!ofs)
338
 
                return -1;
339
 
        ofs->flush();
340
 
        return len;
341
 
}
 
320
    ifs->get(buffer, len+1, '>');
 
321
    streamsize count = strlen(buffer);
 
322
 
 
323
    if(ifs->peek()=='>')
 
324
      {
 
325
        ifs->ignore();
 
326
        buffer[count] = '>';
 
327
        buffer[++count] = '\0';
 
328
      }
 
329
 
 
330
                if (ifs->peek() == '\n' || ifs->peek() == '\r')
 
331
                        {
 
332
                                ifs->get(); // remove any trailing endlines
 
333
                        }
 
334
    return count;
 
335
  }
 
336
 
 
337
  //////////////////////////////////////////////////////////
 
338
  int XMLConversion::WriteStream(void * context, const char * buffer, int len)
 
339
  {
 
340
    XMLConversion* pxmlConv = static_cast<XMLConversion*>(context);
 
341
    ostream* ofs = pxmlConv->GetOutStream();
 
342
    if(len>0)                //a call with len=0 coming from xmlFreeTextWriter
 
343
    {                        //called from destructor of XMLConversion was causing crash
 
344
      ofs->write(buffer,len);
 
345
      if(!ofs)
 
346
        return -1;
 
347
      ofs->flush();
 
348
    }
 
349
    return len;
 
350
  }
342
351
 
343
352
} //namespace OpenBabel
344
353
// http://xmlsoft.org/html/libxml-xmlreader.html
388
397
This causes some difficulty when using libxml2 as the XML parser
389
398
because it is a C application and does not have C++ input streams. 
390
399
xmlReaderForIO is used which requests input data from the callback
391
 
routine XMLConversion::ReadStream() which, using the utility routine
392
 
gettomatch(), obtains data from the XML file no further than the end
393
 
of an object, e.g. up to and including </molecule>. This ensures that
394
 
the input stream is between objects after an object has been parsed,
395
 
ready for the next one. 
 
400
routine XMLConversion::ReadStream(). This inputs chunks of characters
 
401
up to and including '>'. This ensures that the input stream is between 
 
402
objects after an object has been parsed, ready for the next one. 
396
403
 
397
404
Parsing XML
398
405
At the start and end of each element the DoElement() and EndElement()