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 Extraction operator for a std::vector<uint8_t> 147 * 148 * The vector's size is the amount extracted. 149 * 150 * @param[out] value - filled in with the value 151 * @return Stream& 152 */ 153 Stream& operator>>(std::vector<uint8_t>& value) 154 { 155 if (!value.empty()) 156 { 157 read(value.data(), value.size()); 158 } 159 return *this; 160 } 161 162 /** 163 * @brief Extraction operator for a std::vector<char> 164 * 165 * The vector's size is the amount extracted. 166 * 167 * @param[out] value - filled in with the value 168 * @return Stream& 169 */ 170 Stream& operator>>(std::vector<char>& value) 171 { 172 if (!value.empty()) 173 { 174 read(value.data(), value.size()); 175 } 176 return *this; 177 } 178 179 /** 180 * @brief Insert operator for a uint8_t 181 * 182 * @param[in] value - the value to write to the stream 183 * @return Stream& 184 */ 185 Stream& operator<<(uint8_t value) 186 { 187 write(&value, 1); 188 return *this; 189 } 190 191 /** 192 * @brief Insert operator for a char 193 * 194 * @param[in] value - the value to write to the stream 195 * @return Stream& 196 */ 197 Stream& operator<<(char value) 198 { 199 write(&value, 1); 200 return *this; 201 } 202 203 /** 204 * @brief Insert operator for a uint16_t 205 * 206 * @param[in] value - the value to write to the stream 207 * @return Stream& 208 */ 209 Stream& operator<<(uint16_t value) 210 { 211 uint16_t data = ntohs(value); 212 write(&data, 2); 213 return *this; 214 } 215 216 /** 217 * @brief Insert operator for a uint32_t 218 * 219 * @param[in] value - the value to write to the stream 220 * @return Stream& 221 */ 222 Stream& operator<<(uint32_t value) 223 { 224 uint32_t data = ntohl(value); 225 write(&data, 4); 226 return *this; 227 } 228 229 /** 230 * @brief Insert operator for a uint64_t 231 * 232 * @param[in] value - the value to write to the stream 233 * @return Stream& 234 */ 235 Stream& operator<<(uint64_t value) 236 { 237 uint64_t data = detail::ntohll(value); 238 write(&data, 8); 239 return *this; 240 } 241 242 /** 243 * @brief Insert operator for a std::vector<uint8_t> 244 * 245 * The full vector is written to the stream. 246 * 247 * @param[in] value - the value to write to the stream 248 * @return Stream& 249 */ 250 Stream& operator<<(const std::vector<uint8_t>& value) 251 { 252 if (!value.empty()) 253 { 254 write(value.data(), value.size()); 255 } 256 return *this; 257 } 258 259 /** 260 * @brief Insert operator for a std::vector<char> 261 * 262 * The full vector is written to the stream. 263 * 264 * @param[in] value - the value to write to the stream 265 * @return Stream& 266 */ 267 Stream& operator<<(const std::vector<char>& value) 268 { 269 if (!value.empty()) 270 { 271 write(value.data(), value.size()); 272 } 273 return *this; 274 } 275 276 /** 277 * @brief Sets the offset of the stream 278 * 279 * @param[in] newOffset - the new offset 280 */ 281 void offset(std::size_t newOffset) 282 { 283 if (newOffset >= _data.size()) 284 { 285 throw std::out_of_range("new offset out of range"); 286 } 287 288 _offset = newOffset; 289 } 290 291 /** 292 * @brief Returns the current offset of the stream 293 * 294 * @return size_t - the offset 295 */ 296 std::size_t offset() const 297 { 298 return _offset; 299 } 300 301 /** 302 * @brief Returns the remaining bytes left between the current offset 303 * and the data size. 304 * 305 * @return size_t - the remaining size 306 */ 307 std::size_t remaining() const 308 { 309 assert(_data.size() >= _offset); 310 return _data.size() - _offset; 311 } 312 313 /** 314 * @brief Reads a specified number of bytes out of a stream 315 * 316 * @param[out] out - filled in with the data 317 * @param[in] size - the size to read 318 */ 319 void read(void* out, std::size_t size) 320 { 321 rangeCheck(size); 322 memcpy(out, &_data[_offset], size); 323 _offset += size; 324 } 325 326 /** 327 * @brief Writes a specified number of bytes into the stream 328 * 329 * @param[in] in - the data to write 330 * @param[in] size - the size to write 331 */ 332 void write(const void* in, std::size_t size) 333 { 334 size_t newSize = _offset + size; 335 if (newSize > _data.size()) 336 { 337 _data.resize(newSize, 0); 338 } 339 memcpy(&_data[_offset], in, size); 340 _offset += size; 341 } 342 343 private: 344 /** 345 * @brief Throws an exception if the size passed in plus the current 346 * offset is bigger than the current data size. 347 * @param[in] size - the size to check 348 */ 349 void rangeCheck(std::size_t size) 350 { 351 if (_offset + size > _data.size()) 352 { 353 std::string msg{"Attempted stream overflow: offset "}; 354 msg += std::to_string(_offset) + " buffer size " + 355 std::to_string(_data.size()) + " op size " + 356 std::to_string(size); 357 throw std::out_of_range(msg.c_str()); 358 } 359 } 360 361 /** 362 * @brief The data that the stream accesses. 363 */ 364 std::vector<uint8_t>& _data; 365 366 /** 367 * @brief The current offset of the stream. 368 */ 369 std::size_t _offset; 370 }; 371 372 } // namespace pels 373 } // namespace openpower 374