hbmap: fix iterator truncation when size_t < 32bit
[rofl0r-agsutils.git] / ByteArray.c
bloba5a5ff459ab9e1b2fb6f28f2245f9cda1d39a317
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 <errno.h>
14 #include <stdlib.h>
15 #ifndef NO_MMAN /* lame OS like winblows */
16 #include <sys/mman.h>
17 #define BLOWS 0
18 #else
19 #define mmap(...) (void*)0xffffffff
20 #define MAP_FAILED (void*)0xffffffff
21 #define BLOWS 1
22 #endif
24 void ByteArray_defaults(struct ByteArray* self) {
25 memset(self, 0, sizeof(*self));
28 void ByteArray_ctor(struct ByteArray* self) {
29 ByteArray_defaults(self);
30 // original constructor code goes here
31 self->readMultiByte = ByteArray_readMultiByte;
32 self->readByte = ByteArray_readByte;
33 self->readUnsignedByte = ByteArray_readUnsignedByte;
34 self->readShort = ByteArray_readShort;
35 self->readUnsignedShort = ByteArray_readUnsignedShort;
36 self->readInt = ByteArray_readInt;
37 self->readUnsignedInt = ByteArray_readUnsignedInt;
38 self->readUnsignedLongLong = ByteArray_readUnsignedLongLong;
39 self->readBytes = ByteArray_readBytes;
41 self->writeInt = ByteArray_writeInt;
42 self->writeUnsignedInt = ByteArray_writeUnsignedInt;
43 self->writeShort = ByteArray_writeShort;
44 self->writeUnsignedShort = ByteArray_writeUnsignedShort;
45 self->writeByte = ByteArray_writeByte;
46 self->writeUnsignedByte = ByteArray_writeUnsignedByte;;
47 self->writeMem = ByteArray_writeMem;
48 self->writeUTFBytes = ByteArray_writeUTFBytes;
49 self->writeBytes = ByteArray_writeBytes;
50 self->writeFloat = ByteArray_writeFloat;
52 self->set_position = ByteArray_set_position;
53 self->set_position_rel = ByteArray_set_position_rel;
54 self->get_position = ByteArray_get_position;
56 self->bytesAvailable = ByteArray_bytesAvailable;
58 self->sys_endian = ENDIANNESS_BE ? BAE_BIG : BAE_LITTLE;
61 struct ByteArray* ByteArray_new(void) {
62 struct ByteArray* self = (struct ByteArray*) malloc(sizeof(*self));
63 if(self) ByteArray_ctor(self);
64 return self;
67 void ByteArray_set_endian(struct ByteArray* self, enum ByteArray_Endianess endian) {
68 self->endian = endian;
71 void ByteArray_set_flags(struct ByteArray *self, int flags) {
72 self->flags = flags;
75 enum ByteArray_Endianess ByteArray_get_endian(struct ByteArray* self) {
76 return self->endian;
79 // a real byte array clears the mem and resets
80 // "len" and pos to 0
81 // where len is equivalent to the bytes written into it
82 //void* mem_getptr(MG* mem, size_t offset, size_t byteswanted);
83 void ByteArray_clear(struct ByteArray* self) {
84 fprintf(stderr, "clear called\n");
85 assert_op(self->type, ==, BAT_MEMSTREAM);
86 void *p = mem_getptr(&self->source_mem, 0, self->size);
87 if(p) memset(p, 0, self->size);
90 void ByteArray_close(struct ByteArray* self) {
91 assert_op(self->type, ==, BAT_MEMSTREAM);
92 mem_free(&self->source_mem);
95 off_t ByteArray_get_position(struct ByteArray* self) {
96 return self->pos;
99 static void seek_error() {
100 perror("seek error!\n");
101 assert_dbg(0);
104 static void neg_off() {
105 fprintf(stderr, "negative seek attempted\n");
106 assert_dbg(0);
109 static void oob(const char *fn, off_t want, off_t have) {
110 fprintf(stderr, "%s: oob access attempted (want: %jd, have %jd)\n", fn ? fn : "<unknown>", (intmax_t) want, (intmax_t) have);
111 fflush(stderr);
112 assert_dbg(0);
115 void ByteArray_set_length(struct ByteArray* self, off_t len) {
116 if(len > self->size) {
117 oob(self->filename, len, self->size);
118 return;
120 self->size = len;
123 off_t ByteArray_get_length(struct ByteArray* self) {
124 return self->size;
127 int ByteArray_set_position_rel(struct ByteArray* self, int rel) {
128 if((int) self->pos + rel < 0) {
129 neg_off();
130 rel = -self->pos;
132 return ByteArray_set_position(self, self->pos + rel);
135 int ByteArray_set_position(struct ByteArray* self, off_t pos) {
136 if(pos == self->pos) return 1;
137 if(pos > self->size) {
138 oob(self->filename, pos, self->size);
139 return 0;
142 if(self->type == BAT_FILESTREAM) {
143 off_t ret = lseek(self->source_fd, pos, SEEK_SET);
144 if(ret == (off_t) -1) {
145 seek_error();
146 return 0;
149 self->pos = pos;
150 return 1;
153 static void read_error() {
154 perror("read error!\n");
155 assert_dbg(0);
158 static void read_error_short() {
159 perror("read error (short)!\n");
160 assert_dbg(0);
163 int ByteArray_open_file(struct ByteArray* self, const char* filename) {
164 struct stat st;
165 self->type = BAT_FILESTREAM;
166 self->pos = 0;
167 self->size = 0;
168 if(stat(filename, &st) == -1) return 0;
169 self->size = st.st_size;
170 self->filename = filename;
171 self->source_fd = open(filename, O_RDONLY|O_BINARY);
172 if (self->source_fd == -1) return 0;
173 void *addr = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->source_fd, 0);
174 if(addr == MAP_FAILED) {
175 if(!BLOWS)
176 fprintf(stderr, "mmap %s failed (%s) - fd %d, size %llu\n", filename, strerror(errno), self->source_fd, (long long) self->size);
177 #ifdef __POCC__
178 if(sizeof(off_t) < 8 && self->size < 0)
179 fprintf(stderr, "sorry, the PellesC compiled 32 bit windows binaries do not support files > 2GB at this point.\nplease compile from source in a linux environment, WSL or cygwin to access this file.\n");
180 #endif
181 return 1; // fall back to traditional non-mmaped BAT_FILESTREAM
183 return ByteArray_open_mem(self, addr, self->size);
186 void ByteArray_close_file(struct ByteArray *self) {
187 if(self->type == BAT_MEMSTREAM) {
188 munmap(self->source_mem.mem, self->size);
189 self->source_mem.mem = 0;
191 close(self->source_fd);
192 self->source_fd = -1;
195 int ByteArray_open_mem(struct ByteArray* self, char* data, size_t size) {
196 self->size = size;
197 self->type = BAT_MEMSTREAM;
198 mem_set(&self->source_mem, data, size, size);
199 return 1;
202 void* ByteArray_get_mem(struct ByteArray* self, size_t offset, size_t byteswanted) {
203 assert_dbg(self->type == BAT_MEMSTREAM);
204 return mem_getptr(&self->source_mem, offset, byteswanted);
207 ssize_t ByteArray_readMultiByte(struct ByteArray* self, char* buffer, size_t len) {
208 if(self->type == BAT_MEMSTREAM) {
209 assert_op((size_t) self->pos + len, <=, (size_t) self->size);
210 void *p = mem_getptr(&self->source_mem, self->pos, len);
211 if(p) memcpy(buffer, p, len);
212 else return -1;
213 } else {
214 ssize_t ret = read(self->source_fd, buffer, len);
215 if(ret == -1) {
216 read_error();
217 return -1;
218 } else if((size_t) ret != len) {
219 read_error_short();
220 self->pos += len;
221 return -1;
224 self->pos += len;
225 return len;
228 // write contents of self into dest
229 // if len == 0 all available bytes are used.
230 // self->pos is considered the start offset to use for self.
231 // the position in dest will not be advanced.
232 // the position in source will be advanced len bytes.
233 // returns the number of bytes written
234 off_t ByteArray_readBytes(struct ByteArray* self, struct ByteArray *dest, off_t start, off_t len) {
235 off_t left = self->size - self->pos;
236 if(len == 0) len = left;
237 else if(len > left) {
238 oob(self->filename, len, left);
239 len = left;
241 if(len == 0) return 0;
242 else if (len > start + dest->size) {
243 oob(self->filename, len, start + dest->size);
244 len = start + dest->size;
245 if(len == 0) return 0;
247 if(dest->type != BAT_MEMSTREAM) {
248 assert_dbg(0);
250 void *p = mem_getptr(&dest->source_mem, start, len);
251 if(p) self->readMultiByte(self, p, len);
252 else return 0;
253 return len;
256 off_t ByteArray_bytesAvailable(struct ByteArray* self) {
257 if(self->pos < self->size) return self->size - self->pos;
258 return 0;
261 unsigned long long ByteArray_readUnsignedLongLong(struct ByteArray* self) {
262 union {
263 unsigned long long intval;
264 unsigned char charval[sizeof(unsigned long long)];
265 } buf;
266 self->readMultiByte(self, (char*) buf.charval, 8);
267 if(self->endian != self->sys_endian) {
268 buf.intval = end_bswap64(buf.intval);
270 return buf.intval;
273 unsigned int ByteArray_readUnsignedInt(struct ByteArray* self) {
274 union {
275 unsigned int intval;
276 unsigned char charval[sizeof(unsigned int)];
277 } buf;
278 self->readMultiByte(self, (char*) buf.charval, 4);
279 if(self->endian != self->sys_endian) {
280 buf.intval = end_bswap32(buf.intval);
282 return buf.intval;
285 int ByteArray_readInt(struct ByteArray* self) {
286 union {
287 unsigned int intval;
288 unsigned char charval[sizeof(unsigned int)];
289 } buf;
290 self->readMultiByte(self, (char*) buf.charval, 4);
291 if(self->endian != self->sys_endian) {
292 buf.intval = end_bswap32(buf.intval);
294 return buf.intval;
297 unsigned short ByteArray_readUnsignedShort(struct ByteArray* self) {
298 union {
299 unsigned short intval;
300 unsigned char charval[sizeof(unsigned short)];
301 } buf;
302 self->readMultiByte(self, (char*) buf.charval, 2);
303 if(self->endian != self->sys_endian) {
304 buf.intval = end_bswap16(buf.intval);
306 return buf.intval;
309 short ByteArray_readShort(struct ByteArray* self) {
310 union {
311 unsigned short intval;
312 unsigned char charval[sizeof(unsigned short)];
313 } buf;
314 self->readMultiByte(self, (char*) buf.charval, 2);
315 if(self->endian != self->sys_endian) {
316 buf.intval = end_bswap16(buf.intval);
318 return buf.intval;
321 unsigned char ByteArray_readUnsignedByte(struct ByteArray* self) {
322 union {
323 unsigned char intval;
324 } buf;
325 self->readMultiByte(self, (char*) &buf.intval, 1);
326 return buf.intval;
329 signed char ByteArray_readByte(struct ByteArray* self) {
330 union {
331 signed char intval;
332 } buf;
333 self->readMultiByte(self, (char*) &buf.intval, 1);
334 return buf.intval;
337 /* equivalent to foo = self[x]; (pos stays unchanged) */
338 unsigned char ByteArray_getUnsignedByte(struct ByteArray* self, off_t index) {
339 //assert_op(self->type, ==, BAT_MEMSTREAM);
340 assert_op(index, <, self->size);
341 off_t save = self->pos;
342 unsigned char res;
343 ByteArray_set_position(self, index);
344 res = ByteArray_readUnsignedByte(self);
345 ByteArray_set_position(self, save);
346 return res;
349 /* equivalent to self[x] = what (pos stays unchanged) */
350 void ByteArray_setUnsignedByte(struct ByteArray* self, off_t index, unsigned char what) {
351 off_t save = self->pos;
352 if(ByteArray_set_position(self, index)) {
353 ByteArray_writeUnsignedByte(self, what);
354 self->pos = save;
358 off_t ByteArray_writeByte(struct ByteArray* self, signed char what) {
359 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
362 off_t ByteArray_writeUnsignedByte(struct ByteArray* self, unsigned char what) {
363 return ByteArray_writeMem(self, (unsigned char*) &what, 1);
366 off_t ByteArray_writeShort(struct ByteArray* self, signed short what) {
367 union {
368 short intval;
369 unsigned char charval[sizeof(what)];
370 } u;
371 u.intval = what;
372 if(self->sys_endian != self->endian) {
373 u.intval = end_bswap16(u.intval);
375 return ByteArray_writeMem(self, u.charval, sizeof(what));
378 off_t ByteArray_writeUnsignedShort(struct ByteArray* self, unsigned short what) {
379 union {
380 unsigned short intval;
381 unsigned char charval[sizeof(what)];
382 } u;
383 u.intval = what;
384 if(self->sys_endian != self->endian) {
385 u.intval = end_bswap16(u.intval);
387 return ByteArray_writeMem(self, u.charval, sizeof(what));
390 off_t ByteArray_writeInt(struct ByteArray* self, signed int what) {
391 union {
392 int intval;
393 unsigned char charval[sizeof(what)];
394 } u;
395 u.intval = what;
396 if(self->sys_endian != self->endian) {
397 u.intval = end_bswap32(u.intval);
399 return ByteArray_writeMem(self, u.charval, sizeof(what));
402 off_t ByteArray_writeUnsignedInt(struct ByteArray* self, unsigned int what) {
403 union {
404 unsigned int intval;
405 unsigned char charval[sizeof(what)];
406 } u;
407 u.intval = what;
408 if(self->sys_endian != self->endian) {
409 u.intval = end_bswap32(u.intval);
411 return ByteArray_writeMem(self, u.charval, sizeof(what));
414 off_t ByteArray_writeMem(struct ByteArray* self, unsigned char* what, size_t len) {
415 if(self->type == BAT_FILESTREAM) {
416 fprintf(stderr, "tried to write to file!\n");
417 assert_dbg(0);
418 return 0;
420 if(!(self->flags & BAF_CANGROW) && (size_t) self->pos + len > (size_t) self->size) {
421 fprintf(stderr, "oob write attempted");
422 assert_dbg(0);
423 return 0;
426 if(mem_write(&self->source_mem, self->pos, what, len)) {
427 self->pos += len;
428 if(self->pos > self->size) self->size = self->pos; /* apparently CANGROW was used */
430 return len;
433 off_t ByteArray_writeUTFBytes(struct ByteArray* self, char* what) {
434 return ByteArray_writeMem(self, (unsigned char*) what, strlen(what));
437 // write contents of what into self
438 off_t ByteArray_writeBytes(struct ByteArray* self, struct ByteArray* what) {
439 if(what->type == BAT_FILESTREAM) {
440 fprintf(stderr, "tried to write from non-memory stream\n");
441 assert_dbg(0);
442 return 0;
443 } else {
444 unsigned char* p = mem_getptr(&what->source_mem, what->pos, what->size - what->pos);
445 if(p)
446 return ByteArray_writeMem(self, p, what->size - what->pos);
447 return -1;
451 off_t ByteArray_writeFloat(struct ByteArray* self, float what) {
452 union {
453 float floatval;
454 unsigned int intval;
455 unsigned char charval[sizeof(what)];
456 } u;
457 u.floatval = what;
458 if(self->sys_endian != self->endian) {
459 u.intval = end_bswap32(u.intval);
461 return ByteArray_writeMem(self, u.charval, sizeof(what));
464 void ByteArray_dump_to_stream(struct ByteArray* self, FILE *out) {
465 assert_op(self->type, ==, BAT_MEMSTREAM);
466 mem_write_stream(&self->source_mem, out);
469 void ByteArray_dump_to_file(struct ByteArray* self, char* filename) {
470 assert_op(self->type, ==, BAT_MEMSTREAM);
471 mem_write_file(&self->source_mem, filename);