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
-------------
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
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
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 << \"]\"";
+}
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};
void BodyField::GenValidator(std::ostream&) const {
// Do nothing
}
+
+void BodyField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << "\"BODY REPRENTATION_UNIMPLEMENTED " << accessor << " \"";
+}
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};
};
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\"";
+}
virtual void GenValidator(std::ostream&) const override;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
private:
std::string type_name_;
};
std::string ChecksumStartField::GetStartedFieldName() const {
return started_field_name_;
}
+
+void ChecksumStartField::GenStringRepresentation(std::ostream&, std::string) const {
+ // Print nothing for checksum start
+}
virtual std::string GetStartedFieldName() const;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
private:
std::string started_field_name_;
};
void CustomField::GenValidator(std::ostream&) const {
// Do nothing.
}
+
+void CustomField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << accessor << "->ToString()";
+}
virtual void GenValidator(std::ostream&) const override;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
private:
std::string type_name_;
};
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()";
+}
virtual void GenValidator(std::ostream&) const override;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
std::string type_name_;
};
void EnumField::GenValidator(std::ostream&) const {
// Do nothing
}
+
+void EnumField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << GetDataType() << "Text(" << accessor << ")";
+}
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_;
void FixedScalarField::GenValue(std::ostream& s) const {
s << value_;
}
+
+void FixedScalarField::GenStringRepresentation(std::ostream& s, std::string) const {
+ s << "+" << value_;
+}
virtual std::string GetDataType() const override;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
static const std::string field_type;
private:
const PacketField* PacketField::GetElementField() const {
return nullptr;
}
+
+void PacketField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << "\"REPRESENTATION_UNIMPLEMENTED " << GetFieldType() << " " << accessor << "\"";
+}
// 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;
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[]\"";
+}
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.
void ScalarField::GenValidator(std::ostream&) const {
// Do nothing
}
+
+void ScalarField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << "+" << accessor;
+}
virtual void GenValidator(std::ostream&) const override;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
private:
const int size_;
};
std::string SizeField::GetSizedFieldName() const {
return sized_field_name_;
}
+
+void SizeField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << accessor;
+}
virtual std::string GetSizedFieldName() const;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
private:
int size_;
std::string sized_field_name_;
void StructField::GenValidator(std::ostream&) const {
// Do nothing
}
+
+void StructField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
+ s << accessor << ".ToString()";
+}
virtual void GenValidator(std::ostream&) const override;
+ virtual void GenStringRepresentation(std::ostream& s, std::string accessor) const override;
+
private:
std::string type_name_;
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 << \"]\"";
+}
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};
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";
GenValidator(s);
s << "\n";
+ s << " public:";
+ GenParserToString(s);
+ s << "\n";
+
s << " protected:\n";
// Constructor from a View
if (parent_ != nullptr) {
}
}
+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) {
void GenValidator(std::ostream& s) const;
+ void GenParserToString(std::ostream& s) const;
+
TypeDef::Type GetDefinitionType() const;
void GenBuilderDefinition(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>");
GenSpecialize(s);
s << "\n";
+ GenToString(s);
+ s << "\n";
+
GenMembers(s);
for (const auto& field : fields_) {
if (field->GetFieldType() == CountField::kFieldType || field->GetFieldType() == SizeField::kFieldType) {
void GenSpecialize(std::ostream& s) const;
+ void GenToString(std::ostream& s) const;
+
void GenParse(std::ostream& s) const;
void GenParseFunctionPrototype(std::ostream& s) const;
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
bool operator!=(const SixBytes& rhs) const {
return !(*this == rhs);
}
+ std::string ToString() const {
+ return "SixBytes";
+ }
};
} // namespace test
*instance = ss.str();
return it;
}
+
+ std::string ToString() const {
+ return data;
+ }
};
} // namespace test