S3FC project page S3FC home page

Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

s3_xml_config.cc

Go to the documentation of this file.
00001 /*
00002  * Stone Three Foundation Class (s3fc) provides a number of utility classes.
00003  * Copyright (C) 2001 by Stone Three Signal Processing (Pty) Ltd.
00004  *
00005  * Authored by Stone Three Signal Processing (Pty) Ltd.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  * 
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  * 
00021  * Please see the file 'COPYING' in the source root directory.
00022  */
00023 
00030 #include <s3fc/s3_macros.h>
00031 #include <s3fc/s3_xml_config.h>
00032 #include <s3fc/s3_exception.h>
00033 #include <fstream>
00034 #include <iostream>
00035 
00036 //
00037 s3_xml_exception::s3_xml_exception(const std::string& errstr):
00038    s3_exception(errstr)
00039 {
00040 }
00041 
00042 // constructor
00043 // copied from the ORIGINAL s3_config_basse.cc authored by
00044 //    Jan Pool <jpool@stonethree.com>
00045 s3_xml_config::s3_xml_config(const std::string& n_config_file,
00046               bool create_file) throw (s3_generic_exception):
00047    config_file(n_config_file),
00048    rootnode(0)
00049 {
00050    S3FC_DBG( std::cerr << "s3_xml_config::s3_xml_config(const string&"
00051         "n_config_file) " << std::endl);
00052    if ( create_file )
00053    {
00054       // create the file
00055       try
00056       {
00057     std::ofstream a_file( config_file.c_str(), std::ios::out );
00058     a_file.close();
00059       }
00060       catch (const std::exception& e)
00061       {
00062     throw s3_generic_exception("s3_xml_config::s3_xml_config Could not create file", e.what() );
00063       }
00064    }
00065    
00066    // init Xerces
00067    try
00068    {
00069       XMLPlatformUtils::Initialize();
00070    }
00071    catch(const XMLException& toCatch)
00072    {
00073       throw s3_generic_exception("s3_xml_config(const string&)",
00074              domstr_to_string(toCatch.getMessage()));
00075    }
00076    refresh();
00077 }
00078 
00079 // destructor
00080 // copied from the ORIGINAL s3_config_basse.cc authored by
00081 //    Jan Pool <jpool@stonethree.com>
00082 s3_xml_config::~s3_xml_config()
00083 {
00084    S3FC_DBG( std::cerr << "s3_xml_config::~s3_xml_config" << std::endl);
00085 
00086    // object is going out of scope, so clean up
00087    delete rootnode;
00088    rootnode = 0;
00089    
00090    // de-init Xerces
00091    try
00092    {
00093       XMLPlatformUtils::Terminate();
00094    }   
00095    catch(const XMLException& toCatch)
00096    {
00097       throw s3_generic_exception("s3_xml_config()",
00098               domstr_to_string(toCatch.getMessage()));
00099    }
00100 }
00101 
00102 // return the root node
00103 s3_config_node& s3_xml_config::get_rootnode() const
00104 {
00105    return *rootnode;
00106 }
00107 
00108 void s3_xml_config::refresh() 
00109 {
00110    // parse XML document into DOM tree
00111    DOM_Document doc = parse(config_file);
00112 #ifdef DEBUG
00113    // show the DOM tree
00114    dump_tree(doc);
00115 #endif   
00116    
00117    rootnode = build_tree(doc);
00118 }
00119 
00120 void s3_xml_config::set_config_file(const std::string& n_config_file)
00121 {
00122    config_file = n_config_file;
00123 }
00124 
00125 // recursively write contents to file
00126 void s3_xml_config::write_node(const std::string& filename,
00127                 const s3_config_node& node)
00128 {
00129    std::ofstream fs(filename.c_str(), std::ios::out | std::ios::trunc);
00130    write_node(fs, node, 0);
00131    fs.close();
00132 }
00133 
00134 //
00135 void s3_xml_config::write_node(std::ostream& os,
00136                 const s3_config_node& node,
00137                 unsigned int depth)
00138 {
00139    static const int tab_size = 5;
00140    write_spaces(os, depth*tab_size);
00141    os << "<" << node.get_name();
00142    for (std::map<std::string,std::string>::const_iterator ptr =
00143       node.get_attributes().begin();
00144     ptr != node.get_attributes().end();
00145     ptr++) 
00146    {
00147       os << " " << ptr->first << "=\"" << ptr->second << "\"";
00148    }
00149    os << ">" << std::endl;
00150    if ( node.get_value().length() )
00151    {
00152       write_spaces(os, (depth+1)*tab_size);
00153       os << node.get_value();
00154       os << std::endl;
00155    }
00156    for (unsigned int i = 0; i < node.get_num_children(); i++)
00157    {
00158       write_node(os, node.get_child(i), depth+1);
00159    }
00160    write_spaces(os, depth*tab_size);
00161    os << "</" << node.get_name() << ">" << std::endl;
00162 }
00163 
00164 //  write n spaces to os
00165 void s3_xml_config::write_spaces(std::ostream& os, unsigned int n) 
00166 {
00167    for ( unsigned int i = 0; i < n; i++ )
00168    {
00169       os << " ";
00170    }
00171 }
00172 
00173 // parse the XML document into a DOM tree
00174 // copied from the ORIGINAL s3_config_base.cc authored by
00175 //    Jan Pool <jpool@stonethree.com>
00176 DOM_Document s3_xml_config::parse(const std::string& filename)
00177    throw (s3_generic_exception, s3_xml_exception)
00178 {   
00179    DOMParser parser;
00180    // install our own ErrorHandler - this throws an s3_xml_exception
00181    // when presented with any warnings, errors or fatal errors
00182    s3_xml_config::error_handler err_handler;
00183    try
00184    {
00185       parser.setErrorHandler(&err_handler);
00186       parser.setValidationScheme(DOMParser::Val_Auto);
00187       parser.setDoNamespaces(false);
00188       parser.setExitOnFirstFatalError(true);
00189       parser.parse( filename.c_str() );
00190    }
00191    // intercept and rethrow parse errors
00192    catch (const s3_xml_exception& e)
00193    {
00194       throw e;
00195    }
00196    // the following should catch most expected errors
00197    catch (const XMLException& e)
00198    {
00199       throw s3_generic_exception("s3_xml_config::parse() " 
00200              "caught XMLException",
00201              domstr_to_string(e.getMessage()));
00202    }
00203    catch (const DOM_DOMException& e)
00204    {
00205       throw s3_generic_exception("s3_xml_config::parse() "
00206              "caught DOM_DOMException",
00207              domstr_to_string(e.msg));
00208    }
00209    catch (const SAXParseException& e)
00210    {
00211       // this should not really occur as all SAXParseExceptions should
00212       // be caught by our error handler, converted to s3_xml_exceptions and
00213       // rethrown.
00214       std::stringstream ss;
00215       ss << "s3_xml_config::parse():"
00216     << " caught SAXParseException: ";
00217       ss << "" << domstr_to_string(e.getMessage()) << "";
00218       ss << " in file ";
00219       if ( e.getSystemId() )
00220       {
00221     ss << "'" << domstr_to_string(e.getSystemId()) << "'";
00222       }
00223       else
00224       {
00225     ss << "<unknown>";
00226       }
00227       ss << " line " << e.getLineNumber() << ", column "
00228     << e.getColumnNumber();
00229       std::cerr << ss.str() << std::endl << std::flush;
00230    }
00231    // catch-all if we really don't know why
00232    catch (...)
00233    {
00234       throw s3_generic_exception("s3_xml_config::parse(): ",
00235              "An unkown parsing error occured");
00236    }
00237    DOM_Document doc = parser.getDocument();
00238    return doc;
00239 }
00240 
00245 s3_config_node* s3_xml_config::build_tree(const DOM_Node& node)
00246 {
00247    
00248    // name, value, attr
00249    std::string name = get_name(node);
00250    std::string value = get_value(node);
00251    std::map<std::string, std::string> attributes = get_attributes(node);
00252    std::vector<s3_config_node*> c = get_children(node);
00253    // deep copy into list
00254    std::vector<s3_config_node> children;
00255    for (std::vector<s3_config_node*>::iterator it = c.begin();
00256    it != c.end();
00257    ++it) 
00258    {
00259       children.push_back(**it);
00260    }
00261    return new s3_config_node(name, 
00262               value, 
00263               0,
00264               attributes, 
00265               children);
00266 }
00267 
00268 // get and convert name
00269 std::string s3_xml_config::get_name(const DOM_Node& node)
00270 {
00271    return domstr_to_string(node.getNodeName());
00272 }
00273 
00274 // copied from the ORIGINAL s3_config_basse.cc authored by
00275 //    Gerhard Esterhuizen <gesterhuizen@stonethree.com>
00276 std::string s3_xml_config::get_value(const DOM_Node& node)
00277 {
00278    DOM_NodeList dlst = node.getChildNodes();
00279    std::string val;
00280    for (unsigned int i = 0; i < dlst.getLength(); i++)
00281    {
00282       if (dlst.item(i).getNodeType() == DOM_Node::TEXT_NODE)
00283       {
00284     std::string tmpval = domstr_to_string(dlst.item(i).getNodeValue());
00285     // cut whitespace from beginning
00286     int strt_i = tmpval.find_first_not_of(" \t\n\r");
00287     int end_i = tmpval.find_last_not_of(" \t\n\r");
00288     if ( strt_i != -1 )
00289     {
00290        if ( val.length() )
00291        {
00292           val += " ";
00293           val += tmpval.substr(strt_i, end_i-strt_i+1);
00294        }
00295        else
00296        {
00297           val = tmpval.substr(strt_i, end_i-strt_i+1);
00298        }
00299     }
00300       }
00301    } 
00302    return val;
00303    //   return domstr_to_string(node.getNodeValue());
00304 }
00305 
00306 // copied from the ORIGINAL s3_config_basse.cc authored by
00307 //    Gerhard Esterhuizen <gesterhuizen@stonethree.com>
00308 std::map<std::string, std::string> s3_xml_config::get_attributes(
00309    const DOM_Node& node)
00310 {
00311    std::map<std::string, std::string> m;
00312    DOM_NamedNodeMap attrs = node.getAttributes();
00313    if ( attrs != 0 )
00314    {
00315       for ( unsigned int i = 0; i < attrs.getLength(); i++ ) 
00316       {
00317     DOM_Node n = attrs.item(i);
00318     std::string name = domstr_to_string(n.getNodeName());
00319     std::string value = domstr_to_string(n.getNodeValue());
00320     m[name] = value;
00321       }
00322    }
00323    return m;
00324 }
00325 
00326 // adapted from the ORIGINAL s3_config_basse.cc authored by
00327 //    Gerhard Esterhuizen <gesterhuizen@stonethree.com>
00328 // extract DOM nodes with type ELEMENT_NODE
00329 std::vector<s3_config_node*> s3_xml_config::get_children(const DOM_Node& node)
00330 {
00331    // DOM list of immediate children
00332    DOM_NodeList dlst = node.getChildNodes();
00333    std::vector<s3_config_node*> lst;
00334    for (unsigned int i = 0; i < dlst.getLength(); i++)
00335    {
00336       if (dlst.item(i).getNodeType() == DOM_Node::ELEMENT_NODE)
00337       {
00338     lst.push_back( build_tree(dlst.item(i)) );
00339       }
00340    }
00341    return lst;
00342 }
00343 
00344 // copied from the ORIGINAL s3_config_basse.cc authored by
00345 //    Jan Pool <jpool@stonethree.com>
00346 std::string s3_xml_config::domstr_to_string(const DOMString& dstr)
00347 {
00348    const char* c = dstr.transcode();
00349    std::string str(c);
00350    // caller owns char* returned by transcode !
00351 #ifndef _WIN32 // Might leak.
00352    delete c;
00353 #endif
00354    return str;
00355 }
00356   
00357 #ifdef DEBUG
00358 //
00359 void s3_xml_config::dump_DOM_tree(const DOM_Node& node) const
00360 {
00361    S3FC_DBG( std::cerr << "Node type is: " << node.getNodeType() << std::endl);
00362    switch (node.getNodeType())
00363    {
00364    case DOM_Node::ELEMENT_NODE:
00365    {
00366       
00367       S3FC_DBG( std::cerr << "Element: " << node.getNodeName() << std::endl);
00368       
00369       // The NamedNodeMap holds the attributes of the element.
00370       DOM_NamedNodeMap attrib = node.getAttributes();
00371 
00372       for (int i = 0; i < static_cast<int>(attrib.getLength()); i++)
00373       {
00374     S3FC_DBG( std::cerr << "Attrib: " << attrib.item(i).getNodeName() <<
00375          " = " << attrib.item(i).getNodeValue() << std::endl );
00376       }
00377       
00378       break;
00379    }
00380    case DOM_Node::TEXT_NODE:
00381       S3FC_DBG( std::cerr <<  node.getNodeValue() << std::endl);
00382       break;
00383    default:
00384       D ( std::cerr << "Node type is: " << node.getNodeType() << std::endl );
00385       break;
00386    }
00387 
00388    DOM_NodeList  child_list = node.getChildNodes();
00389 
00390    if (child_list.getLength() > 0)
00391    {
00392       for (int i = 0; i < static_cast<int>(child_list.getLength()); i++)
00393       {
00394     dump_tree(child_list.item(i));
00395       }
00396    }
00397 }
00398 #endif
00399 
00400 //
00401 void s3_xml_config::error_handler::warning(const SAXParseException& e)
00402 {
00403    assemble_and_throw(e, "warning");
00404 }
00405 
00406 //
00407 void s3_xml_config::error_handler::error(const SAXParseException& e)
00408 {
00409    assemble_and_throw(e, "error");
00410 }
00411 
00412 //
00413 void s3_xml_config::error_handler::fatalError(const SAXParseException& e)
00414 {
00415    assemble_and_throw(e, "fatal error");
00416 }
00417 
00418 //
00419 void s3_xml_config::error_handler::resetErrors()
00420 {
00421    return;
00422 }
00423 
00424 //
00425 void s3_xml_config::error_handler::assemble_and_throw(
00426    const SAXParseException& e,
00427    const std::string& type)
00428 {
00429       std::stringstream ss;
00430       ss << "XML Parser reported " << type << ": ";
00431       ss << domstr_to_string(e.getMessage());
00432       ss << " in file ";
00433       if ( e.getSystemId() )
00434       {
00435     ss << "'" << domstr_to_string(e.getSystemId()) << "'";
00436       }
00437       else
00438       {
00439     ss << "<unknown>";
00440       }
00441       ss << " line " << e.getLineNumber() << ", column "
00442     << e.getColumnNumber();
00443       throw s3_xml_exception(ss.str());
00444 }
00445 
00446 //
00447 std::ostream& operator<<(std::ostream& str, const DOMString& s)
00448 {
00449    char* buf = s.transcode();
00450    str << buf;
00451    delete [] buf;
00452    return str;
00453 }

Send comments to: s3fc@stonethree.com SourceForge Logo