steam-min-cpp
Loading...
Searching...
No Matches
stream.hpp
1
3// GPT
4
5#pragma once
6#include <steamclient/utilities/err.h>
7
8#include <cstdint>
9#include <cstring>
10#include <stdexcept>
11#include <type_traits>
12#include <vector>
13
14using byte = unsigned char;
15
16namespace Steam::Utils {
17class Stream {
18 public:
19 // Write-mode constructor (default)
20 explicit Stream() : readBuffer(nullptr), position(0) {}
21
22 // Read-mode constructor
23 explicit Stream(const std::vector<byte>& input)
24 : readBuffer(&input), buffer(), position(0) {}
25
26 // Read-mode constructor with offset
27 explicit Stream(const std::vector<byte>& input, size_t offset)
28 : readBuffer(&input), buffer(), position(offset) {}
29
30 size_t Position() const { return position; }
31
32 size_t Length() const {
33 return readBuffer ? readBuffer->size() : buffer.size();
34 }
35
36 const std::vector<byte>& GetBuffer() const { return buffer; }
37
38 std::vector<byte> MoveBuffer() { return std::move(buffer); }
39
40 template <typename T>
41 void Write(T value) {
42 static_assert(std::is_integral_v<T>, "Integral required");
43
44 if (readBuffer) throw std::runtime_error("Stream is in read mode");
45
46 for (size_t i = 0; i < sizeof(T); ++i)
47 buffer.push_back(static_cast<byte>((value >> (8 * i)) & 0xFF));
48 }
49
50 void Write(const std::vector<byte>& data) {
51 if (readBuffer) throw std::runtime_error("Stream is in read mode");
52
53 buffer.insert(buffer.end(), data.begin(), data.end());
54 }
55
56 void Write(const byte* data, size_t size) {
57 if (readBuffer) throw std::runtime_error("Stream is in read mode");
58
59 buffer.insert(buffer.end(), data, data + size);
60 }
61
62 void Write(const void* data, size_t size) {
63 const uint8_t* ptr = static_cast<const uint8_t*>(data);
64 buffer.insert(buffer.end(), ptr, ptr + size);
65 }
66
67 template <typename T>
68 T Read() {
69 static_assert(std::is_integral_v<T>, "Integral required");
70
71 if (!readBuffer) throw std::runtime_error("Stream is in write mode");
72
73 if (position + sizeof(T) > readBuffer->size())
74 throw std::runtime_error("Stream underflow");
75
76 T value = 0;
77 for (size_t i = 0; i < sizeof(T); ++i)
78 value |= static_cast<T>((*readBuffer)[position + i]) << (8 * i);
79
80 position += sizeof(T);
81 return value;
82 }
83
84 void Read(byte* out, size_t size) {
85 if (!readBuffer) throw std::runtime_error("Stream is in write mode");
86
87 if (position + size > readBuffer->size())
88 throw std::runtime_error("Stream underflow");
89
90 std::memcpy(out, readBuffer->data() + position, size);
91 position += size;
92 }
93
94 std::vector<byte> ReadBytes(size_t size) {
95 if (!readBuffer) throw std::runtime_error("Stream is in write mode");
96
97 if (position + size > readBuffer->size())
98 throw std::runtime_error("Stream underflow");
99
100 std::vector<byte> out(readBuffer->begin() + position,
101 readBuffer->begin() + position + size);
102
103 position += size;
104 return out;
105 }
106
107 template <typename T>
108 std::vector<T> ReadArray(size_t count) {
109 static_assert(std::is_integral_v<T>, "Integral required");
110
111 if (!readBuffer) throw std::runtime_error("Stream is in write mode");
112
113 if (position + sizeof(T) * count > readBuffer->size())
114 throw std::runtime_error("Stream underflow");
115
116 std::vector<T> result;
117 result.reserve(count);
118
119 for (size_t i = 0; i < count; ++i) result.push_back(Read<T>());
120
121 return result;
122 }
123
124 private:
125 const std::vector<byte>* readBuffer;
126 std::vector<byte> buffer;
127 size_t position;
128};
129} // namespace Steam::Utils