xref: /openbmc/phosphor-logging/extensions/openpower-pels/stream.hpp (revision 8a09b982ddeb0c1e13190d9cd196e06a778d6140)
1 #pragma once
2 
3 #include <arpa/inet.h>
4 #include <byteswap.h>
5 
6 #include <cassert>
7 #include <cstring>
8 #include <stdexcept>
9 #include <string>
10 #include <vector>
11 
12 namespace openpower
13 {
14 namespace pels
15 {
16 
17 namespace 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  */
htonll(uint64_t value)25 inline 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  */
ntohll(uint64_t value)36 inline 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  */
48 class Stream
49 {
50   public:
51     Stream() = delete;
52     ~Stream() = default;
53     Stream(const Stream&) = default;
54     Stream& operator=(const Stream&) = delete;
55     Stream(Stream&&) = delete;
56     Stream& operator=(Stream&&) = delete;
57 
58     /**
59      * @brief Constructor
60      *
61      * @param[in] data - the vector of data
62      */
Stream(std::vector<uint8_t> & data)63     explicit Stream(std::vector<uint8_t>& data) : _data(data), _offset(0) {}
64 
65     /**
66      * @brief Constructor
67      *
68      * @param[in] data - the vector of data
69      * @param[in] offset - the starting offset
70      */
Stream(std::vector<uint8_t> & data,std::size_t offset)71     Stream(std::vector<uint8_t>& data, std::size_t offset) :
72         _data(data), _offset(offset)
73     {
74         if (_offset >= _data.size())
75         {
76             throw std::out_of_range("Offset out of range");
77         }
78     }
79 
80     /**
81      * @brief Extraction operator for a uint8_t
82      *
83      * @param[out] value - filled in with the value
84      * @return Stream&
85      */
operator >>(uint8_t & value)86     Stream& operator>>(uint8_t& value)
87     {
88         read(&value, 1);
89         return *this;
90     }
91 
92     /**
93      * @brief Extraction operator for a char
94      *
95      * @param[out] value -filled in with the value
96      * @return Stream&
97      */
operator >>(char & value)98     Stream& operator>>(char& value)
99     {
100         read(&value, 1);
101         return *this;
102     }
103 
104     /**
105      * @brief Extraction operator for a uint16_t
106      *
107      * @param[out] value -filled in with the value
108      * @return Stream&
109      */
operator >>(uint16_t & value)110     Stream& operator>>(uint16_t& value)
111     {
112         read(&value, 2);
113         value = htons(value);
114         return *this;
115     }
116 
117     /**
118      * @brief Extraction operator for a uint32_t
119      *
120      * @param[out] value -filled in with the value
121      * @return Stream&
122      */
operator >>(uint32_t & value)123     Stream& operator>>(uint32_t& value)
124     {
125         read(&value, 4);
126         value = htonl(value);
127         return *this;
128     }
129 
130     /**
131      * @brief Extraction operator for a uint64_t
132      *
133      * @param[out] value -filled in with the value
134      * @return Stream&
135      */
operator >>(uint64_t & value)136     Stream& operator>>(uint64_t& value)
137     {
138         read(&value, 8);
139         value = detail::htonll(value);
140         return *this;
141     }
142 
143     /**
144      * @brief Extraction operator for a std::vector<uint8_t>
145      *
146      * The vector's size is the amount extracted.
147      *
148      * @param[out] value - filled in with the value
149      * @return Stream&
150      */
operator >>(std::vector<uint8_t> & value)151     Stream& operator>>(std::vector<uint8_t>& value)
152     {
153         if (!value.empty())
154         {
155             read(value.data(), value.size());
156         }
157         return *this;
158     }
159 
160     /**
161      * @brief Extraction operator for a std::vector<char>
162      *
163      * The vector's size is the amount extracted.
164      *
165      * @param[out] value - filled in with the value
166      * @return Stream&
167      */
operator >>(std::vector<char> & value)168     Stream& operator>>(std::vector<char>& value)
169     {
170         if (!value.empty())
171         {
172             read(value.data(), value.size());
173         }
174         return *this;
175     }
176 
177     /**
178      * @brief Insert operator for a uint8_t
179      *
180      * @param[in] value - the value to write to the stream
181      * @return Stream&
182      */
operator <<(uint8_t value)183     Stream& operator<<(uint8_t value)
184     {
185         write(&value, 1);
186         return *this;
187     }
188 
189     /**
190      * @brief Insert operator for a char
191      *
192      * @param[in] value - the value to write to the stream
193      * @return Stream&
194      */
operator <<(char value)195     Stream& operator<<(char value)
196     {
197         write(&value, 1);
198         return *this;
199     }
200 
201     /**
202      * @brief Insert operator for a uint16_t
203      *
204      * @param[in] value - the value to write to the stream
205      * @return Stream&
206      */
operator <<(uint16_t value)207     Stream& operator<<(uint16_t value)
208     {
209         uint16_t data = ntohs(value);
210         write(&data, 2);
211         return *this;
212     }
213 
214     /**
215      * @brief Insert operator for a uint32_t
216      *
217      * @param[in] value - the value to write to the stream
218      * @return Stream&
219      */
operator <<(uint32_t value)220     Stream& operator<<(uint32_t value)
221     {
222         uint32_t data = ntohl(value);
223         write(&data, 4);
224         return *this;
225     }
226 
227     /**
228      * @brief Insert operator for a uint64_t
229      *
230      * @param[in] value - the value to write to the stream
231      * @return Stream&
232      */
operator <<(uint64_t value)233     Stream& operator<<(uint64_t value)
234     {
235         uint64_t data = detail::ntohll(value);
236         write(&data, 8);
237         return *this;
238     }
239 
240     /**
241      * @brief Insert operator for a std::vector<uint8_t>
242      *
243      * The full vector is written to the stream.
244      *
245      * @param[in] value - the value to write to the stream
246      * @return Stream&
247      */
operator <<(const std::vector<uint8_t> & value)248     Stream& operator<<(const std::vector<uint8_t>& value)
249     {
250         if (!value.empty())
251         {
252             write(value.data(), value.size());
253         }
254         return *this;
255     }
256 
257     /**
258      * @brief Insert operator for a std::vector<char>
259      *
260      * The full vector is written to the stream.
261      *
262      * @param[in] value - the value to write to the stream
263      * @return Stream&
264      */
operator <<(const std::vector<char> & value)265     Stream& operator<<(const std::vector<char>& value)
266     {
267         if (!value.empty())
268         {
269             write(value.data(), value.size());
270         }
271         return *this;
272     }
273 
274     /**
275      * @brief Sets the offset of the stream
276      *
277      * @param[in] newOffset - the new offset
278      */
offset(std::size_t newOffset)279     void offset(std::size_t newOffset)
280     {
281         if (newOffset >= _data.size())
282         {
283             throw std::out_of_range("new offset out of range");
284         }
285 
286         _offset = newOffset;
287     }
288 
289     /**
290      * @brief Returns the current offset of the stream
291      *
292      * @return size_t - the offset
293      */
offset() const294     std::size_t offset() const
295     {
296         return _offset;
297     }
298 
299     /**
300      * @brief Returns the remaining bytes left between the current offset
301      *        and the data size.
302      *
303      * @return size_t - the remaining size
304      */
remaining() const305     std::size_t remaining() const
306     {
307         assert(_data.size() >= _offset);
308         return _data.size() - _offset;
309     }
310 
311     /**
312      * @brief Reads a specified number of bytes out of a stream
313      *
314      * @param[out] out - filled in with the data
315      * @param[in] size - the size to read
316      */
read(void * out,std::size_t size)317     void read(void* out, std::size_t size)
318     {
319         rangeCheck(size);
320         memcpy(out, &_data[_offset], size);
321         _offset += size;
322     }
323 
324     /**
325      * @brief Writes a specified number of bytes into the stream
326      *
327      * @param[in] in - the data to write
328      * @param[in] size - the size to write
329      */
write(const void * in,std::size_t size)330     void write(const void* in, std::size_t size)
331     {
332         size_t newSize = _offset + size;
333         if (newSize > _data.size())
334         {
335             _data.resize(newSize, 0);
336         }
337         memcpy(&_data[_offset], in, size);
338         _offset += size;
339     }
340 
341   private:
342     /**
343      * @brief Throws an exception if the size passed in plus the current
344      *        offset is bigger than the current data size.
345      * @param[in] size - the size to check
346      */
rangeCheck(std::size_t size)347     void rangeCheck(std::size_t size)
348     {
349         if (_offset + size > _data.size())
350         {
351             std::string msg{"Attempted stream overflow: offset "};
352             msg += std::to_string(_offset) + " buffer size " +
353                    std::to_string(_data.size()) + " op size " +
354                    std::to_string(size);
355             throw std::out_of_range(msg.c_str());
356         }
357     }
358 
359     /**
360      * @brief The data that the stream accesses.
361      */
362     std::vector<uint8_t>& _data;
363 
364     /**
365      * @brief The current offset of the stream.
366      */
367     std::size_t _offset;
368 };
369 
370 } // namespace pels
371 } // namespace openpower
372