libdoip  0.1.0
DoIP (Diagnostics over Internet Protocol) ISO 13400 C++17 Library
DoIPIdentifiers.h
Go to the documentation of this file.
1 #ifndef DOIP_IDENTIFIERS_H
2 #define DOIP_IDENTIFIERS_H
3 
4 #include "ByteArray.h"
5 #include <algorithm>
6 #include <array>
7 #include <cstring>
8 #include <iterator>
9 #include <string>
10 #include <sstream>
11 
12 namespace doip {
13 
14 /**
15  * @brief Generic fixed-length identifier class template.
16  *
17  * @tparam IdLength The length of the identifier in bytes.
18  * @tparam zeroPadding Whether to use zero-padding (true) or character-padding (false).
19  * @tparam padChar The character to use for padding (default is null byte).
20  */
21 template <size_t IdLength, bool zeroPadding = false, char padChar = 0>
23  public:
24  /**
25  * @brief Length of the identifier in bytes
26  */
27  static constexpr size_t ID_LENGTH = IdLength;
28 
29  // STL container type aliases
30  using value_type = uint8_t;
31  using size_type = size_t;
32  using difference_type = std::ptrdiff_t;
33  using reference = uint8_t&;
34  using const_reference = const uint8_t&;
35  using iterator = typename std::array<uint8_t, IdLength>::iterator;
36  using const_iterator = typename std::array<uint8_t, IdLength>::const_iterator;
37 
38  /**
39  * @brief Default constructor - creates an identifier filled with zeros
40  */
41  GenericFixedId() : m_id{} { pad(0); }
42 
43  /**
44  * @brief Construct from string
45  *
46  * @param id_string The identifier as string. If shorter than IdLength, padded with zeros. If longer, truncated.
47  */
48  explicit GenericFixedId(const std::string &id_string) : m_id{} {
49  const size_t copy_length = std::min(id_string.length(), ID_LENGTH);
50  std::copy_n(id_string.c_str(), copy_length, m_id.data());
51  pad(copy_length);
52  }
53 
54  /**
55  * @brief Construct from C-style string
56  *
57  * @param id_cstr The identifier as C-string. If shorter than IdLength, padded with zeros. If longer, truncated.
58  */
59  explicit GenericFixedId(const char *id_cstr) : m_id{} {
60  if (id_cstr != nullptr) {
61  const size_t copy_length = std::min(std::strlen(id_cstr), ID_LENGTH);
62  std::copy_n(id_cstr, copy_length, m_id.data());
63  pad(copy_length);
64  } else {
65  pad(0);
66  }
67  }
68 
69  /**
70  * @brief Construct from byte sequence
71  *
72  * @param data Pointer to byte data
73  * @param length Length of the byte data. If shorter than IdLength, padded with zeros. If longer, truncated.
74  */
75  GenericFixedId(const uint8_t *data, size_t length) : m_id{} {
76  if (data != nullptr) {
77  const size_t copy_length = std::min(length, ID_LENGTH);
78  std::copy_n(data, copy_length, m_id.data());
79  pad(copy_length);
80  } else {
81  pad(0);
82  }
83  }
84 
85  /**
86  * @brief Construct from ByteArray
87  *
88  * @param byte_array The identifier as ByteArray. If shorter than IdLength, padded with zeros. If longer, truncated.
89  */
90  explicit GenericFixedId(const ByteArray &byte_array) : m_id{} {
91  const size_t copy_length = std::min(byte_array.size(), ID_LENGTH);
92  std::copy_n(byte_array.data(), copy_length, m_id.data());
93  pad(copy_length);
94  }
95 
96  /**
97  * @brief Construct a new Generic Fixed Id object
98  *
99  * @tparam integral the integral type
100  * @param id_value the identifier value as integral type
101  */
102  template <typename integral,
103  typename = std::enable_if_t<std::is_integral_v<integral>>>
104  explicit GenericFixedId(integral id_value) : m_id{} {
105  // static_assert(ID_LENGTH >= sizeof(integral), "ID_LENGTH is too large for the integral type");
106  // big endian!
107  constexpr size_t sizeof_integral = sizeof(integral);
108  constexpr size_t len = std::min(sizeof_integral, ID_LENGTH);
109  // big endian!
110  for (size_t i = 0; i < len; ++i) {
111  m_id[len - 1 - i] = (id_value >> (i * 8)) & 0xFF;
112  }
113  }
114 
115  /**
116  * @brief Copy constructor
117  */
118  GenericFixedId(const GenericFixedId &other) = default;
119 
120  /**
121  * @brief Copy assignment operator
122  */
123  GenericFixedId &operator=(const GenericFixedId &other) = default;
124 
125  /**
126  * @brief Move constructor
127  */
128  GenericFixedId(GenericFixedId &&other) noexcept = default;
129 
130  /**
131  * @brief Move assignment operator
132  */
133  GenericFixedId &operator=(GenericFixedId &&other) noexcept = default;
134 
135  /**
136  * @brief Destructor
137  */
138  ~GenericFixedId() = default;
139 
140  /**
141  * @brief Get identifier as string
142  *
143  * @return std::string The identifier as string (may contain null bytes if identifier was shorter than IdLength)
144  */
145  std::string toString() const {
146  // Find the effective length (up to first null byte or ID_LENGTH)
147  size_t effective_length = 0;
148  for (size_t i = 0; i < ID_LENGTH; ++i) {
149  if (m_id[i] == 0) {
150  break;
151  }
152  effective_length = i + 1;
153  }
154  return std::string(reinterpret_cast<const char *>(m_id.data()), effective_length);
155  }
156 
157  /**
158  * @brief Get identifier as hex string, bytes separated by '.'
159  *
160  * @return std::string Hex representation (e.g. "01.02.0A")
161  */
162  std::string toHexString() const {
163  std::ostringstream oss;
164  oss << std::uppercase << std::hex << std::setfill('0');
165  for (size_t i = 0; i < ID_LENGTH; ++i) {
166  oss << std::setw(2) << static_cast<int>(m_id[i]);
167  if (i + 1 < ID_LENGTH) {
168  oss << '.';
169  }
170  }
171  return oss.str();
172  }
173 
174  /**
175  * @brief Get identifier as ByteArray with exactly IdLength bytes
176  *
177  * @return ByteArray The identifier as byte array (always IdLength bytes)
178  */
180  return {m_id.data(), ID_LENGTH};
181  }
182 
183  /**
184  * @brief Get direct access to the underlying array
185  *
186  * @return const std::array<uint8_t, ID_LENGTH>& Reference to the internal array
187  */
188  const std::array<uint8_t, ID_LENGTH> &getArray() const {
189  return m_id;
190  }
191 
192  /**
193  * @brief Get pointer to raw data
194  *
195  * @return const uint8_t* Pointer to the identifier data
196  */
197  const uint8_t *data() const {
198  return m_id.data();
199  }
200 
201  /**
202  * @brief Appends this identifier to the given byte array.
203  *
204  * @param bytes the byte array to append to
205  * @return ByteArray& the modified byte array
206  */
207  ByteArray &appendTo(ByteArray &bytes) const {
208  bytes.insert(bytes.end(), m_id.begin(), m_id.end());
209  return bytes;
210  }
211 
212  /**
213  * @brief Get the size (always IdLength)
214  *
215  * @return constexpr size_t Always returns ID_LENGTH (IdLength)
216  */
217  constexpr size_t size() const {
218  return m_id.size();
219  }
220 
221  /**
222  * @brief Check if identifier is all zeros or all padding characters
223  *
224  * @return bool True if all bytes are zero or all bytes are the padding character
225  */
226  bool isEmpty() const {
227  if constexpr (zeroPadding) {
228  // For zero-padded identifiers, check if all bytes are the padding character
229  return std::all_of(m_id.begin(), m_id.end(), [](uint8_t byte) { return byte == static_cast<uint8_t>(padChar); });
230  } else {
231  // For non-padded identifiers, check if all bytes are zero
232  return std::all_of(m_id.begin(), m_id.end(), [](uint8_t byte) { return byte == 0; });
233  }
234  }
235 
236  /**
237  * @brief Equality operator
238  *
239  * @param other The other identifier to compare with
240  * @return bool True if both identifiers are identical
241  */
242  bool operator==(const GenericFixedId &other) const {
243  return m_id == other.m_id;
244  }
245 
246  /**
247  * @brief Inequality operator
248  *
249  * @param other The other identifier to compare with
250  * @return bool True if identifiers are different
251  */
252  bool operator!=(const GenericFixedId &other) const {
253  return m_id != other.m_id;
254  }
255 
256  /**
257  * @brief Array subscript operator (const)
258  *
259  * @param index Index (0 to IdLength-1)
260  * @return const uint8_t& Reference to the byte at the given index
261  */
262  const uint8_t &operator[](size_t index) const {
263  return m_id.at(index);
264  }
265 
266  /**
267  * @brief Get the char used to pad shorter identifiers.
268  *
269  * @return char constexpr the padding character
270  */
271  char constexpr getPadChar() {
272  return padChar;
273  }
274 
275  /**
276  * @brief Get the byte used to pad shorter identifiers.
277  *
278  * @return uint8_t constexpr the padding byte
279  */
280  uint8_t constexpr getPadByte() {
281  return static_cast<uint8_t>(padChar);
282  }
283 
284  /**
285  * @brief Iterator support - begin
286  *
287  * @return auto Iterator to the beginning of the identifier data
288  */
289  auto begin() noexcept { return m_id.begin(); }
290 
291  /**
292  * @brief Iterator support - begin (const)
293  *
294  * @return auto Const iterator to the beginning of the identifier data
295  */
296  auto begin() const noexcept { return m_id.begin(); }
297 
298  /**
299  * @brief Iterator support - cbegin
300  *
301  * @return auto Const iterator to the beginning of the identifier data
302  */
303  auto cbegin() const noexcept { return m_id.cbegin(); }
304 
305  /**
306  * @brief Iterator support - end
307  *
308  * @return auto Iterator to the end of the identifier data
309  */
310  auto end() noexcept { return m_id.end(); }
311 
312  /**
313  * @brief Iterator support - end (const)
314  *
315  * @return auto Const iterator to the end of the identifier data
316  */
317  auto end() const noexcept { return m_id.end(); }
318 
319  /**
320  * @brief Iterator support - cend
321  *
322  * @return auto Const iterator to the end of the identifier data
323  */
324  auto cend() const noexcept { return m_id.cend(); }
325 
326  /**
327  * @brief Static instance containing only zeros
328  */
329  static const GenericFixedId Zero;
330 
331  private:
332  std::array<uint8_t, ID_LENGTH> m_id; ///< The identifier data storage
333 
334  void pad(size_t start_index) {
335  if (zeroPadding && start_index < ID_LENGTH) {
336  std::fill(m_id.begin() + start_index, m_id.end(), padChar);
337  }
338  }
339 };
340 
341 // Definition of the static zero identifier for the template
342 template <size_t IdLength, bool zeroPadding, char padChar>
343 inline const GenericFixedId<IdLength, zeroPadding, padChar> GenericFixedId<IdLength, zeroPadding, padChar>::Zero{};
344 
345 /**
346  * @brief Vehicle Identification Number (VIN) - 17 bytes according to ISO 3779
347  * Padded with ASCII '0' characters when shorter than 17 bytes
348  */
350 
351 /**
352  * @brief Entity Identifier (EID) - 6 bytes for unique entity identification
353  */
355 
356 /**
357  * @brief Group Identifier (GID) - 6 bytes for group identification
358  */
360 
361 /**
362  * @brief Stream output operator for DoIpVin, DoIpEid, and DoIpGid
363  *
364  * @param os the operation stream
365  * @param vin the DoIpVin to output
366  * @return std::ostream& the operation stream
367  */
368 inline std::ostream &operator<<(std::ostream &os, const DoIpVin &vin) {
369  os << vin.toString();
370  return os;
371 }
372 
373 /**
374  * @brief Stream output operator for DoIpEid/DoIpGid
375  *
376  * @param os the operation stream
377  * @param eid the DoIpEid/DoIpGid to output
378  * @return std::ostream& @ref {type} ["{type}"] // @return Returns @c true in the case of success, @c false otherwise.
379  */
380 inline std::ostream &operator<<(std::ostream &os, const DoIpEid &eid) {
381  os << eid.toHexString();
382  return os;
383 }
384 
385 
386 } // namespace doip
387 
388 #endif /* DOIP_IDENTIFIERS_H */
Defines the ByteArray type and utility functions for byte manipulation.
Generic fixed-length identifier class template.
constexpr size_t size() const
Get the size (always IdLength)
auto cbegin() const noexcept
Iterator support - cbegin.
GenericFixedId(const std::string &id_string)
Construct from string.
auto end() const noexcept
Iterator support - end (const)
GenericFixedId()
Default constructor - creates an identifier filled with zeros.
bool operator!=(const GenericFixedId &other) const
Inequality operator.
GenericFixedId & operator=(GenericFixedId &&other) noexcept=default
Move assignment operator.
~GenericFixedId()=default
Destructor.
const uint8_t & const_reference
static const GenericFixedId Zero
Static instance containing only zeros.
const uint8_t & operator[](size_t index) const
Array subscript operator (const)
constexpr char getPadChar()
Get the char used to pad shorter identifiers.
GenericFixedId(const GenericFixedId &other)=default
Copy constructor.
std::string toHexString() const
Get identifier as hex string, bytes separated by '.
static constexpr size_t ID_LENGTH
Length of the identifier in bytes.
auto end() noexcept
Iterator support - end.
typename std::array< uint8_t, IdLength >::iterator iterator
auto begin() const noexcept
Iterator support - begin (const)
const uint8_t * data() const
Get pointer to raw data.
typename std::array< uint8_t, IdLength >::const_iterator const_iterator
GenericFixedId(const ByteArray &byte_array)
Construct from ByteArray.
GenericFixedId & operator=(const GenericFixedId &other)=default
Copy assignment operator.
std::ptrdiff_t difference_type
bool isEmpty() const
Check if identifier is all zeros or all padding characters.
GenericFixedId(GenericFixedId &&other) noexcept=default
Move constructor.
GenericFixedId(integral id_value)
Construct a new Generic Fixed Id object.
ByteArrayRef asByteArray() const
Get identifier as ByteArray with exactly IdLength bytes.
ByteArray & appendTo(ByteArray &bytes) const
Appends this identifier to the given byte array.
bool operator==(const GenericFixedId &other) const
Equality operator.
constexpr uint8_t getPadByte()
Get the byte used to pad shorter identifiers.
GenericFixedId(const char *id_cstr)
Construct from C-style string.
const std::array< uint8_t, ID_LENGTH > & getArray() const
Get direct access to the underlying array.
auto begin() noexcept
Iterator support - begin.
GenericFixedId(const uint8_t *data, size_t length)
Construct from byte sequence.
std::string toString() const
Get identifier as string.
auto cend() const noexcept
Iterator support - cend.
Definition: AnsiColors.h:3
std::pair< const uint8_t *, size_t > ByteArrayRef
Reference to raw array of bytes.
Definition: ByteArray.h:291
std::ostream & operator<<(std::ostream &os, const ByteArray &arr)
Stream operator for ByteArray.
Definition: ByteArray.h:303
A dynamic array of bytes with utility methods for network protocol handling.
Definition: ByteArray.h:60