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