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