OSDN Git Service

PDL: Add Structs
authorMyles Watson <mylesgw@google.com>
Wed, 6 Feb 2019 22:02:36 +0000 (14:02 -0800)
committerMyles Watson <mylesgw@google.com>
Wed, 24 Jul 2019 00:11:57 +0000 (00:11 +0000)
Test: bluetooth_packet_parser_test
Change-Id: I2d0288aa4e62589dd03d93a1b47ce0585584cab5

18 files changed:
gd/packet/parser/Android.bp
gd/packet/parser/declarations.h
gd/packet/parser/fields/all_fields.h
gd/packet/parser/fields/array_field.cc
gd/packet/parser/fields/array_field.h
gd/packet/parser/fields/struct_field.cc [new file with mode: 0644]
gd/packet/parser/fields/struct_field.h [new file with mode: 0644]
gd/packet/parser/fields/vector_field.cc
gd/packet/parser/fields/vector_field.h
gd/packet/parser/language_l.ll
gd/packet/parser/language_y.yy
gd/packet/parser/main.cc
gd/packet/parser/parent_def.cc
gd/packet/parser/struct_def.cc [new file with mode: 0644]
gd/packet/parser/struct_def.h [new file with mode: 0644]
gd/packet/parser/test/generated_packet_test.cc
gd/packet/parser/test/test_packets.pdl
gd/packet/parser/type_def.h

index 4dc4950..0711ade 100644 (file)
@@ -19,12 +19,14 @@ cc_binary_host {
         "fields/reserved_field.cc",
         "fields/scalar_field.cc",
         "fields/size_field.cc",
+        "fields/struct_field.cc",
         "checksum_def.cc",
         "custom_field_def.cc",
         "enum_def.cc",
         "enum_gen.cc",
         "packet_def.cc",
         "parent_def.cc",
+        "struct_def.cc",
         "main.cc",
         "language_y.yy",
         "language_l.ll",
index 1a344f0..21470e7 100644 (file)
@@ -25,6 +25,7 @@
 #include "enum_def.h"
 #include "enum_gen.h"
 #include "packet_def.h"
+#include "struct_def.h"
 
 class Declarations {
  public:
index 91323ea..cf51a3f 100644 (file)
@@ -31,4 +31,5 @@
 #include "fields/reserved_field.h"
 #include "fields/scalar_field.h"
 #include "fields/size_field.h"
+#include "fields/struct_field.h"
 #include "fields/vector_field.h"
index a39236f..4c4d6bf 100644 (file)
@@ -136,6 +136,8 @@ void ArrayField::GenInserter(std::ostream& s) const {
     } else {
       s << "insert(val, i);";
     }
+  } else if (IsStructArray()) {
+    s << "val.Serialize(i);";
   } else {
     s << "insert(val, i, " << element_size_ << ");";
   }
@@ -157,3 +159,7 @@ bool ArrayField::IsEnumArray() const {
 bool ArrayField::IsCustomFieldArray() const {
   return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
 }
+
+bool ArrayField::IsStructArray() const {
+  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::STRUCT;
+}
index 679823f..1892f57 100644 (file)
@@ -59,6 +59,8 @@ class ArrayField : public PacketField {
 
   bool IsCustomFieldArray() const;
 
+  bool IsStructArray() const;
+
   const std::string name_;
 
   const int element_size_{-1};  // in bits
diff --git a/gd/packet/parser/fields/struct_field.cc b/gd/packet/parser/fields/struct_field.cc
new file mode 100644 (file)
index 0000000..8831637
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fields/struct_field.h"
+#include "util.h"
+
+const std::string StructField::kFieldType = "StructField";
+
+StructField::StructField(std::string name, std::string type_name, int size, ParseLocation loc)
+    : PacketField(name, loc), type_name_(type_name), size_(size) {}
+
+const std::string& StructField::GetFieldType() const {
+  return StructField::kFieldType;
+}
+
+Size StructField::GetSize() const {
+  return size_;
+}
+
+Size StructField::GetBuilderSize() const {
+  if (size_ != -1) {
+    return size_;
+  } else {
+    std::string ret = "(" + GetName() + "_.size() * 8) ";
+    return ret;
+  }
+}
+
+std::string StructField::GetDataType() const {
+  return type_name_;
+}
+
+void StructField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
+  s << " // start_offset = " << start_offset.ToString() << "\n";
+  s << " // end_offset = " << end_offset.ToString() << "\n";
+}
+
+void StructField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+  if (size_ != -1) {
+    s << GetDataType();
+  } else {
+    s << "std::vector<" << GetDataType() << ">";
+  }
+  s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+
+  s << "auto it = ";
+  if (!start_offset.empty()) {
+    // Default to start if available.
+    if (start_offset.bits() % 8 != 0) {
+      ERROR(this) << "Struct Field must be byte aligned. start_offset.bits = " << start_offset.bits();
+    }
+    s << "begin() + (" << start_offset << ") / 8;";
+  } else if (size_ != -1) {
+    // If the size of the field is already known, we can determine it's offset based on end().
+    if (!end_offset.empty()) {
+      if (end_offset.bits() % 8) {
+        ERROR(this) << "Struct Field must be byte aligned. end_offset.bits = " << end_offset.bits();
+      }
+
+      s << "end() - (" << size_ << " + " << end_offset << ") / 8;";
+    } else {
+      ERROR(this) << "Ambiguous offset for fixed size custom field.";
+    }
+  } else {
+    ERROR(this) << "Struct Field offset can not be determined from begin().";
+  }
+
+  s << "std::vector<" << GetDataType() << "> to_return;";
+  s << GetDataType() << "::Parse(to_return, it);";
+  if (size_ != -1) {
+    s << "return to_return[0];";
+  } else {
+    s << "return to_return;";
+  }
+  s << "}\n";
+}
+
+bool StructField::GenBuilderParameter(std::ostream& s) const {
+  s << GetDataType() << " " << GetName();
+  return true;
+}
+
+bool StructField::HasParameterValidator() const {
+  return false;
+}
+
+void StructField::GenParameterValidator(std::ostream&) const {
+  // Validated at compile time.
+}
+
+void StructField::GenInserter(std::ostream& s) const {
+  s << GetName() << "_.Serialize(i);";
+}
+
+void StructField::GenValidator(std::ostream&) const {
+  // Do nothing
+}
diff --git a/gd/packet/parser/fields/struct_field.h b/gd/packet/parser/fields/struct_field.h
new file mode 100644 (file)
index 0000000..3577b1d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class StructField : public PacketField {
+ public:
+  StructField(std::string name, std::string type_name, int size, ParseLocation loc);
+
+  static const std::string kFieldType;
+
+  virtual const std::string& GetFieldType() const override;
+
+  virtual Size GetSize() const override;
+
+  virtual Size GetBuilderSize() const override;
+
+  virtual std::string GetDataType() const override;
+
+  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+  virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+  virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+  virtual bool HasParameterValidator() const override;
+
+  virtual void GenParameterValidator(std::ostream&) const override;
+
+  virtual void GenInserter(std::ostream& s) const override;
+
+  virtual void GenValidator(std::ostream&) const override;
+
+ private:
+  std::string type_name_;
+
+ public:
+  const int size_{-1};
+};
index 6fc7f69..b331f5d 100644 (file)
@@ -59,7 +59,7 @@ Size VectorField::GetSize() const {
     return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(element_size_) + ")";
   }
 
-  if (IsCustomFieldArray()) {
+  if (IsCustomFieldArray() || IsStructArray()) {
     if (type_def_->size_ != -1) {
       return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_) +
              ")";
@@ -152,6 +152,8 @@ void VectorField::GenInserter(std::ostream& s) const {
     } else {
       s << "insert(val, i);";
     }
+  } else if (IsStructArray()) {
+    s << "val.Serialize(i);";
   } else {
     s << "insert(val, i, " << element_size_ << ");";
   }
@@ -174,6 +176,10 @@ bool VectorField::IsCustomFieldArray() const {
   return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
 }
 
+bool VectorField::IsStructArray() const {
+  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::STRUCT;
+}
+
 void VectorField::SetSizeField(const SizeField* size_field) {
   if (size_field->GetFieldType() == CountField::kFieldType && !size_modifier_.empty()) {
     ERROR(this, size_field) << "Can not use count field to describe array with a size modifier."
index 34f4b31..d29759a 100644 (file)
@@ -57,6 +57,8 @@ class VectorField : public PacketField {
 
   bool IsCustomFieldArray() const;
 
+  bool IsStructArray() const;
+
   void SetSizeField(const SizeField* size_field);
 
   const std::string& GetSizeModifier() const;
index 1914ae9..f653bb0 100644 (file)
@@ -63,6 +63,7 @@ string_literal \".*\"
 "enum"                  { return(token::ENUM); }
 "group"                 { return(token::GROUP); }
 "packet"                { return(token::PACKET); }
+"struct"                { return(token::STRUCT); }
 "little_endian_packets" {
                           yylval->integer = 1;
                           return token::IS_LITTLE_ENDIAN;
index cc9d214..2623ea3 100644 (file)
@@ -44,6 +44,8 @@
   FieldList* packet_field_definitions;
   PacketField* packet_field_type;
 
+  StructDef* struct_definition_value;
+
   std::map<std::string, std::variant<int64_t, std::string>>* constraint_list_t;
   std::pair<std::string, std::variant<int64_t, std::string>>* constraint_t;
 }
@@ -58,6 +60,7 @@
 %token PACKET "packet"
 %token PAYLOAD "payload"
 %token BODY "body"
+%token STRUCT "struct"
 %token SIZE "size"
 %token COUNT "count"
 %token FIXED "fixed"
@@ -85,6 +88,8 @@
 %type<packet_field_type> reserved_field_definition;
 %type<packet_field_type> array_field_definition;
 
+%type<struct_definition_value> struct_definition;
+
 %type<constraint_list_t> constraint_list;
 %type<constraint_t> constraint;
 %destructor { std::cout << "DESTROYING STRING " << *$$ << "\n"; delete $$; } IDENTIFIER STRING SIZE_MODIFIER
@@ -118,6 +123,11 @@ declaration
       decls->AddPacketDef($1->name_, std::move(*$1));
       delete $1;
     }
+  | struct_definition
+    {
+      std::cerr << "FOUND STRUCT\n\n";
+      decls->AddTypeDef($1->name_, $1);
+    }
   | group_definition
     {
       // All actions are handled in group_definition
@@ -200,6 +210,82 @@ custom_field_definition
       delete $3;
     }
 
+struct_definition
+  : STRUCT IDENTIFIER '{' field_definition_list '}'
+    {
+      auto&& struct_name = *$2;
+      auto&& field_definition_list = *$4;
+
+      DEBUG() << "Struct " << struct_name << " with no parent";
+      DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size();
+      auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list));
+      struct_definition->AssignSizeFields();
+
+      $$ = struct_definition;
+      delete $2;
+      delete $4;
+    }
+  | STRUCT IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
+    {
+      auto&& struct_name = *$2;
+      auto&& parent_struct_name = *$4;
+      auto&& field_definition_list = *$6;
+
+      std::cerr << "Struct " << struct_name << " with parent " << parent_struct_name << "\n";
+      std::cerr << "STRUCT FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+
+      auto parent_struct = decls->GetTypeDef(parent_struct_name);
+      if (parent_struct == nullptr) {
+        ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
+                  << " used as parent for " << struct_name;
+      }
+
+      if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
+        ERRORLOC(LOC) << parent_struct_name << " is not a struct";
+      }
+      auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
+      struct_definition->AssignSizeFields();
+
+      $$ = struct_definition;
+      delete $2;
+      delete $4;
+      delete $6;
+    }
+  | STRUCT IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
+    {
+      auto&& struct_name = *$2;
+      auto&& parent_struct_name = *$4;
+      auto&& constraints = *$6;
+      auto&& field_definition_list = *$9;
+
+      auto parent_struct = decls->GetTypeDef(parent_struct_name);
+      if (parent_struct == nullptr) {
+        ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
+                  << " used as parent for " << struct_name;
+      }
+
+      if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
+        ERRORLOC(LOC) << parent_struct_name << " is not a struct";
+      }
+
+      auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
+      struct_definition->AssignSizeFields();
+
+      for (const auto& constraint : constraints) {
+        const auto& constraint_name = constraint.first;
+        const auto& constraint_value = constraint.second;
+        DEBUG() << "Parent constraint on " << constraint_name;
+        struct_definition->AddParentConstraint(constraint_name, constraint_value);
+      }
+
+      $$ = struct_definition;
+
+      delete $2;
+      delete $4;
+      delete $6;
+      delete $9;
+    }
+
 packet_definition
   : PACKET IDENTIFIER '{' field_definition_list '}'  /* Packet with no parent */
     {
index b347881..6f51edd 100644 (file)
@@ -110,7 +110,9 @@ bool parse_one_file(std::filesystem::path input_file, std::filesystem::path incl
   out_file << "#include \"os/log.h\"\n";
   out_file << "#include \"packet/base_packet_builder.h\"\n";
   out_file << "#include \"packet/bit_inserter.h\"\n";
+  out_file << "#include \"packet/iterator.h\"\n";
   out_file << "#include \"packet/packet_builder.h\"\n";
+  out_file << "#include \"packet/packet_struct.h\"\n";
   out_file << "#include \"packet/packet_view.h\"\n";
   out_file << "#include \"packet/parser/checksum_type_checker.h\"\n";
   out_file << "#include \"packet/parser/custom_type_checker.h\"\n";
@@ -140,8 +142,10 @@ bool parse_one_file(std::filesystem::path input_file, std::filesystem::path incl
   out_file << "using ::bluetooth::packet::BasePacketBuilder;";
   out_file << "using ::bluetooth::packet::BitInserter;";
   out_file << "using ::bluetooth::packet::CustomTypeChecker;";
+  out_file << "using ::bluetooth::packet::Iterator;";
   out_file << "using ::bluetooth::packet::kLittleEndian;";
   out_file << "using ::bluetooth::packet::PacketBuilder;";
+  out_file << "using ::bluetooth::packet::PacketStruct;";
   out_file << "using ::bluetooth::packet::PacketView;";
   out_file << "using ::bluetooth::packet::parser::ChecksumTypeChecker;";
   out_file << "\n\n";
@@ -174,6 +178,14 @@ bool parse_one_file(std::filesystem::path input_file, std::filesystem::path incl
   }
   out_file << "\n";
 
+  for (auto& s : decls.type_defs_queue_) {
+    if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+      ((StructDef*)s.second)->SetEndianness(decls.is_little_endian);
+      ((StructDef*)s.second)->GenDefinition(out_file);
+      out_file << "\n";
+    }
+  }
+
   for (size_t i = 0; i < decls.packet_defs_queue_.size(); i++) {
     decls.packet_defs_queue_[i].second.SetEndianness(decls.is_little_endian);
     decls.packet_defs_queue_[i].second.GenParserDefinition(out_file);
index 32121b5..2483d72 100644 (file)
@@ -216,8 +216,8 @@ FieldList ParentDef::GetParamList() const {
   FieldList params;
 
   std::set<std::string> param_types = {
-      ScalarField::kFieldType, EnumField::kFieldType,   ArrayField::kFieldType,
-      VectorField::kFieldType, CustomField::kFieldType, PayloadField::kFieldType,
+      ScalarField::kFieldType, EnumField::kFieldType,   ArrayField::kFieldType,   VectorField::kFieldType,
+      CustomField::kFieldType, StructField::kFieldType, PayloadField::kFieldType,
   };
 
   if (parent_ != nullptr) {
diff --git a/gd/packet/parser/struct_def.cc b/gd/packet/parser/struct_def.cc
new file mode 100644 (file)
index 0000000..67765cf
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "struct_def.h"
+
+#include "fields/all_fields.h"
+#include "util.h"
+
+StructDef::StructDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr){};
+StructDef::StructDef(std::string name, FieldList fields, StructDef* parent) : ParentDef(name, fields, parent){};
+
+PacketField* StructDef::GetNewField(const std::string& name, ParseLocation loc) const {
+  Size total_size = GetSize(false);
+  if (fields_.HasBody()) {
+    ERROR(new StructField(name, name_, -1, loc)) << "Variable size structs are not supported";
+    fprintf(stderr, "total_size of %s(%s) = %s\n", name_.c_str(), name.c_str(), total_size.ToString().c_str());
+    abort();
+    return new StructField(name, name_, -1, loc);
+  } else {
+    return new StructField(name, name_, total_size.bits(), loc);
+  }
+}
+
+TypeDef::Type StructDef::GetDefinitionType() const {
+  return TypeDef::Type::STRUCT;
+}
+
+void StructDef::GenParse(std::ostream& s) const {
+  if (is_little_endian_) {
+    s << "static Iterator<kLittleEndian> Parse(std::vector<" << name_ << ">& vec, Iterator<kLittleEndian> it) {";
+  } else {
+    s << "static Iterator<!kLittleEndian> Parse(std::vector<" << name_ << ">& vec, Iterator<!kLittleEndian> it) {";
+  }
+  s << "auto begin_it = it;";
+  s << name_ << " one;";
+  if (parent_ != nullptr) {
+    s << "begin_it += one." << parent_->name_ << "::BitsOfHeader() / 8;";
+  }
+  Size field_offset = Size(0);
+  for (const auto& field : fields_) {
+    // TODO: DON'T commit this logging
+    s << "\n/* (before adding) field_offset " << field_offset.bits() << " */\n ";
+    s << "\n/* (before adding) field->GetSize() " << field->GetSize().bits() << " */\n ";
+    // Size next_field_offset = field_offset + field->GetSize();
+    Size next_field_offset = field->GetSize() + field_offset.bits();
+    s << "\n/* field_offset " << field_offset.bits() << " */\n ";
+    if (field->GetFieldType() != ReservedField::kFieldType && field->GetFieldType() != BodyField::kFieldType &&
+        field->GetFieldType() != FixedScalarField::kFieldType && field->GetFieldType() != SizeField::kFieldType &&
+        field->GetFieldType() != CountField::kFieldType) {
+      s << "{";
+      field->GenExtractor(s, field_offset, next_field_offset);
+      s << "one." << field->GetName() << "_ = value;";
+      s << "}";
+    }
+    field_offset = next_field_offset;
+  }
+  s << "vec.push_back(one);";
+  s << "return it + " << field_offset.bytes() << ";";
+  s << "}";
+}
+
+void StructDef::GenDefinition(std::ostream& s) const {
+  s << "class " << name_;
+  if (parent_ != nullptr) {
+    s << " : public " << parent_->name_;
+  } else {
+    if (is_little_endian_) {
+      s << " : public PacketStruct<kLittleEndian>";
+    } else {
+      s << " : public PacketStruct<!kLittleEndian>";
+    }
+  }
+  s << " {";
+  s << " public:";
+
+  GenConstructor(s);
+
+  std::set<std::string> fixed_types = {
+      FixedScalarField::kFieldType,
+      FixedEnumField::kFieldType,
+  };
+
+  // Print all of the public fields which are all the fields minus the fixed fields.
+  const auto& public_fields = fields_.GetFieldsWithoutTypes(fixed_types);
+  bool has_fixed_fields = public_fields.size() != fields_.size();
+  for (const auto& field : public_fields) {
+    // GenParserFieldGetter(s, field);
+    s << "/*FieldGetter for " << field->GetName() << "*/\n";
+    s << "\n";
+  }
+
+  // Print the private fields which are the fixed fields.
+  if (has_fixed_fields) {
+    const auto& private_fields = fields_.GetFieldsWithTypes(fixed_types);
+    s << "/* private: */\n";
+    for (const auto& field : private_fields) {
+      // GenParserFieldGetter(s, field);
+      s << "/* FieldGetter for " << field->GetName() << "*/\n";
+    }
+  }
+  s << " public:\n";
+  s << "  virtual ~" << name_ << "() override = default;\n";
+
+  GenSerialize(s);
+  s << "\n";
+
+  GenParse(s);
+  s << "\n";
+
+  GenSize(s);
+  s << "\n";
+
+  GenMembers(s);
+  s << "};\n";
+}
+
+void StructDef::GenConstructor(std::ostream& s) const {
+  if (parent_ != nullptr) {
+    s << name_ << "() : " << parent_->name_ << "() {";
+  } else {
+    s << name_ << "() {";
+  }
+
+  // Get the list of parent params.
+  FieldList parent_params;
+  if (parent_ != nullptr) {
+    parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+        PayloadField::kFieldType,
+        BodyField::kFieldType,
+    });
+
+    // Set constrained parent fields to their correct values.
+    for (int i = 0; i < parent_params.size(); i++) {
+      const auto& field = parent_params[i];
+      const auto& constraint = parent_constraints_.find(field->GetName());
+      if (constraint != parent_constraints_.end()) {
+        s << parent_->name_ << "::" << field->GetName() << "_ = ";
+        if (field->GetFieldType() == ScalarField::kFieldType) {
+          s << std::get<int64_t>(constraint->second) << ";";
+        } else if (field->GetFieldType() == EnumField::kFieldType) {
+          s << std::get<std::string>(constraint->second) << ";";
+        } else {
+          ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+        }
+      }
+    }
+  }
+
+  /*
+    // Build a list of parameters that excludes all parent parameters.
+    FieldList saved_params;
+    for (const auto& field : params) {
+      if (parent_params.GetField(field->GetName()) == nullptr) {
+        saved_params.AppendField(field);
+      }
+    }
+    if (parent_ != nullptr && saved_params.size() > 0) {
+      s << ",";
+    }
+    for (int i = 0; i < saved_params.size(); i++) {
+      const auto& saved_param_name = saved_params[i]->GetName();
+      s << saved_param_name << "_(" << saved_param_name << ")";
+      if (i != saved_params.size() - 1) {
+        s << ",";
+      }
+    }
+    s << " {";
+
+  */
+  s << "}\n";
+}
diff --git a/gd/packet/parser/struct_def.h b/gd/packet/parser/struct_def.h
new file mode 100644 (file)
index 0000000..7b25ec8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <variant>
+
+#include "enum_def.h"
+#include "field_list.h"
+#include "fields/all_fields.h"
+#include "fields/packet_field.h"
+#include "parent_def.h"
+#include "parse_location.h"
+
+class StructDef : public ParentDef {
+ public:
+  StructDef(std::string name, FieldList fields);
+  StructDef(std::string name, FieldList fields, StructDef* parent);
+
+  PacketField* GetNewField(const std::string& name, ParseLocation loc) const;
+
+  TypeDef::Type GetDefinitionType() const;
+
+  void GenParse(std::ostream& s) const;
+
+  void GenDefinition(std::ostream& s) const;
+
+  void GenConstructor(std::ostream& s) const;
+};
index 2bf1c7e..c424ecd 100644 (file)
@@ -718,6 +718,367 @@ TEST(GeneratedPacketTest, testCountArrayVariableLength) {
     ASSERT_EQ(array[i].data, count_array[i].data);
   }
 }
+
+vector<uint8_t> one_struct{
+    0x01, 0x02, 0x03,  // id = 0x01, count = 0x0302
+};
+
+TEST(GeneratedPacketTest, testOneStruct) {
+  TwoRelatedNumbers trn;
+  trn.id_ = 1;
+  trn.count_ = 0x0302;
+
+  auto packet = OneStructBuilder::Create(trn);
+  ASSERT_EQ(one_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_struct.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_struct.size(); i++) {
+    ASSERT_EQ(one_struct[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOne();
+  ASSERT_EQ(one.id_, trn.id_);
+  ASSERT_EQ(one.count_, trn.count_);
+}
+
+vector<uint8_t> two_structs{
+    0x01, 0x01, 0x02,  // id, id * 0x0201
+    0x02, 0x02, 0x04,
+};
+
+TEST(GeneratedPacketTest, testTwoStructs) {
+  std::vector<TwoRelatedNumbers> count_array;
+  for (uint8_t i = 1; i < 3; i++) {
+    TwoRelatedNumbers trn;
+    trn.id_ = i;
+    trn.count_ = 0x0201 * i;
+    count_array.push_back(trn);
+  }
+
+  auto packet = TwoStructsBuilder::Create(count_array[0], count_array[1]);
+  ASSERT_EQ(two_structs.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(two_structs.size(), packet_bytes->size());
+  for (size_t i = 0; i < two_structs.size(); i++) {
+    ASSERT_EQ(two_structs[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = TwoStructsView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOne();
+  ASSERT_EQ(one.id_, count_array[0].id_);
+  ASSERT_EQ(one.count_, count_array[0].count_);
+  auto two = view.GetTwo();
+  ASSERT_EQ(two.id_, count_array[1].id_);
+  ASSERT_EQ(two.count_, count_array[1].count_);
+}
+
+vector<uint8_t> array_of_struct{
+    0x04,              // _count_
+    0x01, 0x01, 0x02,  // id, id * 0x0201
+    0x02, 0x02, 0x04, 0x03, 0x03, 0x06, 0x04, 0x04, 0x08,
+};
+
+TEST(GeneratedPacketTest, testArrayOfStruct) {
+  std::vector<TwoRelatedNumbers> count_array;
+  for (uint8_t i = 1; i < 5; i++) {
+    TwoRelatedNumbers trn;
+    trn.id_ = i;
+    trn.count_ = 0x0201 * i;
+    count_array.push_back(trn);
+  }
+
+  auto packet = ArrayOfStructBuilder::Create(count_array);
+  ASSERT_EQ(array_of_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(array_of_struct.size(), packet_bytes->size());
+  for (size_t i = 0; i < array_of_struct.size(); i++) {
+    ASSERT_EQ(array_of_struct[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = ArrayOfStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i].id_, count_array[i].id_);
+    ASSERT_EQ(array[i].count_, count_array[i].count_);
+  }
+}
+
+vector<uint8_t> array_of_struct_and_another{
+    0x03,              // _count_
+    0x01, 0x01, 0x02,  // id, id * 0x0201
+    0x02, 0x02, 0x04,  // 2
+    0x03, 0x03, 0x06,  // 3
+    0x04, 0x04, 0x08,  // Another
+};
+
+TEST(GeneratedPacketTest, testArrayOfStructAndAnother) {
+  std::vector<TwoRelatedNumbers> count_array;
+  for (uint8_t i = 1; i < 4; i++) {
+    TwoRelatedNumbers trn;
+    trn.id_ = i;
+    trn.count_ = 0x0201 * i;
+    count_array.push_back(trn);
+  }
+  TwoRelatedNumbers another;
+  another.id_ = 4;
+  another.count_ = 0x0201 * 4;
+
+  auto packet = ArrayOfStructAndAnotherBuilder::Create(count_array, another);
+  ASSERT_EQ(array_of_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(array_of_struct_and_another.size(), packet_bytes->size());
+  for (size_t i = 0; i < array_of_struct_and_another.size(); i++) {
+    ASSERT_EQ(array_of_struct_and_another[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = ArrayOfStructAndAnotherView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i].id_, count_array[i].id_);
+    ASSERT_EQ(array[i].count_, count_array[i].count_);
+  }
+  auto nother = view.GetAnother();
+  ASSERT_EQ(nother.id_, another.id_);
+  ASSERT_EQ(nother.count_, another.count_);
+}
+
+vector<uint8_t> bit_field_group_packet{
+    // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+    0xf7,  // 0x77 | (0x5 & 0x1) << 7
+    0xaa,  //  0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldGroupPacket) {
+  uint8_t seven_bits = 0x77;
+  uint8_t straddle = 0x5;
+  uint8_t five_bits = 0x15;
+
+  auto packet = BitFieldGroupPacketBuilder::Create(seven_bits, straddle, five_bits);
+  ASSERT_EQ(bit_field_group_packet.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(bit_field_group_packet.size(), packet_bytes->size());
+  for (size_t i = 0; i < bit_field_group_packet.size(); i++) {
+    ASSERT_EQ(bit_field_group_packet[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = BitFieldGroupPacketView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  ASSERT_EQ(seven_bits, view.GetSevenBits());
+  ASSERT_EQ(straddle, view.GetStraddle());
+  ASSERT_EQ(five_bits, view.GetFiveBits());
+}
+
+vector<uint8_t> bit_field_packet{
+    // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+    0xf7,  // 0x77 | (0x5 & 0x1) << 7
+    0xaa,  //  0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldPacket) {
+  BitField bit_field;
+  bit_field.seven_bits_ = 0x77;
+  bit_field.straddle_ = 0x5;
+  bit_field.five_bits_ = 0x15;
+
+  auto packet = BitFieldPacketBuilder::Create(bit_field);
+  ASSERT_EQ(bit_field_packet.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(bit_field_packet.size(), packet_bytes->size());
+  for (size_t i = 0; i < bit_field_packet.size(); i++) {
+    ASSERT_EQ(bit_field_packet[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = BitFieldPacketView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  BitField bf = view.GetBitField();
+  ASSERT_EQ(bf.seven_bits_, bit_field.seven_bits_);
+  ASSERT_EQ(bf.straddle_, bit_field.straddle_);
+  ASSERT_EQ(bf.five_bits_, bit_field.five_bits_);
+}
+
+vector<uint8_t> bit_field_group_after_unsized_array_packet{
+    0x01, 0x02, 0x03, 0x04,  // byte array
+    // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+    0xf7,  // 0x77 | (0x5 & 0x1) << 7
+    0xaa,  //  0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldGroupAfterUnsizedArrayPacket) {
+  std::vector<uint8_t> count_array;
+  for (uint8_t i = 1; i < 5; i++) {
+    count_array.push_back(i);
+  }
+  uint8_t seven_bits = 0x77;
+  uint8_t straddle = 0x5;
+  uint8_t five_bits = 0x15;
+
+  auto packet = BitFieldGroupAfterUnsizedArrayPacketBuilder::Create(count_array, seven_bits, straddle, five_bits);
+  ASSERT_EQ(bit_field_group_after_unsized_array_packet.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(bit_field_group_after_unsized_array_packet.size(), packet_bytes->size());
+  for (size_t i = 0; i < bit_field_group_after_unsized_array_packet.size(); i++) {
+    ASSERT_EQ(bit_field_group_after_unsized_array_packet[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto payload_view = BitFieldGroupAfterPayloadPacketView::Create(packet_bytes_view);
+  ASSERT_TRUE(payload_view.IsValid());
+  EXPECT_EQ(seven_bits, payload_view.GetSevenBits());
+  EXPECT_EQ(straddle, payload_view.GetStraddle());
+  EXPECT_EQ(five_bits, payload_view.GetFiveBits());
+
+  auto view = BitFieldGroupAfterUnsizedArrayPacketView::Create(payload_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i], count_array[i]);
+  }
+  ASSERT_EQ(seven_bits, view.GetSevenBits());
+  ASSERT_EQ(straddle, view.GetStraddle());
+  ASSERT_EQ(five_bits, view.GetFiveBits());
+}
+
+vector<uint8_t> bit_field_after_unsized_array_packet{
+    0x01, 0x02, 0x03, 0x04,  // byte array
+    // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+    0xf7,  // 0x77 | (0x5 & 0x1) << 7
+    0xaa,  //  0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldAfterUnsizedArrayPacket) {
+  std::vector<uint8_t> count_array;
+  for (uint8_t i = 1; i < 5; i++) {
+    count_array.push_back(i);
+  }
+  BitField bit_field;
+  bit_field.seven_bits_ = 0x77;
+  bit_field.straddle_ = 0x5;
+  bit_field.five_bits_ = 0x15;
+
+  auto packet = BitFieldAfterUnsizedArrayPacketBuilder::Create(count_array, bit_field);
+  ASSERT_EQ(bit_field_after_unsized_array_packet.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(bit_field_after_unsized_array_packet.size(), packet_bytes->size());
+  for (size_t i = 0; i < bit_field_after_unsized_array_packet.size(); i++) {
+    ASSERT_EQ(bit_field_after_unsized_array_packet[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto payload_view = BitFieldAfterPayloadPacketView::Create(packet_bytes_view);
+  ASSERT_TRUE(payload_view.IsValid());
+  BitField parent_bf = payload_view.GetBitField();
+  ASSERT_EQ(parent_bf.seven_bits_, bit_field.seven_bits_);
+  ASSERT_EQ(parent_bf.straddle_, bit_field.straddle_);
+  ASSERT_EQ(parent_bf.five_bits_, bit_field.five_bits_);
+
+  auto view = BitFieldAfterUnsizedArrayPacketView::Create(payload_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i], count_array[i]);
+  }
+  BitField bf = view.GetBitField();
+  ASSERT_EQ(bf.seven_bits_, bit_field.seven_bits_);
+  ASSERT_EQ(bf.straddle_, bit_field.straddle_);
+  ASSERT_EQ(bf.five_bits_, bit_field.five_bits_);
+}
+
+vector<uint8_t> bit_field_array_packet{
+    0x06,  // _size_(array)
+    // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+    0xf7,  // 0x77 | (0x5 & 0x1) << 7
+    0xaa,  //  0x15 << 3 | (0x5 >> 1)
+
+    // seven_bits_ = 0x78, straddle_ = 0x6, five_bits_ = 0x16
+    0x78,  // 0x78 | (0x6 & 0x1) << 7
+    0xb3,  //  0x16 << 3 | (0x6 >> 1)
+
+    // seven_bits_ = 0x79, straddle_ = 0x7, five_bits_ = 0x17
+    0xf9,  // 0x79 | (0x7 & 0x1) << 7
+    0xbb,  //  0x17 << 3 | (0x7 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldArrayPacket) {
+  std::vector<BitField> count_array;
+  for (size_t i = 0; i < 3; i++) {
+    BitField bf;
+    bf.seven_bits_ = 0x77 + i;
+    bf.straddle_ = 0x5 + i;
+    bf.five_bits_ = 0x15 + i;
+    count_array.push_back(bf);
+  }
+
+  auto packet = BitFieldArrayPacketBuilder::Create(count_array);
+  ASSERT_EQ(bit_field_array_packet.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(bit_field_array_packet.size(), packet_bytes->size());
+  for (size_t i = 0; i < bit_field_array_packet.size(); i++) {
+    ASSERT_EQ(bit_field_array_packet[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = BitFieldArrayPacketView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i].seven_bits_, count_array[i].seven_bits_);
+    ASSERT_EQ(array[i].straddle_, count_array[i].straddle_);
+    ASSERT_EQ(array[i].five_bits_, count_array[i].five_bits_);
+  }
+}
+
 }  // namespace parser
 }  // namespace packet
 }  // namespace bluetooth
index fcb2f3f..899b9b7 100644 (file)
@@ -165,3 +165,71 @@ packet CountArrayVariable {
   _count_(variable_array) : 8,
   variable_array : Variable[],
 }
+
+struct TwoRelatedNumbers {
+  id : 8,
+  count : 16,
+}
+
+packet OneStruct {
+  one : TwoRelatedNumbers,
+}
+
+packet TwoStructs {
+  one : TwoRelatedNumbers,
+  two : TwoRelatedNumbers,
+}
+
+packet ArrayOfStruct {
+  _count_(array) : 8,
+  array : TwoRelatedNumbers[],
+}
+
+packet ArrayOfStructAndAnother {
+  _count_(array) : 8,
+  array : TwoRelatedNumbers[],
+  another : TwoRelatedNumbers,
+}
+
+group BitFieldGroup {
+  seven_bits : 7,
+  straddle : 4,
+  five_bits : 5,
+}
+
+packet BitFieldGroupPacket {
+  BitFieldGroup,
+}
+
+packet BitFieldGroupAfterPayloadPacket {
+  _payload_,
+  BitFieldGroup,
+}
+
+packet BitFieldGroupAfterUnsizedArrayPacket : BitFieldGroupAfterPayloadPacket {
+  array : 8[],
+}
+
+struct BitField {
+  seven_bits : 7,
+  straddle : 4,
+  five_bits : 5,
+}
+
+packet BitFieldPacket {
+  bit_field : BitField,
+}
+
+packet BitFieldAfterPayloadPacket {
+  _payload_,
+  bit_field : BitField,
+}
+
+packet BitFieldAfterUnsizedArrayPacket : BitFieldAfterPayloadPacket {
+  array : 8[],
+}
+
+packet BitFieldArrayPacket {
+  _size_(array): 8,
+  array : BitField[],
+}
index 87d3344..e046e16 100644 (file)
@@ -39,6 +39,7 @@ class TypeDef {
     CHECKSUM,
     CUSTOM,
     PACKET,
+    STRUCT,
   };
 
   virtual Type GetDefinitionType() const = 0;