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 {
48     return field_list_[index];
49   }
50 
GetField(std::string field_name)51   PacketField* GetField(std::string field_name) const {
52     auto it = field_map_.find(field_name);
53     if (it == field_map_.end()) {
54       return nullptr;
55     }
56 
57     return it->second;
58   }
59 
AppendField(PacketField * field)60   void AppendField(PacketField* field) {
61     AddField(field);
62     field_list_.push_back(field);
63   }
64 
PrependField(PacketField * field)65   void PrependField(PacketField* field) {
66     AddField(field);
67     field_list_.insert(field_list_.begin(), field);
68   }
69 
GetFieldsBeforePayloadOrBody()70   FieldList GetFieldsBeforePayloadOrBody() const {
71     FieldList ret;
72     for (auto it = begin(); it != end(); it++) {
73       const auto& field = *it;
74       if (field->GetFieldType() == PayloadField::kFieldType || field->GetFieldType() == BodyField::kFieldType) {
75         break;
76       }
77       ret.AppendField(*it);
78     }
79 
80     return ret;
81   }
82 
GetFieldsAfterPayloadOrBody()83   FieldList GetFieldsAfterPayloadOrBody() const {
84     FieldListIterator it;
85     for (it = begin(); it != end(); it++) {
86       const auto& field = *it;
87       if (field->GetFieldType() == PayloadField::kFieldType || 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 {
152     return has_payload_ || has_body_;
153   }
154 
HasPayload()155   bool HasPayload() const {
156     return has_payload_;
157   }
158 
HasBody()159   bool HasBody() const {
160     return has_body_;
161   }
162 
begin()163   FieldListIterator begin() const {
164     return field_list_.begin();
165   }
166 
end()167   FieldListIterator end() const {
168     return field_list_.end();
169   }
170 
rbegin()171   ReverseFieldListIterator rbegin() const {
172     return field_list_.rbegin();
173   }
174 
rend()175   ReverseFieldListIterator rend() const {
176     return field_list_.rend();
177   }
178 
size()179   size_t size() const {
180     return field_list_.size();
181   }
182 
183  private:
AddField(PacketField * field)184   void AddField(PacketField* field) {
185     if (field_map_.find(field->GetName()) != field_map_.end()) {
186       ERROR(field) << "Field with name \"" << field->GetName() << "\" was previously defined.\n";
187     }
188 
189     if (field->GetFieldType() == PayloadField::kFieldType) {
190       if (has_body_) {
191         ERROR(field) << "Packet already has a body.";
192       }
193       has_payload_ = true;
194     }
195 
196     if (field->GetFieldType() == BodyField::kFieldType) {
197       if (has_payload_) {
198         ERROR(field) << "Packet already has a payload.";
199       }
200       has_body_ = true;
201     }
202 
203     field_map_.insert(std::pair(field->GetName(), field));
204   }
205 
206   std::vector<PacketField*> field_list_;
207   std::map<std::string, PacketField*> field_map_;
208   bool has_payload_ = false;
209   bool has_body_ = false;
210 };
211