File: support for long long
[rofl0r-agsutils.git] / ByteArray.c
blobec915f939847907533f8ccacea6db6d795c75742
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->readUnsignedLongLong = ByteArray_readUnsignedLongLong;
26 self->readBytes = ByteArray_readBytes;
28 self->writeInt = ByteArray_writeInt;
29 self->writeUnsignedInt = ByteArray_writeUnsignedInt;
30 self->writeShort = ByteArray_writeShort;
31 self->writeUnsignedShort = ByteArray_writeUnsignedShort;
32 self->writeByte = ByteArray_writeByte;
33 self->writeUnsignedByte = ByteArray_writeUnsignedByte;;
34 self->writeMem = ByteArray_writeMem;
35 self->writeUTFBytes = ByteArray_writeUTFBytes;
36 self->writeBytes = ByteArray_writeBytes;
37 self->writeFloat = ByteArray_writeFloat;
39 self->set_position = ByteArray_set_position;
40 self->set_position_rel = ByteArray_set_position_rel;
41 self->get_position = ByteArray_get_position;
43 self->bytesAvailable = ByteArray_bytesAvailable;
45 #ifdef IS_LITTLE_ENDIAN
46 self->sys_endian = BAE_LITTLE;
47 #else
48 self->sys_endian = BAE_BIG;
49 #endif
52 struct ByteArray* ByteArray_new(void) {
53 struct ByteArray* self = (struct ByteArray*) malloc(sizeof(*self));
54 if(self) ByteArray_ctor(self);
55 return self;
58 void ByteArray_set_endian(struct ByteArray* self, enum ByteArray_Endianess endian) {
59 self->endian = endian;
62 void ByteArray_set_flags(struct ByteArray *self, int flags) {
63 self->flags = flags;
66 enum ByteArray_Endianess ByteArray_get_endian(struct ByteArray* self) {
67 return self->endian;
70 // a real byte array clears the mem and resets
71 // "len" and pos to 0
72 // where len is equivalent to the bytes written into it
73 //void* mem_getptr(MG* mem, size_t offset, size_t byteswanted);
74 void ByteArray_clear(struct ByteArray* self) {
75 fprintf(stderr, "clear called\n");
76 assert_op(self->type, ==, BAT_MEMSTREAM);
77 void *p = mem_getptr(&self->source.mem, 0, self->size);
78 if(p) memset(p, 0, self->size);
81 void ByteArray_close(struct ByteArray* self) {
82 assert_op(self->type, ==, BAT_MEMSTREAM);
83 mem_free(&self->source.mem);
86 off_t ByteArray_get_position(struct ByteArray* self) {
87 return self->pos;
90 static void seek_error() {
91 perror("seek error!\n");
92 assert_dbg(0);
95 static void neg_off() {
96 fprintf(stderr, "negative seek attempted\n");
97 assert_dbg(0);
100 static void oob() {
101 fprintf(stderr, "oob access attempted\n");
102 assert_dbg(0);
105 void ByteArray_set_length(struct ByteArray* self, off_t len) {
106 if(len > self->size) {
107 oob();
108 return;
110 self->size = len;
113 off_t ByteArray_get_length(struct ByteArray* self) {
114 return self->size;
117 int ByteArray_set_position_rel(struct ByteArray* self, int rel) {
118 if((int) self->pos + rel < 0) {
119 neg_off();
120 rel = -self->pos;
122 return ByteArray_set_position(self, self->pos + rel);
125 int ByteArray_set_position(struct ByteArray* self, off_t pos) {
126 if(pos == self->pos) return 1;
127 if(pos > self->size) {
128 oob();
129 return 0;
132 if(self->type == BAT_FILESTREAM) {
133 off_t ret = lseek(self->source.fd, pos, SEEK_SET);
134 if(ret == (off_t) -1) {
135 seek_error();
136 return 0;
139 self->pos = pos;
140 return 1;
143 static void read_error() {
144 perror("read error!\n");
145 assert_dbg(0);
148 static void read_error_short() {
149 perror("read error (short)!\n");
150 assert_dbg(0);
153 int ByteArray_open_file(struct ByteArray* self, const char* filename) {
154 struct stat st;
155 self->type = BAT_FILESTREAM;
156 self->pos = 0;
157 self->size = 0;
158 if(stat(filename, &st) == -1) return 0;
159 self->size = st.st_size;
160 self->source.fd = open(filename, O_RDONLY);
161 if (self->source.fd == -1) return 0;
162 void *addr = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->source.fd, 0);
163 if(addr == MAP_FAILED) {
164 perror("mmap");
165 return 1;
167 return ByteArray_open_mem(self, addr, self->size);
170 void ByteArray_close_file(struct ByteArray *self) {
171 close(self->source.fd);
172 self->source.fd = -1;
175 int ByteArray_open_mem(struct ByteArray* self, char* data, size_t size) {
176 self->size = size;
177 self->type = BAT_MEMSTREAM;
178 mem_set(&self->source.mem, data, size, size);
179 return 1;
182 ssize_t ByteArray_readMultiByte(struct ByteArray* self, char* buffer, size_t len) {
183 if(self->type == BAT_MEMSTREAM) {
184 assert_op((size_t) self->pos + len, <=, (size_t) self->size);
185 void *p = mem_getptr(&self->source.mem, self->pos, len);
186 if(p) memcpy(buffer, p, len);
187 else return -1;
188 } else {
189 ssize_t ret = read(self->source.fd, buffer, len);
190 if(ret == -1) {
191 read_error();
192 return -1;
193 } else if((size_t) ret != len) {
194 read_error_short();
195 self->pos += len;
196 return -1;
199 self->pos += len;
200 return len;
203 // write contents of self into dest
204 // if len == 0 all available bytes are used.
205 // self->pos is considered the start offset to use for self.
206 // the position in dest will not be advanced.
207 // the position in source will be advanced len bytes.
208 // returns the number of bytes written
209 off_t ByteArray_readBytes(struct ByteArray* self, struct ByteArray *dest, off_t start, off_t len) {
210 off_t left = self->size - self->pos;
211 if(len == 0) len = left;
212 else if(len > left) {
213 oob();
214 len = left;
216 if(len == 0) return 0;
217 else if (len > start + dest->size) {
218 oob();
219 len = start + dest->size;
220 if(len == 0) return 0;
222 if(dest->type != BAT_MEMSTREAM) {
223 assert_dbg(0);
225 void *p = mem_getptr(&dest->source.mem, start, len);
226 if(p) self->readMultiByte(self, p, len);
227 else return 0;
228 return len;
231 off_t ByteArray_bytesAvailable(struct ByteArray* self) {
232 if(self->pos < self->size) return self->size - self->pos;
233 return 0;
236 unsigned long long ByteArray_readUnsignedLongLong(struct ByteArray* self) {
237 union {
238 unsigned long long intval;
239 unsigned char charval[sizeof(unsigned long long)];
240 } buf;
241 self->readMultiByte(self, (char*) buf.charval, 8);
242 if(self->endian != self->sys_endian) {
243 buf.intval = byteswap64(buf.intval);
245 return buf.intval;
248 unsigned int ByteArray_readUnsignedInt(struct ByteArray* self) {
249 union {
250 unsigned int intval;
251 unsigned char charval[sizeof(unsigned int)];
252 } buf;
253 self->readMultiByte(self, (char*) buf.charval, 4);
254 if(self->endian != self->sys_endian) {
255 buf.intval = byteswap32(buf.intval);
257 return buf.intval;
260 int ByteArray_readInt(struct ByteArray* self) {
261 union {
262 unsigned int intval;
263 unsigned char charval[sizeof(unsigned int)];
264 } buf;
265 self->readMultiByte(self, (char*) buf.charval, 4);
266 if(self->endian != self->sys_endian) {
267 buf.intval = byteswap32(buf.intval);
269 return buf.intval;
272 unsigned short ByteArray_readUnsignedShort(struct ByteArray* self) {
273 union {
274 unsigned short intval;
275 unsigned char charval[sizeof(unsigned short)];
276 } buf;
277 self->readMultiByte(self, (char*) buf.charval, 2);
278 if(self->endian != self->sys_endian) {
279 buf.intval = byteswap16(buf.intval);
281 return buf.intval;
284 short ByteArray_readShort(struct ByteArray* self) {
285 union {
286 unsigned short intval;
287 unsigned char charval[sizeof(unsigned short)];
288 } buf;
289 self->readMultiByte(self, (char*) buf.charval, 2);
290 if(self->endian != self->sys_endian) {
291 buf.intval = byteswap16(buf.intval);
293 return buf.intval;
296 unsigned char ByteArray_readUnsignedByte(struct ByteArray* self) {
297 union {
298 unsigned char intval;
299 } buf;
300 self->readMultiByte(self, (char*) &buf.intval, 1);
301 return buf.intval;
304 signed char ByteArray_readByte(struct ByteArray* self) {
305 union {
306 signed char intval;
307 } buf;
308 self->readMultiByte(self, (char*) &buf.intval, 1);
309 return buf.intval;
312 /* equivalent to foo = self[x]; (pos stays unchanged) */
313 unsigned char ByteArray_getUnsignedByte(struct ByteArray* self, off_t index) {
314 //assert_op(self->type, ==, BAT_MEMSTREAM);
315 assert_op(index, <, self->size);
316 off_t save = self->pos;
317 unsigned char res;
318 ByteArray_set_position(self, index);
319 res = ByteArray_readUnsignedByte(self);
320 ByteArray_set_position(self, save);
321 return res;
324 /* equivalent to self[x] = what (pos stays unchanged) */
325 void ByteArray_setUnsignedByte(struct ByteArray* self, off_t index, unsigned char what) {
326 off_t save = self->pos;
327 if(ByteArray_set_position(self, index)) {
328 ByteArray_writeUnsignedByte(self, what);
329 self->pos = save;
333 off_t ByteArray_writeByte(struct ByteArray* self, signed char what) {
334 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
337 off_t ByteArray_writeUnsignedByte(struct ByteArray* self, unsigned char what) {
338 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
341 off_t ByteArray_writeShort(struct ByteArray* self, signed short what) {
342 union {
343 short intval;
344 unsigned char charval[sizeof(what)];
345 } u;
346 u.intval = what;
347 if(self->sys_endian != self->endian) {
348 u.intval = byteswap16(u.intval);
350 return ByteArray_writeMem(self, u.charval, sizeof(what));
353 off_t ByteArray_writeUnsignedShort(struct ByteArray* self, unsigned short what) {
354 union {
355 unsigned short intval;
356 unsigned char charval[sizeof(what)];
357 } u;
358 u.intval = what;
359 if(self->sys_endian != self->endian) {
360 u.intval = byteswap16(u.intval);
362 return ByteArray_writeMem(self, u.charval, sizeof(what));
365 off_t ByteArray_writeInt(struct ByteArray* self, signed int what) {
366 union {
367 int intval;
368 unsigned char charval[sizeof(what)];
369 } u;
370 u.intval = what;
371 if(self->sys_endian != self->endian) {
372 u.intval = byteswap32(u.intval);
374 return ByteArray_writeMem(self, u.charval, sizeof(what));
377 off_t ByteArray_writeUnsignedInt(struct ByteArray* self, unsigned int what) {
378 union {
379 unsigned int intval;
380 unsigned char charval[sizeof(what)];
381 } u;
382 u.intval = what;
383 if(self->sys_endian != self->endian) {
384 u.intval = byteswap32(u.intval);
386 return ByteArray_writeMem(self, u.charval, sizeof(what));
389 off_t ByteArray_writeMem(struct ByteArray* self, unsigned char* what, size_t len) {
390 if(self->type == BAT_FILESTREAM) {
391 fprintf(stderr, "tried to write to file!\n");
392 assert_dbg(0);
393 return 0;
395 if(!(self->flags & BAF_CANGROW) && (size_t) self->pos + len > (size_t) self->size) {
396 fprintf(stderr, "oob write attempted");
397 assert_dbg(0);
398 return 0;
401 if(mem_write(&self->source.mem, self->pos, what, len)) {
402 self->pos += len;
403 if(self->pos > self->size) self->size = self->pos; /* apparently CANGROW was used */
405 return len;
408 off_t ByteArray_writeUTFBytes(struct ByteArray* self, char* what) {
409 return ByteArray_writeMem(self, (unsigned char*) what, strlen(what));
412 // write contents of what into self
413 off_t ByteArray_writeBytes(struct ByteArray* self, struct ByteArray* what) {
414 if(what->type == BAT_FILESTREAM) {
415 fprintf(stderr, "tried to write from non-memory stream\n");
416 assert_dbg(0);
417 return 0;
418 } else {
419 unsigned char* p = mem_getptr(&what->source.mem, what->pos, what->size - what->pos);
420 if(p)
421 return ByteArray_writeMem(self, p, what->size - what->pos);
422 return -1;
426 off_t ByteArray_writeFloat(struct ByteArray* self, float what) {
427 union {
428 float floatval;
429 unsigned int intval;
430 unsigned char charval[sizeof(what)];
431 } u;
432 u.floatval = what;
433 if(self->sys_endian != self->endian) {
434 u.intval = byteswap32(u.intval);
436 return ByteArray_writeMem(self, u.charval, sizeof(what));
439 void ByteArray_dump_to_stream(struct ByteArray* self, FILE *out) {
440 assert_op(self->type, ==, BAT_MEMSTREAM);
441 mem_write_stream(&self->source.mem, out);
444 void ByteArray_dump_to_file(struct ByteArray* self, char* filename) {
445 assert_op(self->type, ==, BAT_MEMSTREAM);
446 mem_write_file(&self->source.mem, filename);