maug
Quick and dirty C mini-augmentation library.
mfile.h
Go to the documentation of this file.
1
2#ifndef MFILE_H
3#define MFILE_H
4
5#if !defined( DEBUG_THRESHOLD )
6# define DEBUG_THRESHOLD 1
7#endif /* !DEBUG_THRESHOLD */
8
9#ifndef UPRINTF_BUFFER_SZ_MAX
10# define UPRINTF_BUFFER_SZ_MAX 1024
11#endif /* !UPRINTF_BUFFER_SZ_MAX */
12
13#if !defined( MAUG_NO_RETRO ) && !defined( DOCUMENTATION )
15 uint8_t flags, const char* title, const char* format, ... );
16#endif /* !MAUG_NO_RETRO && !DOCUMENTATION */
17
18#if !defined( MFILE_MMAP ) && !defined( MAUG_NO_STAT )
19# include <sys/stat.h>
20#endif /* !MFILE_MMAP */
21
22/* TODO: async file_open() call that kicks off download to mem buffer that can
23 * be checked with looped check function.
24 */
25
36#ifndef MAUG_PATH_SZ_MAX
38# define MAUG_PATH_SZ_MAX 40
39#endif /* !MAUG_PATH_SZ_MAX */
40
53#define MFILE_CADDY_TYPE_FILE 0x01
54
58#define MFILE_CADDY_TYPE_MEM_BUFFER 0x80
59 /* maug_mfile_types */
61
66#define MFILE_FLAG_READ_ONLY 0x01
67
74#define MFILE_FLAG_HANDLE_LOCKED 0x02
75
95#define MFILE_READ_FLAG_LSBF 0x01
96
102#define MFILE_READ_FLAG_MSBF 0x01
103
104#define MFILE_ASSIGN_FLAG_TRIM_EXT 0x01
105
106#ifndef MFILE_READ_TRACE_LVL
107# define MFILE_READ_TRACE_LVL 0
108#endif /* !MFILE_READ_TRACE_LVL */
109
110#ifndef MFILE_WRITE_TRACE_LVL
111# define MFILE_WRITE_TRACE_LVL 0
112#endif /* !MFILE_WRITE_TRACE_LVL */
113
114#ifndef MFILE_SEEK_TRACE_LVL
115# define MFILE_SEEK_TRACE_LVL 0
116#endif /* !MFILE_SEEK_TRACE_LVL */
117
118#ifndef MFILE_CONTENTS_TRACE_LVL
119# define MFILE_CONTENTS_TRACE_LVL 0
120#endif /* !MFILE_CONTENTS_TRACE_LVL */
121
139
143#define mfile_cmp_path( a, b ) strncmp( a, b, MAUG_PATH_SZ_MAX )
144 /* maug_retroflt_assets */
146
147struct MFILE_CADDY;
148typedef struct MFILE_CADDY mfile_t;
149
155off_t mfile_mem_cursor( struct MFILE_CADDY* p_file );
156off_t mfile_mem_has_bytes( struct MFILE_CADDY* p_file );
157MERROR_RETVAL mfile_mem_read_byte( struct MFILE_CADDY* p_file, uint8_t* buf );
158MERROR_RETVAL mfile_mem_read_block(
159 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz );
160MERROR_RETVAL mfile_mem_seek( struct MFILE_CADDY* p_file, off_t pos );
161MERROR_RETVAL mfile_mem_read_line(
162 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags );
163MERROR_RETVAL mfile_mem_vprintf(
164 mfile_t* p_file, uint8_t flags, const char* fmt, va_list args );
165
174 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz );
175
178MERROR_RETVAL mfile_plt_init( void );
179
180/* Load the platform-specific file API. */
181#include <mrapifil.h>
182#include <mrapilog.h>
183
186 uint8_t type;
188 union MFILE_HANDLE h;
189 off_t last_read;
193 uint8_t* mem_buffer;
194 uint8_t flags;
196 off_t sz;
197 maug_path filename;
198};
199
200typedef struct MFILE_CADDY mfile_t;
201
212 maug_path tgt, const maug_path src, uint8_t flags );
213
221off_t mfile_file_has_bytes( struct MFILE_CADDY* p_file );
222
223MERROR_RETVAL mfile_file_read_block(
224 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz );
225
226MERROR_RETVAL mfile_file_seek( struct MFILE_CADDY* p_file, off_t pos );
227
228MERROR_RETVAL mfile_file_read_line(
229 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags );
230
231MERROR_RETVAL mfile_file_printf(
232 struct MFILE_CADDY* p_f, uint8_t flags, const char* fmt, ... );
233
234MERROR_RETVAL mfile_file_write_block(
235 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz );
236
237MERROR_RETVAL mfile_file_vprintf(
238 struct MFILE_CADDY* p_f, uint8_t flags, const char* fmt, va_list args );
239
247off_t mfile_cursor( struct MFILE_CADDY* p_file );
248
249off_t mfile_has_bytes( struct MFILE_CADDY* p_file );
250
251MERROR_RETVAL mfile_read_block(
252 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz );
253
254MERROR_RETVAL mfile_seek( struct MFILE_CADDY* p_file, off_t pos );
255
256MERROR_RETVAL mfile_read_int(
257 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags );
258
259MERROR_RETVAL mfile_read_line(
260 struct MFILE_CADDY* p_file, char* buf, off_t buf_sz, uint8_t flags );
261
262MERROR_RETVAL mfile_printf(
263 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, ... );
264
265MERROR_RETVAL mfile_write_block(
266 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz );
267
276 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, va_list args );
277
280#define mfile_get_sz( p_file ) ((p_file)->sz)
281
286 MAUG_MHANDLE, void* ptr, off_t, mfile_t* p_file );
287
293 const maug_path filename, mfile_t* p_file );
294
295MERROR_RETVAL mfile_open_write(
296 const maug_path filename, mfile_t* p_file );
297
301void mfile_close( mfile_t* p_file );
302
303#ifdef MFILE_C
304
305#include <mrapifil.h>
306#include <mrapilog.h>
307
308off_t mfile_cursor( struct MFILE_CADDY* p_file ) {
309 switch( p_file->type ) {
311 return mfile_file_cursor( p_file );
313 return mfile_mem_cursor( p_file );
314 }
315 return -1;
316}
317
318/* === */
319
320off_t mfile_has_bytes( struct MFILE_CADDY* p_file ) {
321 switch( p_file->type ) {
323 return mfile_file_has_bytes( p_file );
325 return mfile_mem_has_bytes( p_file );
326 }
327 return -1;
328}
329
330/* === */
331
332MERROR_RETVAL mfile_read_block(
333 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz
334) {
335 switch( p_file->type ) {
337 return mfile_file_read_block( p_file, buf, buf_sz );
339 return mfile_mem_read_block( p_file, buf, buf_sz );
340 }
341 return MERROR_FILE;
342}
343
344/* === */
345
346MERROR_RETVAL mfile_seek( struct MFILE_CADDY* p_file, off_t pos ) {
347 switch( p_file->type ) {
349 return mfile_file_seek( p_file, pos );
351 return mfile_mem_seek( p_file, pos );
352 }
353 return MERROR_FILE;
354}
355
356/* === */
357
358MERROR_RETVAL mfile_read_int(
359 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags
360) {
361 MERROR_RETVAL retval = MERROR_OK;
362
363 if(
364#ifdef MAUG_LSBF
366#elif defined( MAUG_MSBF )
368#endif
369 ) {
370 debug_printf( MFILE_READ_TRACE_LVL, "reading integer forward" );
371 /* Shrink the buffer moving right and read into it. */
372 switch( p_file->type ) {
374 retval = mfile_file_read_block( p_file, buf, buf_sz );
375 break;
377 retval = mfile_mem_read_block( p_file, buf, buf_sz );
378 break;
379 }
380
381 } else {
382 debug_printf( MFILE_READ_TRACE_LVL, "reading integer reversed" );
383 /* Move to the end of the output buffer and read backwards. */
384 while( 0 < buf_sz ) {
385 switch( p_file->type ) {
387 retval = mfile_file_read_block( p_file, (buf + (buf_sz - 1)), 1 );
388 break;
390 retval = mfile_mem_read_block( p_file, (buf + (buf_sz - 1)), 1 );
391 break;
392 }
393
394 maug_cleanup_if_not_ok();
395 buf_sz--;
396 }
397 }
398
399cleanup:
400
401 return retval;
402}
403
404/* === */
405
406MERROR_RETVAL mfile_read_line(
407 struct MFILE_CADDY* p_file, char* buf, off_t buf_sz, uint8_t flags
408) {
409 switch( p_file->type ) {
411 return mfile_file_read_line( p_file, buf, buf_sz, flags );
413 return mfile_mem_read_line( p_file, buf, buf_sz, flags );
414 }
415 return MERROR_FILE;
416}
417
418/* === */
419
420MERROR_RETVAL mfile_printf(
421 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, ...
422) {
423 MERROR_RETVAL retval = MERROR_FILE;
424 va_list vargs;
425
426 va_start( vargs, fmt );
427 switch( p_file->type ) {
429 retval = mfile_file_vprintf( p_file, flags, fmt, vargs );
430 break;
432 retval = mfile_mem_vprintf( p_file, flags, fmt, vargs );
433 break;
434 }
435 va_end( vargs );
436
437 return retval;
438}
439
440/* === */
441
442
443MERROR_RETVAL mfile_write_block(
444 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz
445) {
446 switch( p_f->type ) {
448 return mfile_file_write_block( p_f, buf, buf_sz );
450 return mfile_mem_write_block( p_f, buf, buf_sz );
451 }
452 return MERROR_FILE;
453}
454
455/* === */
456
457/*
458MERROR_RETVAL mfile_vprintf(
459 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, va_list args );
460*/
461
462/* === */
463
464off_t mfile_file_has_bytes( struct MFILE_CADDY* p_file ) {
465 size_t cursor = 0;
466 cursor = mfile_cursor( p_file );
467 if( p_file->sz > cursor ) {
468#if MFILE_READ_TRACE_LVL > 0
469 debug_printf( MFILE_READ_TRACE_LVL,
470 "file has " OFF_T_FMT " bytes left...",
471 p_file->sz - cursor );
472#endif /* MFILE_READ_TRACE_LVL */
473 return p_file->sz - cursor;
474 } else {
475#if MFILE_READ_TRACE_LVL > 0
476 /* TODO: Improved error message/handling. */
477 debug_printf( MFILE_READ_TRACE_LVL, "file has error bytes left!" );
478#endif /* MFILE_READ_TRACE_LVL */
479 return 0;
480 }
481}
482
483/* === */
484
486 maug_path tgt, const maug_path src, uint8_t flags
487) {
488 MERROR_RETVAL retval = MERROR_OK;
489 char* ext_ptr = NULL;
490
491 maug_mzero( tgt, MAUG_PATH_SZ_MAX );
492 maug_snprintf( tgt, MAUG_PATH_SZ_MAX - 1, "%s", src );
493
494 if( MFILE_ASSIGN_FLAG_TRIM_EXT == (MFILE_ASSIGN_FLAG_TRIM_EXT & flags) ) {
495 ext_ptr = maug_strrchr( tgt, '.' );
496 if( NULL != ext_ptr ) {
497 *ext_ptr = '\0';
498 }
499 }
500
501 return retval;
502}
503
504/* === */
505
506/*
507 * XXX: This should never be needed!
508MERROR_RETVAL mfile_file_printf(
509 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, ...
510) {
511 MERROR_RETVAL retval = MERROR_OK;
512 va_list vargs;
513
514 va_start( vargs, fmt );
515 retval = mfile_file_vprintf( p_file, flags, fmt, vargs );
516 va_end( vargs );
517
518 return retval;
519}
520*/
521
522/* === */
523
524off_t mfile_mem_cursor( struct MFILE_CADDY* p_file ) {
525 return p_file->mem_cursor;
526}
527
528/* === */
529
530off_t mfile_mem_has_bytes( struct MFILE_CADDY* p_file ) {
531 return p_file->sz - p_file->mem_cursor;
532}
533
534/* === */
535
536static MERROR_RETVAL mfile_mem_lock( struct MFILE_CADDY* p_f ) {
537 MERROR_RETVAL retval = MERROR_OK;
538
539 assert(
541
542 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
543
544 /* Only lock if this buffer uses a handle and not a pointer. */
545 if( (MAUG_MHANDLE)NULL != p_f->h.mem ) {
546 assert( NULL == p_f->mem_buffer );
547 maug_mlock( p_f->h.mem, p_f->mem_buffer );
548 p_f->flags |= MFILE_FLAG_HANDLE_LOCKED;
549 }
550
551 return retval;
552}
553
554/* === */
555
556static void mfile_mem_release( struct MFILE_CADDY* p_f ) {
557
558 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
559
560 if( MFILE_FLAG_HANDLE_LOCKED == (MFILE_FLAG_HANDLE_LOCKED & p_f->flags) ) {
561 maug_munlock( p_f->h.mem, p_f->mem_buffer );
562 p_f->flags &= ~MFILE_FLAG_HANDLE_LOCKED;
563 }
564}
565
566/* === */
567
568MERROR_RETVAL mfile_mem_read_block(
569 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz
570) {
571 MERROR_RETVAL retval = MERROR_OK;
572
573 if( p_file->mem_cursor >= p_file->sz ) {
574 return MERROR_FILE;
575 }
576
577 retval = mfile_mem_lock( p_file );
578 maug_cleanup_if_not_ok();
579
580 while( 0 < buf_sz-- ) {
581 *(buf++) = p_file->mem_buffer[p_file->mem_cursor++];
582 }
583
584cleanup:
585
586 mfile_mem_release( p_file );
587
588 return retval;
589}
590
591/* === */
592
593MERROR_RETVAL mfile_mem_seek( struct MFILE_CADDY* p_file, off_t pos ) {
594 MERROR_RETVAL retval = MERROR_OK;
595
596 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_file->type );
597
598 p_file->mem_cursor = pos;
599
600 debug_printf( MFILE_SEEK_TRACE_LVL,
601 "seeking memory buffer to position " OFF_T_FMT " (" OFF_T_FMT ")",
602 pos, p_file->mem_cursor );
603
604 return retval;
605}
606
607/* === */
608
609MERROR_RETVAL mfile_mem_read_line(
610 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags
611) {
612 MERROR_RETVAL retval = MERROR_OK;
613 off_t i = 0;
614
615 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
616
617 /* Check for no bytes at the start, as the loop below won't trigger if so! */
618 if( !mfile_mem_has_bytes( p_f ) ) {
619 error_printf( "file %s out of bytes!", p_f->filename );
620 retval = MERROR_FILE;
621 goto cleanup;
622 }
623
624 while( i < buffer_sz - 1 && mfile_mem_has_bytes( p_f ) ) {
625 /* Check for potential overflow. */
626 if( i + 1 >= buffer_sz ) {
627 error_printf( "overflow reading string from file %s!", p_f->filename );
628 retval = MERROR_FILE;
629 break;
630 }
631
632 retval = mfile_mem_read_block( p_f, (uint8_t*)&(buffer[i]), 1 );
633 maug_cleanup_if_not_ok();
634 if( '\n' == buffer[i] ) {
635 /* Break on newline and overwrite it below. */
636 break;
637 }
638 i++;
639 }
640
641 assert( i < buffer_sz ); /* while() above stops before buffer_sz! */
642
643 /* Append a null terminator. */
644 buffer[i] = '\0';
645
646cleanup:
647
648 return retval;
649}
650
651/* === */
652
653MERROR_RETVAL mfile_mem_vprintf(
654 mfile_t* p_file, uint8_t flags, const char* fmt, va_list args
655) {
656 MERROR_RETVAL retval = MERROR_OK;
657
658 if( MFILE_FLAG_READ_ONLY == (MFILE_FLAG_READ_ONLY & p_file->flags) ) {
659 return MERROR_FILE;
660 }
661
662 /* TODO: Enable writing to memory buffer. */
663 error_printf( "writing to memory buffer not currently supported!" );
664
665 /* TODO: Expand buffer and reflect this in sz if writing beyond the end
666 * of the buffer.
667 */
668
669 return retval;
670}
671
672/* === */
673
675 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz
676) {
677 MERROR_RETVAL retval = MERROR_OK;
678 ssize_t mv_sz = 0;
679
680 if( 0 == buf_sz ) {
681 /* Short-circuit empty writes. */
682 return MERROR_OK;
683 }
684
685 if( MFILE_FLAG_READ_ONLY == (MFILE_FLAG_READ_ONLY & p_f->flags) ) {
686 return MERROR_FILE;
687 }
688
689 retval = mfile_mem_lock( p_f );
690 maug_cleanup_if_not_ok();
691
692#if MFILE_WRITE_TRACE_LVL > 0
693 debug_printf( MFILE_WRITE_TRACE_LVL, "p: %p, sz: %u, cur: %u, buf_sz: %u\n",
694 p_f->mem_buffer, p_f->sz, p_f->mem_cursor, buf_sz );
695#endif /* MFILE_WRITE_TRACE_LVL */
696
697 mv_sz = (p_f->sz - (p_f->mem_cursor + buf_sz));
698 if( 0 < mv_sz ) {
699 memmove(
700 &(p_f->mem_buffer[p_f->mem_cursor + buf_sz]),
701 &(p_f->mem_buffer[p_f->mem_cursor]),
702 mv_sz );
703 }
704
705 memcpy( &(p_f->mem_buffer[p_f->mem_cursor]), buf, buf_sz );
706 p_f->mem_cursor += buf_sz;
707
708 /* TODO: Expand buffer and reflect this in sz if writing beyond the end
709 * of the buffer.
710 */
711
712cleanup:
713
714 mfile_mem_release( p_f );
715
716 return retval;
717}
718
719/* === */
720
722 MAUG_MHANDLE handle, void* ptr, off_t handle_sz, mfile_t* p_file
723) {
724 MERROR_RETVAL retval = MERROR_OK;
725
726 debug_printf( MFILE_SEEK_TRACE_LVL,
727 "locking handle %p as file %p (" OFF_T_FMT " bytes)...",
728 handle, p_file, handle_sz );
729
730 maug_mzero( p_file, sizeof( struct MFILE_CADDY ) );
731
732 /* Determine if this is based on a handle or a pointer. */
733 if( (MAUG_MHANDLE)NULL == handle && NULL != ptr ) {
734 p_file->mem_buffer = ptr;
735 } else if( (MAUG_MHANDLE)NULL != handle && NULL == ptr ) {
736 p_file->h.mem = handle;
737 /* maug_mlock( handle, p_file->mem_buffer ); */
738 } else {
739 error_printf( "must specify handle or pointer!" );
740 retval = MERROR_FILE;
741 goto cleanup;
742 }
743
745
746 p_file->sz = handle_sz;
747
748cleanup:
749
750 return retval;
751}
752
753/* === */
754
756 const maug_path filename, mfile_t* p_file
757) {
758 MERROR_RETVAL retval = MERROR_OK;
759
760 /* Call the platform-specific actual file opener from mrapifil.h. */
761 retval = mfile_plt_open_read( filename, p_file );
762
763 if( MERROR_OK == retval ) {
764 /* Store filename. */
765 retval = mfile_assign_path( p_file->filename, filename, 0 );
766 }
767
768 return retval;
769}
770
771/* === */
772
773MERROR_RETVAL mfile_open_write(
774 const maug_path filename, mfile_t* p_file
775) {
776 MERROR_RETVAL retval = MERROR_OK;
777
778 retval = mfile_plt_open_write( filename, p_file );
779
780 if( MERROR_OK == retval ) {
781 /* Store filename. */
782 retval = mfile_assign_path( p_file->filename, filename, 0 );
783 }
784
785 return retval;
786}
787
788/* === */
789
790void mfile_close( mfile_t* p_file ) {
791# if MFILE_SEEK_TRACE_LVL > 0
792 debug_printf( MFILE_SEEK_TRACE_LVL, "closing file..." );
793# endif /* MFILE_SEEK_TRACE_LVL */
794# ifdef MFILE_MMAP
795 munmap( bytes_ptr_h, bytes_sz );
796# else
797 /* maug_mfree( bytes_ptr_h ); */
798 switch( p_file->type ) {
799 case 0:
800 /* Do nothing silently. */
801 break;
802
804 mfile_plt_close( p_file );
805 p_file->type = 0;
806 break;
807
809 if( NULL != p_file->mem_buffer ) {
810 maug_munlock( p_file->h.mem, p_file->mem_buffer );
811 debug_printf( MFILE_SEEK_TRACE_LVL,
812 "unlocked handle %p from file %p...",
813 p_file->h.mem, p_file );
814 p_file->type = 0;
815 }
816 break;
817
818 default:
819 error_printf( "unknown file type: %d", (p_file)->type );
820 break;
821 }
822# endif /* MFILE_MMAP */
823}
824
825#endif /* MFILE_C */
826 /* maug_mfile */
828
829#endif /* !MFILE_H */
830
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition: merror.h:28
MERROR_RETVAL mfile_mem_write_block(struct MFILE_CADDY *p_f, const uint8_t *buf, size_t buf_sz)
Insert provided buffer into the given file.
#define MFILE_CADDY_TYPE_FILE
A standard UNIX file.
Definition: mfile.h:53
#define MFILE_CADDY_TYPE_MEM_BUFFER
An array of bytes in memory abstracted through this library.
Definition: mfile.h:58
MERROR_RETVAL mfile_vprintf(struct MFILE_CADDY *p_file, uint8_t flags, const char *fmt, va_list args)
Callback to printf the given format string, replacing tokens from the providied pre-initialized list ...
MERROR_RETVAL mfile_open_read(const maug_path filename, mfile_t *p_file)
Open a file and read it into memory or memory-map it.
MERROR_RETVAL mfile_lock_buffer(MAUG_MHANDLE, void *ptr, off_t, mfile_t *p_file)
Lock a buffer and assign it to an ::mfile_t to read/write.
#define MAUG_PATH_SZ_MAX
Maximum size allocated for asset paths.
Definition: mfile.h:38
#define MFILE_READ_FLAG_MSBF
Flag for mfile_read_int_t() indicating integer should always be read most significant byte first.
Definition: mfile.h:102
#define MFILE_READ_FLAG_LSBF
Flag for mfile_read_int_t() indicating integer should always be read least significant byte first.
Definition: mfile.h:95
void mfile_close(mfile_t *p_file)
Close a file opened with mfile_open_read().
MERROR_RETVAL mfile_assign_path(maug_path tgt, const maug_path src, uint8_t flags)
Copy a maug_path from one place to another, safely observing character limits, etc.
char maug_path[MAUG_PATH_SZ_MAX]
Path/name used to load an asset from disk or access other files.
Definition: mfile.h:138
void retroflat_message(uint8_t flags, const char *title, const char *format,...)
Display a message in a dialog box and/or on stderr.
Definition: mfile.h:184
off_t mem_cursor
Current position if its type is MFILE_CADDY_TYPE_MEM_BUFFER.
Definition: mfile.h:191
#define MFILE_FLAG_HANDLE_LOCKED
Flag for MFILE_CADDY::flags indicating subsequent internal unlocks should unlock the handle back to i...
Definition: mfile.h:74
uint8_t type
The RetroFile Types flag describing this file.
Definition: mfile.h:186
union MFILE_HANDLE h
The physical handle or pointer to access the file by.
Definition: mfile.h:188
uint8_t * mem_buffer
Locked pointer for MFILE_HANDLE::mem.
Definition: mfile.h:193
#define MFILE_FLAG_READ_ONLY
Flag for MFILE_CADDY::flags indicating this file is read-only.
Definition: mfile.h:66
off_t sz
Size of the current file/buffer in bytes.
Definition: mfile.h:196