Coverage Report

Created: 2026-09-28 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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