/* * Copyright � 2006-2013 SplinterGU (Fenix/Bennugd) * Copyright � 2002-2006 Fenix Team (Fenix) * Copyright � 1999-2002 Jos� Luis Cebri�n Pag�e (Fenix) * * This file is part of Bennu - Game Development * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * */ #ifdef _WIN32 #include #endif #include #include #include #ifdef TARGET_BEOS #include #else #include #endif #include #include #include #include #include "files.h" #define MAX_POSSIBLE_PATHS 128 char * possible_paths[MAX_POSSIBLE_PATHS] = { NULL } ; int opened_files = 0; typedef struct { char * stubname ; char * name ; int offset ; int size ; FILE * fp ; } XFILE ; XFILE * x_file = NULL ; int max_x_files = 0; int x_files_count = 0 ; /* Add new file to PATH */ void xfile_init( int maxfiles ) { x_file = ( XFILE * ) calloc( sizeof( XFILE ), maxfiles ); max_x_files = maxfiles; } void file_add_xfile( file * fp, char * stubname, long offset, char * name, int size ) { char * ptr ; assert( x_files_count < max_x_files ) ; assert( fp->type == F_FILE ) ; x_file[x_files_count].stubname = strdup( stubname ); x_file[x_files_count].fp = fp->fp ; x_file[x_files_count].offset = offset ; x_file[x_files_count].size = size ; x_file[x_files_count].name = strdup( name ) ; ptr = x_file[x_files_count].name; while ( *ptr ) { if ( *ptr == '\\' ) *ptr = '/'; /* Unix style */ ptr++; } x_files_count++ ; } /* Read a datablock from file */ int file_read( file * fp, void * buffer, int len ) { assert( len != 0 ); if ( fp->type == F_XFILE ) { XFILE * xf ; int result ; xf = &x_file[fp->n] ; if (( len + fp->pos ) > ( xf->offset + xf->size ) ) { fp->eof = 1 ; len = xf->size + xf->offset - fp->pos ; } fseek( fp->fp, fp->pos, SEEK_SET ) ; result = fread( buffer, 1, len, fp->fp ) ; fp->pos = ftell( fp->fp ) ; return result ; } #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) { int result = gzread( fp->gz, buffer, len ) ; fp->error = ( result < len ); if ( result < 0 ) result = 0; return result ; } #endif return fread( buffer, 1, len, fp->fp ) ; } /* Save a unquoted string to a file */ int file_qputs( file * fp, char * buffer ) { char dest[1024], * optr ; const char * ptr ; ptr = buffer ; optr = dest ; while ( *ptr ) { if ( optr > dest + 1000 ) { *optr++ = '\\' ; *optr++ = '\n' ; *optr = 0 ; file_write( fp, dest, optr - dest ) ; optr = dest ; } if ( *ptr == '\n' ) { *optr++ = '\\' ; *optr++ = 'n' ; ptr++ ; continue ; } if ( *ptr == '\\' ) { *optr++ = '\\' ; *optr++ = *ptr++ ; continue ; } *optr++ = *ptr++ ; } *optr++ = '\n' ; return file_write( fp, dest, optr - dest ) ; } /* Load a string from a file and unquoted it */ int file_qgets( file * fp, char * buffer, int len ) { char * ptr, * result = NULL ; if ( fp->type == F_XFILE ) { XFILE * xf ; int l = 0; char * ptr = result = buffer ; xf = &x_file[fp->n] ; fseek( fp->fp, fp->pos, SEEK_SET ) ; while ( l < len ) { if ( fp->pos >= xf->offset + xf->size ) { fp->eof = 1 ; break ; } fread( ptr, 1, 1, fp->fp ) ; l++ ; fp->pos++ ; if ( *ptr++ == '\n' ) break ; } *ptr = 0 ; fp->pos = ftell( fp->fp ) ; if ( l == 0 ) return 0 ; } #ifndef NO_ZLIB else if ( fp->type == F_GZFILE ) { result = gzgets( fp->gz, buffer, len ) ; } #endif else { result = fgets( buffer, len, fp->fp ); } if ( result == NULL ) { buffer[0] = 0 ; return 0 ; } ptr = buffer ; while ( *ptr ) { if ( *ptr == '\\' ) { if ( ptr[1] == 'n' ) ptr[1] = '\n' ; strcpy( ptr, ptr + 1 ) ; ptr++ ; continue ; } if ( *ptr == '\n' ) { *ptr = 0 ; break ; } ptr++ ; } return strlen( buffer ) ; } /* Save a string to file */ int file_puts( file * fp, char * buffer ) { return file_write( fp, buffer, strlen( buffer ) ) ; } /* Load a string from a file and unquoted it */ int file_gets( file * fp, char * buffer, int len ) { char * result = NULL ; if ( fp->type == F_XFILE ) { XFILE * xf ; int l = 0; char * ptr = result = buffer ; xf = &x_file[fp->n] ; fseek( fp->fp, fp->pos, SEEK_SET ) ; while ( l < len ) { if ( fp->pos >= xf->offset + xf->size ) { fp->eof = 1 ; break ; } fread( ptr, 1, 1, fp->fp ) ; l++ ; fp->pos++ ; if ( *ptr++ == '\n' ) break ; } *ptr = 0 ; fp->pos = ftell( fp->fp ) ; if ( l == 0 ) return 0 ; } #ifndef NO_ZLIB else if ( fp->type == F_GZFILE ) { result = gzgets( fp->gz, buffer, len ) ; } #endif else { result = fgets( buffer, len, fp->fp ); } if ( result == NULL ) { buffer[0] = 0 ; return 0 ; } return strlen( buffer ) ; } /* Save an int data to a binary file */ int file_writeSint8( file * fp, int8_t * buffer ) { return file_write( fp, buffer, sizeof( uint8_t ) ); } int file_writeUint8( file * fp, uint8_t * buffer ) { return file_write( fp, buffer, sizeof( uint8_t ) ); } int file_writeSint16( file * fp, int16_t * buffer ) { #if __BYTEORDER == __LIL_ENDIAN return file_write( fp, buffer, sizeof( int16_t ) ); #else file_write( fp, ( uint8_t * )buffer + 1, 1 ); return file_write( fp, ( uint8_t * )buffer, 1 ); #endif } int file_writeUint16( file * fp, uint16_t * buffer ) { return file_writeSint16( fp, ( int16_t * ) buffer ); } int file_writeSint32( file * fp, int32_t * buffer ) { #if __BYTEORDER == __LIL_ENDIAN return file_write( fp, buffer, sizeof( int32_t ) ); #else file_write( fp, ( uint8_t * )buffer + 3, 1 ); file_write( fp, ( uint8_t * )buffer + 2, 1 ); file_write( fp, ( uint8_t * )buffer + 1, 1 ); return file_write( fp, ( uint8_t * )buffer, 1 ); #endif } int file_writeUint32( file * fp, uint32_t * buffer ) { return file_writeSint32( fp, ( int32_t * )buffer ); } /* Save an array to a binary file */ int file_writeSint8A( file * fp, int8_t * buffer, int n ) { return file_write( fp, buffer, n ); } int file_writeUint8A( file * fp, uint8_t * buffer, int n ) { return file_write( fp, buffer, n ); } int file_writeSint16A( file * fp, int16_t * buffer, int n ) { #if __BYTEORDER == __LIL_ENDIAN return file_write( fp, buffer, n << 1 ) >> 1 ; #else int i; for ( i = 0; i < n; i++ ) if ( !file_writeSint16( fp, ( int16_t * )buffer++ ) ) break; return i; #endif } int file_writeUint16A( file * fp, uint16_t * buffer, int n ) { return file_writeSint16A( fp, ( int16_t * )buffer, n ); } int file_writeSint32A( file * fp, int32_t * buffer, int n ) { #if __BYTEORDER == __LIL_ENDIAN return file_write( fp, buffer, n << 2 ) >> 2; #else int i; for ( i = 0; i < n; i++ ) if ( !file_writeSint32( fp, ( int32_t * )buffer++ ) ) break; return i; #endif } int file_writeUint32A( file * fp, uint32_t * buffer, int n ) { return file_writeSint32A( fp, ( int32_t * )buffer, n ); } /* Read an int data from a binary file */ int file_readSint8( file * fp, int8_t * buffer ) { return file_read( fp, buffer, sizeof( int8_t ) ); } int file_readUint8( file * fp, uint8_t * buffer ) { return file_read( fp, buffer, sizeof( int8_t ) ); } int file_readSint16( file * fp, int16_t * buffer ) { #if __BYTEORDER == __LIL_ENDIAN return file_read( fp, buffer, sizeof( int16_t ) ); #else file_read( fp, ( uint8_t * )buffer + 1, 1 ); return file_read( fp, ( uint8_t * )buffer, 1 ); #endif } int file_readUint16( file * fp, uint16_t * buffer ) { return file_readSint16( fp, (int16_t *)buffer ); } int file_readSint32( file * fp, int32_t * buffer ) { #if __BYTEORDER == __LIL_ENDIAN return file_read( fp, buffer, sizeof( int32_t ) ); #else file_read( fp, ( uint8_t * )buffer + 3, 1 ); file_read( fp, ( uint8_t * )buffer + 2, 1 ); file_read( fp, ( uint8_t * )buffer + 1, 1 ); return file_read( fp, ( uint8_t * )buffer, 1 ); #endif } int file_readUint32( file * fp, uint32_t * buffer ) { return file_readSint32( fp, ( int32_t * )buffer ); } /* Read an array from a binary file */ int file_readSint8A( file * fp, int8_t * buffer, int n ) { return file_read( fp, buffer, n ); } int file_readUint8A( file * fp, uint8_t * buffer, int n ) { return file_read( fp, buffer, n ); } int file_readSint16A( file * fp, int16_t * buffer, int n ) { #if __BYTEORDER == __LIL_ENDIAN return file_read( fp, buffer, n << 1 ) >> 1; #else int i; for ( i = 0; i < n; i++ ) if ( !file_readSint16( fp, ( int16_t * )buffer++ ) ) break; return i; #endif } int file_readUint16A( file * fp, uint16_t * buffer, int n ) { return file_readSint16A( fp, ( int16_t * )buffer, n ); } int file_readSint32A( file * fp, int32_t * buffer, int n ) { #if __BYTEORDER == __LIL_ENDIAN return file_read( fp, buffer, n << 2 ) >> 2; #else int i; for ( i = 0; i < n; i++ ) if ( !file_readSint32( fp, ( int32_t * )buffer++ ) ) break; return i; #endif } int file_readUint32A( file * fp, uint32_t * buffer, int n ) { return file_readSint32A( fp, ( int32_t * )buffer, n ); } /* Write a datablock to a file */ int file_write( file * fp, void * buffer, int len ) { if ( fp->type == F_XFILE ) { XFILE * xf ; int result ; xf = &x_file[fp->n] ; if (( len + fp->pos ) > ( xf->offset + xf->size ) ) { fp->eof = 1 ; len = xf->size + xf->offset - fp->pos ; } fseek( fp->fp, fp->pos, SEEK_SET ) ; result = fwrite( buffer, 1, len, fp->fp ) ; fp->pos = ftell( fp->fp ) ; return result ; } #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) { int result = gzwrite( fp->gz, buffer, len ) ; if (( fp->error = ( result < 0 ) ) != 0 ) result = 0 ; return ( result < len ) ? 0 : len ; } #endif return fwrite( buffer, 1, len, fp->fp ) ; } /* Return file size */ int file_size( file * fp ) { long pos, size ; if ( fp->type == F_XFILE ) return x_file[fp->n].size ; pos = file_pos( fp ); #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) { char buffer[8192]; size = pos; while ( !file_eof( fp ) ) size += file_read( fp, buffer, sizeof(buffer) ); } else #endif { file_seek(fp, 0, SEEK_END ) ; size = file_pos( fp ) ; } file_seek(fp, pos, SEEK_SET ) ; return size ; } /* Get current file pointer position */ int file_pos( file * fp ) { if ( fp->type == F_XFILE ) return fp->pos - x_file[fp->n].offset ; #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) return gztell( fp->gz ) ; #endif return ftell( fp->fp ) ; } int file_flush( file * fp ) { if ( fp->type == F_XFILE ) return 0 ; #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) return 0 ; #endif return fflush( fp->fp ) ; } /* Set current file pointer position */ int file_seek( file * fp, int pos, int where ) { assert( fp ); if ( fp->type == F_XFILE ) { if ( where == SEEK_END ) pos = x_file[fp->n].size - pos + 1 ; else if ( where == SEEK_CUR ) pos += ( fp->pos - x_file[fp->n].offset ); if ( x_file[fp->n].size < pos ) pos = x_file[fp->n].size ; if ( pos < 0 ) pos = 0 ; fp->pos = pos + x_file[fp->n].offset ; return pos ; } #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) { assert( fp->gz ); return gzseek( fp->gz, pos, where ) ; } #endif assert( fp->fp ); return fseek( fp->fp, pos, where ) ; } void file_rewind( file * fp ) { fp->error = 0; switch ( fp->type ) { case F_XFILE: fp->pos = x_file[fp->n].offset ; break; #ifndef NO_ZLIB case F_GZFILE: gzrewind( fp->gz ) ; break; #endif default: rewind( fp->fp ) ; } } /* Open file */ static int open_raw( file * f, const char * filename, const char * mode ) { char _mode[5]; char *p; #ifndef NO_ZLIB if ( !strchr( mode, '0' ) ) { f->type = F_GZFILE ; f->gz = gzopen( filename, mode ) ; f->eof = 0 ; if ( f->gz ) return 1 ; } #endif p = _mode; while ( *mode ) { if ( *mode != '0' ) { *p = *mode; p++; } mode++; } *p = '\0'; f->eof = 0 ; f->type = F_FILE ; f->fp = fopen( filename, _mode ) ; if ( f->fp ) return 1 ; return 0 ; } file * file_open( const char * filename, char * mode ) { char work [__MAX_PATH]; char here [__MAX_PATH]; char * name = NULL ; char * p, c ; int i; file * f ; f = ( file * ) calloc( 1, sizeof( file ) ) ; assert( f ) ; p = f->name; while ( *filename ) { *p++ = *filename++; if ( p[-1] == '\\' ) p[-1] = '/'; /* Unix style */ } p[0] = '\0'; filename = f->name; if ( open_raw( f, filename, mode ) ) { opened_files++; return f ; } /* if real file don't exists in disk */ if ( strchr( mode, 'r' ) && strchr( mode, 'b' ) && /* Only read-only files */ !strchr( mode, '+' ) && !strchr( mode, 'w' ) ) { for ( i = 0 ; i < x_files_count ; i++ ) { if ( strcmp( filename, x_file[i].name ) == 0 ) { f->eof = 0; f->pos = x_file[i].offset; f->type = F_XFILE; f->n = i; f->fp = fopen( x_file[i].stubname, "rb" ); opened_files++; return f ; } } } p = name = work; while (( c = *filename ) ) { if ( c == '\\' || c == '/' ) { c = 0; name = p + 1; } *p++ = c; filename++; } *p = '\0'; /* Use file extension for search in a directory named as it (for example: FPG dir for .FPG files) */ if ( strchr( name, '.' ) ) { strcpy( here, strrchr( name, '.' ) + 1 ) ; strcat( here, PATH_SEP ) ; strcat( here, name ) ; if ( open_raw( f, here, mode ) ) { opened_files++; return f ; } } for ( i = 0 ; possible_paths[i] ; i++ ) { strcpy( here, possible_paths[i] ) ; strcat( here, name ) ; if ( open_raw( f, here, mode ) ) { opened_files++; return f ; } } free( f ) ; return 0 ; } /* Close file */ void file_close( file * fp ) { if ( fp == NULL ) return; if ( fp->type == F_FILE ) fclose( fp->fp ) ; if ( fp->type == F_XFILE ) fclose( fp->fp ) ; #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) gzclose( fp->gz ) ; #endif opened_files--; free( fp ) ; } /* Add a new dir to PATH */ void file_addp( const char * path ) { char truepath[__MAX_PATH]; int n ; if ( !path || !*path ) return; strcpy( truepath, path ) ; for ( n = 0 ; truepath[n] ; n++ ) if ( truepath[n] == '\\' ) truepath[n] = '/' ; if ( truepath[strlen( truepath )-1] != '/' ) strcat( truepath, "/" ) ; for ( n = 0 ; n < MAX_POSSIBLE_PATHS - 1 && possible_paths[n] ; n++ ) ; possible_paths[n] = strdup( truepath ) ; possible_paths[n+1] = NULL ; } /* --- */ int file_remove( const char * filename ) { return ( remove( filename ) ); } /* --- */ int file_move( const char * source_file, const char * target_file ) { return ( rename( source_file, target_file ) ); } /* Check for file exists */ int file_exists( const char * filename ) { file * fp ; fp = file_open( filename, "rb" ) ; if ( fp ) { file_close( fp ) ; return 1 ; } return 0 ; } /* Check for file end is reached */ int file_eof( file * fp ) { if ( fp->type == F_XFILE ) { return fp->eof ? 1 : 0; } #ifndef NO_ZLIB if ( fp->type == F_GZFILE ) { if ( fp->error ) return 1 ; return gzeof( fp->gz ) ? 1 : 0; } #endif return feof( fp->fp ) ? 1 : 0; } /* Get the FILE * of the file */ FILE * file_fp( file * f ) { if ( f->type == F_XFILE ) { // XFILE * xf = &x_file[f->n] ; fseek( f->fp, f->pos, SEEK_SET ) ; return f->fp ; } return f->fp ; } /* ------------------------------------------------------------------------------------ */ char * getfullpath( char *rel_path ) { char fullpath[ __MAX_PATH ] = ""; #ifdef _WIN32 GetFullPathName( rel_path, sizeof( fullpath ), fullpath, NULL ); #else realpath( rel_path, fullpath ); #endif if ( *fullpath ) return strdup( fullpath ); return NULL; } /* ------------------------------------------------------------------------------------ */ #ifdef _WIN32 #define ENV_PATH_SEP ';' #else #define ENV_PATH_SEP ':' #endif char * whereis( char *file ) { char * path = getenv( "PATH" ), *pact = path, *p; char fullname[ __MAX_PATH ]; while ( pact && *pact ) { struct stat st; if ( ( p = strchr( pact, ENV_PATH_SEP ) ) ) *p = '\0'; sprintf( fullname, "%s%s%s", pact, ( pact[ strlen( pact ) - 1 ] == ENV_PATH_SEP ) ? "" : PATH_SEP, file ); if ( !stat( fullname, &st ) && S_ISREG( st.st_mode ) ) { pact = strdup( pact ); if ( p ) *p = ENV_PATH_SEP; return ( pact ); } if ( !p ) break; *p = ENV_PATH_SEP; pact = p + 1; } return NULL; } /* ------------------------------------------------------------------------------------ */