1 #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 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 */ 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 */ 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&) = 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 306