1 /* ByteArray (C) 2012 rofl0r
3 * licensed under the LGPL 2.1+ */
7 #include "endianness.h"
15 #ifndef NO_MMAN /* lame OS like winblows */
19 #define mmap(...) (void*)0xffffffff
20 #define MAP_FAILED (void*)0xffffffff
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
);
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
) {
75 enum ByteArray_Endianess
ByteArray_get_endian(struct ByteArray
* self
) {
79 // a real byte array clears the mem and resets
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
) {
99 static void seek_error() {
100 perror("seek error!\n");
104 static void neg_off() {
105 fprintf(stderr
, "negative seek attempted\n");
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
);
115 void ByteArray_set_length(struct ByteArray
* self
, off_t len
) {
116 if(len
> self
->size
) {
117 oob(self
->filename
, len
, self
->size
);
123 off_t
ByteArray_get_length(struct ByteArray
* self
) {
127 int ByteArray_set_position_rel(struct ByteArray
* self
, int rel
) {
128 if((int) self
->pos
+ rel
< 0) {
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
);
142 if(self
->type
== BAT_FILESTREAM
) {
143 off_t ret
= lseek(self
->source_fd
, pos
, SEEK_SET
);
144 if(ret
== (off_t
) -1) {
153 static void read_error() {
154 perror("read error!\n");
158 static void read_error_short() {
159 perror("read error (short)!\n");
163 int ByteArray_open_file(struct ByteArray
* self
, const char* filename
) {
165 self
->type
= BAT_FILESTREAM
;
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
) {
176 fprintf(stderr
, "mmap %s failed (%s) - fd %d, size %llu\n", filename
, strerror(errno
), self
->source_fd
, (long long) self
->size
);
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");
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
) {
197 self
->type
= BAT_MEMSTREAM
;
198 mem_set(&self
->source_mem
, data
, size
, size
);
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
);
214 ssize_t ret
= read(self
->source_fd
, buffer
, len
);
218 } else if((size_t) ret
!= 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
);
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
) {
250 void *p
= mem_getptr(&dest
->source_mem
, start
, len
);
251 if(p
) self
->readMultiByte(self
, p
, len
);
256 off_t
ByteArray_bytesAvailable(struct ByteArray
* self
) {
257 if(self
->pos
< self
->size
) return self
->size
- self
->pos
;
261 unsigned long long ByteArray_readUnsignedLongLong(struct ByteArray
* self
) {
263 unsigned long long intval
;
264 unsigned char charval
[sizeof(unsigned long long)];
266 self
->readMultiByte(self
, (char*) buf
.charval
, 8);
267 if(self
->endian
!= self
->sys_endian
) {
268 buf
.intval
= end_bswap64(buf
.intval
);
273 unsigned int ByteArray_readUnsignedInt(struct ByteArray
* self
) {
276 unsigned char charval
[sizeof(unsigned int)];
278 self
->readMultiByte(self
, (char*) buf
.charval
, 4);
279 if(self
->endian
!= self
->sys_endian
) {
280 buf
.intval
= end_bswap32(buf
.intval
);
285 int ByteArray_readInt(struct ByteArray
* self
) {
288 unsigned char charval
[sizeof(unsigned int)];
290 self
->readMultiByte(self
, (char*) buf
.charval
, 4);
291 if(self
->endian
!= self
->sys_endian
) {
292 buf
.intval
= end_bswap32(buf
.intval
);
297 unsigned short ByteArray_readUnsignedShort(struct ByteArray
* self
) {
299 unsigned short intval
;
300 unsigned char charval
[sizeof(unsigned short)];
302 self
->readMultiByte(self
, (char*) buf
.charval
, 2);
303 if(self
->endian
!= self
->sys_endian
) {
304 buf
.intval
= end_bswap16(buf
.intval
);
309 short ByteArray_readShort(struct ByteArray
* self
) {
311 unsigned short intval
;
312 unsigned char charval
[sizeof(unsigned short)];
314 self
->readMultiByte(self
, (char*) buf
.charval
, 2);
315 if(self
->endian
!= self
->sys_endian
) {
316 buf
.intval
= end_bswap16(buf
.intval
);
321 unsigned char ByteArray_readUnsignedByte(struct ByteArray
* self
) {
323 unsigned char intval
;
325 self
->readMultiByte(self
, (char*) &buf
.intval
, 1);
329 signed char ByteArray_readByte(struct ByteArray
* self
) {
333 self
->readMultiByte(self
, (char*) &buf
.intval
, 1);
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
;
343 ByteArray_set_position(self
, index
);
344 res
= ByteArray_readUnsignedByte(self
);
345 ByteArray_set_position(self
, save
);
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
);
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
) {
369 unsigned char charval
[sizeof(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
) {
380 unsigned short intval
;
381 unsigned char charval
[sizeof(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
) {
393 unsigned char charval
[sizeof(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
) {
405 unsigned char charval
[sizeof(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");
420 if(!(self
->flags
& BAF_CANGROW
) && (size_t) self
->pos
+ len
> (size_t) self
->size
) {
421 fprintf(stderr
, "oob write attempted");
426 if(mem_write(&self
->source_mem
, self
->pos
, what
, len
)) {
428 if(self
->pos
> self
->size
) self
->size
= self
->pos
; /* apparently CANGROW was used */
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");
444 unsigned char* p
= mem_getptr(&what
->source_mem
, what
->pos
, what
->size
- what
->pos
);
446 return ByteArray_writeMem(self
, p
, what
->size
- what
->pos
);
451 off_t
ByteArray_writeFloat(struct ByteArray
* self
, float what
) {
455 unsigned char charval
[sizeof(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
);