"fields/fixed_scalar_field.cc",
"fields/group_field.cc",
"fields/packet_field.cc",
+ "fields/padding_field.cc",
"fields/payload_field.cc",
"fields/reserved_field.cc",
"fields/scalar_field.cc",
#include "fields/fixed_enum_field.h"
#include "fields/fixed_scalar_field.h"
#include "fields/group_field.h"
+#include "fields/padding_field.h"
#include "fields/payload_field.h"
#include "fields/reserved_field.h"
#include "fields/scalar_field.h"
void ChecksumStartField::GenGetter(std::ostream&, Size, Size) const {}
bool ChecksumStartField::GenBuilderParameter(std::ostream&) const {
- // There is no builder parameter for a size field
return false;
}
--- /dev/null
+/*
+ * 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/padding_field.h"
+#include "util.h"
+
+const std::string PaddingField::kFieldType = "PaddingField";
+
+PaddingField::PaddingField(int size, ParseLocation loc)
+ : PacketField("padding_" + std::to_string(size * 8), loc), size_(size * 8) {}
+
+const std::string& PaddingField::GetFieldType() const {
+ return PaddingField::kFieldType;
+}
+
+Size PaddingField::GetSize() const {
+ return size_;
+}
+
+Size PaddingField::GetBuilderSize() const {
+ return 0;
+}
+
+std::string PaddingField::GetDataType() const {
+ return "There's no type for Padding fields";
+}
+
+void PaddingField::GenExtractor(std::ostream&, int, bool) const {}
+
+void PaddingField::GenGetter(std::ostream&, Size, Size) const {}
+
+bool PaddingField::GenBuilderParameter(std::ostream&) const {
+ return false;
+}
+
+bool PaddingField::HasParameterValidator() const {
+ return false;
+}
+
+void PaddingField::GenParameterValidator(std::ostream&) const {}
+
+void PaddingField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for padding fields";
+}
+
+void PaddingField::GenValidator(std::ostream&) const {}
--- /dev/null
+/*
+ * 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 PaddingField : public PacketField {
+ public:
+ PaddingField(int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ std::string GetField() const;
+
+ 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, int num_leading_bits, bool for_struct) const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ Size size_;
+};
"_fixed_" { return(token::FIXED); }
"_reserved_" { return(token::RESERVED); }
"_checksum_start_" { return(token::CHECKSUM_START); }
+"_padding_" { return(token::PADDING); }
/* Types */
"checksum" { return(token::CHECKSUM); }
"custom_field" { return(token::CUSTOM_FIELD); }
%token CUSTOM_FIELD "custom_field"
%token CHECKSUM "checksum"
%token CHECKSUM_START "checksum_start"
+%token PADDING "padding"
%type<enum_definition> enum_definition
%type<enumeration_values> enumeration_list
%type<packet_field_type> type_def_field_definition;
%type<packet_field_type> scalar_field_definition;
%type<packet_field_type> checksum_start_field_definition;
+%type<packet_field_type> padding_field_definition;
%type<packet_field_type> size_field_definition;
%type<packet_field_type> payload_field_definition;
%type<packet_field_type> body_field_definition;
DEBUG() << "Checksum start field\n";
$$ = $1;
}
+ | padding_field_definition
+ {
+ DEBUG() << "Padding field\n";
+ $$ = $1;
+ }
| size_field_definition
{
DEBUG() << "Size field\n";
delete $3;
}
+padding_field_definition
+ : PADDING '[' INTEGER ']'
+ {
+ DEBUG() << "Padding field defined\n";
+ $$ = new PaddingField($3, LOC);
+ }
+
size_field_definition
: SIZE '(' IDENTIFIER ')' ':' INTEGER
{
// Get the static offset for all of our fields.
int bits_size = 0;
for (const auto& field : fields_) {
- bits_size += field->GetSize().bits();
+ if (field->GetFieldType() != PaddingField::kFieldType) {
+ bits_size += field->GetSize().bits();
+ }
}
// Write the function declaration.
s << ";}\n\n";
}
+ Size padded_size;
+ for (const auto& field : header_fields) {
+ if (field->GetFieldType() == PaddingField::kFieldType) {
+ if (!padded_size.empty()) {
+ ERROR() << "Only one padding field is allowed. Second field: " << field->GetName();
+ }
+ padded_size = field->GetSize();
+ }
+ }
+
s << "public:";
s << "virtual size_t size() const override {";
+ if (!padded_size.empty()) {
+ s << "return " << padded_size.bytes() << ";}";
+ s << "size_t unpadded_size() const {";
+ }
s << "return (BitsOfHeader() / 8)";
if (fields_.HasPayload()) {
s << "+ payload_->size()";
s << "i.RegisterObserver(packet::ByteObserver(";
s << "[shared_checksum_ptr](uint8_t byte){ shared_checksum_ptr->AddByte(byte);},";
s << "[shared_checksum_ptr](){ return static_cast<uint64_t>(shared_checksum_ptr->GetChecksum());}));";
+ } else if (field->GetFieldType() == PaddingField::kFieldType) {
+ s << "ASSERT(unpadded_size() <= " << field->GetSize().bytes() << ");";
+ s << "size_t padding_bytes = ";
+ s << field->GetSize().bytes() << " - unpadded_size();";
+ s << "for (size_t padding = 0; padding < padding_bytes; padding++) {i.insert_byte(0);}";
} else if (field->GetFieldType() == CountField::kFieldType) {
const auto& vector_name = ((SizeField*)field)->GetSizedFieldName() + "_";
s << "insert(" << vector_name << ".size(), i, " << field->GetSize().bits() << ");";
}
}
}
+
+vector<uint8_t> one_length_type_value_struct_padded_20{
+ 0x27, // _size_(payload),
+ // _size_(value):16 type value
+ 0x04, 0x00, 0x01, 'o', 'n', 'e', // ONE
+ 0x04, 0x00, 0x02, 't', 'w', 'o', // TWO
+ 0x06, 0x00, 0x03, 't', 'h', 'r', 'e', 'e', // THREE
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 30
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 40
+};
+
+vector<uint8_t> one_length_type_value_struct_padded_28{
+ 0x27, // _size_(payload),
+ // _size_(value):16 type value
+ 0x04, 0x00, 0x01, 'o', 'n', 'e', // ONE
+ 0x04, 0x00, 0x02, 't', 'w', 'o', // TWO
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 20
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 30
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 40
+};
+
+// TODO: Revisit LTV parsing. Right now, the padding bytes are parsed
+// DEFINE_AND_INSTANTIATE_OneLengthTypeValueStructPaddedReflectionTest(one_length_type_value_struct_padded_20,
+// one_length_type_value_struct_padded_28);
+
+TEST(GeneratedPacketTest, testOneLengthTypeValueStructPaddedGeneration) {
+ std::vector<LengthTypeValueStruct> ltv_vector;
+ LengthTypeValueStruct ltv;
+ ltv.type_ = DataType::ONE;
+ ltv.value_ = {
+ 'o',
+ 'n',
+ 'e',
+ };
+ ltv_vector.push_back(ltv);
+ ltv.type_ = DataType::TWO;
+ ltv.value_ = {
+ 't',
+ 'w',
+ 'o',
+ };
+ ltv_vector.push_back(ltv);
+
+ auto packet = OneLengthTypeValueStructPaddedBuilder::Create(ltv_vector);
+ ASSERT_EQ(one_length_type_value_struct_padded_28.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_length_type_value_struct_padded_28.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_length_type_value_struct_padded_28.size(); i++) {
+ ASSERT_EQ(one_length_type_value_struct_padded_28[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneLengthTypeValueStructPaddedView::Create(SizedParentView::Create(packet_bytes_view));
+ ASSERT_TRUE(view.IsValid());
+ auto an_array = view.GetOneArray();
+ // TODO: Revisit LTV parsing. Right now, the padding bytes are parsed
+ // ASSERT_EQ(ltv_vector.size(), an_array.size());
+ for (size_t i = 0; i < ltv_vector.size(); i++) {
+ ASSERT_EQ(ltv_vector[i].type_, an_array[i].type_);
+ ASSERT_EQ(ltv_vector[i].value_, an_array[i].value_);
+ }
+}
} // namespace parser
} // namespace packet
} // namespace bluetooth
packet OneLengthTypeValueStruct {
one_array : LengthTypeValueStruct[],
}
+
+packet SizedParent {
+ _size_(payload) : 8,
+ _payload_,
+}
+
+packet OneLengthTypeValueStructPadded : SizedParent {
+ one_array : LengthTypeValueStruct[],
+ _padding_[40],
+}