| 30 |
30 |
| 31 #include "bytestream.h" |
31 #include "bytestream.h" |
| 32 #include <string.h> |
32 #include <string.h> |
| 33 BEGIN_ZFC_NAMESPACE |
33 BEGIN_ZFC_NAMESPACE |
| 34 |
34 |
| 35 // ------------------------------------------------------------------------------------------------- |
35 /*! |
| 36 // |
36 * \brief Constructs a byte cursor. The cursor is placed to the beginning of the stream. |
| 37 Bytestream::Bytestream (unsigned long length) : |
37 * \param data |
| 38 m_data (nullptr) |
38 */ |
| 39 { |
39 Bytestream::Bytestream(Vector<unsigned char>& data) : |
| 40 resize (length); |
40 m_data(data), |
| 41 clear(); |
41 m_position(0) {} |
| 42 } |
42 |
| 43 |
43 /*! |
| 44 // ------------------------------------------------------------------------------------------------- |
44 * \brief Ensures that the specified amount of bytes can be read. Raises IOError if this is not the case. |
| 45 // |
45 * \param bytes Amount of bytes to check. |
| 46 Bytestream::Bytestream (const unsigned char* data, unsigned long length) : |
46 */ |
| 47 m_data (nullptr) |
47 void Bytestream::ensureReadSpace(int bytes) |
| 48 { |
48 { |
| 49 init (data, length); |
49 if (bytesLeft() < bytes) |
| 50 } |
|
| 51 |
|
| 52 // ------------------------------------------------------------------------------------------------- |
|
| 53 // |
|
| 54 Bytestream::Bytestream (const Vector<unsigned char>& bytes) : |
|
| 55 m_data (nullptr) |
|
| 56 { |
|
| 57 init (bytes.data(), bytes.size()); |
|
| 58 } |
|
| 59 |
|
| 60 // ------------------------------------------------------------------------------------------------- |
|
| 61 // |
|
| 62 Bytestream::Bytestream (const Bytestream& other) : |
|
| 63 m_data (nullptr) |
|
| 64 { |
|
| 65 init (other.data(), other.written_length()); |
|
| 66 } |
|
| 67 |
|
| 68 // ------------------------------------------------------------------------------------------------- |
|
| 69 // |
|
| 70 Bytestream::~Bytestream() |
|
| 71 { |
|
| 72 delete[] m_data; |
|
| 73 } |
|
| 74 |
|
| 75 // ------------------------------------------------------------------------------------------------- |
|
| 76 Bytestream& Bytestream::operator= (const Bytestream& other) |
|
| 77 { |
|
| 78 init (other.data(), other.written_length()); |
|
| 79 return *this; |
|
| 80 } |
|
| 81 |
|
| 82 // ------------------------------------------------------------------------------------------------- |
|
| 83 // |
|
| 84 void Bytestream::resize (unsigned long newsize) |
|
| 85 { |
|
| 86 Vector<unsigned char> olddata; |
|
| 87 unsigned long oldsize = 0L; |
|
| 88 |
|
| 89 if (m_data != nullptr) |
|
| 90 { |
50 { |
| 91 oldsize = allocated_size(); |
51 int bytesPast = bytes - bytesLeft(); |
| 92 olddata.resize (oldsize); |
|
| 93 memcpy (olddata.data(), m_data, oldsize); |
|
| 94 } |
|
| 95 |
|
| 96 delete[] m_data; |
|
| 97 m_allocatedSize = newsize; |
|
| 98 m_data = new unsigned char[newsize]; |
|
| 99 |
|
| 100 if (oldsize > 0L) |
|
| 101 memcpy (m_data, olddata, min (oldsize, newsize)); |
|
| 102 } |
|
| 103 |
|
| 104 // ------------------------------------------------------------------------------------------------- |
|
| 105 // |
|
| 106 void Bytestream::init (const unsigned char* data, unsigned long length) |
|
| 107 { |
|
| 108 resize (length); |
|
| 109 memcpy (m_data, data, length); |
|
| 110 m_cursor = &m_data[0]; |
|
| 111 m_writtenLength = length; |
|
| 112 } |
|
| 113 |
|
| 114 // ------------------------------------------------------------------------------------------------- |
|
| 115 // |
|
| 116 void Bytestream::clear() |
|
| 117 { |
|
| 118 m_cursor = &m_data[0]; |
|
| 119 m_writtenLength = 0; |
|
| 120 } |
|
| 121 |
|
| 122 // ------------------------------------------------------------------------------------------------- |
|
| 123 // |
|
| 124 void Bytestream::ensure_read_space (unsigned int bytes) |
|
| 125 { |
|
| 126 if (bytes_left() < bytes) |
|
| 127 { |
|
| 128 int bytesPast = bytes - bytes_left(); |
|
| 129 |
|
| 130 String message; |
52 String message; |
| 131 message.sprintf ("attempted to read %d byte%s past the end of bytestream", |
53 message.sprintf("attempted to read %d byte%s past the end of bytestream", bytesPast, plural(bytesPast)); |
| 132 bytesPast, bytesPast != -1 ? "s" : ""); |
|
| 133 throw IOError (message); |
54 throw IOError (message); |
| 134 } |
55 } |
| 135 } |
56 } |
| 136 |
57 |
| 137 // ------------------------------------------------------------------------------------------------- |
58 /*! |
| 138 // |
59 * \returns the amount of bytes remaining for reading. |
| 139 int8_t Bytestream::read_byte() |
60 */ |
| 140 { |
61 int Bytestream::bytesLeft() const |
| 141 ensure_read_space (1); |
62 { |
| 142 return *m_cursor++; |
63 return m_data.size() - m_position; |
| 143 } |
64 } |
| 144 |
65 |
| 145 // ------------------------------------------------------------------------------------------------- |
66 /*! |
| 146 // |
67 * \returns an iterator to the current data position. |
| 147 int16_t Bytestream::read_short() |
68 */ |
| 148 { |
69 Vector<unsigned char>::Iterator Bytestream::getCurrentIterator() |
| 149 ensure_read_space (2); |
70 { |
| 150 short int result = 0; |
71 return m_data.begin() + m_position; |
| |
72 } |
| |
73 |
| |
74 /*! |
| |
75 * \brief Reads in a byte. |
| |
76 * \returns the read byte. |
| |
77 */ |
| |
78 int8_t Bytestream::readByte() |
| |
79 { |
| |
80 ensureReadSpace(1); |
| |
81 return read(); |
| |
82 } |
| |
83 |
| |
84 /*! |
| |
85 * \brief Reads in two bytes to form an integer value. |
| |
86 * \returns the read value. |
| |
87 */ |
| |
88 int16_t Bytestream::readShort() |
| |
89 { |
| |
90 ensureReadSpace (2); |
| |
91 int16_t result = 0; |
| 151 |
92 |
| 152 for (int i : range(2)) |
93 for (int i : range(2)) |
| 153 result |= m_cursor[i] << (i * 8); |
94 result |= read() << (i * 8); |
| 154 |
95 |
| 155 m_cursor += 2; |
|
| 156 return result; |
96 return result; |
| 157 } |
97 } |
| 158 |
98 |
| 159 // ------------------------------------------------------------------------------------------------- |
99 /*! |
| 160 // |
100 * \brief Reads in four bytes to form an integer value. |
| 161 int32_t Bytestream::read_long() |
101 * \returns the read value. |
| 162 { |
102 */ |
| 163 ensure_read_space (4); |
103 int32_t Bytestream::readLong() |
| 164 long int result = 0; |
104 { |
| |
105 ensureReadSpace (4); |
| |
106 int32_t result = 0; |
| 165 |
107 |
| 166 for (int i : range(4)) |
108 for (int i : range(4)) |
| 167 result |= m_cursor[i] << (i * 8); |
109 result |= read() << (i * 8); |
| 168 |
110 |
| 169 m_cursor += 4; |
|
| 170 return result; |
111 return result; |
| 171 } |
112 } |
| 172 |
113 |
| 173 // ------------------------------------------------------------------------------------------------- |
114 /*! |
| 174 // |
115 * \brief Reads in four bytes to form a floating point number. |
| 175 float Bytestream::read_float() |
116 * \returns the read value. |
| |
117 */ |
| |
118 float Bytestream::readFloat() |
| 176 { |
119 { |
| 177 float value; |
120 float value; |
| 178 int intvalue = read_long(); |
121 int intvalue = readLong(); |
| 179 memcpy (&value, &intvalue, sizeof intvalue); |
122 memcpy(&value, &intvalue, sizeof intvalue); |
| 180 return value; |
123 return value; |
| 181 } |
124 } |
| 182 |
125 |
| 183 // ------------------------------------------------------------------------------------------------- |
126 /*! |
| 184 // |
127 * \brief Reads in characters until a null terminator is encountered. |
| 185 String Bytestream::read_string() |
128 * \returns the read string. |
| 186 { |
129 */ |
| 187 // Zandronum sends strings of maximum 2048 characters, though it only |
130 String Bytestream::readString() |
| 188 // reads 2047-character long ones so I guess we can follow up and do |
131 { |
| 189 // the same :-) |
132 Vector<unsigned char>::Iterator stringEndIterator; |
| 190 static char buffer[MAX_NETWORK_STRING]; |
|
| 191 unsigned char* stringEnd; |
|
| 192 unsigned char* stringBegin = m_cursor; |
|
| 193 unsigned char* end = m_data + allocated_size(); |
|
| 194 |
133 |
| 195 // Where's the end of the string? |
134 // Where's the end of the string? |
| 196 for (stringEnd = m_cursor; *stringEnd != '\0'; ++stringEnd) |
135 for (stringEndIterator = getCurrentIterator(); *stringEndIterator != '\0'; ++stringEndIterator) |
| 197 { |
136 { |
| 198 if (stringEnd == end) |
137 if (stringEndIterator == m_data.end()) |
| 199 { |
138 { |
| 200 // Past the end of the buffer |
139 // Past the end of the buffer |
| 201 throw IOError ("unterminated or too long string in packet"); |
140 throw IOError("unterminated or too long string in packet"); |
| 202 } |
141 } |
| 203 } |
142 } |
| 204 |
143 |
| 205 unsigned int length = stringEnd - m_cursor; |
144 // Skip past the null terminator. |
| 206 m_cursor = stringEnd + 1; |
145 if (*stringEndIterator == '\0') |
| 207 memcpy (buffer, stringBegin, length); |
146 stringEndIterator += 1; |
| 208 buffer[length] = '\0'; |
147 |
| 209 return String (buffer); |
148 // Build and return the string, and advance the position. |
| 210 } |
149 int stringStart = m_position; |
| 211 |
150 unsigned int length = stringEndIterator - getCurrentIterator(); |
| 212 // ------------------------------------------------------------------------------------------------- |
151 length = min<int>(length, MAX_NETWORK_STRING); |
| 213 // |
152 m_position += length; |
| 214 void Bytestream::read (unsigned char* buffer, unsigned long length) |
153 return String::fromBytes(m_data.splice(stringStart, stringStart + length)); |
| 215 { |
154 } |
| 216 ensure_read_space (length); |
155 |
| 217 memcpy (buffer, m_cursor, length); |
156 /*! |
| 218 m_cursor += length; |
157 * \brief Reads in a buffer of the specified length. |
| 219 } |
158 * \param length Amount of bytes to read. |
| 220 |
159 * \returns the read buffer. |
| 221 // ------------------------------------------------------------------------------------------------- |
160 */ |
| 222 // |
161 Vector<unsigned char> Bytestream::readBuffer(int length) |
| 223 void Bytestream::write (unsigned char val) |
162 { |
| 224 { |
163 ensureReadSpace(length); |
| 225 *m_cursor++ = val; |
164 Vector<unsigned char> result(length); |
| 226 m_writtenLength++; |
165 memcpy(result.data(), m_data.data() + m_position, length); |
| 227 } |
166 m_position += length; |
| 228 |
167 return result; |
| 229 // ------------------------------------------------------------------------------------------------- |
168 } |
| 230 // |
169 |
| 231 void Bytestream::write (const unsigned char* val, unsigned int length) |
170 /*! |
| 232 { |
171 * \brief Writes an integer to the end of the data as one byte. |
| 233 grow_to_fit (length); |
172 * \param value Value to write |
| 234 memcpy (m_cursor, val, length); |
173 */ |
| 235 m_cursor += length; |
174 void Bytestream::writeByte(int8_t value) |
| 236 m_writtenLength += length; |
175 { |
| 237 } |
176 m_data.append(value); |
| 238 |
177 } |
| 239 // ------------------------------------------------------------------------------------------------- |
178 |
| 240 // |
179 /*! |
| 241 void Bytestream::grow_to_fit (unsigned long bytes) |
180 * \brief Writes an integer to the end of the data as 2 bytes. |
| 242 { |
181 * \param value Value to write |
| 243 if (space_left() < bytes) |
182 */ |
| 244 resize (allocated_size() + bytes + 128); |
183 void Bytestream::writeShort(int16_t value) |
| 245 } |
184 { |
| 246 |
|
| 247 // ------------------------------------------------------------------------------------------------- |
|
| 248 // |
|
| 249 void Bytestream::write_byte (int8_t val) |
|
| 250 { |
|
| 251 grow_to_fit (1); |
|
| 252 write (val); |
|
| 253 } |
|
| 254 |
|
| 255 // ------------------------------------------------------------------------------------------------- |
|
| 256 // |
|
| 257 void Bytestream::write_short (int16_t val) |
|
| 258 { |
|
| 259 grow_to_fit (2); |
|
| 260 |
|
| 261 for (int i : range(2)) |
185 for (int i : range(2)) |
| 262 write ((val >> (i * 8)) & 0xFF); |
186 m_data.append((value >> (i * 8)) & 0xFF); |
| 263 } |
187 } |
| 264 |
188 |
| 265 // ------------------------------------------------------------------------------------------------- |
189 /*! |
| 266 // |
190 * \brief Writes an integer to the end of the data as 4 bytes. |
| 267 void Bytestream::write_long (int32_t val) |
191 * \param value Value to write |
| 268 { |
192 */ |
| 269 grow_to_fit (4); |
193 void Bytestream::writeLong(int32_t value) |
| 270 |
194 { |
| 271 for (int i : range(4)) |
195 for (int i : range(4)) |
| 272 write ((val >> (i * 8)) & 0xFF); |
196 m_data.append((value >> (i * 8)) & 0xFF); |
| 273 } |
197 } |
| 274 |
198 |
| 275 // ------------------------------------------------------------------------------------------------- |
199 /*! |
| 276 // |
200 * \brief Writes a floating-point number to the end of the data. |
| 277 void Bytestream::write_float (float val) |
201 * \param value Value to write. |
| |
202 */ |
| |
203 void Bytestream::writeFloat(float value) |
| 278 { |
204 { |
| 279 // I know this is probably dangerous but this is what Zandronum does so yeah |
205 // I know this is probably dangerous but this is what Zandronum does so yeah |
| 280 int intvalue; |
206 int intvalue; |
| 281 memcpy (&intvalue, &val, sizeof val); |
207 memcpy (&intvalue, &value, sizeof value); |
| 282 write_long (intvalue); |
208 writeLong (intvalue); |
| 283 } |
209 } |
| 284 |
210 |
| 285 // ------------------------------------------------------------------------------------------------- |
211 /*! |
| 286 // |
212 * \brief Writes the given string to the end of the data. |
| 287 void Bytestream::write_string (const String& val) |
213 * \param text String to write. |
| 288 { |
214 */ |
| 289 grow_to_fit (val.length() + 1); |
215 void Bytestream::writeString(const String& string) |
| 290 write (reinterpret_cast<const unsigned char*> (val.chars()), val.length()); |
216 { |
| 291 write (0); |
217 m_data.append(string.toBytes(), string.length()); |
| 292 } |
218 m_data.append(0); |
| 293 |
219 } |
| 294 // ------------------------------------------------------------------------------------------------- |
220 |
| 295 // |
221 /*! |
| 296 void Bytestream::write_buffer (const Bytestream& other) |
222 * \returns the current position the stream cursor in the data. |
| 297 { |
223 */ |
| 298 write (other.data(), other.written_length()); |
224 int Bytestream::position() const |
| |
225 { |
| |
226 return m_position; |
| |
227 } |
| |
228 |
| |
229 /*! |
| |
230 * \brief Seeks the stream cursor to the beginning of the data. |
| |
231 */ |
| |
232 void Bytestream::rewind() |
| |
233 { |
| |
234 m_position = 0; |
| |
235 } |
| |
236 |
| |
237 /*! |
| |
238 * \brief Seeks the stream cursor to a custom location. |
| |
239 * \param position Position to seek too. |
| |
240 */ |
| |
241 void Bytestream::seek(int position) |
| |
242 { |
| |
243 m_position = position; |
| |
244 } |
| |
245 |
| |
246 /*! |
| |
247 * \brief Reads a byte and advances the cursor. No safety checks are done. |
| |
248 * \returns the read byte. |
| |
249 */ |
| |
250 int8_t Bytestream::read() |
| |
251 { |
| |
252 return m_data[m_position++]; |
| 299 } |
253 } |
| 300 |
254 |
| 301 END_ZFC_NAMESPACE |
255 END_ZFC_NAMESPACE |