1 /* |
|
2 * ZanDemo: Zandronum demo launcher |
|
3 * Copyright (C) 2013 Santeri Piippo |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include "bytestream.h" |
|
20 #include "misc.h" |
|
21 #include <string.h> |
|
22 |
|
23 union { |
|
24 uint32 i; |
|
25 float f; |
|
26 } g_floatunion; |
|
27 |
|
28 Bytestream::Bytestream (ulong len) { |
|
29 m_data = null; |
|
30 resize (len); |
|
31 clear(); |
|
32 } |
|
33 |
|
34 Bytestream::Bytestream (const char* data, ulong len) { |
|
35 m_data = null; |
|
36 init (data, len); |
|
37 } |
|
38 |
|
39 void Bytestream::resize (ulong newsize) { |
|
40 char* olddata = null; |
|
41 ulong oldsize; |
|
42 |
|
43 if (m_data) { |
|
44 oldsize = m_size; |
|
45 olddata = new char[oldsize]; |
|
46 memcpy (olddata, m_data, oldsize); |
|
47 } |
|
48 |
|
49 delete[] m_data; |
|
50 m_data = new uint8[newsize]; |
|
51 m_size = newsize; |
|
52 |
|
53 if (olddata) |
|
54 memcpy (m_data, olddata, min<ulong> (oldsize, newsize)); |
|
55 } |
|
56 |
|
57 void Bytestream::init (const char* data, ulong len) { |
|
58 resize (len); |
|
59 memcpy (m_data, data, len); |
|
60 m_ptr = &m_data[0]; |
|
61 m_len = len; |
|
62 } |
|
63 |
|
64 size_t Bytestream::len() const { |
|
65 return m_len; |
|
66 } |
|
67 |
|
68 void Bytestream::clear() { |
|
69 m_ptr = &m_data[0]; |
|
70 m_len = 0; |
|
71 } |
|
72 |
|
73 uint8& Bytestream::subscript (ulong idx) { |
|
74 return m_data[idx]; |
|
75 } |
|
76 |
|
77 const uint8& Bytestream::const_subscript (ulong idx) const { |
|
78 return m_data[idx]; |
|
79 } |
|
80 |
|
81 void Bytestream::seek (ulong pos) { |
|
82 m_ptr = m_data + pos; |
|
83 } |
|
84 |
|
85 // ============================================================================= |
|
86 void Bytestream::rewind() { |
|
87 m_ptr = m_data; |
|
88 } |
|
89 |
|
90 ulong Bytestream::bytesLeft() const { |
|
91 return (m_len - (m_ptr - &m_data[0])); |
|
92 } |
|
93 |
|
94 ulong Bytestream::spaceLeft() const { |
|
95 return (m_size - m_len); |
|
96 } |
|
97 |
|
98 // ============================================================================= |
|
99 bool Bytestream::readByte (uint8& val) { |
|
100 if (bytesLeft() < 1) |
|
101 return false; |
|
102 |
|
103 val = *m_ptr++; |
|
104 return true; |
|
105 } |
|
106 |
|
107 // ============================================================================= |
|
108 bool Bytestream::readShort (uint16& val) { |
|
109 if (bytesLeft() < 2) |
|
110 return false; |
|
111 |
|
112 val = 0; |
|
113 |
|
114 for (int i = 0; i < 2; ++i) |
|
115 val |= *m_ptr++ << (i * 8); |
|
116 |
|
117 return true; |
|
118 } |
|
119 |
|
120 // ============================================================================= |
|
121 bool Bytestream::readLong (uint32& val) { |
|
122 if (bytesLeft() < 4) |
|
123 return false; |
|
124 |
|
125 val = 0; |
|
126 |
|
127 for (int i = 0; i < 4; ++i) |
|
128 val |= *m_ptr++ << (i * 8); |
|
129 |
|
130 return true; |
|
131 } |
|
132 |
|
133 // ============================================================================= |
|
134 bool Bytestream::readFloat (float& val) { |
|
135 if (!readLong (g_floatunion.i)) |
|
136 return false; |
|
137 |
|
138 val = g_floatunion.f; |
|
139 return true; |
|
140 } |
|
141 |
|
142 // ============================================================================= |
|
143 bool Bytestream::readString (str& val) { |
|
144 if (bytesLeft() < 1) // need at least the null terminator |
|
145 return false; |
|
146 |
|
147 uint8_t c; |
|
148 |
|
149 while (readByte (c) && c != '\0') |
|
150 val += (char) c; |
|
151 |
|
152 return true; |
|
153 } |
|
154 |
|
155 // ============================================================================= |
|
156 void Bytestream::doWrite (uint8_t val) { |
|
157 *m_ptr++ = val; |
|
158 m_len++; |
|
159 } |
|
160 |
|
161 void Bytestream::growToFit (ulong bytes) { |
|
162 if (spaceLeft() < bytes) |
|
163 resize (m_size + bytes + 128); |
|
164 } |
|
165 |
|
166 bool Bytestream::readBytes (uint8 numbytes, uint8* val) { |
|
167 while (numbytes--) |
|
168 if (!readByte (*val++)) |
|
169 return false; |
|
170 |
|
171 return true; |
|
172 } |
|
173 |
|
174 void Bytestream::writeBytes (uint8 numbytes, const uint8* val) { |
|
175 growToFit (numbytes); |
|
176 |
|
177 while (numbytes--) |
|
178 writeByte (*val++); |
|
179 } |
|
180 |
|
181 // ============================================================================= |
|
182 void Bytestream::writeByte (uint8 val) { |
|
183 growToFit (1); |
|
184 doWrite (val); |
|
185 } |
|
186 |
|
187 // ============================================================================= |
|
188 void Bytestream::writeShort (uint16 val) { |
|
189 growToFit (2); |
|
190 |
|
191 for (int i = 0; i < 2; ++i) |
|
192 doWrite ( (val >> (i * 8)) & 0xFF); |
|
193 } |
|
194 |
|
195 // ============================================================================= |
|
196 void Bytestream::writeLong (uint32 val) { |
|
197 growToFit (4); |
|
198 |
|
199 for (int i = 0; i < 4; ++i) |
|
200 doWrite ( (val >> (i * 8)) & 0xFF); |
|
201 } |
|
202 |
|
203 // ============================================================================= |
|
204 void Bytestream::writeFloat (float val) { |
|
205 g_floatunion.f = val; |
|
206 writeLong (g_floatunion.i); |
|
207 } |
|
208 |
|
209 // ============================================================================= |
|
210 void Bytestream::writeString (str val) { |
|
211 growToFit (val.length() + 1); |
|
212 |
|
213 for (qchar c : val) |
|
214 doWrite (c.toLatin1()); |
|
215 |
|
216 doWrite ('\0'); |
|
217 } |
|
218 |
|
219 // ============================================================================= |
|
220 bool Bytestream::tryMerge (const Bytestream& other) { |
|
221 if (spaceLeft() < other.len()) |
|
222 return false; |
|
223 |
|
224 for (ulong i = 0; i < other.len(); ++i) |
|
225 writeByte (other[i]); |
|
226 |
|
227 return true; |
|
228 } |
|
229 |
|
230 void Bytestream::merge (const Bytestream& other) { |
|
231 growToFit (other.len()); |
|
232 |
|
233 if (!tryMerge (other)) { |
|
234 // Shouldn't happen |
|
235 fprint (stderr, "ByteStream: Not enough space for merge (%1 bytes left, need %2)", |
|
236 spaceLeft(), other.len()); |
|
237 abort(); |
|
238 } |
|
239 } |
|
240 |
|
241 const uint8* Bytestream::data() const { |
|
242 return m_data; |
|
243 } |
|