/*========================================================================= Program: Visualization Toolkit Module: vtkXMLParser.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkXMLParser.h" #include "vtkObjectFactory.h" #include "vtk_expat.h" #include #include vtkStandardNewMacro(vtkXMLParser); //---------------------------------------------------------------------------- vtkXMLParser::vtkXMLParser() { this->Stream = nullptr; this->Parser = nullptr; this->FileName = nullptr; this->Encoding = nullptr; this->InputString = nullptr; this->InputStringLength = 0; this->ParseError = 0; this->IgnoreCharacterData = 0; } //---------------------------------------------------------------------------- vtkXMLParser::~vtkXMLParser() { this->SetStream(nullptr); this->SetFileName(nullptr); this->SetEncoding(nullptr); } //---------------------------------------------------------------------------- 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"; } os << indent << "FileName: " << (this->FileName? this->FileName : "(none)") << "\n"; os << indent << "IgnoreCharacterData: " << (this->IgnoreCharacterData?"On":"Off") << endl; os << indent << "Encoding: " << (this->Encoding? this->Encoding : "(none)") << "\n"; } //---------------------------------------------------------------------------- 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 } //---------------------------------------------------------------------------- vtkTypeInt64 vtkXMLParser::TellG() { // Standard tellg returns -1 if fail() is true. if(!this->Stream || vtkXMLParserFail(this->Stream)) { return -1; } return this->Stream->tellg(); } //---------------------------------------------------------------------------- void vtkXMLParser::SeekG(vtkTypeInt64 position) { // Standard seekg does nothing if fail() is true. if(!this->Stream || vtkXMLParserFail(this->Stream)) { return; } this->Stream->seekg(std::streampos(position)); } //---------------------------------------------------------------------------- int vtkXMLParser::Parse(const char* inputString) { this->InputString = inputString; this->InputStringLength = -1; int result = this->Parse(); this->InputString = nullptr; return result; } //---------------------------------------------------------------------------- int vtkXMLParser::Parse(const char* inputString, unsigned int length) { this->InputString = inputString; this->InputStringLength = length; int result = this->Parse(); this->InputString = nullptr; this->InputStringLength = -1; return result; } //---------------------------------------------------------------------------- int vtkXMLParser::Parse() { // Select source of XML ifstream ifs; if ( !this->InputString && !this->Stream && this->FileName ) { // If it is file, open it and set the appropriate stream vtksys::SystemTools::Stat_t fs; if (vtksys::SystemTools::Stat(this->FileName, &fs) != 0) { vtkErrorMacro("Cannot open XML file: " << this->FileName); return 0; } #ifdef _WIN32 ifs.open(this->FileName, ios::binary | ios::in); #else ifs.open(this->FileName, ios::in); #endif if ( !ifs ) { vtkErrorMacro("Cannot open XML file: " << this->FileName); return 0; } this->Stream = &ifs; } // Create the expat XML parser. this->CreateParser(); XML_SetElementHandler(static_cast(this->Parser), &vtkXMLParserStartElement, &vtkXMLParserEndElement); if (!this->IgnoreCharacterData) { XML_SetCharacterDataHandler(static_cast(this->Parser), &vtkXMLParserCharacterDataHandler); } else { XML_SetCharacterDataHandler(static_cast(this->Parser), nullptr); } XML_SetUserData(static_cast(this->Parser), this); // Parse the input. int result = this->ParseXML(); if(result) { // Tell the expat XML parser about the end-of-input. if(!XML_Parse(static_cast(this->Parser), "", 0, 1)) { this->ReportXmlParseError(); result = 0; } } // Clean up the parser. XML_ParserFree(static_cast(this->Parser)); this->Parser = nullptr; // If the source was a file, reset the stream if ( this->Stream == &ifs ) { this->Stream = nullptr; } return result; } //---------------------------------------------------------------------------- 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; } //---------------------------------------------------------------------------- int vtkXMLParser::InitializeParser() { // Create the expat XML parser. if (!this->CreateParser()) { vtkErrorMacro("Parser already initialized"); this->ParseError = 1; return 0; } XML_SetElementHandler(static_cast(this->Parser), &vtkXMLParserStartElement, &vtkXMLParserEndElement); if (!this->IgnoreCharacterData) { XML_SetCharacterDataHandler(static_cast(this->Parser), &vtkXMLParserCharacterDataHandler); } else { XML_SetCharacterDataHandler(static_cast(this->Parser), nullptr); } XML_SetUserData(static_cast(this->Parser), this); this->ParseError = 0; return 1; } //---------------------------------------------------------------------------- int vtkXMLParser::ParseChunk(const char* inputString, unsigned int length) { if ( !this->Parser ) { vtkErrorMacro("Parser not initialized"); this->ParseError = 1; return 0; } int res; res = this->ParseBuffer(inputString, length); if ( res == 0 ) { this->ParseError = 1; } return res; } //---------------------------------------------------------------------------- int vtkXMLParser::CleanupParser() { if ( !this->Parser ) { vtkErrorMacro("Parser not initialized"); this->ParseError = 1; return 0; } int result = !this->ParseError; if(result) { // Tell the expat XML parser about the end-of-input. if(!XML_Parse(static_cast(this->Parser), "", 0, 1)) { this->ReportXmlParseError(); result = 0; } } // Clean up the parser. XML_ParserFree(static_cast(this->Parser)); this->Parser = nullptr; return result; } //---------------------------------------------------------------------------- int vtkXMLParser::ParseXML() { // Parsing of message if ( this->InputString ) { if ( this->InputStringLength >= 0 ) { return this->ParseBuffer(this->InputString, this->InputStringLength); } else { return this->ParseBuffer(this->InputString); } } // Make sure we have input. if(!this->Stream) { vtkErrorMacro("Parse() called with no Stream set."); return 0; } // Default stream parser just reads a block at a time. istream& in = *(this->Stream); const int bufferSize = 4096; char buffer[bufferSize]; // 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. while(!this->ParseError && !this->ParsingComplete() && in) { in.read(buffer, bufferSize); if(in.gcount()) { if(!this->ParseBuffer(buffer, in.gcount())) { return 0; } } } // 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); 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() { vtkErrorMacro( "Error parsing XML in stream at line " << XML_GetCurrentLineNumber(static_cast(this->Parser)) << ", column " << XML_GetCurrentColumnNumber(static_cast(this->Parser)) << ", byte index " << XML_GetCurrentByteIndex(static_cast(this->Parser)) << ": " << XML_ErrorString(XML_GetErrorCode(static_cast(this->Parser)))); } //---------------------------------------------------------------------------- vtkTypeInt64 vtkXMLParser::GetXMLByteIndex() { return XML_GetCurrentByteIndex(static_cast(this->Parser)); } //---------------------------------------------------------------------------- int vtkXMLParser::ParseBuffer(const char* buffer, unsigned int count) { // Pass the buffer to the expat XML parser. if(!XML_Parse(static_cast(this->Parser), buffer, count, 0)) { this->ReportXmlParseError(); return 0; } return 1; } //---------------------------------------------------------------------------- int vtkXMLParser::ParseBuffer(const char* buffer) { return this->ParseBuffer(buffer, static_cast(strlen(buffer))); } //---------------------------------------------------------------------------- int vtkXMLParser::IsSpace(char c) { return isspace(c); } //---------------------------------------------------------------------------- void vtkXMLParserStartElement(void* parser, const char *name, const char **atts) { // Begin element handler that is registered with the XML_Parser. // This just casts the user data to a vtkXMLParser and calls // StartElement. static_cast(parser)->StartElement(name, atts); } //---------------------------------------------------------------------------- void vtkXMLParserEndElement(void* parser, const char *name) { // End element handler that is registered with the XML_Parser. This // just casts the user data to a vtkXMLParser and calls EndElement. static_cast(parser)->EndElement(name); }