1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <map> 20 #include <set> 21 #include <vector> 22 23 #include "fields/all_fields.h" 24 #include "fields/packet_field.h" 25 26 using FieldListIterator = std::vector<PacketField*>::const_iterator; 27 using ReverseFieldListIterator = std::vector<PacketField*>::const_reverse_iterator; 28 29 class FieldList { 30 public: 31 FieldList() = default; 32 FieldList(std::vector<PacketField * > fields)33 FieldList(std::vector<PacketField*> fields) { 34 for (PacketField* field : fields) { 35 AppendField(field); 36 } 37 } 38 39 template <class Iterator> FieldList(Iterator begin,Iterator end)40 FieldList(Iterator begin, Iterator end) { 41 while (begin != end) { 42 AppendField(*begin); 43 begin++; 44 } 45 } 46 47 PacketField* operator[](int index) const { return field_list_[index]; } 48 GetField(std::string field_name)49 PacketField* GetField(std::string field_name) const { 50 auto it = field_map_.find(field_name); 51 if (it == field_map_.end()) { 52 return nullptr; 53 } 54 55 return it->second; 56 } 57 AppendField(PacketField * field)58 void AppendField(PacketField* field) { 59 AddField(field); 60 field_list_.push_back(field); 61 } 62 PrependField(PacketField * field)63 void PrependField(PacketField* field) { 64 AddField(field); 65 field_list_.insert(field_list_.begin(), field); 66 } 67 GetFieldsBeforePayloadOrBody()68 FieldList GetFieldsBeforePayloadOrBody() const { 69 FieldList ret; 70 for (auto it = begin(); it != end(); it++) { 71 const auto& field = *it; 72 if (field->GetFieldType() == PayloadField::kFieldType || 73 field->GetFieldType() == BodyField::kFieldType) { 74 break; 75 } 76 ret.AppendField(*it); 77 } 78 79 return ret; 80 } 81 GetFieldsAfterPayloadOrBody()82 FieldList GetFieldsAfterPayloadOrBody() const { 83 FieldListIterator it; 84 for (it = begin(); it != end(); it++) { 85 const auto& field = *it; 86 if (field->GetFieldType() == PayloadField::kFieldType || 87 field->GetFieldType() == BodyField::kFieldType) { 88 // Increment it once to get first field after payload/body. 89 it++; 90 break; 91 } 92 } 93 94 return FieldList(it, end()); 95 } 96 GetFieldsWithTypes(std::set<std::string> field_types)97 FieldList GetFieldsWithTypes(std::set<std::string> field_types) const { 98 FieldList ret; 99 100 for (const auto& field : field_list_) { 101 if (field_types.find(field->GetFieldType()) != field_types.end()) { 102 ret.AppendField(field); 103 } 104 } 105 106 return ret; 107 } 108 GetFieldsWithoutTypes(std::set<std::string> field_types)109 FieldList GetFieldsWithoutTypes(std::set<std::string> field_types) const { 110 FieldList ret; 111 112 for (const auto& field : field_list_) { 113 if (field_types.find(field->GetFieldType()) == field_types.end()) { 114 ret.AppendField(field); 115 } 116 } 117 118 return ret; 119 } 120 121 // Appends header fields of param to header fields of the current and 122 // prepends footer fields of the param to footer fields of the current. 123 // Ex. Assuming field_list_X has the layout: 124 // field_list_X_header 125 // payload/body 126 // field_list_X_footer 127 // The call to field_list_1.Merge(field_list_2) would result in 128 // field_list_1_header 129 // field_list_2_header 130 // payload/body (uses whatever was in field_list_2) 131 // field_list_2_footer 132 // field_list_1_footer Merge(FieldList nested)133 FieldList Merge(FieldList nested) const { 134 FieldList ret; 135 136 for (const auto& field : GetFieldsBeforePayloadOrBody()) { 137 ret.AppendField(field); 138 } 139 140 for (const auto& field : nested) { 141 ret.AppendField(field); 142 } 143 144 for (const auto& field : GetFieldsAfterPayloadOrBody()) { 145 ret.AppendField(field); 146 } 147 148 return ret; 149 } 150 HasPayloadOrBody()151 bool HasPayloadOrBody() const { return has_payload_ || has_body_; } 152 HasPayload()153 bool HasPayload() const { return has_payload_; } 154 HasBody()155 bool HasBody() const { return has_body_; } 156 begin()157 FieldListIterator begin() const { return field_list_.begin(); } 158 end()159 FieldListIterator end() const { return field_list_.end(); } 160 rbegin()161 ReverseFieldListIterator rbegin() const { return field_list_.rbegin(); } 162 rend()163 ReverseFieldListIterator rend() const { return field_list_.rend(); } 164 size()165 size_t size() const { return field_list_.size(); } 166 167 private: AddField(PacketField * field)168 void AddField(PacketField* field) { 169 if (field_map_.find(field->GetName()) != field_map_.end()) { 170 ERROR(field) << "Field with name \"" << field->GetName() << "\" was previously defined.\n"; 171 } 172 173 if (field->GetFieldType() == PayloadField::kFieldType) { 174 if (has_body_) { 175 ERROR(field) << "Packet already has a body."; 176 } 177 has_payload_ = true; 178 } 179 180 if (field->GetFieldType() == BodyField::kFieldType) { 181 if (has_payload_) { 182 ERROR(field) << "Packet already has a payload."; 183 } 184 has_body_ = true; 185 } 186 187 field_map_.insert(std::pair(field->GetName(), field)); 188 } 189 190 std::vector<PacketField*> field_list_; 191 std::map<std::string, PacketField*> field_map_; 192 bool has_payload_ = false; 193 bool has_body_ = false; 194 }; 195