ADF_open: add fine grained error reporting, dont fail always
[rofl0r-agsutils.git] / ByteArray.c
blob2632f8fe62b3a4d7afbaa48a71a8377f537280d8
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"
9 #ifndef _WIN32
10 #define O_BINARY 0
11 #endif
13 #include <stdlib.h>
14 #ifndef NO_MMAN /* lame OS like winblows */
15 #include <sys/mman.h>
16 #define BLOWS 0
17 #else
18 #define mmap(...) (void*)0xffffffff
19 #define MAP_FAILED (void*)0xffffffff
20 #define BLOWS 1
21 #endif
23 void ByteArray_defaults(struct ByteArray* self) {
24 memset(self, 0, sizeof(*self));
27 void ByteArray_ctor(struct ByteArray* self) {
28 ByteArray_defaults(self);
29 // original constructor code goes here
30 self->readMultiByte = ByteArray_readMultiByte;
31 self->readByte = ByteArray_readByte;
32 self->readUnsignedByte = ByteArray_readUnsignedByte;
33 self->readShort = ByteArray_readShort;
34 self->readUnsignedShort = ByteArray_readUnsignedShort;
35 self->readInt = ByteArray_readInt;
36 self->readUnsignedInt = ByteArray_readUnsignedInt;
37 self->readUnsignedLongLong = ByteArray_readUnsignedLongLong;
38 self->readBytes = ByteArray_readBytes;
40 self->writeInt = ByteArray_writeInt;
41 self->writeUnsignedInt = ByteArray_writeUnsignedInt;
42 self->writeShort = ByteArray_writeShort;
43 self->writeUnsignedShort = ByteArray_writeUnsignedShort;
44 self->writeByte = ByteArray_writeByte;
45 self->writeUnsignedByte = ByteArray_writeUnsignedByte;;
46 self->writeMem = ByteArray_writeMem;
47 self->writeUTFBytes = ByteArray_writeUTFBytes;
48 self->writeBytes = ByteArray_writeBytes;
49 self->writeFloat = ByteArray_writeFloat;
51 self->set_position = ByteArray_set_position;
52 self->set_position_rel = ByteArray_set_position_rel;
53 self->get_position = ByteArray_get_position;
55 self->bytesAvailable = ByteArray_bytesAvailable;
57 self->sys_endian = ENDIANNESS_BE ? BAE_BIG : BAE_LITTLE;
60 struct ByteArray* ByteArray_new(void) {
61 struct ByteArray* self = (struct ByteArray*) malloc(sizeof(*self));
62 if(self) ByteArray_ctor(self);
63 return self;
66 void ByteArray_set_endian(struct ByteArray* self, enum ByteArray_Endianess endian) {
67 self->endian = endian;
70 void ByteArray_set_flags(struct ByteArray *self, int flags) {
71 self->flags = flags;
74 enum ByteArray_Endianess ByteArray_get_endian(struct ByteArray* self) {
75 return self->endian;
78 // a real byte array clears the mem and resets
79 // "len" and pos to 0
80 // where len is equivalent to the bytes written into it
81 //void* mem_getptr(MG* mem, size_t offset, size_t byteswanted);
82 void ByteArray_clear(struct ByteArray* self) {
83 fprintf(stderr, "clear called\n");
84 assert_op(self->type, ==, BAT_MEMSTREAM);
85 void *p = mem_getptr(&self->source.mem, 0, self->size);
86 if(p) memset(p, 0, self->size);
89 void ByteArray_close(struct ByteArray* self) {
90 assert_op(self->type, ==, BAT_MEMSTREAM);
91 mem_free(&self->source.mem);
94 off_t ByteArray_get_position(struct ByteArray* self) {
95 return self->pos;
98 static void seek_error() {
99 perror("seek error!\n");
100 assert_dbg(0);
103 static void neg_off() {
104 fprintf(stderr, "negative seek attempted\n");
105 assert_dbg(0);
108 static void oob(const char *fn, off_t want, off_t have) {
109 fprintf(stderr, "%s: oob access attempted (want: %jd, have %jd)\n", fn ? fn : "<unknown>", (intmax_t) want, (intmax_t) have);
110 fflush(stderr);
111 assert_dbg(0);
114 void ByteArray_set_length(struct ByteArray* self, off_t len) {
115 if(len > self->size) {
116 oob(self->filename, len, self->size);
117 return;
119 self->size = len;
122 off_t ByteArray_get_length(struct ByteArray* self) {
123 return self->size;
126 int ByteArray_set_position_rel(struct ByteArray* self, int rel) {
127 if((int) self->pos + rel < 0) {
128 neg_off();
129 rel = -self->pos;
131 return ByteArray_set_position(self, self->pos + rel);
134 int ByteArray_set_position(struct ByteArray* self, off_t pos) {
135 if(pos == self->pos) return 1;
136 if(pos > self->size) {
137 oob(self->filename, pos, self->size);
138 return 0;
141 if(self->type == BAT_FILESTREAM) {
142 off_t ret = lseek(self->source.fd, pos, SEEK_SET);
143 if(ret == (off_t) -1) {
144 seek_error();
145 return 0;
148 self->pos = pos;
149 return 1;
152 static void read_error() {
153 perror("read error!\n");
154 assert_dbg(0);
157 static void read_error_short() {
158 perror("read error (short)!\n");
159 assert_dbg(0);
162 int ByteArray_open_file(struct ByteArray* self, const char* filename) {
163 struct stat st;
164 self->type = BAT_FILESTREAM;
165 self->pos = 0;
166 self->size = 0;
167 if(stat(filename, &st) == -1) return 0;
168 self->size = st.st_size;
169 self->filename = filename;
170 self->source.fd = open(filename, O_RDONLY|O_BINARY);
171 if (self->source.fd == -1) return 0;
172 void *addr = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->source.fd, 0);
173 if(addr == MAP_FAILED) {
174 if(!BLOWS) perror("mmap");
175 return 1;
177 return ByteArray_open_mem(self, addr, self->size);
180 void ByteArray_close_file(struct ByteArray *self) {
181 close(self->source.fd);
182 self->source.fd = -1;
185 int ByteArray_open_mem(struct ByteArray* self, char* data, size_t size) {
186 self->size = size;
187 self->type = BAT_MEMSTREAM;
188 mem_set(&self->source.mem, data, size, size);
189 return 1;
192 ssize_t ByteArray_readMultiByte(struct ByteArray* self, char* buffer, size_t len) {
193 if(self->type == BAT_MEMSTREAM) {
194 assert_op((size_t) self->pos + len, <=, (size_t) self->size);
195 void *p = mem_getptr(&self->source.mem, self->pos, len);
196 if(p) memcpy(buffer, p, len);
197 else return -1;
198 } else {
199 ssize_t ret = read(self->source.fd, buffer, len);
200 if(ret == -1) {
201 read_error();
202 return -1;
203 } else if((size_t) ret != len) {
204 read_error_short();
205 self->pos += len;
206 return -1;
209 self->pos += len;
210 return len;
213 // write contents of self into dest
214 // if len == 0 all available bytes are used.
215 // self->pos is considered the start offset to use for self.
216 // the position in dest will not be advanced.
217 // the position in source will be advanced len bytes.
218 // returns the number of bytes written
219 off_t ByteArray_readBytes(struct ByteArray* self, struct ByteArray *dest, off_t start, off_t len) {
220 off_t left = self->size - self->pos;
221 if(len == 0) len = left;
222 else if(len > left) {
223 oob(self->filename, len, left);
224 len = left;
226 if(len == 0) return 0;
227 else if (len > start + dest->size) {
228 oob(self->filename, len, start + dest->size);
229 len = start + dest->size;
230 if(len == 0) return 0;
232 if(dest->type != BAT_MEMSTREAM) {
233 assert_dbg(0);
235 void *p = mem_getptr(&dest->source.mem, start, len);
236 if(p) self->readMultiByte(self, p, len);
237 else return 0;
238 return len;
241 off_t ByteArray_bytesAvailable(struct ByteArray* self) {
242 if(self->pos < self->size) return self->size - self->pos;
243 return 0;
246 unsigned long long ByteArray_readUnsignedLongLong(struct ByteArray* self) {
247 union {
248 unsigned long long intval;
249 unsigned char charval[sizeof(unsigned long long)];
250 } buf;
251 self->readMultiByte(self, (char*) buf.charval, 8);
252 if(self->endian != self->sys_endian) {
253 buf.intval = end_bswap64(buf.intval);
255 return buf.intval;
258 unsigned int ByteArray_readUnsignedInt(struct ByteArray* self) {
259 union {
260 unsigned int intval;
261 unsigned char charval[sizeof(unsigned int)];
262 } buf;
263 self->readMultiByte(self, (char*) buf.charval, 4);
264 if(self->endian != self->sys_endian) {
265 buf.intval = end_bswap32(buf.intval);
267 return buf.intval;
270 int ByteArray_readInt(struct ByteArray* self) {
271 union {
272 unsigned int intval;
273 unsigned char charval[sizeof(unsigned int)];
274 } buf;
275 self->readMultiByte(self, (char*) buf.charval, 4);
276 if(self->endian != self->sys_endian) {
277 buf.intval = end_bswap32(buf.intval);
279 return buf.intval;
282 unsigned short ByteArray_readUnsignedShort(struct ByteArray* self) {
283 union {
284 unsigned short intval;
285 unsigned char charval[sizeof(unsigned short)];
286 } buf;
287 self->readMultiByte(self, (char*) buf.charval, 2);
288 if(self->endian != self->sys_endian) {
289 buf.intval = end_bswap16(buf.intval);
291 return buf.intval;
294 short ByteArray_readShort(struct ByteArray* self) {
295 union {
296 unsigned short intval;
297 unsigned char charval[sizeof(unsigned short)];
298 } buf;
299 self->readMultiByte(self, (char*) buf.charval, 2);
300 if(self->endian != self->sys_endian) {
301 buf.intval = end_bswap16(buf.intval);
303 return buf.intval;
306 unsigned char ByteArray_readUnsignedByte(struct ByteArray* self) {
307 union {
308 unsigned char intval;
309 } buf;
310 self->readMultiByte(self, (char*) &buf.intval, 1);
311 return buf.intval;
314 signed char ByteArray_readByte(struct ByteArray* self) {
315 union {
316 signed char intval;
317 } buf;
318 self->readMultiByte(self, (char*) &buf.intval, 1);
319 return buf.intval;
322 /* equivalent to foo = self[x]; (pos stays unchanged) */
323 unsigned char ByteArray_getUnsignedByte(struct ByteArray* self, off_t index) {
324 //assert_op(self->type, ==, BAT_MEMSTREAM);
325 assert_op(index, <, self->size);
326 off_t save = self->pos;
327 unsigned char res;
328 ByteArray_set_position(self, index);
329 res = ByteArray_readUnsignedByte(self);
330 ByteArray_set_position(self, save);
331 return res;
334 /* equivalent to self[x] = what (pos stays unchanged) */
335 void ByteArray_setUnsignedByte(struct ByteArray* self, off_t index, unsigned char what) {
336 off_t save = self->pos;
337 if(ByteArray_set_position(self, index)) {
338 ByteArray_writeUnsignedByte(self, what);
339 self->pos = save;
343 off_t ByteArray_writeByte(struct ByteArray* self, signed char what) {
344 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
347 off_t ByteArray_writeUnsignedByte(struct ByteArray* self, unsigned char what) {
348 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
351 off_t ByteArray_writeShort(struct ByteArray* self, signed short what) {
352 union {
353 short intval;
354 unsigned char charval[sizeof(what)];
355 } u;
356 u.intval = what;
357 if(self->sys_endian != self->endian) {
358 u.intval = end_bswap16(u.intval);
360 return ByteArray_writeMem(self, u.charval, sizeof(what));
363 off_t ByteArray_writeUnsignedShort(struct ByteArray* self, unsigned short what) {
364 union {
365 unsigned short intval;
366 unsigned char charval[sizeof(what)];
367 } u;
368 u.intval = what;
369 if(self->sys_endian != self->endian) {
370 u.intval = end_bswap16(u.intval);
372 return ByteArray_writeMem(self, u.charval, sizeof(what));
375 off_t ByteArray_writeInt(struct ByteArray* self, signed int what) {
376 union {
377 int intval;
378 unsigned char charval[sizeof(what)];
379 } u;
380 u.intval = what;
381 if(self->sys_endian != self->endian) {
382 u.intval = end_bswap32(u.intval);
384 return ByteArray_writeMem(self, u.charval, sizeof(what));
387 off_t ByteArray_writeUnsignedInt(struct ByteArray* self, unsigned int what) {
388 union {
389 unsigned int intval;
390 unsigned char charval[sizeof(what)];
391 } u;
392 u.intval = what;
393 if(self->sys_endian != self->endian) {
394 u.intval = end_bswap32(u.intval);
396 return ByteArray_writeMem(self, u.charval, sizeof(what));
399 off_t ByteArray_writeMem(struct ByteArray* self, unsigned char* what, size_t len) {
400 if(self->type == BAT_FILESTREAM) {
401 fprintf(stderr, "tried to write to file!\n");
402 assert_dbg(0);
403 return 0;
405 if(!(self->flags & BAF_CANGROW) && (size_t) self->pos + len > (size_t) self->size) {
406 fprintf(stderr, "oob write attempted");
407 assert_dbg(0);
408 return 0;
411 if(mem_write(&self->source.mem, self->pos, what, len)) {
412 self->pos += len;
413 if(self->pos > self->size) self->size = self->pos; /* apparently CANGROW was used */
415 return len;
418 off_t ByteArray_writeUTFBytes(struct ByteArray* self, char* what) {
419 return ByteArray_writeMem(self, (unsigned char*) what, strlen(what));
422 // write contents of what into self
423 off_t ByteArray_writeBytes(struct ByteArray* self, struct ByteArray* what) {
424 if(what->type == BAT_FILESTREAM) {
425 fprintf(stderr, "tried to write from non-memory stream\n");
426 assert_dbg(0);
427 return 0;
428 } else {
429 unsigned char* p = mem_getptr(&what->source.mem, what->pos, what->size - what->pos);
430 if(p)
431 return ByteArray_writeMem(self, p, what->size - what->pos);
432 return -1;
436 off_t ByteArray_writeFloat(struct ByteArray* self, float what) {
437 union {
438 float floatval;
439 unsigned int intval;
440 unsigned char charval[sizeof(what)];
441 } u;
442 u.floatval = what;
443 if(self->sys_endian != self->endian) {
444 u.intval = end_bswap32(u.intval);
446 return ByteArray_writeMem(self, u.charval, sizeof(what));
449 void ByteArray_dump_to_stream(struct ByteArray* self, FILE *out) {
450 assert_op(self->type, ==, BAT_MEMSTREAM);
451 mem_write_stream(&self->source.mem, out);
454 void ByteArray_dump_to_file(struct ByteArray* self, char* filename) {
455 assert_op(self->type, ==, BAT_MEMSTREAM);
456 mem_write_file(&self->source.mem, filename);