vtkXMLParser.cxx 12.9 KB
Newer Older
1 2 3 4 5
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXMLParser.cxx

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 8 9
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

10 11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 13 14 15 16
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkXMLParser.h"
#include "vtkObjectFactory.h"
17
#include "vtk_expat.h"
Sean McBride's avatar
Sean McBride committed
18
#include <cctype>
19
#include <sys/stat.h>
20 21 22 23 24 25

vtkStandardNewMacro(vtkXMLParser);

//----------------------------------------------------------------------------
vtkXMLParser::vtkXMLParser()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
26 27 28
  this->Stream            = 0;
  this->Parser            = 0;
  this->FileName          = 0;
29
  this->Encoding          = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
30 31
  this->InputString       = 0;
  this->InputStringLength = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
32
  this->ParseError        = 0;
33
  this->IgnoreCharacterData = 0;
34 35 36 37 38 39
}

//----------------------------------------------------------------------------
vtkXMLParser::~vtkXMLParser()
{
  this->SetStream(0);
40
  this->SetFileName(0);
41
  this->SetEncoding(0);
42 43 44 45 46 47 48 49 50 51 52 53 54 55
}

//----------------------------------------------------------------------------
void vtkXMLParser::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  if(this->Stream)
    {
    os << indent << "Stream: " << this->Stream << "\n";
    }
  else
    {
    os << indent << "Stream: (none)\n";
    }
56 57
  os << indent << "FileName: " << (this->FileName? this->FileName : "(none)")
     << "\n";
58
  os << indent << "IgnoreCharacterData: "
59 60
     << (this->IgnoreCharacterData?"On":"Off")
     << endl;
61 62
  os << indent << "Encoding: " << (this->Encoding? this->Encoding : "(none)")
     << "\n";
63 64
}

65 66 67 68 69 70 71 72 73 74 75 76
//----------------------------------------------------------------------------
static int vtkXMLParserFail(istream* stream)
{
  // The fail() method returns true if either the failbit or badbit is set.
#if defined(__HP_aCC)
  // The HP compiler sets the badbit too often, so we ignore it.
  return (stream->rdstate() & ios::failbit)? 1:0;
#else
  return stream->fail()? 1:0;
#endif
}

77
//----------------------------------------------------------------------------
78
vtkTypeInt64 vtkXMLParser::TellG()
79 80
{
  // Standard tellg returns -1 if fail() is true.
81
  if(!this->Stream || vtkXMLParserFail(this->Stream))
82 83 84
    {
    return -1;
    }
85
  return this->Stream->tellg();
86 87 88
}

//----------------------------------------------------------------------------
89
void vtkXMLParser::SeekG(vtkTypeInt64 position)
90
{
91
  // Standard seekg does nothing if fail() is true.
92
  if(!this->Stream || vtkXMLParserFail(this->Stream))
93 94 95
    {
    return;
    }
96
  this->Stream->seekg(std::streampos(position));
97 98
}

99 100 101 102
//----------------------------------------------------------------------------
int vtkXMLParser::Parse(const char* inputString)
{
  this->InputString = inputString;
Andy Cedilnik's avatar
Andy Cedilnik committed
103
  this->InputStringLength = -1;
104
  int result = this->Parse();
105 106 107 108
  this->InputString = 0;
  return result;
}

Andy Cedilnik's avatar
Andy Cedilnik committed
109 110 111 112 113
//----------------------------------------------------------------------------
int vtkXMLParser::Parse(const char* inputString, unsigned int length)
{
  this->InputString = inputString;
  this->InputStringLength = length;
114
  int result = this->Parse();
Andy Cedilnik's avatar
Andy Cedilnik committed
115 116 117 118 119
  this->InputString = 0;
  this->InputStringLength = -1;
  return result;
}

120

121 122 123
//----------------------------------------------------------------------------
int vtkXMLParser::Parse()
{
124
  // Select source of XML
125 126 127
  ifstream ifs;
  if ( !this->InputString && !this->Stream && this->FileName )
    {
128
    // If it is file, open it and set the appropriate stream
129
    struct stat fs;
130
    if (stat(this->FileName, &fs) != 0)
131 132 133 134
      {
      vtkErrorMacro("Cannot open XML file: " << this->FileName);
      return 0;
      }
135
#ifdef _WIN32
136
    ifs.open(this->FileName, ios::binary | ios::in);
137
#else
138
    ifs.open(this->FileName, ios::in);
139
#endif
140 141
    if ( !ifs )
      {
142
      vtkErrorMacro("Cannot open XML file: " << this->FileName);
143 144 145 146 147
      return 0;
      }
    this->Stream = &ifs;
    }

148
  // Create the expat XML parser.
149 150
  this->CreateParser();

151
  XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
152 153
                        &vtkXMLParserStartElement,
                        &vtkXMLParserEndElement);
154
  if (!this->IgnoreCharacterData)
155 156 157 158 159 160 161 162
    {
    XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
                                &vtkXMLParserCharacterDataHandler);
    }
  else
    {
    XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser), NULL);
    }
163
  XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
164

165 166
  // Parse the input.
  int result = this->ParseXML();
167

168 169 170
  if(result)
    {
    // Tell the expat XML parser about the end-of-input.
171
    if(!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1))
172 173 174 175 176
      {
      this->ReportXmlParseError();
      result = 0;
      }
    }
177

178
  // Clean up the parser.
179
  XML_ParserFree(static_cast<XML_Parser>(this->Parser));
180
  this->Parser = 0;
181

182
  // If the source was a file, reset the stream
183 184 185 186 187
  if ( this->Stream == &ifs )
    {
    this->Stream = 0;
    }

188 189 190
  return result;
}

191 192 193 194 195 196 197 198 199 200 201 202 203
//----------------------------------------------------------------------------
int vtkXMLParser::CreateParser()
{
  if (this->Parser)
    {
    vtkErrorMacro("Parser already created");
    return 0;
    }
  // Create the expat XML parser.
  this->Parser = XML_ParserCreate(this->Encoding);
  return this->Parser ? 1 : 0;
}

204 205 206
//----------------------------------------------------------------------------
int vtkXMLParser::InitializeParser()
{
207 208
  // Create the expat XML parser.
  if (!this->CreateParser())
Andy Cedilnik's avatar
Andy Cedilnik committed
209 210 211 212 213
    {
    vtkErrorMacro("Parser already initialized");
    this->ParseError = 1;
    return 0;
    }
214

215
  XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
216 217
                        &vtkXMLParserStartElement,
                        &vtkXMLParserEndElement);
218
  if (!this->IgnoreCharacterData)
219 220 221 222 223 224 225 226
    {
    XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
                                &vtkXMLParserCharacterDataHandler);
    }
  else
    {
    XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser), NULL);
    }
227
  XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
228 229 230 231 232 233 234
  this->ParseError = 0;
  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLParser::ParseChunk(const char* inputString, unsigned int length)
{
Andy Cedilnik's avatar
Andy Cedilnik committed
235 236 237 238 239 240
  if ( !this->Parser )
    {
    vtkErrorMacro("Parser not initialized");
    this->ParseError = 1;
    return 0;
    }
241 242 243 244 245 246 247 248 249 250 251 252
  int res;
  res = this->ParseBuffer(inputString, length);
  if ( res == 0 )
    {
    this->ParseError = 1;
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkXMLParser::CleanupParser()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
253 254 255 256 257 258
  if ( !this->Parser )
    {
    vtkErrorMacro("Parser not initialized");
    this->ParseError = 1;
    return 0;
    }
259 260 261 262
  int result = !this->ParseError;
  if(result)
    {
    // Tell the expat XML parser about the end-of-input.
263
    if(!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1))
264 265 266 267 268
      {
      this->ReportXmlParseError();
      result = 0;
      }
    }
269

270
  // Clean up the parser.
271
  XML_ParserFree(static_cast<XML_Parser>(this->Parser));
272
  this->Parser = 0;
273

274 275 276
  return result;
}

277 278 279
//----------------------------------------------------------------------------
int vtkXMLParser::ParseXML()
{
280 281 282
  // Parsing of message
  if ( this->InputString )
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
283 284 285 286 287 288 289 290
    if ( this->InputStringLength >= 0 )
      {
      return this->ParseBuffer(this->InputString, this->InputStringLength);
      }
    else
      {
      return this->ParseBuffer(this->InputString);
      }
291 292
    }

293 294 295 296 297 298
  // Make sure we have input.
  if(!this->Stream)
    {
    vtkErrorMacro("Parse() called with no Stream set.");
    return 0;
    }
299

300 301
  // Default stream parser just reads a block at a time.
  istream& in = *(this->Stream);
302 303 304
  const int bufferSize = 4096;
  char buffer[bufferSize];

305 306 307 308 309 310
  // Read in the stream and send its contents to the XML parser.  This
  // read loop is very sensitive on certain platforms with slightly
  // broken stream libraries (like HPUX).  Normally, it is incorrect
  // to not check the error condition on the fin.read() before using
  // the data, but the fin.gcount() will be zero if an error occurred.
  // Therefore, the loop should be safe everywhere.
311
  while(!this->ParseError && !this->ParsingComplete() && in)
312 313 314 315 316 317 318 319 320 321
    {
    in.read(buffer, bufferSize);
    if(in.gcount())
      {
      if(!this->ParseBuffer(buffer, in.gcount()))
        {
        return 0;
        }
      }
    }
322

323 324 325 326
  // Clear the fail and eof bits on the input stream so we can later
  // seek back to read data.
  this->Stream->clear(this->Stream->rdstate() & ~ios::eofbit);
  this->Stream->clear(this->Stream->rdstate() & ~ios::failbit);
327

328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLParser::ParsingComplete()
{
  // Default behavior is to parse to end of stream.
  return 0;
}

//----------------------------------------------------------------------------
void vtkXMLParser::StartElement(const char *name,
                                const char ** vtkNotUsed(atts))
{
  this->ReportUnknownElement(name);
}

//----------------------------------------------------------------------------
void vtkXMLParser::EndElement(const char * vtkNotUsed(name))
{
}

//----------------------------------------------------------------------------
void vtkXMLParser::CharacterDataHandler(const char* vtkNotUsed(inData),
                                        int vtkNotUsed(inLength))
{
}

//----------------------------------------------------------------------------
void vtkXMLParser::ReportStrayAttribute(const char* element, const char* attr,
                                        const char* value)
{
  vtkWarningMacro("Stray attribute in XML stream: Element " << element
                  << " has " << attr << "=\"" << value << "\"");
}

//----------------------------------------------------------------------------
void vtkXMLParser::ReportMissingAttribute(const char* element,
                                          const char* attr)
{
  vtkErrorMacro("Missing attribute in XML stream: Element " << element
                << " is missing " << attr);
}

//----------------------------------------------------------------------------
void vtkXMLParser::ReportBadAttribute(const char* element, const char* attr,
                                      const char* value)
{
  vtkErrorMacro("Bad attribute value in XML stream: Element " << element
                << " has " << attr << "=\"" << value << "\"");
}

//----------------------------------------------------------------------------
void vtkXMLParser::ReportUnknownElement(const char* element)
{
  vtkErrorMacro("Unknown element in XML stream: " << element);
}

//----------------------------------------------------------------------------
void vtkXMLParser::ReportXmlParseError()
{
389 390 391 392 393 394 395
  vtkErrorMacro(
    "Error parsing XML in stream at line "
    << XML_GetCurrentLineNumber(static_cast<XML_Parser>(this->Parser))
    << ", column "
    << XML_GetCurrentColumnNumber(static_cast<XML_Parser>(this->Parser))
    << ", byte index "
    << XML_GetCurrentByteIndex(static_cast<XML_Parser>(this->Parser))
396
    << ": "
397
    << XML_ErrorString(XML_GetErrorCode(static_cast<XML_Parser>(this->Parser))));
398 399 400
}

//----------------------------------------------------------------------------
401
vtkTypeInt64 vtkXMLParser::GetXMLByteIndex()
402
{
403
  return XML_GetCurrentByteIndex(static_cast<XML_Parser>(this->Parser));
404 405 406 407 408 409
}

//----------------------------------------------------------------------------
int vtkXMLParser::ParseBuffer(const char* buffer, unsigned int count)
{
  // Pass the buffer to the expat XML parser.
410
  if(!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer, count, 0))
411 412 413 414 415 416 417 418 419 420
    {
    this->ReportXmlParseError();
    return 0;
    }
  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLParser::ParseBuffer(const char* buffer)
{
421
  return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer)));
422 423 424
}

//----------------------------------------------------------------------------
425
int vtkXMLParser::IsSpace(char c)
426
{
427
  return isspace(c);
428 429 430
}

//----------------------------------------------------------------------------
431 432
void vtkXMLParserStartElement(void* parser, const char *name,
                              const char **atts)
433
{
434 435 436 437
  // Begin element handler that is registered with the XML_Parser.
  // This just casts the user data to a vtkXMLParser and calls
  // StartElement.
  static_cast<vtkXMLParser*>(parser)->StartElement(name, atts);
438 439 440
}

//----------------------------------------------------------------------------
441
void vtkXMLParserEndElement(void* parser, const char *name)
442
{
443 444 445
  // End element handler that is registered with the XML_Parser.  This
  // just casts the user data to a vtkXMLParser and calls EndElement.
  static_cast<vtkXMLParser*>(parser)->EndElement(name);
446
}