/* "CodeWorker": a scripting language for parsing and generating text. Copyright (C) 1996-1997, 1999-2002 Cédric Lemaire This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA To contact the author: codeworker@free.fr */ #ifdef WIN32 #pragma warning (disable : 4786) #endif #include "UtlString.h" #include "UtlDate.h" #include "UtlException.h" #include "ScpStream.h" #include "UtlXMLStream.h" namespace CodeWorker { UtlXMLStream::UtlXMLStream(const std::string& sFileName, const bool bModeRead) : _bOwnerOfFileStream(true), _pInputStream(NULL), _pOutputStream(NULL) { if (!bModeRead) { _pOutputStream = CodeWorker::openOutputFile(sFileName.c_str()); if (_pOutputStream == NULL) throw UtlException("unable to open file \"" + sFileName + "\" for writing"); getOutputStream() << "" << std::endl; } else { _pInputStream = ScpStream::openSTLInputFile(sFileName.c_str()); if (_pInputStream == NULL) throw UtlException("unable to open file \"" + sFileName + "\" for reading"); std::string sLineVersion; if ( ! readLine(getInputStream() , sLineVersion) ) { throw UtlException("No version line in XML file: " + sFileName ); } } _sFileName=sFileName; } UtlXMLStream::UtlXMLStream(std::istream& myStream) : _pInputStream(&myStream), _bOwnerOfFileStream(false) { std::string sLineVersion; if ( ! readLine(getInputStream() , sLineVersion) ) { throw UtlException("No version line in XML" ); } } UtlXMLStream::UtlXMLStream(std::iostream& myStream) : _pInputStream(&myStream), _pOutputStream(&myStream), _bOwnerOfFileStream(false) { std::string sLineVersion; if ( ! readLine(getInputStream() , sLineVersion) ) { throw UtlException("No version line in XML" ); } } // write part UtlXMLStream::~UtlXMLStream() { if (_bOwnerOfFileStream) { if (_pOutputStream != NULL) { ((std::ofstream*) _pOutputStream)->close(); delete _pOutputStream; } if (_pInputStream != NULL) { ((std::ifstream*) _pInputStream)->close(); delete _pInputStream; } } } void UtlXMLStream::writeStartTag(const std::string& sTag) { getOutputStream() << _sIndentation.c_str() << "<" << sTag.c_str() << ">" << std::endl; _sIndentation += "\t"; } void UtlXMLStream::writeEndTag(const std::string& sTag) { _sIndentation = _sIndentation.substr(1); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeTag(const std::string& sTag) { getOutputStream() << _sIndentation.c_str() << "<" << sTag.c_str() << "/>" << std::endl; } void UtlXMLStream::writeBeginningOfObject(const std::string& sTypeName) { getOutputStream() << _sIndentation.c_str() << "<" << sTypeName.c_str(); _sIndentation += "\t"; } void UtlXMLStream::writeEndOfObject(const std::string& sTypeName) { _sIndentation = _sIndentation.substr(1); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeEndOfObject() { _sIndentation = _sIndentation.substr(1); getOutputStream() << " />" << std::endl; } std::string UtlXMLStream::normalizeAttributeName(const std::string& sName) const { char c = sName[0]; if ((c < 'A') || (c > 'Z')) return sName; if (sName.size() >= 2) { char c1 = sName[1]; if ((c1 >= 'A') && (c1 <= 'Z')) return sName; } std::string sNewName = sName; sNewName[0] = c + ' '; return sNewName; } void UtlXMLStream::writeAttribute(const std::string& sName, int iValue) { std::string sNormalizedName = normalizeAttributeName(sName); getOutputStream() << " " << sNormalizedName.c_str() << "=\"" << iValue << "\""; } void UtlXMLStream::writeAttribute(const std::string& sName, long lValue) { std::string sNormalizedName = normalizeAttributeName(sName); getOutputStream() << " " << sNormalizedName.c_str() << "=\"" << lValue << "\""; } void UtlXMLStream::writeAttribute(const std::string& sName, double dValue) { std::string sNormalizedName = normalizeAttributeName(sName); char sNumber[300]; sprintf(sNumber, "%f", dValue); getOutputStream() << " " << sNormalizedName.c_str() << "=\"" << sNumber << "\""; } void UtlXMLStream::writeAttribute(const std::string& sName, const std::string& sValue) { std::string sNormalizedName = normalizeAttributeName(sName); std::string sXMLText = convertToXMLText(sValue); getOutputStream() << " " << sNormalizedName.c_str() << "=\"" << sXMLText.c_str() << "\""; } void UtlXMLStream::writeAttribute(const std::string& sName, bool bValue) { std::string sNormalizedName = normalizeAttributeName(sName); getOutputStream() << " " << sNormalizedName.c_str() << "=\""; if (bValue) getOutputStream() << "True"; else getOutputStream() << "False"; getOutputStream() << "\""; } void UtlXMLStream::writeAttribute(const std::string& sName, const UtlDate& myValue) { std::string sNormalizedName = normalizeAttributeName(sName); std::string sDate = myValue.getString(); if (!myValue.isNull()) { getOutputStream() << " " << sNormalizedName.c_str() << "=\"" << sDate.c_str() << "\""; } } void UtlXMLStream::writeEndOfAttributes() { getOutputStream() << ">" << std::endl; } void UtlXMLStream::writeArrayElement(int iValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeArrayElement(double dValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeArrayElement(const std::string& sValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeArrayElement(bool bValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeArrayElement(const UtlDate& myValue) { std::string sDate = myValue.getString(); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeHashtableEntry(const std::string& sKey, const std::string& sValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeHashtableEntry(const std::string& sKey, double dValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeHashtableEntry(const std::string& sKey, const std::vector& listOfValues) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; _sIndentation += "\t"; for (std::vector::const_iterator i = listOfValues.begin(); i != listOfValues.end(); i++) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } _sIndentation = _sIndentation.substr(1); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeHashtableEntry(const std::string& sKey, const std::vector& listOfValues) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; _sIndentation += "\t"; for (std::vector::const_iterator i = listOfValues.begin(); i != listOfValues.end(); i++) { getOutputStream() << _sIndentation.c_str() << "c_str() << "\" >" << std::endl; } _sIndentation = _sIndentation.substr(1); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeHashtableEntry(int iKey, int iValue) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeBeginningOfAggregation(const std::string& sOwnerClass, const std::string& sName) { getOutputStream() << _sIndentation.c_str() << "<" << sOwnerClass.c_str() << "_" << sName.c_str() << ">" << std::endl; _sIndentation += "\t"; } void UtlXMLStream::writeEndOfAggregation(const std::string& sOwnerClass, const std::string& sName) { _sIndentation = _sIndentation.substr(1); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeBeginningOfAssociation(const std::string& sOwnerClass, const std::string& sName) { getOutputStream() << _sIndentation.c_str() << "<" << sOwnerClass.c_str() << "_" << sName.c_str() << ">" << std::endl; _sIndentation += "\t"; } void UtlXMLStream::writeEndOfAssociation(const std::string& sOwnerClass, const std::string& sName) { _sIndentation = _sIndentation.substr(1); getOutputStream() << _sIndentation.c_str() << "" << std::endl; } void UtlXMLStream::writeObjectReference(const std::string& sTypeName, const std::string& /*sIDAttrName*/, const std::string& sIdentifier) { getOutputStream() << _sIndentation.c_str() << "" << std::endl; } std::string UtlXMLStream::convertToXMLText(const std::string& sText) { std::string sResult; for (std::string::size_type i = 0; i < sText.size(); i++) { char a = sText[i]; switch(a) { case '&': sResult += "&";break; case '<': sResult += "<";break; case '>': sResult += ">";break; case '\"': sResult += """;break; default: sResult += a; break; } } return sResult; } // read part bool UtlXMLStream::readStartTag( std::string& sTag) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } if (!readWord( getInputStream(), sTag )) return false; iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readEndTag(std::string& sTag) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } if (!readWord( getInputStream(), sTag )) return false; iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readTag(std::string& sTag) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } if (!readWord( getInputStream(), sTag )) return false; if (iChar != '/') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readBeginningOfObject(std::string& sTypeName) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } if (!readWord( getInputStream(), sTypeName )) return false; return true; } bool UtlXMLStream::readName(std::string& sName) { skipBlanks( getInputStream() ); std::string sNonNormaliseName; if (!readWord( getInputStream(), sNonNormaliseName )) return false; sName = normalizeAttributeName(sNonNormaliseName); return true; } bool UtlXMLStream::readBeginningOfAttribute() { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '=') { return false; } iChar=readChar( getInputStream() ); if (iChar != '\"') { return false; } return true; } bool UtlXMLStream::readEndOfAttribute() { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '\"') { return false; } return true; } bool UtlXMLStream::readEndOfObject( std::string& sTypeName) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } if (!readWord( getInputStream(), sTypeName )) return false; iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readEndOfObject() { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readAttribute(std::string& sName, int& iValue) { skipBlanks( getInputStream() ); if (!readName(sName)) return false; if (!readBeginningOfAttribute()) return false; if (!readInt( getInputStream() , iValue)) return false; if (!readEndOfAttribute()) return false; return true; } bool UtlXMLStream::readAttribute(std::string& sName, long& lValue) { skipBlanks( getInputStream() ); if (!readName(sName)) return false; if (!readBeginningOfAttribute()) return false; if (!readLong( getInputStream() , lValue)) return false; if (!readEndOfAttribute()) return false; return true; } bool UtlXMLStream::readAttribute(std::string& sName, double& dValue) { skipBlanks( getInputStream() ); if (!readName(sName)) return false; if (!readBeginningOfAttribute()) return false; if (!readDouble( getInputStream() , dValue)) return false; if (!readEndOfAttribute()) return false; return true; } bool UtlXMLStream::readAttribute(std::string& sName, std::string& sValue) { skipBlanks( getInputStream() ); if (!readName(sName)) return false; // if (!readBeginningOfAttribute()) // return false; // std::string sXMLText; // if (!readName( sXMLText)) // return false; int iChar=readChar( getInputStream() ); if (iChar != '=') { return false; } std::string sXMLText; if (!readString( getInputStream(), sXMLText)) return false; sValue=convertXMLTextToClassicText( sXMLText ); // if (!readEndOfAttribute()) // return false; return true; } bool UtlXMLStream::readAttribute(std::string& sName, bool& bValue) { skipBlanks( getInputStream() ); if (!readName(sName)) return false; if (!readBeginningOfAttribute()) return false; std::string sXMLText; if (!readString( getInputStream() , sXMLText)) return false; if (stricmp(sXMLText.c_str(),"TRUE")) bValue=true; if (stricmp(sXMLText.c_str(),"FALSE")) bValue=false; else return false; if (!readEndOfAttribute()) return false; return true; } bool UtlXMLStream::readAttribute(std::string& sName, UtlDate& myValue) { skipBlanks( getInputStream() ); if (!readName(sName)) return false; if (!readBeginningOfAttribute()) return false; struct tm tmValue; if (!readDate( getInputStream() , tmValue)) return false; myValue=UtlDate( tmValue.tm_year, tmValue.tm_mon, tmValue.tm_mday, 0, 0, 0); if (!readEndOfAttribute()) return false; return true; } bool UtlXMLStream::readEndOfAttributes() { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readArrayElement(int& iValue) { skipBlanks( getInputStream() ); if (!readBeginOfArrayElement("int")) return false; if (!readInt( getInputStream() , iValue)) return false; if (!readEndOfArrayElement()) return false; return true; } bool UtlXMLStream::readArrayElement(double& dValue) { skipBlanks( getInputStream() ); if (!readBeginOfArrayElement("double")) return false; if (!readDouble( getInputStream() , dValue)) return false; if (!readEndOfArrayElement()) return false; return true; } bool UtlXMLStream::readArrayElement(std::string& sValue) { skipBlanks( getInputStream() ); if (!readBeginOfArrayElement("string")) return false; std::string sXMLText; if (!readString( getInputStream() , sXMLText)) return false; sValue=convertXMLTextToClassicText( sXMLText ); if (!readEndOfArrayElement()) return false; return true; } bool UtlXMLStream::readArrayElement(bool& bValue) { skipBlanks( getInputStream() ); if (!readBeginOfArrayElement("bool")) return false; std::string sXMLText; if (!readString( getInputStream() , sXMLText)) return false; if (stricmp(sXMLText.c_str(),"TRUE")) bValue=true; if (stricmp(sXMLText.c_str(),"FALSE")) bValue=false; else return false; if (!readEndOfArrayElement()) return false; return true; } bool UtlXMLStream::readArrayElement(UtlDate& myValue) { skipBlanks( getInputStream() ); if (!readBeginOfArrayElement("date")) return false; struct tm tmValue; if (!readDate( getInputStream() , tmValue)) return false; myValue=UtlDate( tmValue.tm_year, tmValue.tm_mon, tmValue.tm_mday, 0, 0, 0); if (!readEndOfArrayElement()) return false; return true; } bool UtlXMLStream::readKeyOfHashTable(std::string& sKey) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } std::string sTrash; if (!readString( getInputStream() , sTrash)) return false; if (strcmp(sTrash.c_str(),"pair")) return false; std::string sKeyTag; if (!readAttribute( sKeyTag , sKey)) return false; if (strcmp(sKeyTag.c_str(),"key")) return false; return true; } bool UtlXMLStream::readEndOfHashTable() { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readHashtableEntry(std::string& sKey, std::string& sValue) { int iChar; skipBlanks( getInputStream() ); if (!readKeyOfHashTable(sKey)) return false; iChar=readChar( getInputStream() ); if (iChar != ' ') { return false; } std::string sValueTag; if (!readAttribute( sValueTag , sValue)) return false; if (!readEndOfHashTable()) return false; return true; } bool UtlXMLStream::readBeginOfArrayElement(std::string sType) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } std::string sReadType; if (!readString( getInputStream(), sReadType)) if (sReadType!=sType) return false; std::string sValue; if (!readString( getInputStream(), sValue)) return false; iChar=readChar( getInputStream() ); if (iChar != ' ') { return false; } if (strcmp(sValue.c_str(),"value") ) return false; return true; } bool UtlXMLStream::readEndOfArrayElement() { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readHashtableEntry(std::string& sKey, double& dValue) { int iChar; skipBlanks( getInputStream() ); if (!readKeyOfHashTable(sKey)) return false; iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } std::string sValueTag; if (!readAttribute( sValueTag , dValue)) return false; if (!readEndOfHashTable()) return false; return true; } bool UtlXMLStream::readHashtableEntry(std::string& sKey, std::vector& listOfValues) { int iChar; skipBlanks( getInputStream() ); if (!readKeyOfHashTable(sKey)) return false; iChar=readChar( getInputStream() ); if (iChar != ' ') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } bool bAtLeastOne=false; bool bContinue=true; listOfValues.clear(); while (bContinue) { double dValue; int iPos = getInputStream().tellg(); bContinue=readArrayElement(dValue); if (bContinue) { listOfValues.push_back(dValue); bAtLeastOne=true; } else { getInputStream().seekg(iPos); } } if (!bAtLeastOne) { return false; } if (!readEndOfHashTable()) return false; return true; } bool UtlXMLStream::readHashtableEntry(std::string& sKey, std::vector& listOfValues) { int iChar; skipBlanks( getInputStream() ); if (!readKeyOfHashTable(sKey)) return false; iChar=readChar( getInputStream() ); if (iChar != ' ') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } bool bAtLeastOne=false; bool bContinue=true; listOfValues.clear(); while (bContinue) { int iPos = getInputStream().tellg(); std::string sValue; bContinue=readArrayElement(sValue); if (bContinue) { listOfValues.push_back(sValue); bAtLeastOne=true; } else { getInputStream().seekg(iPos); } } if (!bAtLeastOne) { return false; } if (!readEndOfHashTable()) return false; return true; } bool UtlXMLStream::readBeginningOfAggregation(std::string& sOwnerClass, std::string& sName) { return readBeginningOfAssociation( sOwnerClass, sName); } bool UtlXMLStream::readEndOfAggregation(std::string& sOwnerClass, std::string& sName) { return readEndOfAssociation( sOwnerClass, sName); } bool UtlXMLStream::readBeginningOfAssociation(std::string& sOwnerClass, std::string& sName) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } // Read a string, search '_' and split the string in two std::string sCompletWord,sDebut,sFin; if (!readWord( getInputStream(), sCompletWord )) return false; if (!splitString( sCompletWord, '_', sOwnerClass, sName)) return false; iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readEndOfAssociation(std::string& sOwnerClass, std::string& sName) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } // Read a string, search '_' and split the string in two std::string sCompletWord,sDebut,sFin; if (!readWord( getInputStream(), sCompletWord )) return false; if (!splitString( sCompletWord, '_', sOwnerClass, sName)) return false; iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } bool UtlXMLStream::readObjectReference(std::string& sTypeName, std::string& sIDAttrName, std::string& sIdentifier) { int iChar; skipBlanks( getInputStream() ); iChar=readChar( getInputStream() ); if (iChar != '<') { return false; } std::string sTrash; // reference if (!readString( getInputStream(), sTrash)) return false; if (strcmp(sTrash.c_str(),"reference")) return false; // type if (!readAttribute(sTrash, sTypeName)) return false; // ID if (!readAttribute( sIDAttrName, sIdentifier)) return false; iChar=readChar( getInputStream() ); if (iChar != '/') { return false; } iChar=readChar( getInputStream() ); if (iChar != '>') { return false; } return true; } std::string UtlXMLStream::convertXMLTextToClassicText(const std::string& sText) { std::string sResult,sResultInter; for (std::string::size_type i = 0; i < sText.size(); i++) { char a = sText[i]; switch(a) { case '&': sResultInter += "&";break; case 'a': sResultInter += "a";break; case 'm': sResultInter += "m";break; case 'p': sResultInter += "p";break; case ';': if (!strcmp(sResultInter.c_str(),"&")) { sResult += "&"; sResultInter = ""; } break; default: if (!sResultInter.empty()) { sResult+=sResultInter; sResultInter = ""; } sResult += a; break; } } if (!sResultInter.empty()) { sResult+=sResultInter; sResultInter = ""; } return sResult; } }