iolegacy.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2000-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: Wed Sep 27 08:40:04 2000
00010 // commit: $Id: iolegacy.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/io/iolegacy.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_IOLEGACY_CC_UTC20050626084021_DEFINED
00035 #define GROOVX_IO_IOLEGACY_CC_UTC20050626084021_DEFINED
00036 
00037 #include "io/iolegacy.h"
00038 
00039 #include "nub/objmgr.h"
00040 #include "nub/ref.h"
00041 
00042 #include "rutz/error.h"
00043 #include "rutz/fstring.h"
00044 #include "rutz/sfmt.h"
00045 #include "rutz/value.h"
00046 
00047 #include <cctype>
00048 #include <cstring>
00049 #include <iostream>
00050 
00051 #include "rutz/trace.h"
00052 #include "rutz/debug.h"
00053 GVX_DBG_REGISTER
00054 
00055 using rutz::fstring;
00056 
00057 using nub::ref;
00058 using nub::soft_ref;
00059 
00061 //
00062 // legacy_reader::impl definition
00063 //
00065 
00066 class io::legacy_reader::impl
00067 {
00068   impl(const impl&);
00069   impl& operator=(const impl&);
00070 
00071 public:
00072 
00073   io::legacy_reader*  m_owner;
00074   std::istream&       m_stream;
00075   int                 m_legacy_version_id;
00076 
00077   impl(io::legacy_reader* owner, std::istream& is) :
00078     m_owner(owner),
00079     m_stream(is),
00080     m_legacy_version_id(0)
00081   {}
00082 
00083   void throw_if_error(const char* type, const rutz::file_pos& pos)
00084   {
00085     if (m_stream.fail())
00086       {
00087         dbg_print(3, "throw_if_error for"); dbg_eval_nl(3, type);
00088         throw rutz::error(type, pos);
00089       }
00090   }
00091 
00092   void throw_if_error(const fstring& type, const rutz::file_pos& pos)
00093   {
00094     throw_if_error(type.c_str(), pos);
00095   }
00096 
00097   void read_typename(const fstring& correct_name)
00098   {
00099     GVX_TRACE("io::legacy_reader::impl::read_typename(fstring)");
00100 
00101     fstring name;
00102     m_stream >> name;
00103 
00104     if (! name.equals(correct_name))
00105       {
00106         // If we got here, then none of the substrings matched so we must
00107         // raise an exception.
00108         throw rutz::error(rutz::sfmt("couldn't read typename for %s",
00109                                      correct_name.c_str()), SRC_POS);
00110       }
00111   }
00112 
00113   // An override for when we have two alternative names
00114   void read_typename(const fstring& correct_name, const fstring& alt_name)
00115   {
00116     GVX_TRACE("io::legacy_reader::impl::read_typename(fstring, fstring)");
00117 
00118     fstring name;
00119     m_stream >> name;
00120 
00121     if ( !name.equals(correct_name) && !name.equals(alt_name) )
00122       {
00123         // If we got here, then none of the substrings matched so we must
00124         // raise an exception.
00125         throw rutz::error(rutz::sfmt("couldn't read typename for %s",
00126                                      correct_name.c_str()), SRC_POS);
00127       }
00128   }
00129 
00130   int get_legacy_version_id()
00131   {
00132     GVX_TRACE("io::legacy_reader::impl::get_legacy_version_id");
00133     while ( isspace(m_stream.peek()) )
00134       { m_stream.get(); }
00135 
00136     int version = -1;
00137 
00138     if (m_stream.peek() == '@')
00139       {
00140         int c = m_stream.get();
00141         GVX_ASSERT(c == '@');
00142 
00143         m_stream >> version;
00144         dbg_eval_nl(3, version);
00145         throw_if_error("version id", SRC_POS);
00146       }
00147     else
00148       {
00149         throw rutz::error("missing legacy version id", SRC_POS);
00150       }
00151 
00152     return version;
00153   }
00154 
00155   void grab_left_brace()
00156   {
00157     char brace;
00158     m_stream >> brace;
00159     if (brace != '{')
00160       {
00161         dbg_print_nl(3, "grab_left_brace failed");
00162         throw rutz::error("missing left-brace", SRC_POS);
00163       }
00164   }
00165 
00166   void grab_right_brace()
00167   {
00168     char brace;
00169     m_stream >> brace;
00170     if (brace != '}')
00171       {
00172         dbg_print_nl(3, "grab_right_brace failed");
00173         throw rutz::error("missing right-brace", SRC_POS);
00174       }
00175   }
00176 
00177   void inflate_object(const fstring& name, ref<io::serializable> obj)
00178   {
00179     GVX_TRACE("io::legacy_reader::impl::inflate_object");
00180 
00181     dbg_eval_nl(3, name);
00182 
00183     m_legacy_version_id = get_legacy_version_id();
00184     if (m_legacy_version_id != -1)
00185       {
00186         grab_left_brace();
00187         obj->read_from(*m_owner);
00188         grab_right_brace();
00189       }
00190 
00191     throw_if_error(name, SRC_POS);
00192   }
00193 };
00194 
00196 //
00197 // legacy_reader member definitions
00198 //
00200 
00201 io::legacy_reader::legacy_reader(std::istream& is) :
00202   rep(new impl(this, is))
00203 {
00204 GVX_TRACE("io::legacy_reader::legacy_reader");
00205 }
00206 
00207 io::legacy_reader::~legacy_reader() throw()
00208 {
00209 GVX_TRACE("io::legacy_reader::~legacy_reader");
00210   delete rep;
00211 }
00212 
00213 io::version_id io::legacy_reader::input_version_id()
00214 {
00215 GVX_TRACE("io::legacy_reader::input_version_id");
00216   dbg_eval_nl(3, rep->m_legacy_version_id);
00217   return rep->m_legacy_version_id;
00218 }
00219 
00220 char io::legacy_reader::read_char(const fstring& name)
00221 {
00222 GVX_TRACE("io::legacy_reader::read_char");
00223   dbg_eval(3, name);
00224   char val;
00225   rep->m_stream >> val;   dbg_eval_nl(3, val);
00226   rep->throw_if_error(name, SRC_POS);
00227   return val;
00228 }
00229 
00230 int io::legacy_reader::read_int(const fstring& name)
00231 {
00232 GVX_TRACE("io::legacy_reader::read_int");
00233   dbg_eval(3, name);
00234   int val;
00235   rep->m_stream >> val;   dbg_eval_nl(3, val);
00236   rep->throw_if_error(name, SRC_POS);
00237   return val;
00238 }
00239 
00240 bool io::legacy_reader::read_bool(const fstring& name)
00241 {
00242 GVX_TRACE("io::legacy_reader::read_bool");
00243   dbg_eval(3, name);
00244   int val;
00245   rep->m_stream >> val;   dbg_eval_nl(3, val);
00246   rep->throw_if_error(name, SRC_POS);
00247   return bool(val);
00248 }
00249 
00250 double io::legacy_reader::read_double(const fstring& name)
00251 {
00252 GVX_TRACE("io::legacy_reader::read_double");
00253   dbg_eval(3, name);
00254   double val;
00255   rep->m_stream >> val;   dbg_eval_nl(3, val);
00256   rep->throw_if_error(name, SRC_POS);
00257   return val;
00258 }
00259 
00260 fstring io::legacy_reader::read_string_impl(const fstring& name)
00261 {
00262 GVX_TRACE("io::legacy_reader::read_string_impl");
00263   dbg_eval_nl(3, name);
00264 
00265   int numchars = 0;
00266   rep->m_stream >> numchars;
00267 
00268   rep->throw_if_error(name, SRC_POS);
00269 
00270   if (numchars < 0)
00271     {
00272       throw rutz::error("legacy_reader::read_string_impl "
00273                         "saw negative character count", SRC_POS);
00274     }
00275 
00276   int c = rep->m_stream.get();
00277   if (c != ' ')
00278     {
00279       throw rutz::error("legacy_reader::read_string_impl "
00280                         "did not have whitespace after character count", SRC_POS);
00281     }
00282 
00283   fstring new_string;
00284   new_string.readsome(rep->m_stream, static_cast<unsigned int>(numchars));
00285 
00286   rep->throw_if_error(name, SRC_POS);
00287 
00288   dbg_eval_nl(3, new_string);
00289 
00290   return new_string;
00291 }
00292 
00293 void io::legacy_reader::read_value_obj(const fstring& name, rutz::value& v)
00294 {
00295 GVX_TRACE("io::legacy_reader::read_value_obj");
00296   dbg_eval_nl(3, name);
00297   v.scan_from(rep->m_stream);
00298   rep->throw_if_error(name, SRC_POS);
00299 }
00300 
00301 ref<io::serializable>
00302 io::legacy_reader::read_object(const fstring& name)
00303 {
00304 GVX_TRACE("io::legacy_reader::read_object");
00305   return ref<io::serializable>(read_weak_object(name));
00306 }
00307 
00308 soft_ref<io::serializable>
00309 io::legacy_reader::read_weak_object(const fstring& name)
00310 {
00311 GVX_TRACE("io::legacy_reader::read_weak_object");
00312   dbg_eval(3, name);
00313   fstring type;
00314   rep->m_stream >> type; dbg_eval(3, type);
00315 
00316   if (type == "NULL")
00317     {
00318       return soft_ref<io::serializable>();
00319     }
00320 
00321   ref<io::serializable> obj(nub::obj_mgr::new_typed_obj<io::serializable>(type));
00322   dbg_eval_nl(3, obj->obj_typename());
00323 
00324   rep->inflate_object(name, obj);
00325 
00326   return obj;
00327 }
00328 
00329 void io::legacy_reader::read_owned_object(const fstring& name,
00330                                        ref<io::serializable> obj)
00331 {
00332 GVX_TRACE("io::legacy_reader::read_owned_object");
00333 
00334   rep->read_typename(obj->obj_typename());
00335   rep->inflate_object(name, obj);
00336 }
00337 
00338 void io::legacy_reader::read_base_class(const fstring& base_class_name,
00339                                         ref<io::serializable> base_part)
00340 {
00341 GVX_TRACE("io::legacy_reader::read_base_class");
00342 
00343   // For backward-compatibility, we allow the typename to match either
00344   // the real typename of the base part, or the descriptive name given
00345   // to the base class.
00346   rep->read_typename(base_part->obj_typename(), base_class_name);
00347   rep->inflate_object(base_class_name, base_part);
00348 }
00349 
00350 ref<io::serializable> io::legacy_reader::read_root(io::serializable* given_root)
00351 {
00352 GVX_TRACE("io::legacy_reader::read_root");
00353   if (given_root == 0)
00354     {
00355       return read_object("root_object");
00356     }
00357 
00358   dbg_eval_nl(3, given_root->obj_typename());
00359 
00360   ref<io::serializable> root(given_root);
00361   read_owned_object("root_object", root);
00362 
00363   return root;
00364 }
00365 
00367 //
00368 // legacy_writer::impl definition
00369 //
00371 
00372 class io::legacy_writer::impl
00373 {
00374 private:
00375   impl(const impl&);
00376   impl& operator=(const impl&);
00377 
00378 public:
00379   impl(io::legacy_writer* owner, std::ostream& os, bool write_bases) :
00380     m_owner(owner),
00381     m_stream(os),
00382     m_write_bases(write_bases),
00383     m_field_sep(' '),
00384     m_indent_level(0),
00385     m_needs_newline(false),
00386     m_needs_whitespace(false),
00387     m_is_beginning(true),
00388     m_do_pretty_print(true)
00389   {}
00390 
00391   void throw_if_error(const char* type, const rutz::file_pos& pos)
00392   {
00393     if (m_stream.fail())
00394       {
00395         dbg_print(3, "throw_if_error for"); dbg_eval_nl(3, type);
00396         throw rutz::error(type, pos);
00397       }
00398   }
00399 
00400   io::legacy_writer*  m_owner;
00401 private:
00402   std::ostream&       m_stream;
00403 public:
00404   const bool          m_write_bases;
00405   const char          m_field_sep;
00406   int                 m_indent_level;
00407   bool                m_needs_newline;
00408   bool                m_needs_whitespace;
00409   bool                m_is_beginning;
00410   bool                m_do_pretty_print;
00411 
00412   std::ostream& stream()
00413     {
00414       flush_whitespace();
00415       m_is_beginning = false;
00416       return m_stream;
00417     }
00418 
00419   void flush_whitespace()
00420     {
00421       update_newline();
00422       update_whitespace();
00423     }
00424 
00425 private:
00426   class Indenter
00427   {
00428   private:
00429     impl* m_owner;
00430 
00431     Indenter(const Indenter&);
00432     Indenter& operator=(const Indenter&);
00433 
00434   public:
00435     Indenter(impl* impl) : m_owner(impl) { ++(m_owner->m_indent_level); }
00436     ~Indenter() { --(m_owner->m_indent_level); }
00437   };
00438 
00439   void do_newline_and_tabs()
00440     {
00441       m_stream << '\n';
00442       for (int i = 0; i < m_indent_level; ++i)
00443         m_stream << '\t';
00444     }
00445 
00446   void do_whitespace()
00447     {
00448       if (m_do_pretty_print)
00449         do_newline_and_tabs();
00450       else
00451         m_stream << ' ';
00452     }
00453 
00454   void update_newline()
00455     {
00456       if (m_needs_newline)
00457         {
00458           do_newline_and_tabs();
00459           no_newline_needed();
00460           no_whitespace_needed();
00461         }
00462     }
00463 
00464   void update_whitespace()
00465     {
00466       if (m_needs_whitespace)
00467         {
00468           do_whitespace();
00469           no_whitespace_needed();
00470         }
00471     }
00472 
00473 public:
00474   void use_pretty_print(bool yes) { m_do_pretty_print = yes; }
00475 
00476   void request_newline() { if (!m_is_beginning) m_needs_newline = true; }
00477   void request_whitespace() { if (!m_is_beginning) m_needs_whitespace = true; }
00478   void no_newline_needed() { m_needs_newline = false; }
00479   void no_whitespace_needed() { m_needs_whitespace = false; }
00480 
00481   void flatten_object(const char* obj_name,
00482                       soft_ref<const io::serializable> obj,
00483                       bool stub_out = false)
00484   {
00485     if (m_indent_level > 0)
00486       request_whitespace();
00487     else
00488       request_newline();
00489 
00490     if ( !(obj.is_valid()) )
00491       {
00492         stream() << "NULL" << m_field_sep;
00493         throw_if_error(obj_name, SRC_POS);
00494         return;
00495       }
00496 
00497     GVX_ASSERT(obj.is_valid());
00498 
00499     stream() << obj->obj_typename() << m_field_sep;
00500     throw_if_error(obj->obj_typename().c_str(), SRC_POS);
00501 
00502     stream() << '@';
00503 
00504     if (stub_out)
00505       {
00506         stream() << "-1 ";
00507       }
00508     else
00509       {
00510         stream() << obj->class_version_id() << " {";
00511         {
00512           Indenter indent(this);
00513           request_whitespace();
00514           obj->write_to(*m_owner);
00515         }
00516         request_whitespace();
00517         stream() << "}";
00518       }
00519 
00520     if (m_indent_level > 0)
00521       request_whitespace();
00522     else
00523       request_newline();
00524 
00525     throw_if_error(obj_name, SRC_POS);
00526   }
00527 };
00528 
00530 //
00531 // legacy_writer member definitions
00532 //
00534 
00535 
00536 io::legacy_writer::legacy_writer(std::ostream& os, bool write_bases) :
00537   rep(new impl(this, os, write_bases))
00538 {
00539 GVX_TRACE("io::legacy_writer::legacy_writer");
00540 }
00541 
00542 io::legacy_writer::~legacy_writer() throw()
00543 {
00544 GVX_TRACE("io::legacy_writer::~legacy_writer");
00545   rep->flush_whitespace();
00546   delete rep;
00547 }
00548 
00549 void io::legacy_writer::use_pretty_print(bool yes)
00550 {
00551 GVX_TRACE("io::legacy_writer::use_pretty_print");
00552   rep->use_pretty_print(yes);
00553 }
00554 
00555 void io::legacy_writer::write_char(const char* name, char val)
00556 {
00557 GVX_TRACE("io::legacy_writer::write_char");
00558   rep->stream() << val << rep->m_field_sep;
00559   rep->throw_if_error(name, SRC_POS);
00560 }
00561 
00562 void io::legacy_writer::write_int(const char* name, int val)
00563 {
00564 GVX_TRACE("io::legacy_writer::write_int");
00565   rep->stream() << val << rep->m_field_sep;
00566   rep->throw_if_error(name, SRC_POS);
00567 }
00568 
00569 void io::legacy_writer::write_bool(const char* name, bool val)
00570 {
00571 GVX_TRACE("io::legacy_writer::write_bool");
00572   rep->stream() << val << rep->m_field_sep;
00573   rep->throw_if_error(name, SRC_POS);
00574 }
00575 
00576 void io::legacy_writer::write_double(const char* name, double val)
00577 {
00578 GVX_TRACE("io::legacy_writer::write_double");
00579   rep->stream() << val << rep->m_field_sep;
00580   rep->throw_if_error(name, SRC_POS);
00581 }
00582 
00583 void io::legacy_writer::write_cstring(const char* name, const char* val)
00584 {
00585 GVX_TRACE("io::legacy_writer::write_cstring");
00586 
00587   rep->stream() << strlen(val) << " " << val << rep->m_field_sep;
00588 
00589   rep->throw_if_error(name, SRC_POS);
00590 }
00591 
00592 void io::legacy_writer::write_value_obj(const char* name,
00593                                      const rutz::value& v)
00594 {
00595 GVX_TRACE("io::legacy_writer::write_value_obj");
00596   v.print_to(rep->stream());
00597   rep->stream() << rep->m_field_sep;
00598   rep->throw_if_error(name, SRC_POS);
00599 }
00600 
00601 void io::legacy_writer::write_byte_array(const char* name,
00602                                          const unsigned char* data,
00603                                          unsigned int length)
00604 {
00605 GVX_TRACE("io::legacy_writer::write_byte_array");
00606   default_write_byte_array(name, data, length);
00607 }
00608 
00609 void io::legacy_writer::write_object(const char* name,
00610                                      soft_ref<const io::serializable> obj)
00611 {
00612 GVX_TRACE("io::legacy_writer::write_object");
00613 
00614   rep->flatten_object(name, obj);
00615 }
00616 
00617 void io::legacy_writer::write_owned_object(const char* name,
00618                                            ref<const io::serializable> obj)
00619 {
00620 GVX_TRACE("io::legacy_writer::write_owned_object");
00621 
00622   rep->flatten_object(name, obj);
00623 }
00624 
00625 void io::legacy_writer::write_base_class(const char* base_class_name,
00626                                          ref<const io::serializable> base_part)
00627 {
00628 GVX_TRACE("io::legacy_writer::write_base_class");
00629   if (rep->m_write_bases)
00630     {
00631       rep->flatten_object(base_class_name, base_part);
00632     }
00633   else
00634     {
00635       rep->flatten_object(base_class_name, base_part, true);
00636     }
00637 }
00638 
00639 void io::legacy_writer::write_root(const io::serializable* root)
00640 {
00641 GVX_TRACE("io::legacy_writer::write_root");
00642 
00643   rep->flatten_object
00644     ("root_object", soft_ref<io::serializable>(const_cast<io::serializable*>(root),
00645                                                nub::STRONG,
00646                                                nub::PRIVATE));
00647 }
00648 
00649 static const char __attribute__((used)) vcid_groovx_io_iolegacy_cc_utc20050626084021[] = "$Id: iolegacy.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00650 #endif // !GROOVX_IO_IOLEGACY_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.