asciistreamreader.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 1999-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: Mon Jun  7 12:54:55 1999
00010 // commit: $Id: asciistreamreader.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/io/asciistreamreader.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_ASCIISTREAMREADER_CC_UTC20050626084021_DEFINED
00035 #define GROOVX_IO_ASCIISTREAMREADER_CC_UTC20050626084021_DEFINED
00036 
00037 #include "io/asciistreamreader.h"
00038 
00039 #include "io/io.h"
00040 #include "io/reader.h"
00041 #include "io/readattribmap.h"
00042 #include "io/readobjectmap.h"
00043 
00044 #include "nub/ref.h"
00045 
00046 #include "rutz/cstrstream.h"
00047 #include "rutz/error.h"
00048 #include "rutz/fstring.h"
00049 #include "rutz/gzstreambuf.h"
00050 #include "rutz/sfmt.h"
00051 #include "rutz/shared_ptr.h"
00052 #include "rutz/value.h"
00053 
00054 #include <istream>
00055 #include <vector>
00056 
00057 #include "rutz/trace.h"
00058 #include "rutz/debug.h"
00059 GVX_DBG_REGISTER
00060 
00061 using rutz::fstring;
00062 using rutz::shared_ptr;
00063 
00064 using nub::ref;
00065 using nub::soft_ref;
00066 
00067 using io::attrib_map;
00068 
00069 namespace
00070 {
00071   void throw_attr_error(const fstring& attrib_name,
00072                         const fstring& attrib_value,
00073                         const rutz::file_pos& pos)
00074   {
00075     throw rutz::error(rutz::sfmt("error reading attribute '%s' "
00076                                  "with value '%s'",
00077                                  attrib_name.c_str(),
00078                                  attrib_value.c_str()),
00079                       pos);
00080   }
00081 
00082   fstring read_and_unescape(std::istream& is)
00083   {
00084   GVX_TRACE("<asciistreamreader.cc>::read_and_unescape");
00085 
00086     static const char STRING_ENDER = '^';
00087 
00088     static std::vector<char> buffer(4096);
00089 
00090     buffer.resize(0);
00091 
00092     int brace_level = 0;
00093 
00094     int ch = 0;
00095 
00096     while ( (ch = is.get()) != EOF &&
00097             !(brace_level == 0 && ch == STRING_ENDER) )
00098       {
00099         // We only substitute in the escape sequence if we are reading
00100         // at the zero-th brace level; otherwise, we leave the escape
00101         // sequence in since it will eventually be parsed when the
00102         // brace-nested object itself is parsed.
00103         if (ch != '\\' || brace_level > 0)
00104           {
00105             if (ch == '{') ++brace_level;
00106             if (ch == '}') --brace_level;
00107             buffer.push_back(char(ch));
00108             continue;
00109           }
00110         else
00111           {
00112             const int ch2 = is.get();
00113 
00114             if (ch2 == EOF || ch2 == STRING_ENDER)
00115               throw rutz::error("missing character "
00116                                 "after trailing backslash", SRC_POS);
00117 
00118             switch (ch2)
00119               {
00120               case '\\': buffer.push_back('\\'); break;
00121               case 'c':  buffer.push_back('^');  break;
00122               case '{':  buffer.push_back('{');  break;
00123               case '}':  buffer.push_back('}');  break;
00124 
00125               default:
00126                 buffer.push_back('\0');
00127                 throw rutz::error
00128                   (rutz::sfmt("invalid escape character '%c' "
00129                               "with buffer contents: %s",
00130                               ch2, &buffer[0]),
00131                    SRC_POS);
00132                 break;
00133               }
00134           }
00135       } // while loop
00136 
00137     return fstring(rutz::char_range(&buffer[0], buffer.size()));
00138   }
00139 
00140   class asw_reader : public io::reader
00141   {
00142   public:
00143     asw_reader(std::istream& is);
00144     asw_reader(const char* filename);
00145 
00146     virtual ~asw_reader() throw();
00147 
00148     virtual io::version_id input_version_id();
00149 
00150     virtual char read_char(const fstring& name);
00151     virtual int read_int(const fstring& name);
00152     virtual bool read_bool(const fstring& name);
00153     virtual double read_double(const fstring& name);
00154     virtual void read_value_obj(const fstring& name, rutz::value& v);
00155 
00156     virtual void read_byte_array(const fstring& name, rutz::byte_array& data)
00157     { default_read_byte_array(name, data); }
00158 
00159     virtual nub::ref<io::serializable> read_object(const fstring& name);
00160     virtual nub::soft_ref<io::serializable>
00161     read_weak_object(const fstring& name);
00162 
00163     virtual void read_owned_object(const fstring& name,
00164                                    nub::ref<io::serializable> obj);
00165     virtual void read_base_class(const fstring& base_class_name,
00166                                  nub::ref<io::serializable> base_part);
00167 
00168     virtual nub::ref<io::serializable> read_root(io::serializable* root=0);
00169 
00170   protected:
00171     virtual fstring read_string_impl(const fstring& name);
00172 
00173   private:
00174     shared_ptr<std::istream>              m_owned_stream;
00175     std::istream&                         m_buf;
00176     io::object_map                        m_objects;
00177     std::vector<shared_ptr<attrib_map> >  m_attribs;
00178 
00179     attrib_map& current_attribs()
00180     {
00181       if ( m_attribs.empty() )
00182         throw rutz::error("attempted to read attribute "
00183                           "when no attribute map was active", SRC_POS);
00184       return *(m_attribs.back());
00185     }
00186 
00187     void inflate_object(std::istream& buf,
00188                         const fstring& obj_tag,
00189                         ref<io::serializable> obj);
00190 
00191     template <class T>
00192     T read_basic_type(const fstring& name)
00193     {
00194       dbg_eval_nl(3, name);
00195 
00196       attrib_map::attrib a = current_attribs().get(name);
00197       rutz::icstrstream ist(a.value.c_str());
00198 
00199       T return_val;
00200       ist >> return_val;
00201       dbg_eval(3, a.value); dbg_eval_nl(3, return_val);
00202 
00203       if (ist.fail())
00204         throw_attr_error(name, a.value, SRC_POS);
00205 
00206       return return_val;
00207     }
00208   };
00209 
00211   //
00212   // asw_reader member definitions
00213   //
00215 
00216   asw_reader::asw_reader(std::istream& is) :
00217     m_owned_stream(),
00218     m_buf(is),
00219     m_objects(),
00220     m_attribs()
00221   {
00222   GVX_TRACE("asw_reader::asw_reader");
00223   }
00224 
00225   asw_reader::asw_reader(const char* filename) :
00226     m_owned_stream(rutz::igzopen(filename)),
00227     m_buf(*m_owned_stream),
00228     m_objects(),
00229     m_attribs()
00230   {
00231   GVX_TRACE("asw_reader::asw_reader");
00232   }
00233 
00234   asw_reader::~asw_reader () throw()
00235   {
00236   GVX_TRACE("asw_reader::~asw_reader");
00237   }
00238 
00239   io::version_id asw_reader::input_version_id()
00240   {
00241   GVX_TRACE("asw_reader::input_version_id");
00242     return current_attribs().get_version_id();
00243   }
00244 
00245   char asw_reader::read_char(const fstring& name)
00246   {
00247   GVX_TRACE("asw_reader::read_char");
00248     return read_basic_type<char>(name);
00249   }
00250 
00251   int asw_reader::read_int(const fstring& name)
00252   {
00253   GVX_TRACE("asw_reader::read_int");
00254     return read_basic_type<int>(name);
00255   }
00256 
00257   bool asw_reader::read_bool(const fstring& name)
00258   {
00259   GVX_TRACE("asw_reader::read_bool");
00260     return bool(read_basic_type<int>(name));
00261   }
00262 
00263   double asw_reader::read_double(const fstring& name)
00264   {
00265   GVX_TRACE("asw_reader::read_double");
00266     return read_basic_type<double>(name);
00267   }
00268 
00269   fstring asw_reader::read_string_impl(const fstring& name)
00270   {
00271   GVX_TRACE("asw_reader::read_string_impl");
00272     dbg_eval_nl(3, name);
00273 
00274     attrib_map::attrib a = current_attribs().get(name);
00275     rutz::icstrstream ist(a.value.c_str());
00276 
00277     int len;
00278     ist >> len;                     dbg_eval_nl(3, len);
00279     ist.get(); // ignore one char of whitespace after the length
00280 
00281     if (len < 0)
00282       {
00283         throw rutz::error(rutz::sfmt("found a negative length "
00284                                      "for a string attribute: %d", len),
00285                           SRC_POS);
00286       }
00287 
00288     fstring new_string;
00289     new_string.readsome(ist, static_cast<unsigned int>(len));
00290 
00291     if (ist.fail())
00292       {
00293         throw_attr_error(name, a.value, SRC_POS);
00294       }
00295 
00296     dbg_eval(3, a.value); dbg_eval_nl(3, new_string);
00297     return new_string;
00298   }
00299 
00300   void asw_reader::read_value_obj(const fstring& name,
00301                                   rutz::value& v)
00302   {
00303   GVX_TRACE("asw_reader::read_value_obj");
00304     dbg_eval_nl(3, name);
00305 
00306     attrib_map::attrib a = current_attribs().get(name);
00307 
00308     v.set_string(a.value);
00309   }
00310 
00311   ref<io::serializable>
00312   asw_reader::read_object(const fstring& name)
00313   {
00314   GVX_TRACE("asw_reader::read_object");
00315     dbg_eval_nl(3, name);
00316     return ref<io::serializable>(read_weak_object(name));
00317   }
00318 
00319   soft_ref<io::serializable>
00320   asw_reader::read_weak_object(const fstring& name)
00321   {
00322   GVX_TRACE("asw_reader::read_weak_object");
00323     dbg_eval_nl(3, name);
00324 
00325     attrib_map::attrib attrib = current_attribs().get(name);
00326 
00327     rutz::icstrstream ist(attrib.value.c_str());
00328     nub::uid id;
00329     ist >> id;
00330 
00331     if (ist.fail())
00332       throw_attr_error(name, attrib.value, SRC_POS);
00333 
00334     if (id == 0) { return soft_ref<io::serializable>(); }
00335 
00336     // Return the object for this id, creating a new object if necessary:
00337     return m_objects.fetch_object(attrib.type, id);
00338   }
00339 
00340   void asw_reader::read_owned_object(const fstring& name,
00341                                      ref<io::serializable> obj)
00342   {
00343   GVX_TRACE("asw_reader::read_owned_object");
00344     dbg_eval_nl(3, name);
00345 
00346     attrib_map::attrib a = current_attribs().get(name);
00347     rutz::icstrstream ist(a.value.c_str());
00348     char bracket[16];
00349 
00350     ist >> bracket;
00351 
00352     inflate_object(ist, name, obj);
00353 
00354     ist >> bracket >> std::ws;
00355   }
00356 
00357   void asw_reader::read_base_class(const fstring& base_class_name,
00358                                    ref<io::serializable> base_part)
00359   {
00360   GVX_TRACE("asw_reader::read_base_class");
00361     dbg_eval_nl(3, base_class_name);
00362     read_owned_object(base_class_name, base_part);
00363   }
00364 
00365   ref<io::serializable> asw_reader::read_root(io::serializable* given_root)
00366   {
00367   GVX_TRACE("asw_reader::read_root");
00368 
00369     m_objects.clear();
00370 
00371     bool got_root = false;
00372     nub::uid rootid = 0;
00373 
00374     fstring type;
00375     fstring equal;
00376     fstring bracket;
00377     nub::uid id;
00378 
00379     while ( m_buf.peek() != EOF )
00380       {
00381         m_buf >> type >> id >> equal >> bracket;
00382         dbg_eval(3, type); dbg_eval_nl(3, id);
00383 
00384         if ( m_buf.fail() )
00385           {
00386             const fstring msg =
00387               rutz::sfmt("input failed while reading "
00388                          "typename and object id\n"
00389                          "\ttype: %s\n"
00390                          "\tid: %lu\n"
00391                          "\tequal: %s\n"
00392                          "\tbracket: %s",
00393                          type.c_str(), id, equal.c_str(), bracket.c_str());
00394             throw rutz::error(msg, SRC_POS);
00395           }
00396 
00397         if ( !got_root )
00398           {
00399             rootid = id;
00400 
00401             if (given_root != 0)
00402               m_objects.add_object_for_id
00403                 (rootid, ref<io::serializable>(given_root));
00404 
00405             got_root = true;
00406           }
00407 
00408         ref<io::serializable> obj = m_objects.fetch_object(type, id);
00409 
00410         inflate_object(m_buf, type, obj);
00411 
00412         m_buf >> bracket >> std::ws;
00413 
00414         if ( m_buf.fail() )
00415           {
00416             throw rutz::error(rutz::sfmt("input failed "
00417                                          "while parsing ending bracket\n"
00418                                          "\tbracket: %s", bracket.c_str()),
00419                               SRC_POS);
00420           }
00421       }
00422 
00423     return m_objects.get_existing_object(rootid);
00424   }
00425 
00426   void asw_reader::inflate_object(std::istream& buf,
00427                                   const fstring& obj_tag,
00428                                   ref<io::serializable> obj)
00429   {
00430   GVX_TRACE("asw_reader::inflate_object");
00431 
00432     //
00433     // (1) read the object's attributes from the stream...
00434     //
00435     shared_ptr<attrib_map> attribs( new attrib_map(obj_tag) );
00436 
00437     // Skip all whitespace
00438     buf >> std::ws;
00439 
00440     io::version_id svid = 0;
00441 
00442     // Check if there is a version id in the stream
00443     if (buf.peek() == 'v')
00444       {
00445         int ch = buf.get();  GVX_ASSERT(ch == 'v');
00446         buf >> svid;
00447         if ( buf.fail() )
00448           throw rutz::error("input failed while reading "
00449                             "serialization version id", SRC_POS);
00450       }
00451 
00452     attribs->set_version_id(svid);
00453 
00454     // Get the attribute count
00455     int attrib_count;
00456     buf >> attrib_count;    dbg_eval_nl(3, attrib_count);
00457 
00458     if (attrib_count < 0)
00459       {
00460         throw rutz::error(rutz::sfmt("found a negative attribute count: %d",
00461                                      attrib_count), SRC_POS);
00462       }
00463 
00464     if ( buf.fail() )
00465       {
00466         throw rutz::error(rutz::sfmt("input failed while reading "
00467                                      "attribute count: %d", attrib_count),
00468                           SRC_POS);
00469       }
00470 
00471     // Loop and load all the attributes
00472     fstring type;
00473     fstring name;
00474     fstring equal;
00475 
00476     for (int i = 0; i < attrib_count; ++i)
00477       {
00478         buf >> type >> name >> equal;   dbg_eval(3, type); dbg_eval_nl(3, name);
00479 
00480         if ( buf.fail() )
00481           {
00482             const fstring msg =
00483               rutz::sfmt("input failed while reading "
00484                          "attribute type and name\n"
00485                          "\ttype: %s\n"
00486                          "\tname: %s\n"
00487                          "\tequal: %s",
00488                          type.c_str(), name.c_str(), equal.c_str());
00489 
00490             throw rutz::error(msg, SRC_POS);
00491           }
00492 
00493         attribs->add_attrib(name, type, read_and_unescape(buf));
00494       }
00495 
00496     m_attribs.push_back(attribs);
00497 
00498     //
00499     // (2) now the object can query us for its attributes...
00500     //
00501     obj->read_from(*this);
00502 
00503     m_attribs.pop_back();
00504   }
00505 }
00506 
00507 shared_ptr<io::reader> io::make_asw_reader(std::istream& os)
00508 {
00509   return rutz::make_shared( new asw_reader(os) );
00510 }
00511 
00512 shared_ptr<io::reader> io::make_asw_reader(const char* filename)
00513 {
00514   return rutz::make_shared( new asw_reader(filename) );
00515 }
00516 
00517 static const char __attribute__((used)) vcid_groovx_io_asciistreamreader_cc_utc20050626084021[] = "$Id: asciistreamreader.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00518 #endif // !GROOVX_IO_ASCIISTREAMREADER_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.