diff --git a/src/tl/tl/tlProtocolBuffer.cc b/src/tl/tl/tlProtocolBuffer.cc index 279512474..92b0292ea 100644 --- a/src/tl/tl/tlProtocolBuffer.cc +++ b/src/tl/tl/tlProtocolBuffer.cc @@ -21,10 +21,14 @@ */ #include "tlProtocolBuffer.h" +#include "tlLog.h" namespace tl { +// @@@ +// Missing: readers should check for proper wire type (i.e. read(int64)->either VARINT or I64, not I32 + // ---------------------------------------------------------------------------------- ProtocolBufferReader::ProtocolBufferReader (tl::InputStream &input) @@ -284,11 +288,17 @@ ProtocolBufferReader::error (const std::string &msg) // ---------------------------------------------------------------------------------- ProtocolBufferWriter::ProtocolBufferWriter (tl::OutputStream &stream) - : mp_stream (&stream), m_bytes_counted (0) + : mp_stream (&stream), m_bytes_counted (0), m_debug (false), m_debug_pos (0) { // .. nothing yet .. } +void ProtocolBufferWriter::set_debug (bool f) +{ + m_debug = f; + m_debug_pos = 0; +} + void ProtocolBufferWriter::write (int tag, float v) { write (tag, *reinterpret_cast (&v), true); @@ -303,7 +313,7 @@ void ProtocolBufferWriter::write (int tag, uint32_t v, bool fixed) { if (fixed) { - write_varint (pb_varint ((tag << 3) + PB_I32)); + write_varint (pb_varint ((tag << 3) + PB_I32), true); if (is_counting ()) { @@ -311,19 +321,25 @@ void ProtocolBufferWriter::write (int tag, uint32_t v, bool fixed) } else { + auto vv = v; + char b[sizeof (v)]; for (unsigned int i = 0; i < sizeof (v); ++i) { b[sizeof (v) - 1 - i] = (char) v; v >>= 8; } + if (m_debug) { + dump (b, sizeof (v), "I32", tl::to_string (vv)); + } + mp_stream->put (b, sizeof (v)); } } else { - write_varint (pb_varint ((tag << 3) + PB_VARINT)); + write_varint (pb_varint ((tag << 3) + PB_VARINT), true); write_varint (pb_varint (v)); } @@ -346,7 +362,7 @@ void ProtocolBufferWriter::write (int tag, uint64_t v, bool fixed) { if (fixed) { - write_varint (pb_varint ((tag << 3) + PB_I64)); + write_varint (pb_varint ((tag << 3) + PB_I64), true); if (is_counting ()) { @@ -354,19 +370,25 @@ void ProtocolBufferWriter::write (int tag, uint64_t v, bool fixed) } else { + auto vv = v; + char b[sizeof (v)]; for (unsigned int i = 0; i < sizeof (v); ++i) { b[sizeof (v) - 1 - i] = (char) v; v >>= 8; } + if (m_debug) { + dump (b, sizeof (v), "I64", tl::to_string (vv)); + } + mp_stream->put (b, sizeof (v)); } } else { - write_varint (pb_varint ((tag << 3) + PB_VARINT)); + write_varint (pb_varint ((tag << 3) + PB_VARINT), true); write_varint (pb_varint (v)); } @@ -392,13 +414,21 @@ void ProtocolBufferWriter::write (int tag, bool b) void ProtocolBufferWriter::write (int tag, const std::string &s) { - write_varint (pb_varint ((tag << 3) + PB_LEN)); + write_varint (pb_varint ((tag << 3) + PB_LEN), true); write_varint (s.size ()); if (is_counting ()) { + m_byte_counter_stack.back () += s.size (); + } else { + + if (m_debug) { + dump (s.c_str (), s.size (), "(string)", s); + } + mp_stream->put (s.c_str (), s.size ()); + } } @@ -411,16 +441,15 @@ void ProtocolBufferWriter::begin_seq (int tag, bool counting) { if (counting) { - // header only - m_byte_counter_stack.push_back (0); - write_varint (pb_varint ((tag << 3) + PB_LEN)); + if (is_counting ()) { + write_varint (pb_varint ((tag << 3) + PB_LEN), true); + } - // body only m_byte_counter_stack.push_back (0); } else { - write_varint (pb_varint ((tag << 3) + PB_LEN)); + write_varint (pb_varint ((tag << 3) + PB_LEN), true); write_varint (m_bytes_counted); } @@ -434,17 +463,15 @@ void ProtocolBufferWriter::end_seq () m_byte_counter_stack.pop_back (); // just for adding the required bytes - write_varint (m_bytes_counted); - - // now add header bytes - m_bytes_counted += m_byte_counter_stack.back (); - m_byte_counter_stack.pop_back (); + if (is_counting ()) { + write_varint (m_bytes_counted); + } } } void -ProtocolBufferWriter::write_varint (pb_varint v) +ProtocolBufferWriter::write_varint (pb_varint v, bool id) { if (is_counting ()) { @@ -461,6 +488,8 @@ ProtocolBufferWriter::write_varint (pb_varint v) } else { + auto vv = v; + char b[16]; char *cp = b; while (true) { @@ -473,9 +502,75 @@ ProtocolBufferWriter::write_varint (pb_varint v) v >>= 7; } + if (m_debug) { + if (id) { + unsigned int wt = v & 7; + std::string wire_type; + if (wt == PB_EGROUP) { + wire_type = "EGROUP"; + } else if (wt == PB_SGROUP) { + wire_type = "SGROUP"; + } else if (wt == PB_VARINT) { + wire_type = "VARINT"; + } else if (wt == PB_I32) { + wire_type = "I32"; + } else if (wt == PB_I64) { + wire_type = "I64"; + } else if (wt == PB_LEN) { + wire_type = "LEN"; + } + dump (b, cp - b, "(id)", "#" + tl::to_string (vv >> 3) + " " + wire_type); + } else { + dump (b, cp - b, "VARINT", tl::to_string (vv)); + } + } + mp_stream->put (b, cp - b); } } +void +ProtocolBufferWriter::dump (const char *cp, size_t n, const std::string &type, const std::string &value) +{ + bool first = true; + size_t nn = n; + + while (n > 0) { + + std::string line; + if (first) { + line += tl::sprintf ("%08ld", m_debug_pos); + } else { + line += " "; + } + line += " "; + + for (unsigned int i = 0; i < 8; ++i) { + if (n > 0) { + line += tl::sprintf ("%02x", (unsigned int) ((unsigned char) *cp)); + ++cp; + --n; + } else { + line += " "; + } + line += " "; + } + + if (first) { + line += " "; + line += type; + line += " "; + line += value; + } + + tl::info << line; + + first = false; + + } + + m_debug_pos += nn; +} + } diff --git a/src/tl/tl/tlProtocolBuffer.h b/src/tl/tl/tlProtocolBuffer.h index fdb7f7d1b..106401719 100644 --- a/src/tl/tl/tlProtocolBuffer.h +++ b/src/tl/tl/tlProtocolBuffer.h @@ -259,12 +259,21 @@ public: */ void end_seq (); + /** + * @brief Enables or disables debug mode + * In debug mode, the stream will be dumped in a human readable form + */ + void set_debug (bool f); + private: - void write_varint (pb_varint v); + void write_varint (pb_varint v, bool id = false); + void dump (const char *cp, size_t n, const std::string &type, const std::string &value); tl::OutputStream *mp_stream; size_t m_bytes_counted; std::vector m_byte_counter_stack; + bool m_debug; + size_t m_debug_pos; }; } diff --git a/src/tl/tl/tlProtocolBufferStruct.cc b/src/tl/tl/tlProtocolBufferStruct.cc index b41f1b459..a52bc879d 100644 --- a/src/tl/tl/tlProtocolBufferStruct.cc +++ b/src/tl/tl/tlProtocolBufferStruct.cc @@ -68,6 +68,7 @@ PBParser::parse_element (const PBElementBase *parent, tl::ProtocolBufferReader & } else { new_element->create (parent, *mp_state); new_element->parse (this, reader); + new_element->finish (parent, *mp_state); } } diff --git a/src/tl/tl/tlProtocolBufferStruct.h b/src/tl/tl/tlProtocolBufferStruct.h index abf6a4f3c..613bc3024 100644 --- a/src/tl/tl/tlProtocolBufferStruct.h +++ b/src/tl/tl/tlProtocolBufferStruct.h @@ -604,7 +604,9 @@ public: virtual void parse (PBParser *parser, tl::ProtocolBufferReader &reader) const { + reader.open (); parser->parse_element (this, reader); + reader.close (); } virtual void write (const PBElementBase * /*parent*/, tl::ProtocolBufferWriter &writer, PBWriterState &objs) const @@ -660,7 +662,7 @@ private: } objs.pop (self_tag); writer.end_seq (); - if (! writer.is_counting ()) { + if (writer.is_counting ()) { break; } } diff --git a/src/tl/unit_tests/tlProtocolBufferTests.cc b/src/tl/unit_tests/tlProtocolBufferTests.cc index d5ae4db05..fb73a859b 100644 --- a/src/tl/unit_tests/tlProtocolBufferTests.cc +++ b/src/tl/unit_tests/tlProtocolBufferTests.cc @@ -155,17 +155,18 @@ struct Child { struct Root { long m; unsigned int mi; + bool b; std::vector m_subs; std::vector m_isubs; std::vector m_children; Child m_child; - Root () : m(0), mi(0) { } + Root () : m(0), mi(0), b(false) { } bool operator== (const Root &x) const { return m == x.m && mi == x.mi && m_subs == x.m_subs && m_isubs == x.m_isubs && m_children == x.m_children - && m_child == x.m_child; } + && m_child == x.m_child && b == x.b; } int get_mi () const { return mi; } void set_mi (int i) { mi = i; } @@ -204,23 +205,26 @@ struct Root { const Child &get_child () const { return m_child; } }; -TEST (100) +TEST (100_BasicStruct) { Root root; + tl::PBElementList child_struct = + tl::pb_make_member (&Child::txt, 1) + + tl::pb_make_member (&Child::d, 2) + + tl::pb_make_element (&Child::begin_children, &Child::end_children, &Child::add_child, 3, &child_struct); + tl::PBStruct structure ( tl::pb_make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, 1) + tl::pb_make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, 2) + - tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, 3, - tl::pb_make_member (&Child::txt, 1) + - tl::pb_make_member (&Child::d, 2) - ) + + tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, 3, &child_struct) + tl::pb_make_element (&Root::get_child, &Root::set_child, 4, tl::pb_make_member (&Child::txt, 1) + tl::pb_make_member (&Child::d, 2) ) + tl::pb_make_member (&Root::m, 5) + - tl::pb_make_member (&Root::get_mi, &Root::set_mi, 6) + tl::pb_make_member (&Root::get_mi, &Root::set_mi, 6) + + tl::pb_make_member (&Root::b, 7) ); root.add_sub (0.5); @@ -228,6 +232,7 @@ TEST (100) root.add_isub (420000000); root.m = -1700000; root.set_mi (21); + root.b = true; Child c1; c1.txt = "c1"; @@ -265,6 +270,7 @@ TEST (100) { tl::OutputStream os (fn); tl::ProtocolBufferWriter writer (os); + // For development: writer.set_debug (true); structure.write (writer, root); } @@ -287,10 +293,11 @@ TEST (100) EXPECT_EQ (root.m_isubs.size (), size_t (1)); EXPECT_EQ (root.m_isubs [0], 420000000); EXPECT_EQ (root.m, -1700000); + EXPECT_EQ (root.b, true); EXPECT_EQ (root.mi, (unsigned int) 21); EXPECT_EQ (root.m_children.size (), size_t (2)); EXPECT_EQ (root.m_children [0].txt, "c1"); - EXPECT_EQ (root.m_children [1].d, 1.0); + EXPECT_EQ (root.m_children [0].d, 1.0); EXPECT_EQ (root.m_children [1].txt, "c2"); EXPECT_EQ (root.m_children [1].d, 2.0); EXPECT_EQ (root.m_children [1].end_children () - root.m_children [1].begin_children (), 3); @@ -322,4 +329,29 @@ TEST (100) EXPECT_EQ (error, ""); EXPECT_EQ (root == rsave, true); + + // write empty object + out.clear (); + root = Root (); + + { + tl::OutputStream os (out); + tl::ProtocolBufferWriter writer (os); + structure.write (writer, root); + } + + // and read again. + try { + error.clear (); + tl::InputMemoryStream s2 (out.data (), out.size ()); + tl::InputStream is (s2); + root = Root (); + tl::ProtocolBufferReader reader (is); + structure.parse (reader, root); + } catch (tl::Exception &ex) { + error = ex.msg (); + } + + EXPECT_EQ (error, ""); + EXPECT_EQ (root == Root (), true); }