PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
wire.h
Go to the documentation of this file.
1
4
5#pragma once
6
7#include <cstdint>
8#include <cstring>
9#include <span>
10#include <stdexcept>
11#include <vector>
12
14{
15
19inline void PutU8(std::vector<std::uint8_t>& out, std::uint8_t v)
20{
21 out.push_back(v);
22}
23
27inline void PutU16(std::vector<std::uint8_t>& out, std::uint16_t v)
28{
29 out.push_back(static_cast<std::uint8_t>(v >> OneOctetShift));
30 out.push_back(static_cast<std::uint8_t>(v & LowByteMask));
31}
32
36inline void PutU32(std::vector<std::uint8_t>& out, std::uint32_t v)
37{
38 out.push_back(static_cast<std::uint8_t>(v >> ThreeOctetsShift));
39 out.push_back(static_cast<std::uint8_t>((v >> TwoOctetsShift) & LowByteMask));
40 out.push_back(static_cast<std::uint8_t>((v >> OneOctetShift) & LowByteMask));
41 out.push_back(static_cast<std::uint8_t>(v & LowByteMask));
42}
43
48inline void PutBytes(std::vector<std::uint8_t>& out, const std::uint8_t* data, std::size_t len)
49{
50 out.insert(out.end(), data, data + len);
51}
52
57template <std::size_t N>
58inline void PutFixed(std::vector<std::uint8_t>& out, const std::array<std::uint8_t, N>& data)
59{
60 out.insert(out.end(), data.begin(), data.end());
61}
62
66class Reader
67{
68 public:
72 Reader(const std::uint8_t* data, std::size_t len)
73 : data(data), len(len)
74 {
75 }
76
79 explicit Reader(std::span<const std::uint8_t> bytes)
80 : data(bytes.data()), len(bytes.size())
81 {
82 }
83
86 explicit Reader(const std::vector<std::uint8_t>& v)
87 : data(v.data()), len(v.size())
88 {
89 }
90
93 [[nodiscard]] std::size_t Remaining() const
94 {
95 return len - pos;
96 }
97
100 [[nodiscard]] std::size_t Position() const
101 {
102 return pos;
103 }
104
107 [[nodiscard]] const std::uint8_t* Cursor() const
108 {
109 return data + pos;
110 }
111
115 void Need(std::size_t n) const
116 {
117 if (Remaining() < n)
118 {
119 throw std::out_of_range("wire::Reader: not enough data");
120 }
121 }
122
125 std::uint8_t U8()
126 {
127 Need(1);
128 return data[pos++];
129 }
130
133 std::uint16_t U16()
134 {
135 Need(2);
136 auto v = static_cast<std::uint16_t>(data[pos] << OneOctetShift | data[pos + 1]);
137 pos += 2;
138 return v;
139 }
140
143 std::uint32_t U32()
144 {
145 Need(4);
146 std::uint32_t v = static_cast<std::uint32_t>(data[pos]) << ThreeOctetsShift |
147 static_cast<std::uint32_t>(data[pos + 1]) << TwoOctetsShift |
148 static_cast<std::uint32_t>(data[pos + 2]) << OneOctetShift |
149 static_cast<std::uint32_t>(data[pos + 3]);
150 pos += 4;
151 return v;
152 }
153
157 std::vector<std::uint8_t> ReadBytes(std::size_t n)
158 {
159 Need(n);
160 std::vector<std::uint8_t> v(data + pos, data + pos + n);
161 pos += n;
162 return v;
163 }
164
168 template <std::size_t N>
169 std::array<std::uint8_t, N> Fixed()
170 {
171 Need(N);
172 std::array<std::uint8_t, N> v{};
173 std::memcpy(v.data(), data + pos, N);
174 pos += N;
175 return v;
176 }
177
180 void Skip(std::size_t n)
181 {
182 Need(n);
183 pos += n;
184 }
185
186 private:
188 const std::uint8_t* data;
189
191 std::size_t len;
192
194 std::size_t pos = 0;
195};
196
197} // namespace profinet::wire
Lightweight cursor for parsing a big-endian byte buffer without copies.
Definition wire.h:67
std::uint8_t U8()
Read and consume one byte.
Definition wire.h:125
const std::uint8_t * Cursor() const
Pointer to the next unread byte.
Definition wire.h:107
std::size_t Position() const
Current read offset from the start of the buffer.
Definition wire.h:100
std::uint32_t U32()
Read and consume a big-endian 32-bit value.
Definition wire.h:143
const std::uint8_t * data
Pointer to the start of the underlying buffer (not owned).
Definition wire.h:188
Reader(const std::uint8_t *data, std::size_t len)
Construct a reader over a raw pointer/length pair.
Definition wire.h:72
std::size_t Remaining() const
Number of bytes not yet consumed.
Definition wire.h:93
std::array< std::uint8_t, N > Fixed()
Read and consume a fixed-size byte array.
Definition wire.h:169
Reader(std::span< const std::uint8_t > bytes)
Construct a reader over a byte span.
Definition wire.h:79
std::size_t pos
Current read offset from the start of the buffer.
Definition wire.h:194
void Need(std::size_t n) const
Assert that at least n bytes remain.
Definition wire.h:115
void Skip(std::size_t n)
Advance the read position without returning the skipped bytes.
Definition wire.h:180
Reader(const std::vector< std::uint8_t > &v)
Construct a reader over an existing byte vector.
Definition wire.h:86
std::vector< std::uint8_t > ReadBytes(std::size_t n)
Read and consume a variable-length byte range.
Definition wire.h:157
std::uint16_t U16()
Read and consume a big-endian 16-bit value.
Definition wire.h:133
std::size_t len
Total length of the underlying buffer in bytes.
Definition wire.h:191
void PutU16(std::vector< std::uint8_t > &out, std::uint16_t v)
Append a 16-bit value to a buffer in big-endian order.
Definition wire.h:27
void PutBytes(std::vector< std::uint8_t > &out, const std::uint8_t *data, std::size_t len)
Append a raw byte range to a buffer.
Definition wire.h:48
void PutU8(std::vector< std::uint8_t > &out, std::uint8_t v)
Append a single byte to a buffer.
Definition wire.h:19
void PutU32(std::vector< std::uint8_t > &out, std::uint32_t v)
Append a 32-bit value to a buffer in big-endian order.
Definition wire.h:36
void PutFixed(std::vector< std::uint8_t > &out, const std::array< std::uint8_t, N > &data)
Append a fixed-size byte array to a buffer.
Definition wire.h:58
static constexpr int OneOctetShift
The bit-shift distance required to move data across a single octet.
Definition util.h:50
static constexpr int ThreeOctetsShift
The bit-shift distance required to move data across three octets.
Definition util.h:56
static constexpr int TwoOctetsShift
The bit-shift distance required to move data across two octets.
Definition util.h:53
static constexpr std::uint8_t LowByteMask
Bitmask used to isolate the lowest significant byte (8 bits) of a larger integer.
Definition util.h:59