PDL: Extract CustomFieldFixedSize

Test: bluetooth_packet_parser_test
Change-Id: Ia93442ca1cc173d0b6c813a45c722f14d2f34fa0
diff --git a/system/gd/packet/parser/Android.bp b/system/gd/packet/parser/Android.bp
index 55a983b..63aaa7a 100644
--- a/system/gd/packet/parser/Android.bp
+++ b/system/gd/packet/parser/Android.bp
@@ -7,6 +7,7 @@
         "fields/checksum_start_field.cc",
         "fields/count_field.cc",
         "fields/custom_field.cc",
+        "fields/custom_field_fixed_size.cc",
         "fields/enum_field.cc",
         "fields/fixed_enum_field.cc",
         "fields/fixed_field.cc",
diff --git a/system/gd/packet/parser/custom_field_def.cc b/system/gd/packet/parser/custom_field_def.cc
index 1ac6779..5dc9316 100644
--- a/system/gd/packet/parser/custom_field_def.cc
+++ b/system/gd/packet/parser/custom_field_def.cc
@@ -28,7 +28,11 @@
 }
 
 PacketField* CustomFieldDef::GetNewField(const std::string& name, ParseLocation loc) const {
-  return new CustomField(name, name_, size_, loc);
+  if (size_ == -1) {
+    return new CustomField(name, name_, loc);
+  } else {
+    return new CustomFieldFixedSize(name, name_, size_, loc);
+  }
 }
 
 TypeDef::Type CustomFieldDef::GetDefinitionType() const {
diff --git a/system/gd/packet/parser/custom_field_def.h b/system/gd/packet/parser/custom_field_def.h
index d14c437..62cf363 100644
--- a/system/gd/packet/parser/custom_field_def.h
+++ b/system/gd/packet/parser/custom_field_def.h
@@ -19,6 +19,7 @@
 #include <iostream>
 
 #include "fields/custom_field.h"
+#include "fields/custom_field_fixed_size.h"
 #include "parse_location.h"
 #include "type_def.h"
 
diff --git a/system/gd/packet/parser/fields/all_fields.h b/system/gd/packet/parser/fields/all_fields.h
index 37ffe98..5797076 100644
--- a/system/gd/packet/parser/fields/all_fields.h
+++ b/system/gd/packet/parser/fields/all_fields.h
@@ -22,6 +22,7 @@
 #include "fields/checksum_start_field.h"
 #include "fields/count_field.h"
 #include "fields/custom_field.h"
+#include "fields/custom_field_fixed_size.h"
 #include "fields/enum_field.h"
 #include "fields/fixed_enum_field.h"
 #include "fields/fixed_scalar_field.h"
diff --git a/system/gd/packet/parser/fields/custom_field.cc b/system/gd/packet/parser/fields/custom_field.cc
index 9ff1e86..5a098e6 100644
--- a/system/gd/packet/parser/fields/custom_field.cc
+++ b/system/gd/packet/parser/fields/custom_field.cc
@@ -19,24 +19,20 @@
 
 const std::string CustomField::kFieldType = "CustomField";
 
-CustomField::CustomField(std::string name, std::string type_name, int size, ParseLocation loc)
-    : PacketField(name, loc), type_name_(type_name), size_(size) {}
+CustomField::CustomField(std::string name, std::string type_name, ParseLocation loc)
+    : PacketField(name, loc), type_name_(type_name) {}
 
 const std::string& CustomField::GetFieldType() const {
   return CustomField::kFieldType;
 }
 
 Size CustomField::GetSize() const {
-  return size_;
+  return Size();
 }
 
 Size CustomField::GetBuilderSize() const {
-  if (size_ != -1) {
-    return size_;
-  } else {
-    std::string ret = "(" + GetName() + "_.size() * 8) ";
-    return ret;
-  }
+  std::string ret = "(" + GetName() + "_.size() * 8) ";
+  return ret;
 }
 
 std::string CustomField::GetDataType() const {
@@ -52,42 +48,11 @@
 }
 
 void CustomField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  if (size_ != -1) {
-    s << GetDataType();
-  } else {
-    s << "std::vector<" << GetDataType() << ">";
-  }
+  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) << "Custom 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 custom field is already known, we can determine it's offset based on end().
-    if (!end_offset.empty()) {
-      if (end_offset.bits() % 8) {
-        ERROR(this) << "Custom 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) << "Custom Field offset can not be determined from begin().";
-  }
-
-  if (size_ != -1) {
-    s << "return it.extract<" << GetDataType() << ">();";
-  } else {
-    s << "std::vector<" << GetDataType() << "> to_return;";
-    s << GetDataType() << "::Parse(to_return, it);";
-    s << "return to_return;";
-  }
+  GenExtractor(s, start_offset, end_offset);
+  s << "return vec;";
   s << "}\n";
 }
 
@@ -105,11 +70,7 @@
 }
 
 void CustomField::GenInserter(std::ostream& s) const {
-  if (size_ != -1) {
-    s << "insert(" << GetName() << "_, i);";
-  } else {
-    s << GetName() << "_.Serialize(i);";
-  }
+  s << GetName() << "_.Serialize(i);";
 }
 
 void CustomField::GenValidator(std::ostream&) const {
diff --git a/system/gd/packet/parser/fields/custom_field.h b/system/gd/packet/parser/fields/custom_field.h
index d54db0a..86fefd2 100644
--- a/system/gd/packet/parser/fields/custom_field.h
+++ b/system/gd/packet/parser/fields/custom_field.h
@@ -21,7 +21,7 @@
 
 class CustomField : public PacketField {
  public:
-  CustomField(std::string name, std::string type_name, int size, ParseLocation loc);
+  CustomField(std::string name, std::string type_name, ParseLocation loc);
 
   static const std::string kFieldType;
 
@@ -49,7 +49,4 @@
 
  private:
   std::string type_name_;
-
- public:
-  const int size_{-1};
 };
diff --git a/system/gd/packet/parser/fields/custom_field_fixed_size.cc b/system/gd/packet/parser/fields/custom_field_fixed_size.cc
new file mode 100644
index 0000000..08d3a0e
--- /dev/null
+++ b/system/gd/packet/parser/fields/custom_field_fixed_size.cc
@@ -0,0 +1,59 @@
+/*
+ * 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/custom_field_fixed_size.h"
+#include "util.h"
+
+const std::string CustomFieldFixedSize::kFieldType = "CustomField";
+
+CustomFieldFixedSize::CustomFieldFixedSize(std::string name, std::string type_name, int size, ParseLocation loc)
+    : ScalarField(name, size, loc), type_name_(type_name) {}
+
+const std::string& CustomFieldFixedSize::GetFieldType() const {
+  return CustomFieldFixedSize::kFieldType;
+}
+
+std::string CustomFieldFixedSize::GetDataType() const {
+  return type_name_;
+}
+
+void CustomFieldFixedSize::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
+  int field_size = GetSize().bits();
+
+  if (!start_offset.empty()) {
+    // Default to start if available.
+    s << "auto it = begin_it + (" << start_offset << ") / 8;";
+  } else if (!end_offset.empty()) {
+    Size byte_offset = Size(field_size) + end_offset;
+    s << "auto it = end_it - (" << byte_offset << ") / 8;";
+  } else {
+    ERROR(this) << "Ambiguous offset for field.";
+  }
+
+  s << GetDataType() << " value = it.extract<" << GetDataType() << ">();";
+}
+
+bool CustomFieldFixedSize::HasParameterValidator() const {
+  return false;
+}
+
+void CustomFieldFixedSize::GenParameterValidator(std::ostream&) const {
+  // Do nothing.
+}
+
+void CustomFieldFixedSize::GenValidator(std::ostream&) const {
+  // Do nothing.
+}
diff --git a/system/gd/packet/parser/fields/custom_field_fixed_size.h b/system/gd/packet/parser/fields/custom_field_fixed_size.h
new file mode 100644
index 0000000..5a11c0d
--- /dev/null
+++ b/system/gd/packet/parser/fields/custom_field_fixed_size.h
@@ -0,0 +1,41 @@
+/*
+ * 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/scalar_field.h"
+#include "parse_location.h"
+
+class CustomFieldFixedSize : public ScalarField {
+ public:
+  CustomFieldFixedSize(std::string name, std::string type_name, int size, ParseLocation loc);
+
+  static const std::string kFieldType;
+
+  virtual const std::string& GetFieldType() const override;
+
+  virtual std::string GetDataType() const override;
+
+  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+  virtual bool HasParameterValidator() const override;
+
+  virtual void GenParameterValidator(std::ostream&) const override;
+
+  virtual void GenValidator(std::ostream&) const override;
+
+  std::string type_name_;
+};