blob: eb91d4c5c1021f9137130479871cd70a9c3c0fb6 [file] [log] [blame]
Matt Spinler113ad282019-07-09 14:44:13 -05001#pragma once
2
3#include <arpa/inet.h>
4#include <byteswap.h>
5
6#include <cassert>
7#include <cstring>
8#include <memory>
9#include <string>
10#include <vector>
11
12namespace openpower
13{
14namespace pels
15{
16
17namespace detail
18{
19/**
20 * @brief A host-to-network implementation for uint64_t
21 *
22 * @param[in] value - the value to convert to
23 * @return uint64_t - the byteswapped value
24 */
25inline uint64_t htonll(uint64_t value)
26{
27 return bswap_64(value);
28}
29
30/**
31 * @brief A network-to-host implementation for uint64_t
32 *
33 * @param[in] value - the value to convert to
34 * @return uint64_t - the byteswapped value
35 */
36inline uint64_t ntohll(uint64_t value)
37{
38 return bswap_64(value);
39}
40} // namespace detail
41
42/**
43 * @class Stream
44 *
45 * This class is used for getting data types into and out of a vector<uint8_t>
46 * that contains data in network byte (big endian) ordering.
47 */
48class Stream
49{
50 public:
51 Stream() = delete;
52 ~Stream() = default;
53 Stream(const Stream&) = default;
54 Stream& operator=(const Stream&) = default;
55 Stream(Stream&&) = default;
56 Stream& operator=(Stream&&) = default;
57
58 /**
59 * @brief Constructor
60 *
61 * @param[in] data - the vector of data
62 */
63 explicit Stream(std::vector<uint8_t>& data) : _data(data), _offset(0)
64 {
65 }
66
67 /**
68 * @brief Constructor
69 *
70 * @param[in] data - the vector of data
71 * @param[in] offset - the starting offset
72 */
73 Stream(std::vector<uint8_t>& data, std::size_t offset) :
74 _data(data), _offset(offset)
75 {
76 if (_offset >= _data.size())
77 {
78 throw std::out_of_range("Offset out of range");
79 }
80 }
81
82 /**
83 * @brief Extraction operator for a uint8_t
84 *
85 * @param[out] value - filled in with the value
86 * @return Stream&
87 */
88 Stream& operator>>(uint8_t& value)
89 {
90 read(&value, 1);
91 return *this;
92 }
93
94 /**
95 * @brief Extraction operator for a char
96 *
97 * @param[out] value -filled in with the value
98 * @return Stream&
99 */
100 Stream& operator>>(char& value)
101 {
102 read(&value, 1);
103 return *this;
104 }
105
106 /**
107 * @brief Extraction operator for a uint16_t
108 *
109 * @param[out] value -filled in with the value
110 * @return Stream&
111 */
112 Stream& operator>>(uint16_t& value)
113 {
114 read(&value, 2);
115 value = htons(value);
116 return *this;
117 }
118
119 /**
120 * @brief Extraction operator for a uint32_t
121 *
122 * @param[out] value -filled in with the value
123 * @return Stream&
124 */
125 Stream& operator>>(uint32_t& value)
126 {
127 read(&value, 4);
128 value = htonl(value);
129 return *this;
130 }
131
132 /**
133 * @brief Extraction operator for a uint64_t
134 *
135 * @param[out] value -filled in with the value
136 * @return Stream&
137 */
138 Stream& operator>>(uint64_t& value)
139 {
140 read(&value, 8);
141 value = detail::htonll(value);
142 return *this;
143 }
144
145 /**
146 * @brief Insert operator for a uint8_t
147 *
148 * @param[in] value - the value to write to the stream
149 * @return Stream&
150 */
151 Stream& operator<<(uint8_t& value)
152 {
153 write(&value, 1);
154 return *this;
155 }
156
157 /**
158 * @brief Insert operator for a char
159 *
160 * @param[in] value - the value to write to the stream
161 * @return Stream&
162 */
163 Stream& operator<<(char& value)
164 {
165 write(&value, 1);
166 return *this;
167 }
168
169 /**
170 * @brief Insert operator for a uint16_t
171 *
172 * @param[in] value - the value to write to the stream
173 * @return Stream&
174 */
175 Stream& operator<<(uint16_t& value)
176 {
177 uint16_t data = ntohs(value);
178 write(&data, 2);
179 return *this;
180 }
181
182 /**
183 * @brief Insert operator for a uint32_t
184 *
185 * @param[in] value - the value to write to the stream
186 * @return Stream&
187 */
188 Stream& operator<<(uint32_t& value)
189 {
190 uint32_t data = ntohl(value);
191 write(&data, 4);
192 return *this;
193 }
194
195 /**
196 * @brief Insert operator for a uint64_t
197 *
198 * @param[in] value - the value to write to the stream
199 * @return Stream&
200 */
201 Stream& operator<<(uint64_t& value)
202 {
203 uint64_t data = detail::ntohll(value);
204 write(&data, 8);
205 return *this;
206 }
207
208 /**
209 * @brief Sets the offset of the stream
210 *
211 * @param[in] newOffset - the new offset
212 */
213 void offset(std::size_t newOffset)
214 {
215 if (newOffset >= _data.size())
216 {
217 throw std::out_of_range("new offset out of range");
218 }
219
220 _offset = newOffset;
221 }
222
223 /**
224 * @brief Returns the current offset of the stream
225 *
226 * @return size_t - the offset
227 */
228 std::size_t offset() const
229 {
230 return _offset;
231 }
232
233 /**
234 * @brief Returns the remaining bytes left between the current offset
235 * and the data size.
236 *
237 * @return size_t - the remaining size
238 */
239 std::size_t remaining() const
240 {
241 assert(_data.size() >= _offset);
242 return _data.size() - _offset;
243 }
244
245 /**
246 * @brief Reads a specified number of bytes out of a stream
247 *
248 * @param[out] out - filled in with the data
249 * @param[in] size - the size to read
250 */
251 void read(void* out, std::size_t size)
252 {
253 rangeCheck(size);
254 memcpy(out, &_data[_offset], size);
255 _offset += size;
256 }
257
258 /**
259 * @brief Writes a specified number of bytes into the stream
260 *
261 * @param[in] in - the data to write
262 * @param[in] size - the size to write
263 */
264 void write(void* in, std::size_t size)
265 {
266 size_t newSize = _offset + size;
267 if (newSize > _data.size())
268 {
269 _data.resize(newSize, 0);
270 }
271 memcpy(&_data[_offset], in, size);
272 _offset += size;
273 }
274
275 private:
276 /**
277 * @brief Throws an exception if the size passed in plus the current
278 * offset is bigger than the current data size.
279 * @param[in] size - the size to check
280 */
281 void rangeCheck(std::size_t size)
282 {
283 if (_offset + size > _data.size())
284 {
285 std::string msg{"Attempted stream overflow: offset "};
286 msg += std::to_string(_offset) + " buffer size " +
287 std::to_string(_data.size()) + " op size " +
288 std::to_string(size);
289 throw std::out_of_range(msg.c_str());
290 }
291 }
292
293 /**
294 * @brief The data that the stream accesses.
295 */
296 std::vector<uint8_t>& _data;
297
298 /**
299 * @brief The current offset of the stream.
300 */
301 std::size_t _offset;
302};
303
304} // namespace pels
305} // namespace openpower