5#if !defined( MFILE_MMAP ) && !defined( RETROFLAT_API_WINCE )
25# define MAUG_PATH_MAX 256
40#define MFILE_CADDY_TYPE_FILE 0x01
45#define MFILE_CADDY_TYPE_MEM_BUFFER 0x80
49#define MFILE_FLAG_READ_ONLY 0x01
51#define MFILE_READ_FLAG_LSBF 0x01
53#ifndef MFILE_TRACE_LVL
54# define MFILE_TRACE_LVL 0
61 struct MFILE_CADDY* p_file, uint8_t* buf,
size_t buf_sz, uint8_t flags );
63 struct MFILE_CADDY* p_file,
char* buf, off_t buf_sz, uint8_t flags );
87 mfile_read_int_t read_int;
88 mfile_read_line_t read_line;
93#define mfile_check_lock( p_file ) (NULL != (p_file)->mem_buffer)
95#define mfile_default_case( p_file ) \
97 error_printf( "unknown file type: %d", (p_file)->type ); \
101# define mfile_has_bytes( p_file ) \
102 ((MFILE_CADDY_TYPE_FILE == ((p_file)->type) ? \
103 (off_t)SetFilePointer( (p_file)->h.handle, 0, NULL, FILE_CURRENT ) : \
104 (p_file)->mem_cursor) < (p_file)->sz)
106# define mfile_has_bytes( p_file ) \
107 ((MFILE_CADDY_TYPE_FILE == ((p_file)->type) ? \
108 (off_t)ftell( (p_file)->h.file ) : \
109 (p_file)->mem_cursor) < (p_file)->sz)
112#ifdef MFILE_LEGACY_MACROS
114#define mfile_seek( p_file, idx ) \
115 switch( (p_file)->type ) { \
116 case MFILE_CADDY_TYPE_FILE: \
117 fseek( (p_file)->h.file, idx, SEEK_SET ); \
119 case MFILE_CADDY_TYPE_MEM_BUFFER: \
120 (p_file)->mem_cursor = idx; \
122 mfile_default_case( p_file ); \
125#define mfile_cread( p_file, p_c ) \
126 switch( (p_file)->type ) { \
127 case MFILE_CADDY_TYPE_FILE: \
128 (p_file)->last_read = fread( p_c, 1, 1, (p_file)->h.file ); \
130 case MFILE_CADDY_TYPE_MEM_BUFFER: \
131 ((uint8_t*)(p_c))[0] = (p_file)->mem_buffer[(p_file)->mem_cursor++]; \
133 mfile_default_case( p_file ); \
136#define mfile_cread_at( p_file, p_c, idx ) \
137 switch( (p_file)->type ) { \
138 case MFILE_CADDY_TYPE_FILE: \
139 fseek( (p_file)->h.file, idx, SEEK_SET ); \
140 (p_file)->last_read = fread( p_c, 1, 1, (p_file)->h.file ); \
142 case MFILE_CADDY_TYPE_MEM_BUFFER: \
143 *p_c = (p_file)->mem_buffer[idx]; \
144 (p_file)->mem_cursor += 1; \
146 mfile_default_case( p_file ); \
149#define mfile_u16read_at( p_file, p_u16, idx ) \
150 switch( (p_file)->type ) { \
151 case MFILE_CADDY_TYPE_FILE: \
152 fseek( (p_file)->h.file, idx, SEEK_SET ); \
153 (p_file)->last_read = \
154 fread( (((uint8_t*)p_u16) + 1), 1, 1, (p_file)->h.file ); \
155 (p_file)->last_read += \
156 fread( ((uint8_t*)p_u16), 1, 1, (p_file)->h.file ); \
158 case MFILE_CADDY_TYPE_MEM_BUFFER: \
159 ((uint8_t*)(p_u16))[0] = (p_file)->mem_buffer[idx]; \
160 ((uint8_t*)(p_u16))[1] = (p_file)->mem_buffer[idx + 1]; \
161 (p_file)->mem_cursor += 2; \
163 mfile_default_case( p_file ); \
166#define mfile_u16read_lsbf_at( p_file, p_u16, idx ) \
167 switch( (p_file)->type ) { \
168 case MFILE_CADDY_TYPE_FILE: \
169 fseek( (p_file)->h.file, idx, SEEK_SET ); \
170 (p_file)->last_read = fread( p_u16, 1, 2, (p_file)->h.file ); \
172 case MFILE_CADDY_TYPE_MEM_BUFFER: \
173 ((uint8_t*)(p_u16))[0] = (p_file)->mem_buffer[idx + 1]; \
174 ((uint8_t*)(p_u16))[1] = (p_file)->mem_buffer[idx]; \
175 (p_file)->mem_cursor += 2; \
177 mfile_default_case( p_file ); \
180#define mfile_u32read_at( p_file, p_u32, idx ) \
181 switch( (p_file)->type ) { \
182 case MFILE_CADDY_TYPE_FILE: \
183 fseek( (p_file)->h.file, idx, SEEK_SET ); \
184 (p_file)->last_read = \
185 fread( (((uint8_t*)p_u32) + 3), 1, 1, (p_file)->h.file ); \
186 (p_file)->last_read += \
187 fread( (((uint8_t*)p_u32) + 2), 1, 1, (p_file)->h.file ); \
188 (p_file)->last_read += \
189 fread( (((uint8_t*)p_u32) + 1), 1, 1, (p_file)->h.file ); \
190 (p_file)->last_read += \
191 fread( ((uint8_t*)p_u32), 1, 1, (p_file)->h.file ); \
193 case MFILE_CADDY_TYPE_MEM_BUFFER: \
194 ((uint8_t*)(p_u32))[0] = (p_file)->mem_buffer[idx]; \
195 ((uint8_t*)(p_u32))[1] = (p_file)->mem_buffer[idx + 1]; \
196 ((uint8_t*)(p_u32))[2] = (p_file)->mem_buffer[idx + 2]; \
197 ((uint8_t*)(p_u32))[3] = (p_file)->mem_buffer[idx + 3]; \
198 (p_file)->mem_cursor += 4; \
200 mfile_default_case( p_file ); \
203#define mfile_u32read_lsbf( p_file, p_u32 ) \
204 switch( (p_file)->type ) { \
205 case MFILE_CADDY_TYPE_FILE: \
206 (p_file)->last_read = fread( p_u32, 1, 4, (p_file)->h.file ); \
208 case MFILE_CADDY_TYPE_MEM_BUFFER: \
209 ((uint8_t*)(p_u32))[3] = (p_file)->mem_buffer[(p_file)->mem_cursor]; \
210 ((uint8_t*)(p_u32))[2] = (p_file)->mem_buffer[(p_file)->mem_cursor + 1]; \
211 ((uint8_t*)(p_u32))[1] = (p_file)->mem_buffer[(p_file)->mem_cursor + 2]; \
212 ((uint8_t*)(p_u32))[0] = (p_file)->mem_buffer[(p_file)->mem_cursor + 3]; \
213 (p_file)->mem_cursor += 4; \
215 mfile_default_case( p_file ); \
218#define mfile_u32read_lsbf_at( p_file, p_u32, idx ) \
219 switch( (p_file)->type ) { \
220 case MFILE_CADDY_TYPE_FILE: \
221 fseek( (p_file)->h.file, idx, SEEK_SET ); \
222 (p_file)->last_read = fread( p_u32, 1, 4, (p_file)->h.file ); \
224 case MFILE_CADDY_TYPE_MEM_BUFFER: \
225 ((uint8_t*)(p_u32))[3] = (p_file)->mem_buffer[idx]; \
226 ((uint8_t*)(p_u32))[2] = (p_file)->mem_buffer[idx + 1]; \
227 ((uint8_t*)(p_u32))[1] = (p_file)->mem_buffer[idx + 2]; \
228 ((uint8_t*)(p_u32))[0] = (p_file)->mem_buffer[idx + 3]; \
229 (p_file)->mem_cursor += 4; \
231 mfile_default_case( p_file ); \
234#define mfile_reset( p_file ) \
235 switch( (p_file)->type ) { \
236 case MFILE_CADDY_TYPE_FILE: \
237 fseek( (p_file)->h.file, 0, SEEK_SET ); \
239 case MFILE_CADDY_TYPE_MEM_BUFFER: \
240 (p_file)->mem_cursor = 0; \
242 mfile_default_case( p_file ); \
247#define mfile_get_sz( p_file ) ((p_file)->sz)
272# include <sys/mman.h>
275# include <sys/stat.h>
283 struct MFILE_CADDY* p_f, uint8_t* buf,
size_t buf_sz, uint8_t flags
291 if( MFILE_READ_FLAG_LSBF == (MFILE_READ_FLAG_LSBF & flags) ) {
293 read_ok = ReadFile( p_f->
h.handle, buf, buf_sz, &last_read, NULL );
294 if( !read_ok || buf_sz > last_read ) {
295 error_printf(
"unable to read from file!" );
296 retval = MERROR_FILE;
302 while( 0 < buf_sz ) {
304 p_f->
h.handle, (buf + (buf_sz - 1)) , 1, &last_read, NULL );
305 if( !read_ok || buf_sz > last_read ) {
306 error_printf(
"unable to read from file!" );
307 retval = MERROR_FILE;
322 SetFilePointer( (p_file)->
h.handle, pos, NULL, FILE_BEGIN );
327#define MFILE_READ_LINE_BUF_SZ 4096
330 struct MFILE_CADDY* p_f,
char* buffer, off_t buffer_sz, uint8_t flags
334 DWORD chunk_bytes_read = 0;
335 DWORD line_bytes_read = 0;
336 int32_t newline_diff = 0;
337 char line_buf[MFILE_READ_LINE_BUF_SZ + 1];
338 char* newline_ptr = NULL;
342 start = SetFilePointer( p_f->
h.handle, 0, NULL, FILE_CURRENT );
345 p_f->
h.handle, line_buf, MFILE_READ_LINE_BUF_SZ, &chunk_bytes_read, NULL
349 line_buf[chunk_bytes_read] =
'\0';
350 newline_ptr = maug_strchr( line_buf,
'\n' );
351 if( NULL != newline_ptr ) {
353 newline_diff = (newline_ptr - line_buf) + 1;
361 (chunk_bytes_read - newline_diff) * -1, NULL, FILE_CURRENT );
364 chunk_bytes_read = newline_diff;
366 debug_printf( 1,
"line buffer (%u): %s", chunk_bytes_read, line_buf );
367 if( line_bytes_read + chunk_bytes_read > buffer_sz ) {
368 error_printf(
"line buffer exceeded!" );
369 retval = MERROR_FILE;
373 &(buffer[line_bytes_read]), line_buf, chunk_bytes_read );
374 if( NULL != newline_ptr ) {
388 struct MFILE_CADDY* p_file, uint8_t* buf,
size_t buf_sz, uint8_t flags
391 ssize_t last_read = 0;
395 if( MFILE_READ_FLAG_LSBF == (MFILE_READ_FLAG_LSBF & flags) ) {
397 last_read = fread( buf, 1, buf_sz, p_file->
h.file );
398 if( buf_sz > last_read ) {
399 error_printf(
"unable to read from file!" );
400 retval = MERROR_FILE;
406 while( 0 < buf_sz ) {
407 last_read = fread( (buf + (buf_sz - 1)), 1, 1, p_file->
h.file );
408 if( 0 >= last_read ) {
409 error_printf(
"unable to read from file!" );
410 retval = MERROR_FILE;
429 if( fseek( p_file->
h.file, pos, SEEK_SET ) ) {
430 error_printf(
"unable to seek file!" );
431 retval = MERROR_FILE;
440 struct MFILE_CADDY* p_f,
char* buffer, off_t buffer_sz, uint8_t flags
447 if( NULL == fgets( buffer, buffer_sz - 1, p_f->
h.file ) ) {
448 error_printf(
"error while reading line from file!" );
449 retval = MERROR_FILE;
460 struct MFILE_CADDY* p_file, uint8_t* buf,
size_t buf_sz, uint8_t flags
466 if( MFILE_READ_FLAG_LSBF != (MFILE_READ_FLAG_LSBF & flags) ) {
468 while( 0 < buf_sz ) {
471 retval = MERROR_FILE;
473 "cursor " OFF_T_FMT
" beyond end of buffer " OFF_T_FMT
"!",
479 debug_printf( MFILE_TRACE_LVL,
"byte #" SIZE_T_FMT
" = # " OFF_T_FMT,
487 while( 0 < buf_sz ) {
490 retval = MERROR_FILE;
492 "cursor " OFF_T_FMT
" beyond end of buffer " OFF_T_FMT
"!",
498 debug_printf( MFILE_TRACE_LVL,
"byte #" SIZE_T_FMT
" = # " OFF_T_FMT,
521 "seeking memory buffer to position " OFF_T_FMT
" (" OFF_T_FMT
")",
530 struct MFILE_CADDY* p_f,
char* buffer, off_t buffer_sz, uint8_t flags
537 while( i < buffer_sz - 1 && mfile_has_bytes( p_f ) ) {
539 if( i + 1 >= buffer_sz ) {
540 error_printf(
"overflow reading string from file!" );
541 retval = MERROR_FILE;
545 p_f->read_int( p_f, (uint8_t*)&(buffer[i]), 1, 0 );
546 if(
'\n' == buffer[i] ) {
553 assert( i < buffer_sz );
564 MAUG_MHANDLE handle, off_t handle_sz,
mfile_t* p_file
569 "locking handle %p as file %p (" OFF_T_FMT
" bytes)...",
570 handle, p_file, handle_sz );
576 p_file->read_int = mfile_mem_read_int;
577 p_file->seek = mfile_mem_seek;
578 p_file->read_line = mfile_mem_read_line;
580 p_file->sz = handle_sz;
589# if defined( MVFS_ENABLED )
591# elif defined( MFILE_MMAP )
592 uint8_t* bytes_ptr = NULL;
595# elif defined( RETROFLAT_API_WINCE )
598 struct stat file_stat;
606# if defined( MVFS_ENABLED )
608 while( NULL != gc_mvfs_data[i] ) {
609 if( 0 == strcmp( filename, gc_mvfs_filenames[i] ) ) {
610 debug_printf( 1,
"found file \"%s\" at VFS index: " SIZE_T_FMT
611 " (size: " OFF_T_FMT
" bytes)",
612 filename, i, *(gc_mvfs_lens[i]) );
618 if( NULL == gc_mvfs_data[i] ) {
619 retval = MERROR_FILE;
620 error_printf(
"file \"%s\" not found in VFS!", filename );
625 p_file->read_int = mfile_mem_read_int;
626 p_file->seek = mfile_mem_seek;
627 p_file->read_line = mfile_mem_read_line;
628 p_file->flags = MFILE_FLAG_READ_ONLY;
630 p_file->sz = *(gc_mvfs_lens[i]);
635# elif defined( MFILE_MMAP )
637 in_file = open( filename, O_RDONLY );
639 error_printf(
"could not open file: %s", filename );
640 retval = MERROR_FILE;
644 fstat( in_file, &st );
647 mmap( (caddr_t)0, st.st_size, PROT_READ, MAP_SHARED, in_file, 0 );
648 maug_cleanup_if_null_alloc( uint8_t*, *p_bytes_ptr_h );
649 *p_bytes_sz = st.st_size;
657# elif defined( MAUG_API_WIN32 )
662 if( 0 == MultiByteToWideChar(
663 CP_ACP, MB_PRECOMPOSED, filename, -1, filename_w,
MAUG_PATH_MAX
665 error_printf(
"could not create wide filename path!" );
666 retval = MERROR_FILE;
672 p_file->
h.handle = CreateFile(
682 FILE_ATTRIBUTE_NORMAL,
685 if( INVALID_HANDLE_VALUE == p_file->
h.handle ) {
686 error_printf(
"could not open file: %s", filename );
689 p_file->sz = GetFileSize( p_file->
h.handle, NULL );
691 debug_printf( 1,
"opened file %s (" OFF_T_FMT
" bytes)...",
692 filename, p_file->sz );
696 p_file->read_int = mfile_file_read_int;
697 p_file->seek = mfile_file_seek;
698 p_file->read_line = mfile_file_read_line;
699 p_file->flags = MFILE_FLAG_READ_ONLY;
707 stat( filename, &file_stat );
708 p_file->sz = file_stat.st_size;
712 p_file->
h.file = fopen( filename,
"rb" );
713 if( NULL == p_file->
h.file ) {
714 error_printf(
"could not open file: %s", filename );
715 retval = MERROR_FILE;
723 debug_printf( 2,
"falling back to seek file size..." );
724 fseek( p_file->
h.file, 0, SEEK_END );
725 p_file->sz = ftell( p_file->
h.file );
726 fseek( p_file->
h.file, 0, SEEK_SET );
729 debug_printf( 1,
"opened file %s (" OFF_T_FMT
" bytes)...",
730 filename, p_file->sz );
734 p_file->read_int = mfile_file_read_int;
735 p_file->seek = mfile_file_seek;
736 p_file->read_line = mfile_file_read_line;
737 p_file->flags = MFILE_FLAG_READ_ONLY;
750 munmap( bytes_ptr_h, bytes_sz );
753 switch( p_file->
type ) {
760 CloseHandle( p_file->
h.handle );
762 fclose( p_file->
h.file );
770 debug_printf( 1,
"unlocked handle %p from file %p...",
771 p_file->
h.mem, p_file );
776 mfile_default_case( p_file );
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define maug_mzero(ptr, sz)
Zero the block of memory pointed to by ptr.
Definition mmem.h:62
#define MFILE_CADDY_TYPE_FILE
A standard UNIX file.
Definition mfile.h:40
#define MFILE_CADDY_TYPE_MEM_BUFFER
An array of bytes in memory abstracted through this library.
Definition mfile.h:45
#define MAUG_PATH_MAX
Maximum size allocated for asset paths.
Definition mfile.h:25
MERROR_RETVAL mfile_open_read(const char *filename, mfile_t *p_file)
Open a file and read it into memory or memory-map it.
void mfile_close(mfile_t *p_file)
Close a file opened with mfile_open_read().
MERROR_RETVAL mfile_lock_buffer(MAUG_MHANDLE, off_t, mfile_t *p_file)
Lock a buffer and assign it to an mfile_t to read/write.
off_t mem_cursor
Current position if its type is MFILE_CADDY_TYPE_MEM_BUFFER.
Definition mfile.h:82
uint8_t type
The RetroFile Types flag describing this file.
Definition mfile.h:76
union MFILE_HANDLE h
The physical handle or pointer to access the file by.
Definition mfile.h:78
uint8_t * mem_buffer
Locked pointer for MFILE_HANDLE::mem.
Definition mfile.h:84