// --------------------------------------------------------------------------- // - XmlDocument.cpp - // - afnix:xml module - xml document class implementation - // --------------------------------------------------------------------------- // - This program is free software; you can redistribute it and/or modify - // - it provided that this copyright notice is kept intact. - // - - // - This program 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. In no event shall - // - the copyright holder be liable for any direct, indirect, incidental or - // - special damages arising in any way out of the use of this software. - // --------------------------------------------------------------------------- // - copyright (c) 1999-2007 amaury darsch - // --------------------------------------------------------------------------- #include "Runnable.hpp" #include "InputFile.hpp" #include "QuarkZone.hpp" #include "Exception.hpp" #include "XmlReader.hpp" #include "XmlTexter.hpp" #include "XmlDocument.hpp" namespace afnix { // ------------------------------------------------------------------------- // - private section - // ------------------------------------------------------------------------- // this procedure reads an input stream and return a root text node static XmlRoot* get_rtxt_node (Input* is) { // check the stream if (is == nilp) return nilp; // create a new reader and parse the input stream XmlTexter* xmlt = new XmlTexter; try { // parse the input stream xmlt->parse (is); // get the root node and protect it XmlRoot* result = xmlt-> getroot (); // clean the reader and result Object::iref (result); delete xmlt; Object::tref (result); // this is it return result; } catch (...) { delete xmlt; throw; } } // this procedure reads an input file and returns a root text node // the reference counter for the node is already increased static XmlRoot* get_rtxt_node (const String& name) { // open the file InputFile is (name); // get the root node return get_rtxt_node (&is); } // this procedure reads an input stream and return a root node static XmlRoot* get_root_node (Input* is) { // check the stream if (is == nilp) return nilp; // create a new reader and parse the input stream XmlReader* xmlr = new XmlReader; try { // parse the input stream xmlr->parse (is); // get the root node and protect it XmlRoot* result = xmlr-> getroot (); // clean the reader and result Object::iref (result); delete xmlr; Object::tref (result); // this is it return result; } catch (...) { delete xmlr; throw; } } // this procedure reads an input file and returns a root node // the reference counter for the node is already increased static XmlRoot* get_root_node (const String& name) { // open the file InputFile is (name); // get the root node return get_root_node (&is); } // ------------------------------------------------------------------------- // - class section - // ------------------------------------------------------------------------- // create a default document XmlDocument::XmlDocument (void) { p_root = nilp; } // create a document by name XmlDocument::XmlDocument (const String& name) { d_name = name; p_root = nilp; setroot (name); } // create a document by name and input stream XmlDocument::XmlDocument (const String& name, Input* is) { p_root = nilp; setroot (name, is); } // create a document by name and root node XmlDocument::XmlDocument (const String& name, XmlRoot* root) { d_name = name; Object::iref (p_root = root); } // copy construct this document XmlDocument::XmlDocument (const XmlDocument& that) { that.rdlock (); try { d_name = that.d_name; if (that.p_root == nilp) { p_root = nilp; } else { p_root = dynamic_cast (that.p_root->copy ()); } that.unlock (); } catch (...) { that.unlock (); throw; } } // destroy this document XmlDocument::~XmlDocument (void) { // release the root node if (p_root != nilp) p_root->release (); // eventually clean the root node Object::dref (p_root); } // return the document class name String XmlDocument::repr (void) const { return "XmlDocument"; } // make this document shared void XmlDocument::mksho (void) { if (p_shared != nilp) return; Object::mksho (); if (p_root != nilp) p_root->mksho (); } // get a clone of this object Object* XmlDocument::clone (void) const { return new XmlDocument (*this); } // return the document name String XmlDocument::getname (void) const { rdlock (); String result = d_name; unlock (); return result; } // set the document name void XmlDocument::setname (const String& name) { wrlock (); d_name = name; unlock (); } // set the document root by name void XmlDocument::setroot (const String& name) { wrlock (); Object::dref (p_root); p_root = nilp; try { d_name = name; Object::iref (p_root = get_root_node (name)); if ((p_shared != nilp) && (p_root != nilp)) p_root->mksho (); unlock (); } catch (...) { unlock (); throw; } } // set the document root by name and input stream void XmlDocument::setroot (const String& name, Input* is) { wrlock (); Object::dref (p_root); p_root = nilp; try { d_name = name; Object::iref (p_root = get_root_node (is)); if ((p_shared != nilp) && (p_root != nilp)) p_root->mksho (); unlock (); } catch (...) { unlock (); throw; } } // set the document root text by name void XmlDocument::setrtxt (const String& name){ wrlock (); Object::dref (p_root); p_root = nilp; try { d_name = name; Object::iref (p_root = get_rtxt_node (name)); if ((p_shared != nilp) && (p_root != nilp)) p_root->mksho (); unlock (); } catch (...) { unlock (); throw; } } // set the document root text by name and input stream void XmlDocument::setrtxt (const String& name, Input* is) { wrlock (); Object::dref (p_root); p_root = nilp; try { d_name = name; Object::iref (p_root = get_rtxt_node (is)); if ((p_shared != nilp) && (p_root != nilp)) p_root->mksho (); unlock (); } catch (...) { unlock (); throw; } } // get the root node XmlRoot* XmlDocument::getroot (void) const { rdlock (); XmlRoot* result = p_root; unlock (); return result; } // ------------------------------------------------------------------------- // - object section - // ------------------------------------------------------------------------- // the quark zone static const long QUARK_ZONE_LENGTH = 4; static QuarkZone zone (QUARK_ZONE_LENGTH); // the object supported quarks static const long QUARK_SETNAME = zone.intern ("set-name"); static const long QUARK_SETROOT = zone.intern ("set-root"); static const long QUARK_SETRTXT = zone.intern ("set-text"); static const long QUARK_GETROOT = zone.intern ("get-root"); // create a new object in a generic way Object* XmlDocument::mknew (Vector* argv) { long argc = (argv == nilp) ? 0 : argv->length (); // create a default document object if (argc == 0) return new XmlDocument; // check for 1 argument if (argc == 1) { String name = argv->getstring (0); return new XmlDocument (name); } // check for 2 arguments if (argc == 2) { // get the document name String name = argv->getstring (0); // get the object and check Object* obj = argv->get (1); // check for an input stream Input* is = dynamic_cast (obj); if (is != nilp) return new XmlDocument (name, is); // check for a root node XmlRoot* root = dynamic_cast (obj); if (root != nilp) return new XmlDocument (name, root); throw Exception ("type-error", "invalid object with document constructor", Object::repr (obj)); } throw Exception ("argument-error", "too many argument with xml document constructor"); } // return true if the given quark is defined bool XmlDocument::isquark (const long quark, const bool hflg) const { rdlock (); if (zone.exists (quark) == true) { unlock (); return true; } bool result = hflg ? Nameable::isquark (quark, hflg) : false; unlock (); return result; } // apply this object with a set of arguments and a quark Object* XmlDocument::apply (Runnable* robj, Nameset* nset, const long quark, Vector* argv) { // get the number of arguments long argc = (argv == nilp) ? 0 : argv->length (); // check for 0 argument if (argc == 0) { if (quark == QUARK_GETROOT) { rdlock (); Object* result = getroot (); robj->post (result); unlock (); return result; } } // check for 1 argument if (argc == 1) { if (quark == QUARK_SETNAME) { String name = argv->getstring (0); setname (name); return nilp; } if (quark == QUARK_SETROOT) { String name = argv->getstring (0); setroot (name); return nilp; } if (quark == QUARK_SETRTXT) { String name = argv->getstring (0); setrtxt (name); return nilp; } } // check for 2 argument if (argc == 2) { if (quark == QUARK_SETROOT) { // get the document name String name = argv->getstring (0); // get the input stream Object* obj = argv->get (1); // check for an input stream Input* is = dynamic_cast (obj); if (is == nilp) { throw Exception ("type-error", "invalid input stream object with set-root", Object::repr (obj)); } setroot (name, is); return nilp; } if (quark == QUARK_SETRTXT) { // get the document name String name = argv->getstring (0); // get the input stream Object* obj = argv->get (1); // check for an input stream Input* is = dynamic_cast (obj); if (is == nilp) { throw Exception ("type-error", "invalid input stream object with set-root", Object::repr (obj)); } setrtxt (name, is); return nilp; } } // call the nameable method return Nameable::apply (robj, nset, quark, argv); } }