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( 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( MFILE_MMAP ) && \
14 !defined( RETROFLAT_API_WINCE ) && \
15 !defined( RETROFLAT_API_PALM )
16# include <sys/stat.h>
17#endif /* !MFILE_MMAP */
18
19/* TODO: async file_open() call that kicks off download to mem buffer that can
20 * be checked with looped check function.
21 */
22
28
32
33#ifndef MAUG_PATH_SZ_MAX
35# define MAUG_PATH_SZ_MAX 256
36#endif /* !MAUG_PATH_SZ_MAX */
37
46
50#define MFILE_CADDY_TYPE_FILE 0x01
51
55#define MFILE_CADDY_TYPE_MEM_BUFFER 0x80
56 /* maug_mfile_types */
58
63#define MFILE_FLAG_READ_ONLY 0x01
64
71#define MFILE_FLAG_HANDLE_LOCKED 0x02
72
86
92#define MFILE_READ_FLAG_LSBF 0x01
93
99#define MFILE_READ_FLAG_MSBF 0x01
100
101#define MFILE_ASSIGN_FLAG_TRIM_EXT 0x01
102
103#ifndef MFILE_READ_TRACE_LVL
104# define MFILE_READ_TRACE_LVL 0
105#endif /* !MFILE_READ_TRACE_LVL */
106
107#ifndef MFILE_WRITE_TRACE_LVL
108# define MFILE_WRITE_TRACE_LVL 0
109#endif /* !MFILE_WRITE_TRACE_LVL */
110
111#ifndef MFILE_SEEK_TRACE_LVL
112# define MFILE_SEEK_TRACE_LVL 0
113#endif /* !MFILE_SEEK_TRACE_LVL */
114
115#ifndef MFILE_CONTENTS_TRACE_LVL
116# define MFILE_CONTENTS_TRACE_LVL 0
117#endif /* !MFILE_CONTENTS_TRACE_LVL */
118
125
130
134#define mfile_cmp_path( a, b ) strncmp( a, b, MAUG_PATH_SZ_MAX )
135 /* maug_retroflt_assets */
137
138struct MFILE_CADDY;
139typedef struct MFILE_CADDY mfile_t;
140
141typedef off_t (*mfile_cursor_t)( struct MFILE_CADDY* p_file );
142typedef off_t (*mfile_has_bytes_t)( struct MFILE_CADDY* p_file );
143typedef MERROR_RETVAL (*mfile_read_byte_t)(
144 struct MFILE_CADDY* p_file, uint8_t* buf );
145typedef MERROR_RETVAL (*mfile_read_block_t)(
146 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz );
147typedef MERROR_RETVAL (*mfile_seek_t)( struct MFILE_CADDY* p_file, off_t pos );
148typedef MERROR_RETVAL (*mfile_read_int_t)(
149 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags );
150typedef MERROR_RETVAL (*mfile_read_line_t)(
151 struct MFILE_CADDY* p_file, char* buf, off_t buf_sz, uint8_t flags );
152typedef MERROR_RETVAL (*mfile_printf_t)(
153 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, ... );
154typedef MERROR_RETVAL (*mfile_write_block_t)(
155 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz );
156
157off_t mfile_mem_cursor( struct MFILE_CADDY* p_file );
158off_t mfile_mem_has_bytes( struct MFILE_CADDY* p_file );
159MERROR_RETVAL mfile_mem_read_byte( struct MFILE_CADDY* p_file, uint8_t* buf );
160MERROR_RETVAL mfile_mem_read_block(
161 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz );
162MERROR_RETVAL mfile_mem_seek( struct MFILE_CADDY* p_file, off_t pos );
163MERROR_RETVAL mfile_mem_read_line(
164 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags );
165MERROR_RETVAL mfile_mem_vprintf(
166 mfile_t* p_file, uint8_t flags, const char* fmt, va_list args );
167
176 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz );
177
178MERROR_RETVAL mfile_plt_init();
179
188 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, va_list args );
189
190/* Load the platform-specific file API. */
191#include <mrapifil.h>
192#include <mrapilog.h>
193
196 uint8_t type;
198 union MFILE_HANDLE h;
199 off_t last_read;
203 uint8_t* mem_buffer;
204 uint8_t flags;
206 off_t sz;
207 char filename[MAUG_PATH_SZ_MAX + 1];
208 mfile_has_bytes_t has_bytes;
209 mfile_cursor_t cursor;
210 mfile_read_byte_t read_byte;
211 mfile_read_block_t read_block;
212 mfile_seek_t seek;
213 mfile_read_int_t read_int;
214 mfile_read_line_t read_line;
215 mfile_printf_t printf;
216 mfile_vprintf_t vprintf;
217 mfile_write_block_t write_block;
218};
219
220typedef struct MFILE_CADDY mfile_t;
221
226
227MERROR_RETVAL mfile_assign_path(
228 retroflat_asset_path tgt, const retroflat_asset_path src, uint8_t flags );
229
231
232off_t mfile_file_has_bytes( struct MFILE_CADDY* p_file );
233
234MERROR_RETVAL mfile_file_read_byte( struct MFILE_CADDY* p_file, uint8_t* buf );
235
236MERROR_RETVAL mfile_file_read_block(
237 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz );
238
239MERROR_RETVAL mfile_file_read_int(
240 struct MFILE_CADDY* p_f, uint8_t* buf, size_t buf_sz, uint8_t flags );
241
242MERROR_RETVAL mfile_file_seek( struct MFILE_CADDY* p_file, off_t pos );
243
244MERROR_RETVAL mfile_file_read_line(
245 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags );
246
247MERROR_RETVAL mfile_file_printf(
248 struct MFILE_CADDY* p_f, uint8_t flags, const char* fmt, ... );
249
250MERROR_RETVAL mfile_file_write_block(
251 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz );
252
253MERROR_RETVAL mfile_file_vprintf(
254 struct MFILE_CADDY* p_f, uint8_t flags, const char* fmt, va_list args );
255
256#define mfile_get_sz( p_file ) ((p_file)->sz)
257
262 MAUG_MHANDLE, void* ptr, off_t, mfile_t* p_file );
263
268MERROR_RETVAL mfile_open_read( const char* filename, mfile_t* p_file );
269
270MERROR_RETVAL mfile_open_write( const char* filename, mfile_t* p_file );
271
275void mfile_close( mfile_t* p_file );
276
277#ifdef MFILE_C
278
279#include <mrapifil.h>
280#include <mrapilog.h>
281
282off_t mfile_file_has_bytes( struct MFILE_CADDY* p_file ) {
283 size_t cursor = 0;
284 cursor = p_file->cursor( p_file );
285 if( p_file->sz > cursor ) {
286#if MFILE_READ_TRACE_LVL > 0
287 debug_printf( MFILE_READ_TRACE_LVL,
288 "file has " OFF_T_FMT " bytes left...",
289 p_file->sz - cursor );
290#endif /* MFILE_READ_TRACE_LVL */
291 return p_file->sz - cursor;
292 } else {
293#if MFILE_READ_TRACE_LVL > 0
294 /* TODO: Improved error message/handling. */
295 debug_printf( MFILE_READ_TRACE_LVL, "file has error bytes left!" );
296#endif /* MFILE_READ_TRACE_LVL */
297 return 0;
298 }
299}
300
301/* === */
302
303MERROR_RETVAL mfile_assign_path(
304 retroflat_asset_path tgt, const retroflat_asset_path src, uint8_t flags
305) {
306 MERROR_RETVAL retval = MERROR_OK;
307 char* ext_ptr = NULL;
308
309 maug_snprintf( tgt, MAUG_PATH_SZ_MAX, "%s", src );
310
311 if( MFILE_ASSIGN_FLAG_TRIM_EXT == (MFILE_ASSIGN_FLAG_TRIM_EXT & flags) ) {
312 ext_ptr = maug_strrchr( tgt, '.' );
313 if( NULL != ext_ptr ) {
314 *ext_ptr = '\0';
315 }
316 }
317
318 return retval;
319}
320
321/* === */
322
323MERROR_RETVAL mfile_file_read_int(
324 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz, uint8_t flags
325) {
326 MERROR_RETVAL retval = MERROR_OK;
327
328 if(
329#ifdef MAUG_LSBF
331#elif defined( MAUG_MSBF )
333#endif
334 ) {
335 debug_printf( MFILE_READ_TRACE_LVL, "reading integer forward" );
336 /* Shrink the buffer moving right and read into it. */
337 retval = p_file->read_block( p_file, buf, buf_sz );
338
339 } else {
340 debug_printf( MFILE_READ_TRACE_LVL, "reading integer reversed" );
341 /* Move to the end of the output buffer and read backwards. */
342 while( 0 < buf_sz ) {
343 retval = p_file->read_byte( p_file, (buf + (buf_sz - 1)) );
344 maug_cleanup_if_not_ok();
345 buf_sz--;
346 }
347 }
348
349cleanup:
350
351 return retval;
352}
353
354/* === */
355
356MERROR_RETVAL mfile_file_printf(
357 struct MFILE_CADDY* p_file, uint8_t flags, const char* fmt, ...
358) {
359 MERROR_RETVAL retval = MERROR_OK;
360 va_list vargs;
361
362 va_start( vargs, fmt );
363 retval = p_file->vprintf( p_file, flags, fmt, vargs );
364 va_end( vargs );
365
366 return retval;
367}
368
369/* === */
370
371off_t mfile_mem_cursor( struct MFILE_CADDY* p_file ) {
372 return p_file->mem_cursor;
373}
374
375/* === */
376
377off_t mfile_mem_has_bytes( struct MFILE_CADDY* p_file ) {
378 return p_file->sz - p_file->mem_cursor;
379}
380
381/* === */
382
383static MERROR_RETVAL mfile_mem_lock( struct MFILE_CADDY* p_f ) {
384 MERROR_RETVAL retval = MERROR_OK;
385
386 assert(
388
389 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
390
391 /* Only lock if this buffer uses a handle and not a pointer. */
392 if( (MAUG_MHANDLE)NULL != p_f->h.mem ) {
393 assert( NULL == p_f->mem_buffer );
394 maug_mlock( p_f->h.mem, p_f->mem_buffer );
395 p_f->flags |= MFILE_FLAG_HANDLE_LOCKED;
396 }
397
398 return retval;
399}
400
401/* === */
402
403static void mfile_mem_release( struct MFILE_CADDY* p_f ) {
404
405 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
406
407 if( MFILE_FLAG_HANDLE_LOCKED == (MFILE_FLAG_HANDLE_LOCKED & p_f->flags) ) {
408 maug_munlock( p_f->h.mem, p_f->mem_buffer );
409 p_f->flags &= ~MFILE_FLAG_HANDLE_LOCKED;
410 }
411}
412
413/* === */
414
415MERROR_RETVAL mfile_mem_read_byte( struct MFILE_CADDY* p_file, uint8_t* buf ) {
416 return p_file->read_block( p_file, buf, 1 );
417}
418
419/* === */
420
421MERROR_RETVAL mfile_mem_read_block(
422 struct MFILE_CADDY* p_file, uint8_t* buf, size_t buf_sz
423) {
424 MERROR_RETVAL retval = MERROR_OK;
425
426 if( p_file->mem_cursor >= p_file->sz ) {
427 return MERROR_FILE;
428 }
429
430 retval = mfile_mem_lock( p_file );
431 maug_cleanup_if_not_ok();
432
433 while( 0 < buf_sz-- ) {
434 *(buf++) = p_file->mem_buffer[p_file->mem_cursor++];
435 }
436
437cleanup:
438
439 mfile_mem_release( p_file );
440
441 return retval;
442}
443
444/* === */
445
446MERROR_RETVAL mfile_mem_seek( struct MFILE_CADDY* p_file, off_t pos ) {
447 MERROR_RETVAL retval = MERROR_OK;
448
449 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_file->type );
450
451 p_file->mem_cursor = pos;
452
453 debug_printf( MFILE_SEEK_TRACE_LVL,
454 "seeking memory buffer to position " OFF_T_FMT " (" OFF_T_FMT ")",
455 pos, p_file->mem_cursor );
456
457 return retval;
458}
459
460/* === */
461
462MERROR_RETVAL mfile_mem_read_line(
463 struct MFILE_CADDY* p_f, char* buffer, off_t buffer_sz, uint8_t flags
464) {
465 MERROR_RETVAL retval = MERROR_OK;
466 off_t i = 0;
467
468 assert( MFILE_CADDY_TYPE_MEM_BUFFER == p_f->type );
469
470 while( i < buffer_sz - 1 && p_f->has_bytes( p_f ) ) {
471 /* Check for potential overflow. */
472 if( i + 1 >= buffer_sz ) {
473 error_printf( "overflow reading string from file!" );
474 retval = MERROR_FILE;
475 break;
476 }
477
478 p_f->read_int( p_f, (uint8_t*)&(buffer[i]), 1, 0 );
479 if( '\n' == buffer[i] ) {
480 /* Break on newline and overwrite it below. */
481 break;
482 }
483 i++;
484 }
485
486 assert( i < buffer_sz ); /* while() above stops before buffer_sz! */
487
488 /* Append a null terminator. */
489 buffer[i] = '\0';
490
491 return retval;
492}
493
494/* === */
495
496MERROR_RETVAL mfile_mem_vprintf(
497 mfile_t* p_file, uint8_t flags, const char* fmt, va_list args
498) {
499 MERROR_RETVAL retval = MERROR_OK;
500
501 if( MFILE_FLAG_READ_ONLY == (MFILE_FLAG_READ_ONLY & p_file->flags) ) {
502 return MERROR_FILE;
503 }
504
505 /* TODO: Enable writing to memory buffer. */
506 error_printf( "writing to memory buffer not currently supported!" );
507
508 /* TODO: Expand buffer and reflect this in sz if writing beyond the end
509 * of the buffer.
510 */
511
512 return retval;
513}
514
515/* === */
516
518 struct MFILE_CADDY* p_f, const uint8_t* buf, size_t buf_sz
519) {
520 MERROR_RETVAL retval = MERROR_OK;
521 ssize_t mv_sz = 0;
522
523 if( 0 == buf_sz ) {
524 /* Short-circuit empty writes. */
525 return MERROR_OK;
526 }
527
528 if( MFILE_FLAG_READ_ONLY == (MFILE_FLAG_READ_ONLY & p_f->flags) ) {
529 return MERROR_FILE;
530 }
531
532 retval = mfile_mem_lock( p_f );
533 maug_cleanup_if_not_ok();
534
535#if MFILE_WRITE_TRACE_LVL > 0
536 debug_printf( MFILE_WRITE_TRACE_LVL, "p: %p, sz: %u, cur: %u, buf_sz: %u\n",
537 p_f->mem_buffer, p_f->sz, p_f->mem_cursor, buf_sz );
538#endif /* MFILE_WRITE_TRACE_LVL */
539
540 mv_sz = (p_f->sz - (p_f->mem_cursor + buf_sz));
541 if( 0 < mv_sz ) {
542 memmove(
543 &(p_f->mem_buffer[p_f->mem_cursor + buf_sz]),
544 &(p_f->mem_buffer[p_f->mem_cursor]),
545 mv_sz );
546 }
547
548 memcpy( &(p_f->mem_buffer[p_f->mem_cursor]), buf, buf_sz );
549 p_f->mem_cursor += buf_sz;
550
551 /* TODO: Expand buffer and reflect this in sz if writing beyond the end
552 * of the buffer.
553 */
554
555cleanup:
556
557 mfile_mem_release( p_f );
558
559 return retval;
560}
561
562/* === */
563
565 MAUG_MHANDLE handle, void* ptr, off_t handle_sz, mfile_t* p_file
566) {
567 MERROR_RETVAL retval = MERROR_OK;
568
569 debug_printf( MFILE_SEEK_TRACE_LVL,
570 "locking handle %p as file %p (" OFF_T_FMT " bytes)...",
571 handle, p_file, handle_sz );
572
573 maug_mzero( p_file, sizeof( struct MFILE_CADDY ) );
574
575 /* Determine if this is based on a handle or a pointer. */
576 if( (MAUG_MHANDLE)NULL == handle && NULL != ptr ) {
577 p_file->mem_buffer = ptr;
578 } else if( (MAUG_MHANDLE)NULL != handle && NULL == ptr ) {
579 p_file->h.mem = handle;
580 /* maug_mlock( handle, p_file->mem_buffer ); */
581 } else {
582 error_printf( "must specify handle or pointer!" );
583 retval = MERROR_FILE;
584 goto cleanup;
585 }
586
588
589 p_file->has_bytes = mfile_mem_has_bytes;
590 p_file->cursor = mfile_mem_cursor;
591 p_file->read_byte = mfile_mem_read_byte;
592 p_file->read_block = mfile_mem_read_block;
593 p_file->read_int = mfile_file_read_int;
594 p_file->seek = mfile_mem_seek;
595 p_file->read_line = mfile_mem_read_line;
596 p_file->write_block = mfile_mem_write_block;
597
598 p_file->sz = handle_sz;
599
600cleanup:
601
602 return retval;
603}
604
605/* === */
606
607MERROR_RETVAL mfile_open_read( const char* filename, mfile_t* p_file ) {
608 MERROR_RETVAL retval = MERROR_OK;
609
610 /* Call the platform-specific actual file opener from mrapifil.h. */
611 retval = mfile_plt_open_read( filename, p_file );
612
613 if( MERROR_OK == retval ) {
614 /* Store filename. */
615 maug_mzero( p_file->filename, MAUG_PATH_SZ_MAX );
616 maug_strncpy( p_file->filename, filename, MAUG_PATH_SZ_MAX );
617 }
618
619 return retval;
620}
621
622/* === */
623
624MERROR_RETVAL mfile_open_write( const char* filename, mfile_t* p_file ) {
625 MERROR_RETVAL retval = MERROR_OK;
626
627 retval = mfile_plt_open_write( filename, p_file );
628
629 if( MERROR_OK == retval ) {
630 /* Store filename. */
631 maug_mzero( p_file->filename, MAUG_PATH_SZ_MAX );
632 maug_strncpy( p_file->filename, filename, MAUG_PATH_SZ_MAX );
633 }
634
635 return retval;
636}
637
638/* === */
639
640void mfile_close( mfile_t* p_file ) {
641# if MFILE_SEEK_TRACE_LVL > 0
642 debug_printf( MFILE_SEEK_TRACE_LVL, "closing file..." );
643# endif /* MFILE_SEEK_TRACE_LVL */
644# ifdef MFILE_MMAP
645 munmap( bytes_ptr_h, bytes_sz );
646# else
647 /* maug_mfree( bytes_ptr_h ); */
648 switch( p_file->type ) {
649 case 0:
650 /* Do nothing silently. */
651 break;
652
654 mfile_plt_close( p_file );
655 p_file->type = 0;
656 break;
657
659 if( NULL != p_file->mem_buffer ) {
660 maug_munlock( p_file->h.mem, p_file->mem_buffer );
661 debug_printf( MFILE_SEEK_TRACE_LVL,
662 "unlocked handle %p from file %p...",
663 p_file->h.mem, p_file );
664 p_file->type = 0;
665 }
666 break;
667
668 default:
669 error_printf( "unknown file type: %d", (p_file)->type );
670 break;
671 }
672# endif /* MFILE_MMAP */
673}
674
675#endif /* MFILE_C */
676 /* maug_mfile */
678
679#endif /* !MFILE_H */
680
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define MFILE_CADDY_TYPE_FILE
A standard UNIX file.
Definition mfile.h:50
#define MFILE_CADDY_TYPE_MEM_BUFFER
An array of bytes in memory abstracted through this library.
Definition mfile.h:55
#define MFILE_FLAG_HANDLE_LOCKED
Flag for MFILE_CADDY::flags indicating subsequent internal unlocks should unlock the handle back to i...
Definition mfile.h:71
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:35
#define MFILE_READ_FLAG_MSBF
Flag for mfile_read_int_t() indicating integer should always be read most significant byte first.
Definition mfile.h:99
MERROR_RETVAL(* mfile_vprintf_t)(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 ...
Definition mfile.h:187
#define MFILE_READ_FLAG_LSBF
Flag for mfile_read_int_t() indicating integer should always be read least significant byte first.
Definition mfile.h:92
MERROR_RETVAL mfile_open_read(const char *filename, mfile_t *p_file)
Open a file and read it into memory or memory-map it.
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.
void mfile_close(mfile_t *p_file)
Close a file opened with mfile_open_read().
#define MFILE_FLAG_READ_ONLY
Flag for MFILE_CADDY::flags indicating this file is read-only.
Definition mfile.h:63
char retroflat_asset_path[MAUG_PATH_SZ_MAX+1]
Path/name used to load an asset from disk.
Definition mfile.h:129
Definition mfile.h:194
off_t mem_cursor
Current position if its type is MFILE_CADDY_TYPE_MEM_BUFFER.
Definition mfile.h:201
uint8_t type
The RetroFile Types flag describing this file.
Definition mfile.h:196
union MFILE_HANDLE h
The physical handle or pointer to access the file by.
Definition mfile.h:198
uint8_t * mem_buffer
Locked pointer for MFILE_HANDLE::mem.
Definition mfile.h:203
off_t sz
Size of the current file/buffer in bytes.
Definition mfile.h:206