/* * 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 #include #include #include "fields/all_fields.h" #include "fields/packet_field.h" using FieldListIterator = std::vector::const_iterator; using ReverseFieldListIterator = std::vector::const_reverse_iterator; class FieldList { public: FieldList() = default; FieldList(std::vector fields) { for (PacketField* field : fields) { AppendField(field); } } template FieldList(Iterator begin, Iterator end) { while (begin != end) { AppendField(*begin); begin++; } } PacketField* operator[](int index) const { return field_list_[index]; } PacketField* GetField(std::string field_name) const { auto it = field_map_.find(field_name); if (it == field_map_.end()) { return nullptr; } return it->second; } void AppendField(PacketField* field) { AddField(field); field_list_.push_back(field); } void PrependField(PacketField* field) { AddField(field); field_list_.insert(field_list_.begin(), field); } FieldList GetFieldsBeforePayloadOrBody() const { FieldList ret; for (auto it = begin(); it != end(); it++) { const auto& field = *it; if (field->GetFieldType() == PayloadField::kFieldType || field->GetFieldType() == BodyField::kFieldType) { break; } ret.AppendField(*it); } return ret; } FieldList GetFieldsAfterPayloadOrBody() const { FieldListIterator it; for (it = begin(); it != end(); it++) { const auto& field = *it; if (field->GetFieldType() == PayloadField::kFieldType || field->GetFieldType() == BodyField::kFieldType) { // Increment it once to get first field after payload/body. it++; break; } } return FieldList(it, end()); } FieldList GetFieldsWithTypes(std::set field_types) const { FieldList ret; for (const auto& field : field_list_) { if (field_types.find(field->GetFieldType()) != field_types.end()) { ret.AppendField(field); } } return ret; } FieldList GetFieldsWithoutTypes(std::set field_types) const { FieldList ret; for (const auto& field : field_list_) { if (field_types.find(field->GetFieldType()) == field_types.end()) { ret.AppendField(field); } } return ret; } // Appends header fields of param to header fields of the current and // prepends footer fields of the param to footer fields of the current. // Ex. Assuming field_list_X has the layout: // field_list_X_header // payload/body // field_list_X_footer // The call to field_list_1.Merge(field_list_2) would result in // field_list_1_header // field_list_2_header // payload/body (uses whatever was in field_list_2) // field_list_2_footer // field_list_1_footer FieldList Merge(FieldList nested) const { FieldList ret; for (const auto& field : GetFieldsBeforePayloadOrBody()) { ret.AppendField(field); } for (const auto& field : nested) { ret.AppendField(field); } for (const auto& field : GetFieldsAfterPayloadOrBody()) { ret.AppendField(field); } return ret; } bool HasPayloadOrBody() const { return has_payload_ || has_body_; } bool HasPayload() const { return has_payload_; } bool HasBody() const { return has_body_; } FieldListIterator begin() const { return field_list_.begin(); } FieldListIterator end() const { return field_list_.end(); } ReverseFieldListIterator rbegin() const { return field_list_.rbegin(); } ReverseFieldListIterator rend() const { return field_list_.rend(); } size_t size() const { return field_list_.size(); } private: void AddField(PacketField* field) { if (field_map_.find(field->GetName()) != field_map_.end()) { ERROR(field) << "Field with name \"" << field->GetName() << "\" was previously defined.\n"; } if (field->GetFieldType() == PayloadField::kFieldType) { if (has_body_) { ERROR(field) << "Packet already has a body."; } has_payload_ = true; } if (field->GetFieldType() == BodyField::kFieldType) { if (has_payload_) { ERROR(field) << "Packet already has a payload."; } has_body_ = true; } field_map_.insert(std::pair(field->GetName(), field)); } std::vector field_list_; std::map field_map_; bool has_payload_ = false; bool has_body_ = false; };