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_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
00100
00101
00102
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 }
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
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();
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
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
00434
00435 shared_ptr<attrib_map> attribs( new attrib_map(obj_tag) );
00436
00437
00438 buf >> std::ws;
00439
00440 io::version_id svid = 0;
00441
00442
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
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
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
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