OSDN Git Service

PacketParser: ToString() method for PacketViews
authorJakub Pawlowski <jpawlowski@google.com>
Mon, 9 Mar 2020 20:15:34 +0000 (21:15 +0100)
committerJakub Pawlowski <jpawlowski@google.com>
Wed, 11 Mar 2020 11:13:05 +0000 (11:13 +0000)
This is a helper method that should make debugging easier.

Bug: 150669615
Test: added
Change-Id: I15aceaa6a5b7ef628bbc98d9a1ef37950ebc22a2

38 files changed:
gd/packet/parser/README
gd/packet/parser/custom_type_checker.h
gd/packet/parser/fields/array_field.cc
gd/packet/parser/fields/array_field.h
gd/packet/parser/fields/body_field.cc
gd/packet/parser/fields/body_field.h
gd/packet/parser/fields/checksum_field.cc
gd/packet/parser/fields/checksum_field.h
gd/packet/parser/fields/checksum_start_field.cc
gd/packet/parser/fields/checksum_start_field.h
gd/packet/parser/fields/custom_field.cc
gd/packet/parser/fields/custom_field.h
gd/packet/parser/fields/custom_field_fixed_size.cc
gd/packet/parser/fields/custom_field_fixed_size.h
gd/packet/parser/fields/enum_field.cc
gd/packet/parser/fields/enum_field.h
gd/packet/parser/fields/fixed_scalar_field.cc
gd/packet/parser/fields/fixed_scalar_field.h
gd/packet/parser/fields/packet_field.cc
gd/packet/parser/fields/packet_field.h
gd/packet/parser/fields/payload_field.cc
gd/packet/parser/fields/payload_field.h
gd/packet/parser/fields/scalar_field.cc
gd/packet/parser/fields/scalar_field.h
gd/packet/parser/fields/size_field.cc
gd/packet/parser/fields/size_field.h
gd/packet/parser/fields/struct_field.cc
gd/packet/parser/fields/struct_field.h
gd/packet/parser/fields/vector_field.cc
gd/packet/parser/fields/vector_field.h
gd/packet/parser/main.cc
gd/packet/parser/packet_def.cc
gd/packet/parser/packet_def.h
gd/packet/parser/struct_def.cc
gd/packet/parser/struct_def.h
gd/packet/parser/test/generated_packet_test.cc
gd/packet/parser/test/six_bytes.h
gd/packet/parser/test/variable.h

index 9006c94..6915538 100644 (file)
@@ -14,11 +14,11 @@ Packet Views and Builders
 
 Checksum types
   checksum MyChecksumClass : 16 "path/to/the/class/"
-  Checksum fields need to implement the following three static methods:
-    static void Initialize(MyChecksumClass&);
-    static void AddByte(MyChecksumClass&, uint8_t);
+  Checksum fields need to implement the following three methods:
+    void Initialize(MyChecksumClass&);
+    void AddByte(MyChecksumClass&, uint8_t);
     // Assuming a 16-bit (uint16_t) checksum:
-    static uint16_t GetChecksum(MyChecksumClass&);
+    uint16_t GetChecksum(MyChecksumClass&);
 -------------
  LIMITATIONS
 -------------
@@ -57,3 +57,4 @@ Custom fields need the folowing functions:
   static void Serialize(const Type&, MutableView&);
   static std::optional<size_t> Size(Iterator);
   static Type Parse(Iterator);
+  std::string ToString();
\ No newline at end of file
index 5d99622..31b4660 100644 (file)
@@ -36,14 +36,17 @@ class CustomTypeChecker {
   template <class C, bool little_endian, std::optional<Iterator<little_endian>> (*)(C* vec, Iterator<little_endian> it)>
   struct ParseChecker {};
 
+  template <class C, std::string (C::*)() const>
+  struct ToStringChecker {};
+
   template <class C, bool little_endian>
   static int Test(SerializeChecker<C, &C::Serialize>*, SizeChecker<C, &C::size>*,
-                  ParseChecker<C, little_endian, &C::Parse>*);
+                  ParseChecker<C, little_endian, &C::Parse>*, ToStringChecker<C, &C::ToString>*);
 
   template <class C, bool little_endian>
   static char Test(...);
 
-  static constexpr bool value = (sizeof(Test<T, packet_little_endian>(0, 0, 0)) == sizeof(int));
+  static constexpr bool value = (sizeof(Test<T, packet_little_endian>(0, 0, 0, 0)) == sizeof(int));
 };
 }  // namespace packet
 }  // namespace bluetooth
index 37dea16..c66252e 100644 (file)
@@ -175,3 +175,23 @@ bool ArrayField::IsContainerField() const {
 const PacketField* ArrayField::GetElementField() const {
   return element_field_;
 }
+
+void ArrayField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << "\"ARRAY[\";";
+  s << "/* " << element_field_->GetDataType() << "   " << element_field_->GetFieldType() << " */";
+
+  std::string arr_idx = "arridx_" + accessor;
+  std::string arr_size = std::to_string(array_size_);
+  s << "for (size_t index = 0; index < " << arr_size << "; index++) {";
+  std::string element_accessor = "(" + accessor + "[index])";
+  s << "ss << ((index == 0) ? \"\" : \", \") << ";
+
+  if (element_field_->GetFieldType() == CustomField::kFieldType) {
+    s << element_accessor << ".ToString()";
+  } else {
+    element_field_->GenStringRepresentation(s, element_accessor);
+  }
+
+  s << ";}";
+  s << "ss << \"]\"";
+}
index dd49f26..e31e8de 100644 (file)
@@ -62,6 +62,8 @@ class ArrayField : public PacketField {
 
   virtual const PacketField* GetElementField() const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
   const std::string name_;
 
   const PacketField* element_field_{nullptr};
index 30abf6e..632456f 100644 (file)
@@ -71,3 +71,7 @@ void BodyField::GenInserter(std::ostream&) const {
 void BodyField::GenValidator(std::ostream&) const {
   // Do nothing
 }
+
+void BodyField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << "\"BODY REPRENTATION_UNIMPLEMENTED " << accessor << " \"";
+}
index 656a935..d8c4ee0 100644 (file)
@@ -50,6 +50,8 @@ class BodyField : public PacketField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
   // Body fields can only be dynamically sized.
   const SizeField* size_field_{nullptr};
 };
index 4647992..67863c2 100644 (file)
@@ -58,3 +58,8 @@ void ChecksumField::GenInserter(std::ostream& s) const {
 void ChecksumField::GenValidator(std::ostream&) const {
   // Done in packet_def.cc
 }
+
+void ChecksumField::GenStringRepresentation(std::ostream& s, std::string) const {
+  // TODO: there is currently no way to get checksum value
+  s << "\"CHECKSUM\"";
+}
index c15f023..0e0a4c2 100644 (file)
@@ -46,6 +46,8 @@ class ChecksumField : public ScalarField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   std::string type_name_;
 };
index 5531c5a..3f87db2 100644 (file)
@@ -61,3 +61,7 @@ void ChecksumStartField::GenValidator(std::ostream&) const {}
 std::string ChecksumStartField::GetStartedFieldName() const {
   return started_field_name_;
 }
+
+void ChecksumStartField::GenStringRepresentation(std::ostream&, std::string) const {
+  // Print nothing for checksum start
+}
index c63806b..8c61a82 100644 (file)
@@ -51,6 +51,8 @@ class ChecksumStartField : public PacketField {
 
   virtual std::string GetStartedFieldName() const;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   std::string started_field_name_;
 };
index 4e387f8..fd39714 100644 (file)
@@ -91,3 +91,7 @@ void CustomField::GenInserter(std::ostream& s) const {
 void CustomField::GenValidator(std::ostream&) const {
   // Do nothing.
 }
+
+void CustomField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << accessor << "->ToString()";
+}
index 621a3c8..7ba1b0f 100644 (file)
@@ -49,6 +49,8 @@ class CustomField : public PacketField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   std::string type_name_;
 };
index 687d48d..54463cd 100644 (file)
@@ -62,3 +62,8 @@ void CustomFieldFixedSize::GenInserter(std::ostream& s) const {
 void CustomFieldFixedSize::GenValidator(std::ostream&) const {
   // Do nothing.
 }
+
+void CustomFieldFixedSize::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  // We assume that custom fields will have a ToString() method
+  s << accessor << ".ToString()";
+}
index 97acff9..c53f0b0 100644 (file)
@@ -41,5 +41,7 @@ class CustomFieldFixedSize : public ScalarField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
   std::string type_name_;
 };
index 3080d43..8fe56c2 100644 (file)
@@ -51,3 +51,7 @@ void EnumField::GenInserter(std::ostream& s) const {
 void EnumField::GenValidator(std::ostream&) const {
   // Do nothing
 }
+
+void EnumField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << GetDataType() << "Text(" << accessor << ")";
+}
index 11c64e0..f413553 100644 (file)
@@ -41,6 +41,8 @@ class EnumField : public ScalarField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   EnumDef enum_def_;
   std::string value_;
index 9bfdf0e..e0ad2dd 100644 (file)
@@ -33,3 +33,7 @@ std::string FixedScalarField::GetDataType() const {
 void FixedScalarField::GenValue(std::ostream& s) const {
   s << value_;
 }
+
+void FixedScalarField::GenStringRepresentation(std::ostream& s, std::string) const {
+  s << "+" << value_;
+}
index 0070f6c..0112b27 100644 (file)
@@ -33,6 +33,8 @@ class FixedScalarField : public FixedField {
 
   virtual std::string GetDataType() const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
   static const std::string field_type;
 
  private:
index 7b0bdb7..b51999f 100644 (file)
@@ -100,3 +100,7 @@ bool PacketField::IsContainerField() const {
 const PacketField* PacketField::GetElementField() const {
   return nullptr;
 }
+
+void PacketField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << "\"REPRESENTATION_UNIMPLEMENTED " << GetFieldType() << " " << accessor << "\"";
+}
index d9cc019..55653bd 100644 (file)
@@ -106,6 +106,9 @@ class PacketField : public Loggable {
   // Get field of nested elements if this is a container field, nullptr if none
   virtual const PacketField* GetElementField() const;
 
+  // Return string representation of this field, that can be displayed for debugging or logging purposes
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const;
+
   std::string GetDebugName() const override;
 
   ParseLocation GetLocation() const override;
index c075996..57a1822 100644 (file)
@@ -107,3 +107,8 @@ void PayloadField::GenInserter(std::ostream&) const {
 void PayloadField::GenValidator(std::ostream&) const {
   // Do nothing
 }
+
+void PayloadField::GenStringRepresentation(std::ostream& s, std::string) const {
+  // TODO: we should parse the child packets
+  s << "\"PAYLOAD[]\"";
+}
index 11e6267..b4ead5b 100644 (file)
@@ -54,6 +54,8 @@ class PayloadField : public PacketField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
   // Payload fields can only be dynamically sized.
   const SizeField* size_field_;
   // Only used if the size of the payload is based on another field.
index 320534a..1421273 100644 (file)
@@ -129,3 +129,7 @@ void ScalarField::GenInserter(std::ostream& s) const {
 void ScalarField::GenValidator(std::ostream&) const {
   // Do nothing
 }
+
+void ScalarField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << "+" << accessor;
+}
index 65f897e..e15d6c1 100644 (file)
@@ -49,6 +49,8 @@ class ScalarField : public PacketField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   const int size_;
 };
index 0a1b80b..ce2c899 100644 (file)
@@ -61,3 +61,7 @@ void SizeField::GenValidator(std::ostream&) const {
 std::string SizeField::GetSizedFieldName() const {
   return sized_field_name_;
 }
+
+void SizeField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << accessor;
+}
index b6e8639..2d40c42 100644 (file)
@@ -46,6 +46,8 @@ class SizeField : public ScalarField {
 
   virtual std::string GetSizedFieldName() const;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   int size_;
   std::string sized_field_name_;
index fbdafcf..5ada67a 100644 (file)
@@ -83,3 +83,7 @@ void StructField::GenInserter(std::ostream& s) const {
 void StructField::GenValidator(std::ostream&) const {
   // Do nothing
 }
+
+void StructField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << accessor << ".ToString()";
+}
index 1f4f100..9d1d463 100644 (file)
@@ -49,6 +49,8 @@ class StructField : public PacketField {
 
   virtual void GenValidator(std::ostream&) const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
  private:
   std::string type_name_;
 
index 6990d30..7f37dbe 100644 (file)
@@ -230,3 +230,22 @@ bool VectorField::IsContainerField() const {
 const PacketField* VectorField::GetElementField() const {
   return element_field_;
 }
+
+void VectorField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+  s << "\"VECTOR[\";";
+
+  std::string arr_idx = "arridx_" + accessor;
+  std::string vec_size = accessor + ".size()";
+  s << "for (size_t index = 0; index < " << vec_size << "; index++) {";
+  std::string element_accessor = "(" + accessor + "[index])";
+  s << "ss << ((index == 0) ? \"\" : \", \") << ";
+
+  if (element_field_->GetFieldType() == CustomField::kFieldType) {
+    s << element_accessor << ".ToString()";
+  } else {
+    element_field_->GenStringRepresentation(s, element_accessor);
+  }
+
+  s << ";}";
+  s << "ss << \"]\"";
+}
index b2ae95d..827f718 100644 (file)
@@ -67,6 +67,8 @@ class VectorField : public PacketField {
 
   virtual const PacketField* GetElementField() const override;
 
+  virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
   const std::string name_;
 
   const PacketField* element_field_{nullptr};
index 8b6737a..82deacf 100644 (file)
@@ -121,6 +121,7 @@ bool generate_cpp_headers_one_file(const Declarations& decls, const std::filesys
   out_file << "#pragma once\n";
   out_file << "\n\n";
   out_file << "#include <stdint.h>\n";
+  out_file << "#include <sstream>\n";
   out_file << "#include <string>\n";
   out_file << "#include <functional>\n";
   out_file << "\n\n";
index c37b63b..b2eb199 100644 (file)
@@ -62,6 +62,10 @@ void PacketDef::GenParserDefinition(std::ostream& s) const {
   GenValidator(s);
   s << "\n";
 
+  s << " public:";
+  GenParserToString(s);
+  s << "\n";
+
   s << " protected:\n";
   // Constructor from a View
   if (parent_ != nullptr) {
@@ -283,6 +287,35 @@ void PacketDef::GenValidator(std::ostream& s) const {
   }
 }
 
+void PacketDef::GenParserToString(std::ostream& s) const {
+  s << "virtual std::string ToString() " << (parent_ != nullptr ? " override" : "") << " {";
+  s << "std::stringstream ss;";
+  s << "ss << std::showbase << std::hex << \"" << name_ << " { \";";
+
+  if (fields_.size() > 0) {
+    s << "ss << \"\" ";
+    bool firstfield = true;
+    for (const auto& field : fields_) {
+      if (field->GetFieldType() == ReservedField::kFieldType || field->GetFieldType() == FixedScalarField::kFieldType ||
+          field->GetFieldType() == ChecksumStartField::kFieldType)
+        continue;
+
+      s << (firstfield ? " << \"" : " << \", ") << field->GetName() << " = \" << ";
+
+      field->GenStringRepresentation(s, field->GetGetterFunctionName() + "()");
+
+      if (firstfield) {
+        firstfield = false;
+      }
+    }
+    s << ";";
+  }
+
+  s << "ss << \" }\";";
+  s << "return ss.str();";
+  s << "}\n";
+}
+
 void PacketDef::GenBuilderDefinition(std::ostream& s) const {
   s << "class " << name_ << "Builder";
   if (parent_ != nullptr) {
index e8acdc3..91be98d 100644 (file)
@@ -39,6 +39,8 @@ class PacketDef : public ParentDef {
 
   void GenValidator(std::ostream& s) const;
 
+  void GenParserToString(std::ostream& s) const;
+
   TypeDef::Type GetDefinitionType() const;
 
   void GenBuilderDefinition(std::ostream& s) const;
index ebd8b45..54269a3 100644 (file)
@@ -45,6 +45,37 @@ void StructDef::GenSpecialize(std::ostream& s) const {
   s << "}";
 }
 
+void StructDef::GenToString(std::ostream& s) const {
+  s << "std::string ToString() {";
+  s << "std::stringstream ss;";
+  s << "ss << std::hex << std::showbase << \"" << name_ << " { \";";
+
+  if (fields_.size() > 0) {
+    s << "ss";
+    bool firstfield = true;
+    for (const auto& field : fields_) {
+      if (field->GetFieldType() == ReservedField::kFieldType ||
+          field->GetFieldType() == ChecksumStartField::kFieldType ||
+          field->GetFieldType() == FixedScalarField::kFieldType || field->GetFieldType() == CountField::kFieldType ||
+          field->GetFieldType() == SizeField::kFieldType)
+        continue;
+
+      s << (firstfield ? " << \"" : " << \", ") << field->GetName() << " = \" << ";
+
+      field->GenStringRepresentation(s, field->GetName() + "_");
+
+      if (firstfield) {
+        firstfield = false;
+      }
+    }
+    s << ";";
+  }
+
+  s << "ss << \" }\";";
+  s << "return ss.str();";
+  s << "}\n";
+}
+
 void StructDef::GenParse(std::ostream& s) const {
   std::string iterator = (is_little_endian_ ? "Iterator<kLittleEndian>" : "Iterator<!kLittleEndian>");
 
@@ -175,6 +206,9 @@ void StructDef::GenDefinition(std::ostream& s) const {
   GenSpecialize(s);
   s << "\n";
 
+  GenToString(s);
+  s << "\n";
+
   GenMembers(s);
   for (const auto& field : fields_) {
     if (field->GetFieldType() == CountField::kFieldType || field->GetFieldType() == SizeField::kFieldType) {
index 74c1b04..b4c890b 100644 (file)
@@ -36,6 +36,8 @@ class StructDef : public ParentDef {
 
   void GenSpecialize(std::ostream& s) const;
 
+  void GenToString(std::ostream& s) const;
+
   void GenParse(std::ostream& s) const;
 
   void GenParseFunctionPrototype(std::ostream& s) const;
index 4feb11e..45b3ec8 100644 (file)
@@ -1899,6 +1899,68 @@ TEST(GeneratedPacketTest, testOneGenericStructArrayNoZeroEmpty) {
   ASSERT_EQ(1, view.GetAnArray().size());
 }
 
+TEST(GeneratedPacketTest, testToStringOutput) {
+  std::vector<TwoRelatedNumbersBe> count_array;
+  for (uint8_t i = 1; i < 5; i++) {
+    TwoRelatedNumbersBe trn;
+    trn.id_ = i;
+    trn.count_ = 0x0102 * i;
+    count_array.push_back(trn);
+  }
+
+  auto packet = ArrayOfStructBeBuilder::Create(count_array);
+
+  ASSERT_EQ(array_of_struct_be.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(array_of_struct_be.size(), packet_bytes->size());
+  for (size_t i = 0; i < array_of_struct_be.size(); i++) {
+    ASSERT_EQ(array_of_struct_be[i], packet_bytes->at(i));
+  }
+
+  PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = ArrayOfStructBeView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+
+  ASSERT_EQ(
+      "ArrayOfStructBe { array_count = 0x4, array = VECTOR[TwoRelatedNumbersBe { id = 0x1, count = 0x102 }, "
+      "TwoRelatedNumbersBe { id = 0x2, count = 0x204 }, TwoRelatedNumbersBe { id = 0x3, count = 0x306 }, "
+      "TwoRelatedNumbersBe { id = 0x4, count = 0x408 }] }",
+      view.ToString());
+}
+
+TEST(GeneratedPacketTest, testToStringOneFixedTypesStruct) {
+  StructWithFixedTypes swf;
+  swf.four_bits_ = FourBits::FIVE;
+  swf.id_ = 0x0d;
+  swf.array_ = {{0x01, 0x02, 0x03}};
+  swf.six_bytes_ = SixBytes{{0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6}};
+
+  auto packet = OneFixedTypesStructBuilder::Create(swf);
+  ASSERT_EQ(one_fixed_types_struct.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(one_fixed_types_struct.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_fixed_types_struct.size(); i++) {
+    ASSERT_EQ(one_fixed_types_struct[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneFixedTypesStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+
+  ASSERT_EQ(
+      "OneFixedTypesStruct { one = StructWithFixedTypes { four_bits = FIVE, id = 0xd, array = ARRAY[0x1, 0x2, 0x3], "
+      "example_checksum = CHECKSUM, six_bytes = SixBytes } }",
+      view.ToString());
+}
+
 }  // namespace parser
 }  // namespace packet
 }  // namespace bluetooth
index 0f26324..04b0599 100644 (file)
@@ -53,6 +53,9 @@ class SixBytes final {
   bool operator!=(const SixBytes& rhs) const {
     return !(*this == rhs);
   }
+  std::string ToString() const {
+    return "SixBytes";
+  }
 };
 
 }  // namespace test
index c452a37..920c14f 100644 (file)
@@ -62,6 +62,10 @@ class Variable final {
     *instance = ss.str();
     return it;
   }
+
+  std::string ToString() const {
+    return data;
+  }
 };
 
 }  // namespace test