maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
mfile.h
Go to the documentation of this file.
1
2#ifndef MFILE_H
3#define MFILE_H
4
5#if !defined( MFILE_MMAP ) && !defined( RETROFLAT_API_WINCE )
6# include <sys/stat.h>
7#endif /* !MFILE_MMAP */
8
9/* TODO: async file_open() call that kicks off download to mem buffer that can
10 * be checked with looped check function.
11 */
12
23#ifndef MAUG_PATH_MAX
25# define MAUG_PATH_MAX 256
26#endif /* !MAUG_PATH_MAX */
27
40#define MFILE_CADDY_TYPE_FILE 0x01
41
45#define MFILE_CADDY_TYPE_MEM_BUFFER 0x80
46
47 /* maug_mfile_types */
48
49#define MFILE_FLAG_READ_ONLY 0x01
50
51#define MFILE_READ_FLAG_LSBF 0x01
52
53#ifndef MFILE_TRACE_LVL
54# define MFILE_TRACE_LVL 0
55#endif /* !MFILE_TRACE_LVL */
56
57struct MFILE_CADDY;
58
59typedef MERROR_RETVAL (*mfile_seek_t)( struct MFILE_CADDY* p_file, off_t pos );
60typedef MERROR_RETVAL (*mfile_read_int_t)(
61 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags );
62typedef MERROR_RETVAL (*mfile_read_line_t)(
63 struct MFILE_CADDY* p_file, char* buf, off_t buf_sz, uint8_t flags );
64
66#ifdef MAUG_API_WIN32
67 HANDLE handle;
68#else
69 FILE* file;
70#endif /* !MAUG_API_WIN32 */
71 MAUG_MHANDLE mem;
72};
73
76 uint8_t type;
79 off_t sz;
80 off_t last_read;
84 uint8_t* mem_buffer;
85 uint8_t flags;
86 mfile_seek_t seek;
87 mfile_read_int_t read_int;
88 mfile_read_line_t read_line;
89};
90
91typedef struct MFILE_CADDY mfile_t;
92
93#define mfile_check_lock( p_file ) (NULL != (p_file)->mem_buffer)
94
95#define mfile_default_case( p_file ) \
96 default: \
97 error_printf( "unknown file type: %d", (p_file)->type ); \
98 break;
99
100#ifdef MAUG_API_WIN32
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)
105#else
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)
110#endif /* MAUG_NO_FILE */
111
112#ifdef MFILE_LEGACY_MACROS
113
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 ); \
118 break; \
119 case MFILE_CADDY_TYPE_MEM_BUFFER: \
120 (p_file)->mem_cursor = idx; \
121 break; \
122 mfile_default_case( p_file ); \
123 }
124
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 ); \
129 break; \
130 case MFILE_CADDY_TYPE_MEM_BUFFER: \
131 ((uint8_t*)(p_c))[0] = (p_file)->mem_buffer[(p_file)->mem_cursor++]; \
132 break; \
133 mfile_default_case( p_file ); \
134 }
135
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 ); \
141 break; \
142 case MFILE_CADDY_TYPE_MEM_BUFFER: \
143 *p_c = (p_file)->mem_buffer[idx]; \
144 (p_file)->mem_cursor += 1; \
145 break; \
146 mfile_default_case( p_file ); \
147 }
148
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 ); \
157 break; \
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; \
162 break; \
163 mfile_default_case( p_file ); \
164 }
165
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 ); \
171 break; \
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; \
176 break; \
177 mfile_default_case( p_file ); \
178 }
179
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 ); \
192 break; \
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; \
199 break; \
200 mfile_default_case( p_file ); \
201 }
202
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 ); \
207 break; \
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; \
214 break; \
215 mfile_default_case( p_file ); \
216 }
217
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 ); \
223 break; \
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; \
230 break; \
231 mfile_default_case( p_file ); \
232 }
233
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 ); \
238 break; \
239 case MFILE_CADDY_TYPE_MEM_BUFFER: \
240 (p_file)->mem_cursor = 0; \
241 break; \
242 mfile_default_case( p_file ); \
243 }
244
245#endif /* MFILE_LEGACY_MACROS */
246
247#define mfile_get_sz( p_file ) ((p_file)->sz)
248
252MERROR_RETVAL mfile_lock_buffer( MAUG_MHANDLE, off_t, mfile_t* p_file );
253
258MERROR_RETVAL mfile_open_read( const char* filename, mfile_t* p_file );
259
263void mfile_close( mfile_t* p_file );
264
265#ifdef MFILE_C
266
267#ifdef MVFS_ENABLED
268# include <mvfs.h>
269#endif /* MVFS_ENABLED */
270
271#ifdef MFILE_MMAP
272# include <sys/mman.h> /* mmap() */
273# include <unistd.h> /* close() */
274# include <fcntl.h> /* open() */
275# include <sys/stat.h> /* fstat() */
276#endif /* RETROFLAT_OS_UNIX */
277
278/* === */
279
280#ifdef MAUG_API_WIN32
281
282MERROR_RETVAL mfile_file_read_int(
283 struct MFILE_CADDY* p_f, uint8_t* buf, size_t buf_sz, uint8_t flags
284) {
285 MERROR_RETVAL retval = MERROR_OK;
286 DWORD last_read = 0;
287 BOOL read_ok = 0;
288
289 assert( MFILE_CADDY_TYPE_FILE == p_f->type );
290
291 if( MFILE_READ_FLAG_LSBF == (MFILE_READ_FLAG_LSBF & flags) ) {
292 /* Shrink the buffer moving right and read into it. */
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;
297 goto cleanup;
298 }
299
300 } else {
301 /* Move to the end of the output buffer and read backwards. */
302 while( 0 < buf_sz ) {
303 read_ok = ReadFile(
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;
308 goto cleanup;
309 }
310 buf_sz--;
311 }
312 }
313
314cleanup:
315
316 return retval;
317}
318
319MERROR_RETVAL mfile_file_seek( struct MFILE_CADDY* p_file, off_t pos ) {
320 MERROR_RETVAL retval = MERROR_OK;
321
322 SetFilePointer( (p_file)->h.handle, pos, NULL, FILE_BEGIN );
323
324 return retval;
325}
326
327#define MFILE_READ_LINE_BUF_SZ 4096
328
329MERROR_RETVAL mfile_file_read_line(
330 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags
331) {
332 MERROR_RETVAL retval = MERROR_OK;
333 DWORD start = 0;
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;
339
340 assert( MFILE_CADDY_TYPE_FILE == p_f->type );
341
342 start = SetFilePointer( p_f->h.handle, 0, NULL, FILE_CURRENT );
343
344 while( ReadFile(
345 p_f->h.handle, line_buf, MFILE_READ_LINE_BUF_SZ, &chunk_bytes_read, NULL
346 ) ) {
347 /* debug_printf( 1, "---" );
348 debug_printf( 1, "chunk read: %u bytes: %s", chunk_bytes_read, line_buf ); */
349 line_buf[chunk_bytes_read] = '\0';
350 newline_ptr = maug_strchr( line_buf, '\n' );
351 if( NULL != newline_ptr ) {
352 /* Move the read counter back in the chunk to the newline. */
353 newline_diff = (newline_ptr - line_buf) + 1;
354 *newline_ptr = '\0';
355 /* debug_printf( 1, "len to newline is: %u bytes...", newline_diff ); */
356 /* Back up the file pointer to the end of the line we just read and
357 * continue with the length of that line.
358 */
359 SetFilePointer(
360 p_f->h.handle,
361 (chunk_bytes_read - newline_diff) * -1, NULL, FILE_CURRENT );
362 /* debug_printf( 1, "backing up file ptr by %u bytes (sfp: %d)...",
363 chunk_bytes_read - newline_diff, sfp ); */
364 chunk_bytes_read = newline_diff;
365 }
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;
370 goto cleanup;
371 }
372 strncpy(
373 &(buffer[line_bytes_read]), line_buf, chunk_bytes_read );
374 if( NULL != newline_ptr ) {
375 /* Line was completed. */
376 break;
377 }
378 }
379
380cleanup:
381
382 return retval;
383}
384
385#else
386
387MERROR_RETVAL mfile_file_read_int(
388 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags
389) {
390 MERROR_RETVAL retval = MERROR_OK;
391 ssize_t last_read = 0;
392
393 assert( MFILE_CADDY_TYPE_FILE == p_file->type );
394
395 if( MFILE_READ_FLAG_LSBF == (MFILE_READ_FLAG_LSBF & flags) ) {
396 /* Shrink the buffer moving right and read into it. */
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;
401 goto cleanup;
402 }
403
404 } else {
405 /* Move to the end of the output buffer and read backwards. */
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;
411 goto cleanup;
412 }
413 buf_sz--;
414 }
415 }
416
417cleanup:
418
419 return retval;
420}
421
422/* === */
423
424MERROR_RETVAL mfile_file_seek( struct MFILE_CADDY* p_file, off_t pos ) {
425 MERROR_RETVAL retval = MERROR_OK;
426
427 assert( MFILE_CADDY_TYPE_FILE == p_file->type );
428
429 if( fseek( p_file->h.file, pos, SEEK_SET ) ) {
430 error_printf( "unable to seek file!" );
431 retval = MERROR_FILE;
432 }
433
434 return retval;
435}
436
437/* === */
438
439MERROR_RETVAL mfile_file_read_line(
440 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags
441) {
442 MERROR_RETVAL retval = MERROR_OK;
443
444 assert( MFILE_CADDY_TYPE_FILE == p_f->type );
445
446 /* Trivial case; use a native function. Much faster! */
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;
450 }
451
452 return retval;
453}
454
455#endif /* !MAUG_API_WIN32 */
456
457/* === */
458
459MERROR_RETVAL mfile_mem_read_int(
460 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags
461) {
462 MERROR_RETVAL retval = MERROR_OK;
463
464 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_file->type );
465
466 if( MFILE_READ_FLAG_LSBF != (MFILE_READ_FLAG_LSBF & flags) ) {
467 /* Shrink the buffer moving right and read into it. */
468 while( 0 < buf_sz ) {
469 /* Check for EOF. */
470 if( p_file->mem_cursor >= p_file->sz ) {
471 retval = MERROR_FILE;
472 error_printf(
473 "cursor " OFF_T_FMT " beyond end of buffer " OFF_T_FMT "!",
474 p_file->mem_cursor, p_file->sz );
475 goto cleanup;
476 }
477
478 buf[buf_sz - 1] = p_file->mem_buffer[p_file->mem_cursor];
479 debug_printf( MFILE_TRACE_LVL, "byte #" SIZE_T_FMT " = # " OFF_T_FMT,
480 buf_sz - 1, p_file->mem_cursor );
481 buf_sz--;
482 p_file->mem_cursor++;
483 }
484
485 } else {
486 /* Move to the end of the output buffer and read backwards. */
487 while( 0 < buf_sz ) {
488 /* Check for EOF. */
489 if( p_file->mem_cursor >= p_file->sz ) {
490 retval = MERROR_FILE;
491 error_printf(
492 "cursor " OFF_T_FMT " beyond end of buffer " OFF_T_FMT "!",
493 p_file->mem_cursor, p_file->sz );
494 goto cleanup;
495 }
496
497 buf[buf_sz - 1] = p_file->mem_buffer[p_file->mem_cursor];
498 debug_printf( MFILE_TRACE_LVL, "byte #" SIZE_T_FMT " = # " OFF_T_FMT,
499 buf_sz - 1, p_file->mem_cursor );
500 buf_sz--;
501 buf++;
502 p_file->mem_cursor++;
503 }
504 }
505
506cleanup:
507
508 return retval;
509}
510
511/* === */
512
513MERROR_RETVAL mfile_mem_seek( struct MFILE_CADDY* p_file, off_t pos ) {
514 MERROR_RETVAL retval = MERROR_OK;
515
516 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_file->type );
517
518 p_file->mem_cursor = pos;
519
520 debug_printf( 1,
521 "seeking memory buffer to position " OFF_T_FMT " (" OFF_T_FMT ")",
522 pos, p_file->mem_cursor );
523
524 return retval;
525}
526
527/* === */
528
529MERROR_RETVAL mfile_mem_read_line(
530 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags
531) {
532 MERROR_RETVAL retval = MERROR_OK;
533 off_t i = 0;
534
535 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
536
537 while( i < buffer_sz - 1 && mfile_has_bytes( p_f ) ) {
538 /* Check for potential overflow. */
539 if( i + 1 >= buffer_sz ) {
540 error_printf( "overflow reading string from file!" );
541 retval = MERROR_FILE;
542 break;
543 }
544
545 p_f->read_int( p_f, (uint8_t*)&(buffer[i]), 1, 0 );
546 if( '\n' == buffer[i] ) {
547 /* Break on newline and overwrite it below. */
548 break;
549 }
550 i++;
551 }
552
553 assert( i < buffer_sz ); /* while() above stops before buffer_sz! */
554
555 /* Append a null terminator. */
556 buffer[i] = '\0';
557
558 return retval;
559}
560
561/* === */
562
564 MAUG_MHANDLE handle, off_t handle_sz, mfile_t* p_file
565) {
566 MERROR_RETVAL retval = MERROR_OK;
567
568 debug_printf( 1,
569 "locking handle %p as file %p (" OFF_T_FMT " bytes)...",
570 handle, p_file, handle_sz );
571
572 maug_mzero( p_file, sizeof( struct MFILE_CADDY ) );
573 maug_mlock( handle, p_file->mem_buffer );
575
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;
579
580 p_file->sz = handle_sz;
581
582 return retval;
583}
584
585/* === */
586
587MERROR_RETVAL mfile_open_read( const char* filename, mfile_t* p_file ) {
588 MERROR_RETVAL retval = MERROR_OK;
589# if defined( MVFS_ENABLED )
590 size_t i = 0;
591# elif defined( MFILE_MMAP )
592 uint8_t* bytes_ptr = NULL;
593 struct stat st;
594 int in_file = 0;
595# elif defined( RETROFLAT_API_WINCE )
596 STATSTG file_stat;
597# else
598 struct stat file_stat;
599# endif /* MFILE_MMAP */
600# ifdef MAUG_WCHAR
601 wchar_t filename_w[MAUG_PATH_MAX + 1] = { 0 };
602# endif /* MAUG_WCHAR */
603
604 /* MAUG_MHANDLE* p_bytes_ptr_h, off_t* p_bytes_sz */
605
606# if defined( MVFS_ENABLED )
607
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]) );
613 break;
614 }
615 i++;
616 }
617
618 if( NULL == gc_mvfs_data[i] ) {
619 retval = MERROR_FILE;
620 error_printf( "file \"%s\" not found in VFS!", filename );
621 goto cleanup;
622 }
623
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;
629 p_file->mem_buffer = gc_mvfs_data[i];
630 p_file->sz = *(gc_mvfs_lens[i]);
631 p_file->mem_cursor = 0;
632
633cleanup:
634
635# elif defined( MFILE_MMAP )
636
637 in_file = open( filename, O_RDONLY );
638 if( 0 >= in_file ) {
639 error_printf( "could not open file: %s", filename );
640 retval = MERROR_FILE;
641 goto cleanup;
642 }
643
644 fstat( in_file, &st );
645
646 *p_bytes_ptr_h =
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;
650
651cleanup:
652
653 if( 0 < in_file ) {
654 close( in_file );
655 }
656
657# elif defined( MAUG_API_WIN32 )
658
659 /* TODO: Wide chars. */
660
661# ifdef MAUG_WCHAR
662 if( 0 == MultiByteToWideChar(
663 CP_ACP, MB_PRECOMPOSED, filename, -1, filename_w, MAUG_PATH_MAX
664 ) ) {
665 error_printf( "could not create wide filename path!" );
666 retval = MERROR_FILE;
667 goto cleanup;
668 }
669# endif /* MAUG_WCHAR */
670
671 /* Actually open the file. */
672 p_file->h.handle = CreateFile(
673# ifdef MAUG_WCHAR
674 filename_w,
675# else
676 filename,
677# endif /* MAUG_WCHAR */
678 GENERIC_READ,
679 FILE_SHARE_READ,
680 NULL,
681 OPEN_EXISTING,
682 FILE_ATTRIBUTE_NORMAL,
683 NULL );
684
685 if( INVALID_HANDLE_VALUE == p_file->h.handle ) {
686 error_printf( "could not open file: %s", filename );
687 }
688
689 p_file->sz = GetFileSize( p_file->h.handle, NULL );
690
691 debug_printf( 1, "opened file %s (" OFF_T_FMT " bytes)...",
692 filename, p_file->sz );
693
694 p_file->type = MFILE_CADDY_TYPE_FILE;
695
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;
700
701cleanup:
702
703# else
704
705# ifndef MAUG_NO_STAT
706 /* Get the file size from the OS. */
707 stat( filename, &file_stat );
708 p_file->sz = file_stat.st_size;
709# endif /* !MAUG_NO_STAT */
710
711 /* Open the permanent file handle. */
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;
716 goto cleanup;
717 }
718
719# ifdef MAUG_NO_STAT
720 /* The standard is not required to support SEEK_END, among other issues.
721 * This is probably the worst way to get file size.
722 */
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 );
727# endif /* MAUG_NO_STAT */
728
729 debug_printf( 1, "opened file %s (" OFF_T_FMT " bytes)...",
730 filename, p_file->sz );
731
732 p_file->type = MFILE_CADDY_TYPE_FILE;
733
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;
738
739cleanup:
740
741# endif /* MFILE_MMAP */
742
743 return retval;
744}
745
746/* === */
747
748void mfile_close( mfile_t* p_file ) {
749# ifdef MFILE_MMAP
750 munmap( bytes_ptr_h, bytes_sz );
751# else
752 /* maug_mfree( bytes_ptr_h ); */
753 switch( p_file->type ) {
754 case 0:
755 /* Do nothing silently. */
756 break;
757
759#ifdef MAUG_API_WIN32
760 CloseHandle( p_file->h.handle );
761#else
762 fclose( p_file->h.file );
763#endif /* !MAUG_NO_FILE */
764 p_file->type = 0;
765 break;
766
768 if( NULL != p_file->mem_buffer ) {
769 maug_munlock( p_file->h.mem, p_file->mem_buffer );
770 debug_printf( 1, "unlocked handle %p from file %p...",
771 p_file->h.mem, p_file );
772 p_file->type = 0;
773 }
774 break;
775
776 mfile_default_case( p_file );
777 }
778# endif /* MFILE_MMAP */
779}
780
781#endif /* MFILE_C */
782
783 /* maug_mfile */
784
785#endif /* !MFILE_H */
786
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.
Definition mfile.h:74
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
Definition mfile.h:65