00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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>
00054 #include <iostream>
00055 #include <istream>
00056 #include <map>
00057 #include <ostream>
00058 #include <string>
00059 #include <typeinfo>
00060 #include <vector>
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;
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* , el_ptr )
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* , int ) { }
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* ) : 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
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& ) { 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* )
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
00423
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* )
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 }
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