/src/PcapPlusPlus/Common++/header/Serializers.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include <cstdint> |
4 | | #include <iosfwd> |
5 | | #include <string> |
6 | | #include <type_traits> |
7 | | #include <vector> |
8 | | |
9 | | /// @file |
10 | | |
11 | | /// @namespace pcpp |
12 | | /// @brief The main namespace for the PcapPlusPlus lib |
13 | | namespace pcpp |
14 | | { |
15 | | /// @struct FieldDescriptor |
16 | | /// Describes a serializable field. |
17 | | struct FieldDescriptor |
18 | | { |
19 | | /// Stable numeric identifier of the field. |
20 | | const uint16_t id; |
21 | | |
22 | | /// Name of the field. |
23 | | const std::string name; |
24 | | |
25 | | /// Function returning the descriptors of the field's children, or nullptr if the field has no children. |
26 | | std::vector<FieldDescriptor> (*const getChildren)(); |
27 | | |
28 | | /// Create a field descriptor. |
29 | | /// @param[in] fieldId The stable numeric identifier of the field |
30 | | /// @param[in] fieldName The name of the field |
31 | | /// @param[in] fieldChildren A function returning the field's child descriptors, or nullptr if the field has no |
32 | | /// children |
33 | | FieldDescriptor(uint16_t fieldId, std::string fieldName, |
34 | | std::vector<FieldDescriptor> (*fieldChildren)() = nullptr) |
35 | | : id(fieldId), name(std::move(fieldName)), getChildren(fieldChildren) |
36 | 0 | {} |
37 | | |
38 | | /// Check whether the field has child fields. |
39 | | /// @return True if the field has child fields, false otherwise |
40 | | bool hasChildren() const |
41 | 0 | { |
42 | 0 | return getChildren != nullptr; |
43 | 0 | } |
44 | | }; |
45 | | |
46 | | /// @struct ObjectFieldDescriptor |
47 | | /// Describes a serializable object field and its child fields. |
48 | | template <typename Derived> struct ObjectFieldDescriptor : FieldDescriptor |
49 | | { |
50 | | /// Create an object field descriptor. |
51 | | /// @param[in] fieldId The stable numeric identifier of the field |
52 | | /// @param[in] fieldName The name of the field |
53 | | ObjectFieldDescriptor(uint16_t fieldId, std::string fieldName) |
54 | | : FieldDescriptor(fieldId, std::move(fieldName), &Derived::all) |
55 | | {} |
56 | | }; |
57 | | |
58 | | class ScopeBase; |
59 | | class ArrayScope; |
60 | | class ObjectScope; |
61 | | |
62 | | namespace internal |
63 | | { |
64 | | template <typename T> |
65 | | using EnableIfSignedIntegral = |
66 | | std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value && !std::is_same<T, bool>::value, |
67 | | int>; |
68 | | |
69 | | template <typename T> |
70 | | using EnableIfUnsignedIntegral = |
71 | | std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value && !std::is_same<T, bool>::value, |
72 | | int>; |
73 | | } // namespace internal |
74 | | |
75 | | /// @class ISerializer |
76 | | /// Interface for streaming structured data to a serializer. |
77 | | class ISerializer |
78 | | { |
79 | | friend class ScopeBase; |
80 | | friend class ArrayScope; |
81 | | friend class ObjectScope; |
82 | | |
83 | | public: |
84 | | /// Destroy the serializer. |
85 | | virtual ~ISerializer() = default; |
86 | | |
87 | | /// Open an array field. |
88 | | /// @param[in] field The descriptor of the array field |
89 | | /// @return A scope representing the newly opened array |
90 | | ArrayScope writeArray(const FieldDescriptor& field); |
91 | | |
92 | | /// Open an object field. |
93 | | /// @param[in] field The descriptor of the object field |
94 | | /// @return A scope representing the newly opened object |
95 | | ObjectScope writeObject(const FieldDescriptor& field); |
96 | | |
97 | | protected: |
98 | | // --- Scalar field writes (canonical virtuals) --- |
99 | | virtual void writeField(const FieldDescriptor& field, const std::string& value) = 0; |
100 | | virtual void writeField(const FieldDescriptor& field, int64_t value) = 0; |
101 | | virtual void writeField(const FieldDescriptor& field, uint64_t value) = 0; |
102 | | virtual void writeField(const FieldDescriptor& field, double value) = 0; |
103 | | virtual void writeField(const FieldDescriptor& field, bool value) = 0; |
104 | | virtual void writeNullField(const FieldDescriptor& field) = 0; |
105 | | |
106 | | virtual void writeField(const FieldDescriptor& field, const char* value) |
107 | 0 | { |
108 | 0 | writeField(field, std::string(value)); |
109 | 0 | } |
110 | | |
111 | | template <typename T, internal::EnableIfSignedIntegral<T> = 0> |
112 | | void writeField(const FieldDescriptor& field, T value) |
113 | | { |
114 | | writeField(field, static_cast<int64_t>(value)); |
115 | | } |
116 | | |
117 | | template <typename T, internal::EnableIfUnsignedIntegral<T> = 0> |
118 | | void writeField(const FieldDescriptor& field, T value) |
119 | | { |
120 | | writeField(field, static_cast<uint64_t>(value)); |
121 | | } |
122 | | |
123 | | virtual void writeHexField(const FieldDescriptor& field, uint64_t value) = 0; |
124 | | |
125 | | template <typename T, std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, int> = 0> |
126 | | void writeHexField(const FieldDescriptor& field, T value) |
127 | | { |
128 | | writeHexField(field, static_cast<uint64_t>(value)); |
129 | | } |
130 | | |
131 | | virtual void startObject(const FieldDescriptor& field) = 0; |
132 | | virtual void endObject() = 0; |
133 | | virtual void startArray(const FieldDescriptor& field) = 0; |
134 | | virtual void endArray() = 0; |
135 | | |
136 | | void enforceOneRoot(); |
137 | | |
138 | | bool m_ShouldEnforceOneRoot = true; |
139 | | |
140 | | private: |
141 | | bool m_RootWritten = false; |
142 | | }; |
143 | | |
144 | | /// @class ScopeBase |
145 | | /// Base class for serializer scopes. |
146 | | class ScopeBase : public ISerializer |
147 | | { |
148 | | public: |
149 | | using ISerializer::writeField; |
150 | | |
151 | | /// Write a string field. |
152 | | /// @param[in] field The descriptor of the field |
153 | | /// @param[in] value The string value to write |
154 | | void writeField(const FieldDescriptor& field, const std::string& value) override; |
155 | | |
156 | | /// Write a signed int64 field. |
157 | | /// @param[in] field The descriptor of the field |
158 | | /// @param[in] value The signed integer value to write |
159 | | void writeField(const FieldDescriptor& field, int64_t value) override; |
160 | | |
161 | | /// Write an unsigned int64 field. |
162 | | /// @param[in] field The descriptor of the field |
163 | | /// @param[in] value The unsigned integer value to write |
164 | | void writeField(const FieldDescriptor& field, uint64_t value) override; |
165 | | |
166 | | /// Write a floating-point field. |
167 | | /// @param[in] field The descriptor of the field |
168 | | /// @param[in] value The floating-point value to write |
169 | | void writeField(const FieldDescriptor& field, double value) override; |
170 | | |
171 | | /// Write a boolean field. |
172 | | /// @param[in] field The descriptor of the field |
173 | | /// @param[in] value The boolean value to write |
174 | | void writeField(const FieldDescriptor& field, bool value) override; |
175 | | |
176 | | /// Write a null field. |
177 | | /// @param[in] field The descriptor of the field |
178 | | void writeNullField(const FieldDescriptor& field) override; |
179 | | |
180 | | /// Write an unsigned integer field in hexadecimal notation. |
181 | | /// @param[in] field The descriptor of the field |
182 | | /// @param[in] value The unsigned integer value to write |
183 | | void writeHexField(const FieldDescriptor& field, uint64_t value) override; |
184 | | |
185 | | template <typename T, internal::EnableIfSignedIntegral<T> = 0> |
186 | | void writeField(const FieldDescriptor& field, T value) |
187 | | { |
188 | | writeField(field, static_cast<int64_t>(value)); |
189 | | } |
190 | | |
191 | | template <typename T, internal::EnableIfUnsignedIntegral<T> = 0> |
192 | | void writeField(const FieldDescriptor& field, T value) |
193 | | { |
194 | | writeField(field, static_cast<uint64_t>(value)); |
195 | | } |
196 | | |
197 | | protected: |
198 | | void startObject(const FieldDescriptor& field) override; |
199 | | void endObject() override; |
200 | | void startArray(const FieldDescriptor& field) override; |
201 | | void endArray() override; |
202 | | |
203 | | explicit ScopeBase(ISerializer* serializer) : m_Serializer(serializer) |
204 | 0 | { |
205 | 0 | m_ShouldEnforceOneRoot = false; |
206 | 0 | } |
207 | | |
208 | | ISerializer* m_Serializer; |
209 | | }; |
210 | | |
211 | | /// @class ArrayScope |
212 | | /// RAII scope for a serialized array. |
213 | | class ArrayScope : public ScopeBase |
214 | | { |
215 | | public: |
216 | | using ScopeBase::writeField; |
217 | | |
218 | | /// Create an array scope. |
219 | | /// @param[in] serializer The serializer owning the array |
220 | | /// @param[in] field The descriptor of the array field |
221 | | ArrayScope(ISerializer* serializer, const FieldDescriptor& field); |
222 | | |
223 | | /// Close the array. |
224 | | ~ArrayScope() override; |
225 | | }; |
226 | | |
227 | | /// @class ObjectScope |
228 | | /// RAII scope for a serialized object. |
229 | | class ObjectScope : public ScopeBase |
230 | | { |
231 | | public: |
232 | | using ScopeBase::writeField; |
233 | | |
234 | | /// Create an object scope. |
235 | | /// @param[in] serializer The serializer owning the object |
236 | | /// @param[in] field The descriptor of the object field |
237 | | ObjectScope(ISerializer* serializer, const FieldDescriptor& field); |
238 | | |
239 | | /// Close the object. |
240 | | ~ObjectScope() override; |
241 | | }; |
242 | | |
243 | | /// @class JsonSerializer |
244 | | /// Serializer that writes JSON. |
245 | | class JsonSerializer : public ISerializer |
246 | | { |
247 | | public: |
248 | | using ISerializer::writeField; |
249 | | using ISerializer::writeHexField; |
250 | | |
251 | | /// Create a JSON serializer. |
252 | | /// @param[in] out The output stream to which JSON is written |
253 | | explicit JsonSerializer(std::ostream& out); |
254 | | |
255 | | protected: |
256 | | void writeField(const FieldDescriptor& field, const std::string& value) override; |
257 | | void writeField(const FieldDescriptor& field, int64_t value) override; |
258 | | void writeField(const FieldDescriptor& field, uint64_t value) override; |
259 | | void writeField(const FieldDescriptor& field, double value) override; |
260 | | void writeField(const FieldDescriptor& field, bool value) override; |
261 | | void writeNullField(const FieldDescriptor& field) override; |
262 | | void writeHexField(const FieldDescriptor& field, uint64_t value) override; |
263 | | void startObject(const FieldDescriptor& field) override; |
264 | | void endObject() override; |
265 | | void startArray(const FieldDescriptor& field) override; |
266 | | void endArray() override; |
267 | | |
268 | | private: |
269 | | enum class Context |
270 | | { |
271 | | Array, |
272 | | Object |
273 | | }; |
274 | | |
275 | | void writeSeparatorIfNeeded(); |
276 | | void writeKey(const std::string& name); |
277 | | |
278 | | std::ostream& m_Out; |
279 | | std::vector<Context> m_ContextStack; |
280 | | std::vector<bool> m_FirstAtLevel; |
281 | | }; |
282 | | } // namespace pcpp |