#ifndef __boost_msg_h_incl #define __boost_msg_h_incl #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace boost; using namespace boost::gregorian; using namespace boost::posix_time; typedef std::string msg_string; typedef boost::make_recursive_variant< int, double, msg_string, date, ptime, vector, map >::type field_t; typedef std::map map_t; typedef std::vector vec_t; struct bencode : public static_visitor<> { bencode (ostream& os) : strm_ (os) {} void operator() (const int& i) const { char buf[15]; int len = sprintf (buf, "i%de", i); strm_.write (buf, len); } void operator() (const double& d) const { char buf[64]; int len = sprintf (buf, "f%.15gf", d); strm_.write (buf, len); } void operator() (const msg_string& s) const { char buf[16]; int len = sprintf (buf, "%d:", s.size()); strm_.write (buf, len); strm_.write (s.data (), s.size ()); } void operator() (const date& d) const { char buf[16]; date::ymd_type ymd = d.year_month_day (); int len = sprintf (buf, "g%04d%02d%02de", (unsigned short) ymd.year, (unsigned short) ymd.month, (unsigned short) ymd.day); strm_.write (buf, len); } void operator() (const ptime& t) const { static const double to_micros = (time_duration::num_fractional_digits() == 9 ? .001 : time_duration::num_fractional_digits() == 6 ? 1.0 : time_duration::num_fractional_digits() == 3 ? 1000 : 0); char buf[64]; date d = t.date (); date::ymd_type ymd = d.year_month_day (); time_duration tod = t.time_of_day (); int len = sprintf (buf, "t%04d%02d%02dT%02d%02d%02d.%de", (unsigned short) ymd.year, (unsigned short) ymd.month, (unsigned short) ymd.day, tod.hours (), tod.minutes (), tod.seconds (), tod.fractional_seconds () * to_micros); strm_.write (buf, len); } void operator() (const vec_t& v) const { strm_.put ('l'); for_each (v.begin(), v.end(), apply_visitor (*this)); strm_.put ('e'); } void operator() (const map_t& m) const { strm_.put ('d'); for (map_t::const_iterator i = m.begin(); i != m.end(); ++i) { this->operator () (i->first); apply_visitor (*this, i->second); } strm_.put ('e'); } private: ostream& strm_; }; /// decoder for bencoded data streams struct bdecode { istream& is; bool swap; bdecode (istream& is) : is (is) {} bool decode_int (field_t& value) { if (is.get () != 'i') return false; char buf[32]; if (!(is.get (buf, sizeof (buf), 'e')) || is.get () != 'e') return false; char* end; value = (int) strtol (buf, &end, 0); if (*end != 0) return false; return true; } bool decode_int (int& value) { if (is.get () != 'i') return false; char buf[32]; if (!(is.get (buf, sizeof (buf), 'e')) || is.get () != 'e') return false; char* end; value = (int) strtol (buf, &end, 0); if (*end != 0) return false; return true; } bool decode_double (field_t& value) { if (is.get () != 'f') return false; char buf[64]; if (!is.get (buf, sizeof (buf), 'f') || is.get () != 'f') return false; char* end; value = strtod (buf, &end); if (*end != 0) return false; return true; } bool decode_dict (map_t& dict) { if (is.get () != 'd') return false; msg_string k; field_t v; do { if (decode_string (k) && decode (v)) dict.insert (make_pair (k, v)); else return false; } while (is.peek () != 'e'); return is.get () == 'e'; } bool decode_dict (field_t& dict) { dict = map_t (); return decode_dict (*get (&dict)); } bool decode_list (field_t& list) { list = vec_t (); return decode_list (*get (&list)); } bool decode_list (vec_t& list) { if (is.get () != 'l') return false; field_t value; do { if (!decode (value)) return false; list.push_back (value); } while (is.peek () != 'e'); return is.get () == 'e'; } bool decode_string (field_t& value) { char buf[32]; if (!is.get (buf, sizeof (buf), ':') || is.get () != ':') return false; char* end; long len = strtol (buf, &end, 0); if (*end != 0) return false; value = msg_string (len, '\0'); is.read (const_cast (get (&value)->data()), len); return !is.fail (); } // we need this form for the decode_dict method bool decode_string (msg_string& s) { char buf[32]; if (!is.get (buf, sizeof (buf), ':') || is.get () != ':') return false; char* end; long len = strtol (buf, &end, 0); if (*end != 0) return false; s.resize (len); is.read (const_cast (s.data()), len); return !is.fail (); } bool decode_date (field_t& value) { if (is.get () != 'g') return false; char buf[16]; if (!is.get (buf, sizeof (buf), 'e') || is.get () != 'e') return false; value = from_undelimited_string (buf); return true; } bool decode_time (field_t& value) { if (is.get () != 't') return false; char buf[20]; if (!is.get (buf, sizeof (buf), 'e') || is.get () != 'e') return false; int yy, mm, dd, h, m, s, us; int result = sscanf (buf, "%4d%2d%2dT%2d%2d%2d.%de", &yy, &mm, &dd, &h, &m, &s, &us); if (result != 7) return false; value = ptime (date (yy, mm, dd), time_duration (h, m, s) + microseconds (us)); return true; } bool decode (field_t& value) { char type = is.peek (); if (type == 'i') return decode_int (value); else if (type == 'f') return decode_double (value); else if (type == 'l') return decode_list (value); else if (type == 'd') return decode_dict (value); else if (type == 'g' /* gregorian */) return decode_date (value); else if (type == 't' /* posix time */) return decode_time (value); else return decode_string (value); } }; struct printer : public static_visitor<> { printer (ostream& os) : strm_ (os) {} void operator() (const int& i) const { strm_ << i << ' '; } void operator() (const double& d) const { strm_ << d << ' '; } void operator() (const msg_string& s) const { strm_ << '\'' << s << "' "; } void operator() (const date& d) const { char buf[16]; date::ymd_type ymd = d.year_month_day (); int len = sprintf (buf, "%04d-%02d%-02d ", (unsigned short) ymd.year, (unsigned short) ymd.month, (unsigned short) ymd.day); strm_.write (buf, len); } void operator() (const ptime& t) const { char buf[24]; date d = t.date (); date::ymd_type ymd = d.year_month_day (); time_duration tod = t.time_of_day (); int len = sprintf (buf, "%04d-%02d-%02d %02d:%02d:%02d ", (unsigned short) ymd.year, (unsigned short) ymd.month, (unsigned short) ymd.day, tod.hours (), tod.minutes (), tod.seconds ()); strm_.write (buf, len); } template void operator() (const vector& v) const { strm_ << "[ "; for_each (v.begin(), v.end(), apply_visitor (*this)); strm_ << " ] "; } template void operator() (const map& m) const { strm_ << "{ "; for (typename map::const_iterator i = m.begin(); i != m.end(); ++i) { this->operator () (i->first); strm_ << "= "; apply_visitor (*this, i->second); } strm_ << "} "; } private: ostream& strm_; }; #endif // macro guard