agssim: allow interactive mode with file
[rofl0r-agsutils.git] / ByteArray.c
blobf89b2b4e36e7fe71bb4e54d023a972665b33fb77
1 /* ByteArray (C) 2012 rofl0r
2 *
3 * licensed under the LGPL 2.1+ */
5 #include "ByteArray.h"
6 #include "debug.h"
7 #include "endianness.h"
8 #include <stdlib.h>
9 #include <sys/mman.h>
11 void ByteArray_defaults(struct ByteArray* self) {
12 memset(self, 0, sizeof(*self));
15 void ByteArray_ctor(struct ByteArray* self) {
16 ByteArray_defaults(self);
17 // original constructor code goes here
18 self->readMultiByte = ByteArray_readMultiByte;
19 self->readByte = ByteArray_readByte;
20 self->readUnsignedByte = ByteArray_readUnsignedByte;
21 self->readShort = ByteArray_readShort;
22 self->readUnsignedShort = ByteArray_readUnsignedShort;
23 self->readInt = ByteArray_readInt;
24 self->readUnsignedInt = ByteArray_readUnsignedInt;
25 self->readBytes = ByteArray_readBytes;
27 self->writeInt = ByteArray_writeInt;
28 self->writeUnsignedInt = ByteArray_writeUnsignedInt;
29 self->writeShort = ByteArray_writeShort;
30 self->writeUnsignedShort = ByteArray_writeUnsignedShort;
31 self->writeByte = ByteArray_writeByte;
32 self->writeUnsignedByte = ByteArray_writeUnsignedByte;;
33 self->writeMem = ByteArray_writeMem;
34 self->writeUTFBytes = ByteArray_writeUTFBytes;
35 self->writeBytes = ByteArray_writeBytes;
36 self->writeFloat = ByteArray_writeFloat;
38 self->set_position = ByteArray_set_position;
39 self->set_position_rel = ByteArray_set_position_rel;
40 self->get_position = ByteArray_get_position;
42 self->bytesAvailable = ByteArray_bytesAvailable;
44 #ifdef IS_LITTLE_ENDIAN
45 self->sys_endian = BAE_LITTLE;
46 #else
47 self->sys_endian = BAE_BIG;
48 #endif
51 struct ByteArray* ByteArray_new(void) {
52 struct ByteArray* self = (struct ByteArray*) malloc(sizeof(*self));
53 if(self) ByteArray_ctor(self);
54 return self;
57 void ByteArray_set_endian(struct ByteArray* self, enum ByteArray_Endianess endian) {
58 self->endian = endian;
61 void ByteArray_set_flags(struct ByteArray *self, int flags) {
62 self->flags = flags;
65 enum ByteArray_Endianess ByteArray_get_endian(struct ByteArray* self) {
66 return self->endian;
69 // a real byte array clears the mem and resets
70 // "len" and pos to 0
71 // where len is equivalent to the bytes written into it
72 //void* mem_getptr(MG* mem, size_t offset, size_t byteswanted);
73 void ByteArray_clear(struct ByteArray* self) {
74 fprintf(stderr, "clear called\n");
75 assert_op(self->type, ==, BAT_MEMSTREAM);
76 void *p = mem_getptr(&self->source.mem, 0, self->size);
77 if(p) memset(p, 0, self->size);
80 void ByteArray_close(struct ByteArray* self) {
81 assert_op(self->type, ==, BAT_MEMSTREAM);
82 mem_free(&self->source.mem);
85 off_t ByteArray_get_position(struct ByteArray* self) {
86 return self->pos;
89 static void seek_error() {
90 perror("seek error!\n");
91 assert_dbg(0);
94 static void neg_off() {
95 fprintf(stderr, "negative seek attempted\n");
96 assert_dbg(0);
99 static void oob() {
100 fprintf(stderr, "oob access attempted\n");
101 assert_dbg(0);
104 void ByteArray_set_length(struct ByteArray* self, off_t len) {
105 if(len > self->size) {
106 oob();
107 return;
109 self->size = len;
112 off_t ByteArray_get_length(struct ByteArray* self) {
113 return self->size;
116 int ByteArray_set_position_rel(struct ByteArray* self, int rel) {
117 if((int) self->pos + rel < 0) {
118 neg_off();
119 rel = -self->pos;
121 return ByteArray_set_position(self, self->pos + rel);
124 int ByteArray_set_position(struct ByteArray* self, off_t pos) {
125 if(pos == self->pos) return 1;
126 if(pos > self->size) {
127 oob();
128 return 0;
131 if(self->type == BAT_FILESTREAM) {
132 off_t ret = lseek(self->source.fd, pos, SEEK_SET);
133 if(ret == (off_t) -1) {
134 seek_error();
135 return 0;
138 self->pos = pos;
139 return 1;
142 static void read_error() {
143 perror("read error!\n");
144 assert_dbg(0);
147 static void read_error_short() {
148 perror("read error (short)!\n");
149 assert_dbg(0);
152 int ByteArray_open_file(struct ByteArray* self, const char* filename) {
153 struct stat st;
154 self->type = BAT_FILESTREAM;
155 self->pos = 0;
156 self->size = 0;
157 if(stat(filename, &st) == -1) return 0;
158 self->size = st.st_size;
159 self->source.fd = open(filename, O_RDONLY);
160 if (self->source.fd == -1) return 0;
161 void *addr = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->source.fd, 0);
162 if(addr == MAP_FAILED) {
163 perror("mmap");
164 return 1;
166 return ByteArray_open_mem(self, addr, self->size);
169 void ByteArray_close_file(struct ByteArray *self) {
170 close(self->source.fd);
171 self->source.fd = -1;
174 int ByteArray_open_mem(struct ByteArray* self, char* data, size_t size) {
175 self->size = size;
176 self->type = BAT_MEMSTREAM;
177 mem_set(&self->source.mem, data, size, size);
178 return 1;
181 ssize_t ByteArray_readMultiByte(struct ByteArray* self, char* buffer, size_t len) {
182 if(self->type == BAT_MEMSTREAM) {
183 assert_op((size_t) self->pos + len, <=, (size_t) self->size);
184 void *p = mem_getptr(&self->source.mem, self->pos, len);
185 if(p) memcpy(buffer, p, len);
186 else return -1;
187 } else {
188 ssize_t ret = read(self->source.fd, buffer, len);
189 if(ret == -1) {
190 read_error();
191 return -1;
192 } else if((size_t) ret != len) {
193 read_error_short();
194 self->pos += len;
195 return -1;
198 self->pos += len;
199 return len;
202 // write contents of self into dest
203 // if len == 0 all available bytes are used.
204 // self->pos is considered the start offset to use for self.
205 // the position in dest will not be advanced.
206 // the position in source will be advanced len bytes.
207 // returns the number of bytes written
208 off_t ByteArray_readBytes(struct ByteArray* self, struct ByteArray *dest, off_t start, off_t len) {
209 off_t left = self->size - self->pos;
210 if(len == 0) len = left;
211 else if(len > left) {
212 oob();
213 len = left;
215 if(len == 0) return 0;
216 else if (len > start + dest->size) {
217 oob();
218 len = start + dest->size;
219 if(len == 0) return 0;
221 if(dest->type != BAT_MEMSTREAM) {
222 assert_dbg(0);
224 void *p = mem_getptr(&dest->source.mem, start, len);
225 if(p) self->readMultiByte(self, p, len);
226 else return 0;
227 return len;
230 off_t ByteArray_bytesAvailable(struct ByteArray* self) {
231 if(self->pos < self->size) return self->size - self->pos;
232 return 0;
235 unsigned int ByteArray_readUnsignedInt(struct ByteArray* self) {
236 union {
237 unsigned int intval;
238 unsigned char charval[sizeof(unsigned int)];
239 } buf;
240 self->readMultiByte(self, (char*) buf.charval, 4);
241 if(self->endian != self->sys_endian) {
242 buf.intval = byteswap32(buf.intval);
244 return buf.intval;
247 int ByteArray_readInt(struct ByteArray* self) {
248 union {
249 unsigned int intval;
250 unsigned char charval[sizeof(unsigned int)];
251 } buf;
252 self->readMultiByte(self, (char*) buf.charval, 4);
253 if(self->endian != self->sys_endian) {
254 buf.intval = byteswap32(buf.intval);
256 return buf.intval;
259 unsigned short ByteArray_readUnsignedShort(struct ByteArray* self) {
260 union {
261 unsigned short intval;
262 unsigned char charval[sizeof(unsigned short)];
263 } buf;
264 self->readMultiByte(self, (char*) buf.charval, 2);
265 if(self->endian != self->sys_endian) {
266 buf.intval = byteswap16(buf.intval);
268 return buf.intval;
271 short ByteArray_readShort(struct ByteArray* self) {
272 union {
273 unsigned short intval;
274 unsigned char charval[sizeof(unsigned short)];
275 } buf;
276 self->readMultiByte(self, (char*) buf.charval, 2);
277 if(self->endian != self->sys_endian) {
278 buf.intval = byteswap16(buf.intval);
280 return buf.intval;
283 unsigned char ByteArray_readUnsignedByte(struct ByteArray* self) {
284 union {
285 unsigned char intval;
286 } buf;
287 self->readMultiByte(self, (char*) &buf.intval, 1);
288 return buf.intval;
291 signed char ByteArray_readByte(struct ByteArray* self) {
292 union {
293 signed char intval;
294 } buf;
295 self->readMultiByte(self, (char*) &buf.intval, 1);
296 return buf.intval;
299 /* equivalent to foo = self[x]; (pos stays unchanged) */
300 unsigned char ByteArray_getUnsignedByte(struct ByteArray* self, off_t index) {
301 //assert_op(self->type, ==, BAT_MEMSTREAM);
302 assert_op(index, <, self->size);
303 off_t save = self->pos;
304 unsigned char res;
305 ByteArray_set_position(self, index);
306 res = ByteArray_readUnsignedByte(self);
307 ByteArray_set_position(self, save);
308 return res;
311 /* equivalent to self[x] = what (pos stays unchanged) */
312 void ByteArray_setUnsignedByte(struct ByteArray* self, off_t index, unsigned char what) {
313 off_t save = self->pos;
314 if(ByteArray_set_position(self, index)) {
315 ByteArray_writeUnsignedByte(self, what);
316 self->pos = save;
320 off_t ByteArray_writeByte(struct ByteArray* self, signed char what) {
321 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
324 off_t ByteArray_writeUnsignedByte(struct ByteArray* self, unsigned char what) {
325 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
328 off_t ByteArray_writeShort(struct ByteArray* self, signed short what) {
329 union {
330 short intval;
331 unsigned char charval[sizeof(what)];
332 } u;
333 u.intval = what;
334 if(self->sys_endian != self->endian) {
335 u.intval = byteswap16(u.intval);
337 return ByteArray_writeMem(self, u.charval, sizeof(what));
340 off_t ByteArray_writeUnsignedShort(struct ByteArray* self, unsigned short what) {
341 union {
342 unsigned short intval;
343 unsigned char charval[sizeof(what)];
344 } u;
345 u.intval = what;
346 if(self->sys_endian != self->endian) {
347 u.intval = byteswap16(u.intval);
349 return ByteArray_writeMem(self, u.charval, sizeof(what));
352 off_t ByteArray_writeInt(struct ByteArray* self, signed int what) {
353 union {
354 int intval;
355 unsigned char charval[sizeof(what)];
356 } u;
357 u.intval = what;
358 if(self->sys_endian != self->endian) {
359 u.intval = byteswap32(u.intval);
361 return ByteArray_writeMem(self, u.charval, sizeof(what));
364 off_t ByteArray_writeUnsignedInt(struct ByteArray* self, unsigned int what) {
365 union {
366 unsigned int intval;
367 unsigned char charval[sizeof(what)];
368 } u;
369 u.intval = what;
370 if(self->sys_endian != self->endian) {
371 u.intval = byteswap32(u.intval);
373 return ByteArray_writeMem(self, u.charval, sizeof(what));
376 off_t ByteArray_writeMem(struct ByteArray* self, unsigned char* what, size_t len) {
377 if(self->type == BAT_FILESTREAM) {
378 fprintf(stderr, "tried to write to file!\n");
379 assert_dbg(0);
380 return 0;
382 if(!(self->flags & BAF_CANGROW) && (size_t) self->pos + len > (size_t) self->size) {
383 fprintf(stderr, "oob write attempted");
384 assert_dbg(0);
385 return 0;
388 if(mem_write(&self->source.mem, self->pos, what, len)) {
389 self->pos += len;
390 if(self->pos > self->size) self->size = self->pos; /* apparently CANGROW was used */
392 return len;
395 off_t ByteArray_writeUTFBytes(struct ByteArray* self, char* what) {
396 return ByteArray_writeMem(self, (unsigned char*) what, strlen(what));
399 // write contents of what into self
400 off_t ByteArray_writeBytes(struct ByteArray* self, struct ByteArray* what) {
401 if(what->type == BAT_FILESTREAM) {
402 fprintf(stderr, "tried to write from non-memory stream\n");
403 assert_dbg(0);
404 return 0;
405 } else {
406 unsigned char* p = mem_getptr(&what->source.mem, what->pos, what->size - what->pos);
407 if(p)
408 return ByteArray_writeMem(self, p, what->size - what->pos);
409 return -1;
413 off_t ByteArray_writeFloat(struct ByteArray* self, float what) {
414 union {
415 float floatval;
416 unsigned int intval;
417 unsigned char charval[sizeof(what)];
418 } u;
419 u.floatval = what;
420 if(self->sys_endian != self->endian) {
421 u.intval = byteswap32(u.intval);
423 return ByteArray_writeMem(self, u.charval, sizeof(what));
426 void ByteArray_dump_to_stream(struct ByteArray* self, FILE *out) {
427 assert_op(self->type, ==, BAT_MEMSTREAM);
428 mem_write_stream(&self->source.mem, out);
431 void ByteArray_dump_to_file(struct ByteArray* self, char* filename) {
432 assert_op(self->type, ==, BAT_MEMSTREAM);
433 mem_write_file(&self->source.mem, filename);