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(ByteArray& 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 ByteArray::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 ByteArray::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 ByteArray Bytestream::readBuffer(int length) |
223 void Bytestream::write (unsigned char val) |
162 { |
224 { |
163 ensureReadSpace(length); |
225 *m_cursor++ = val; |
164 ByteArray 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 |