xmlreader.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2003-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Fri Jun 20 16:09:33 2003
00010 // commit: $Id: xmlreader.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/io/xmlreader.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_IO_XMLREADER_CC_UTC20050626084021_DEFINED
00035 #define GROOVX_IO_XMLREADER_CC_UTC20050626084021_DEFINED
00036 
00037 #include "io/xmlreader.h"
00038 
00039 #include "io/reader.h"
00040 #include "io/readobjectmap.h"
00041 #include "io/xmlparser.h"
00042 
00043 #include "nub/ref.h"
00044 
00045 #include "rutz/demangle.h"
00046 #include "rutz/error.h"
00047 #include "rutz/fstring.h"
00048 #include "rutz/gzstreambuf.h"
00049 #include "rutz/sfmt.h"
00050 #include "rutz/shared_ptr.h"
00051 #include "rutz/value.h"
00052 
00053 #include <cstring>           // for strcmp()
00054 #include <iostream>          // for cout in xml_debug()
00055 #include <istream>           // for tree_builder constructor
00056 #include <map>               // for group_element
00057 #include <ostream>           // for xml_element::trace()
00058 #include <string>            // for string_element implementation
00059 #include <typeinfo>          // for error reporting and xml_element::trace()
00060 #include <vector>            // for stack in tree_builder
00061 
00062 #include "rutz/trace.h"
00063 #include "rutz/debug.h"
00064 GVX_DBG_REGISTER
00065 
00066 using rutz::fstring;
00067 using rutz::shared_ptr;
00068 
00069 using nub::ref;
00070 using nub::soft_ref;
00071 
00072 namespace
00073 {
00074   void invalid_attr(const char* attname, const char* eltype,
00075                     const char* elname, const rutz::file_pos& pos)
00076   {
00077     throw rutz::error(rutz::sfmt("invalid '%s' attribute for <%s> "
00078                                  "element with name: %s",
00079                                  attname, eltype, elname),
00080                       pos);
00081   }
00082 
00083   const char* find_attr(const char** attr, const char* attname,
00084                         const char* eltype, const char* elname,
00085                         const rutz::file_pos& pos)
00086   {
00087     for (int i = 0; attr[i] != 0; i += 2)
00088       {
00089         if (strcmp(attr[i], attname) == 0)
00090           return attr[i+1];
00091       }
00092 
00093     throw rutz::error(rutz::sfmt("missing '%s' attribute for <%s> "
00094                                  "element with name: %s",
00095                                  attname, eltype, elname),
00096                       pos);
00097 
00098     GVX_ASSERT(0);
00099     return 0; // can't happen
00100   }
00101 
00102   class xml_element;
00103 
00104   typedef shared_ptr<xml_element> el_ptr;
00105 
00106   class xml_element
00107   {
00108   public:
00109     virtual ~xml_element();
00110 
00111     virtual void add_child(const char* /*name*/, el_ptr /*elp*/)
00112     {
00113       throw rutz::error(rutz::sfmt("child elements not allowed "
00114                                    "within elements of type: %s",
00115                                    rutz::demangled_name(typeid(*this))),
00116                         SRC_POS);
00117     }
00118 
00119     virtual void character_data(const char* /*text*/, int /*len*/) { }
00120 
00121     virtual void trace(std::ostream& os,
00122                        int depth, const char* name) const = 0;
00123 
00124     virtual void finish() {}
00125   };
00126 
00127   xml_element::~xml_element() {}
00128 
00129   template <class T>
00130   T& element_cast(xml_element* elp, const fstring& name,
00131                  const rutz::file_pos& pos)
00132   {
00133     if (elp == 0)
00134       throw rutz::error(rutz::sfmt("no element with name: %s",
00135                                    name.c_str()),
00136                         SRC_POS);
00137     T* t = dynamic_cast<T*>(elp);
00138     if (t == 0)
00139       throw rutz::error(rutz::sfmt("wrong element type; expected %s, got %s",
00140                                    rutz::demangled_name(typeid(T)),
00141                                    rutz::demangled_name(typeid(*elp))),
00142                         pos);
00143     return *t;
00144   }
00145 
00146   template <class T>
00147   class basic_element : public xml_element
00148   {
00149   public:
00150     basic_element(const char* str, const char* name);
00151     virtual ~basic_element() {}
00152 
00153     virtual void trace(std::ostream& os,
00154                        int depth, const char* name) const
00155     {
00156       for (int i = 0; i < depth; ++i) os << "  ";
00157       os << name << "(" << typeid(T).name() << ") value=" << m_value << "\n";
00158     }
00159 
00160     T m_value;
00161   };
00162 
00163   template <>
00164   basic_element<double>::basic_element(const char* str, const char* name) :
00165     m_value(0.0)
00166   {
00167     int n = sscanf(str, "%lf", &m_value);
00168     if (n != 1)
00169       {
00170         invalid_attr("value", "double", name, SRC_POS);
00171       }
00172   }
00173 
00174   template <>
00175   basic_element<int>::basic_element(const char* str, const char* name) :
00176     m_value(0)
00177   {
00178     int n = sscanf(str, "%d", &m_value);
00179     if (n != 1)
00180       {
00181         invalid_attr("value", "int", name, SRC_POS);
00182       }
00183   }
00184 
00185   template <>
00186   basic_element<bool>::basic_element(const char* str, const char* name) :
00187     m_value(true)
00188   {
00189     int i = 0;
00190     int n = sscanf(str, "%d", &i);
00191     if (n != 1)
00192       {
00193         invalid_attr("value", "bool", name, SRC_POS);
00194       }
00195     m_value = bool(i);
00196   }
00197 
00198   class string_element : public xml_element
00199   {
00200   public:
00201     string_element() : m_value() {}
00202     virtual ~string_element() {}
00203 
00204     virtual void trace(std::ostream& os,
00205                        int depth, const char* name) const
00206     {
00207       for (int i = 0; i < depth; ++i) os << "  ";
00208       os << name << "(string) value=" << m_value << "\n";
00209     }
00210 
00211     virtual void character_data(const char* text, int len)
00212     {
00213       m_value.append(text, len);
00214     }
00215 
00216     std::string m_value;
00217   };
00218 
00219   typedef basic_element<double> double_element;
00220   typedef basic_element<int> int_element;
00221   typedef basic_element<bool> bool_element;
00222 
00223   class value_element : public xml_element
00224   {
00225   public:
00226     value_element(const char* val, const char* /*name*/) : m_value(val) {}
00227     virtual ~value_element() {}
00228 
00229     virtual void trace(std::ostream& os,
00230                        int depth, const char* name) const
00231     {
00232       for (int i = 0; i < depth; ++i) os << "  ";
00233       os << name << "(valobj) value=" << m_value << "\n";
00234     }
00235 
00236     fstring m_value;
00237   };
00238 
00239   class objref_element : public xml_element
00240   {
00241   public:
00242     objref_element(const char** attr, const char* eltype, const char* name,
00243                   shared_ptr<io::object_map> objmap) :
00244       m_type(""),
00245       m_id(-1),
00246       m_objects(objmap)
00247     {
00248       m_id = atoi(find_attr(attr, "id", eltype, name, SRC_POS));
00249       m_type = find_attr(attr, "type", eltype, name, SRC_POS);
00250 
00251       if (m_id < 0)
00252         {
00253           invalid_attr("id", eltype, name, SRC_POS);
00254         }
00255 
00256       GVX_ASSERT(m_id >= 0);
00257 
00258       if (m_type.empty())
00259         {
00260           invalid_attr("type", eltype, name, SRC_POS);
00261         }
00262 
00263       GVX_ASSERT(!m_type.empty());
00264     }
00265 
00266     virtual ~objref_element() {}
00267 
00268     virtual void trace(std::ostream& os,
00269                        int depth, const char* name) const
00270     {
00271       for (int i = 0; i < depth; ++i) os << "  ";
00272       os << name << "(objref:" << m_type << ") id=" << m_id << "\n";
00273     }
00274 
00275     soft_ref<io::serializable> get_object()
00276     {
00277       if (m_id == 0)
00278         return soft_ref<io::serializable>();
00279       // else...
00280       return m_objects->get_existing_object(m_id);
00281     }
00282 
00283     fstring m_type;
00284     int m_id;
00285     shared_ptr<io::object_map> m_objects;
00286   };
00287 
00288   class group_element : public objref_element, public io::reader
00289   {
00290   public:
00291     group_element(const char** attr, const char* eltype, const char* name,
00292                  shared_ptr<io::object_map> objmap) :
00293       objref_element(attr, eltype, name, objmap),
00294       m_version(-1),
00295       m_elems()
00296     {
00297       m_version = atoi(find_attr(attr, "version", eltype, name, SRC_POS));
00298 
00299       if (m_version < 0)
00300         {
00301           invalid_attr("version", eltype, name, SRC_POS);
00302         }
00303       GVX_ASSERT(m_version >= 0);
00304     }
00305 
00306     virtual ~group_element() throw() {}
00307 
00308     virtual void add_child(const char* name, el_ptr elp)
00309     {
00310       m_elems[name] = elp;
00311     }
00312 
00313     virtual void trace(std::ostream& os,
00314                        int depth, const char* name) const
00315     {
00316       for (int i = 0; i < depth; ++i) os << "  ";
00317       os << name << "(object:" << m_type << "):\n";
00318       for (map_type::const_iterator
00319              itr = m_elems.begin(),
00320              stop = m_elems.end();
00321            itr != stop;
00322            ++itr)
00323         {
00324           (*itr).second->trace(os, depth+1, (*itr).first.c_str());
00325         }
00326     }
00327 
00328     virtual io::version_id input_version_id()
00329     {
00330       return m_version;
00331     }
00332 
00333     virtual char read_char(const fstring& /*name*/) { GVX_ASSERT(0); return '\0'; }
00334 
00335     virtual int read_int(const fstring& name)
00336     {
00337       el_ptr el = m_elems[name];
00338       int_element& ilp = element_cast<int_element>(el.get(), name, SRC_POS);
00339       return ilp.m_value;
00340     }
00341 
00342     virtual bool read_bool(const fstring& name)
00343     {
00344       el_ptr el = m_elems[name];
00345       bool_element& blp = element_cast<bool_element>(el.get(), name, SRC_POS);
00346       return blp.m_value;
00347     }
00348 
00349     virtual double read_double(const fstring& name)
00350     {
00351       el_ptr el = m_elems[name];
00352       double_element& dlp = element_cast<double_element>(el.get(), name, SRC_POS);
00353       return dlp.m_value;
00354     }
00355 
00356     virtual void read_value_obj(const fstring& name, rutz::value& v)
00357     {
00358       el_ptr el = m_elems[name];
00359       value_element& vlp = element_cast<value_element>(el.get(), name, SRC_POS);
00360       v.set_string(vlp.m_value);
00361     }
00362 
00363     virtual void read_byte_array(const fstring& name, rutz::byte_array& data)
00364     {
00365       default_read_byte_array(name, data);
00366     }
00367 
00368     virtual ref<io::serializable> read_object(const fstring& name)
00369     {
00370       return read_weak_object(name);
00371     }
00372 
00373     virtual soft_ref<io::serializable> read_weak_object(const fstring& name);
00374 
00375     virtual void read_owned_object(const fstring& name,
00376                                  ref<io::serializable> obj)
00377     {
00378       el_ptr el = m_elems[name];
00379       group_element& glp = element_cast<group_element>(el.get(), name, SRC_POS);
00380       glp.inflate(*obj);
00381     }
00382 
00383     virtual void read_base_class(const fstring& name,
00384                                  ref<io::serializable> base_part)
00385     {
00386       el_ptr el = m_elems[name];
00387       group_element& glp = element_cast<group_element>(el.get(), name, SRC_POS);
00388       glp.inflate(*base_part);
00389     }
00390 
00391     virtual ref<io::serializable> read_root(io::serializable* /*root*/)
00392     {
00393       GVX_ASSERT(0); return ref<io::serializable>(static_cast<io::serializable*>(0));
00394     }
00395 
00396     void inflate(io::serializable& obj)
00397     {
00398       obj.read_from(*this);
00399     }
00400 
00401   protected:
00402     virtual fstring read_string_impl(const fstring& name)
00403     {
00404       el_ptr el = m_elems[name];
00405       string_element& slp = element_cast<string_element>(el.get(), name, SRC_POS);
00406       return fstring(slp.m_value.c_str());
00407     }
00408 
00409   public:
00410     int m_version;
00411     typedef std::map<fstring, el_ptr> map_type;
00412     map_type m_elems;
00413   };
00414 
00415   class object_element : public group_element
00416   {
00417   public:
00418     object_element(const char** attr, const char* name,
00419                   shared_ptr<io::object_map> objmap) :
00420       group_element(attr, "object", name, objmap)
00421     {
00422       // Return the object for this id, creating a new object if
00423       // necessary:
00424       m_object = objmap->fetch_object(m_type.c_str(), m_id);
00425     }
00426 
00427     soft_ref<io::serializable> m_object;
00428 
00429     virtual void finish()
00430     {
00431       if (m_object.is_valid())
00432         inflate(*m_object);
00433     }
00434   };
00435 
00436   soft_ref<io::serializable> group_element::read_weak_object(const fstring& name)
00437   {
00438     el_ptr el = m_elems[name];
00439     objref_element& olp = element_cast<objref_element>(el.get(), name, SRC_POS);
00440     return olp.get_object();
00441   }
00442 
00443   el_ptr make_element(const char* el, const char** attr,
00444                       const char* name,
00445                       shared_ptr<io::object_map> objmap)
00446   {
00447     if (strcmp(el, "object") == 0)
00448       {
00449         return el_ptr(new object_element(attr, name, objmap));
00450       }
00451     else if (strcmp(el, "ownedobj") == 0)
00452       {
00453         return el_ptr(new group_element(attr, "ownedobj", name, objmap));
00454       }
00455     else if (strcmp(el, "baseclass") == 0)
00456       {
00457         return el_ptr(new group_element(attr, "baseclass", name, objmap));
00458       }
00459     else if (strcmp(el, "objref") == 0)
00460       {
00461         return el_ptr(new objref_element(attr, "objref", name, objmap));
00462       }
00463     else if (strcmp(el, "string") == 0)
00464       {
00465         return el_ptr(new string_element);
00466       }
00467     else
00468       {
00469         const char* val = find_attr(attr, "value", el, name, SRC_POS);
00470 
00471         if (strcmp(el, "double") == 0)
00472           {
00473             return el_ptr(new double_element(val, name));
00474           }
00475         else if (strcmp(el, "int") == 0)
00476           {
00477             return el_ptr(new int_element(val, name));
00478           }
00479         else if (strcmp(el, "bool") == 0)
00480           {
00481             return el_ptr(new bool_element(val, name));
00482           }
00483         else if (strcmp(el, "valobj") == 0)
00484           {
00485             return el_ptr(new value_element(val, name));
00486           }
00487         else
00488           {
00489             throw rutz::error(rutz::sfmt("unknown element type: %s", el),
00490                               SRC_POS);
00491           }
00492       }
00493   }
00494 
00495   class tree_builder : public io::xml_parser
00496   {
00497   public:
00498     tree_builder(std::istream& is) :
00499       io::xml_parser(is),
00500       m_root(),
00501       m_stack(),
00502       m_depth(0),
00503       m_start_count(0),
00504       m_end_count(0),
00505       m_objects(new io::object_map),
00506       m_el_count(0)
00507     {}
00508 
00509     virtual ~tree_builder() {}
00510 
00511     object_element& get_root() const
00512     {
00513       if (m_root.get() == 0)
00514         {
00515           throw rutz::error("no root element found", SRC_POS);
00516         }
00517 
00518       return element_cast<object_element>(m_root.get(), "root", SRC_POS);
00519     }
00520 
00521   protected:
00522     virtual void element_start(const char* el, const char** attr);
00523     virtual void element_end(const char* el);
00524     virtual void character_data(const char* text, int length);
00525 
00526   private:
00527     el_ptr m_root;
00528     std::vector<el_ptr> m_stack;
00529     int m_depth;
00530     int m_start_count;
00531     int m_end_count;
00532     shared_ptr<io::object_map> m_objects;
00533     int m_el_count;
00534   };
00535 
00536   void tree_builder::element_start(const char* el, const char** attr)
00537   {
00538     ++m_el_count;
00539     ++m_start_count;
00540     ++m_depth;
00541 
00542     const char* name = find_attr(attr, "name", el, "(noname)", SRC_POS);
00543 
00544     GVX_ASSERT(name != 0);
00545 
00546     el_ptr elp = make_element(el, attr, name, m_objects);
00547 
00548     if (m_stack.size() > 0)
00549       m_stack.back()->add_child(name, elp);
00550     else
00551       m_root = elp;
00552 
00553     m_stack.push_back(elp);
00554 
00555     if (GVX_DBG_LEVEL() >= 3)
00556       {
00557         dbg_eval(3, m_el_count);
00558         dbg_eval(3, el);
00559         dbg_eval(3, name);
00560         dbg_eval(3, elp.get());
00561         dbg_eval_nl(3, m_stack.size());
00562       }
00563   }
00564 
00565   void tree_builder::element_end(const char* /*el*/)
00566   {
00567     --m_end_count;
00568     GVX_ASSERT(m_stack.size() > 0);
00569     GVX_ASSERT(m_stack.back().get() != 0);
00570     m_stack.back()->finish();
00571     m_stack.pop_back();
00572     --m_depth;
00573   }
00574 
00575   void tree_builder::character_data(const char* text, int length)
00576   {
00577     GVX_ASSERT(m_stack.size() > 0);
00578     GVX_ASSERT(m_stack.back().get() != 0);
00579     m_stack.back()->character_data(text, length);
00580   }
00581 
00582 } // end anonymous namespace
00583 
00584 
00585 nub::ref<io::serializable> io::load_gvx(const char* filename)
00586 {
00587 GVX_TRACE("io::load_gvx");
00588   shared_ptr<std::istream> ifs(rutz::igzopen(filename));
00589   tree_builder x(*ifs);
00590   x.parse();
00591 
00592   object_element& root = x.get_root();
00593   return root.m_object;
00594 }
00595 
00596 void io::xml_debug(const char* filename)
00597 {
00598 GVX_TRACE("io::xml_debug");
00599   shared_ptr<std::istream> ifs(rutz::igzopen(filename));
00600   tree_builder x(*ifs);
00601   x.parse();
00602 
00603   object_element& root = x.get_root();
00604   root.trace(std::cout, 0, "root");
00605 }
00606 
00607 static const char __attribute__((used)) vcid_groovx_io_xmlreader_cc_utc20050626084021[] = "$Id: xmlreader.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00608 #endif // !GROOVX_IO_XMLREADER_CC_UTC20050626084021_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:39 2008 by Doxygen version 1.5.5.