📄 resmgr.c
字号:
/* The only way to insure that the heads will be in the right place is
to reseek on every read (since multiple threads may be reading this
file). This is actually not as expensive as it seems. First of all,
if the heads are in the same position, or the cache contains the byte
stream from that offset, no seek will be done. If that isn't so, a
seek was going to happen anyway when the OS tries to do the read. */
lseek( file -> os_handle, (file -> seek_start + file -> current_pos), SEEK_SET );
len = _read( file -> os_handle, buffer, count );
if( len < 0 ) /* error, see if media has changed */
ResCheckMedia( file -> device );
else
file -> current_pos += len;
IF_LOG( LOG( "read (%s): %d\n", file -> filename, len ));
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( len );
}
else {
if( count > (file -> size - file -> current_pos))
count = file -> size - file -> current_pos;
memcpy( buffer, file -> zip -> out_buffer + file -> current_pos, count );
file -> current_pos += count;
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return(count);
}
return( 0 );
}
/* =======================================================
FUNCTION: ResLoadFile
PURPOSE: Load an entire file into memory. This is
really a convenience function that
encorporates these components:
ResOpenFile
malloc
ResReadFile
ResCloseFile
PARAMETERS: Filename, optional ptr to store number
of bytes actually read, optional ptr to
buffer you want file read to.
RETURNS: Ptr to buffer holding file or NULL (on error).
======================================================= */
RES_EXPORT char * ResLoadFile( const char * filename, char * buffer, size_t * size )
{
int file;
int check;
int s;
char * alloc_buffer;
IF_LOG( LOG( "load (%s):\n", filename ));
#if( RES_DEBUG_PARAMS )
if( !filename ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResLoadFile" );
return( NULL );
}
#endif /* RES_DEBUG_PARAMS */
file = ResOpenFile( filename, _O_RDONLY | _O_BINARY );
if( EMPTY(file))
return( NULL ); /* message will already have been printed if using the debug version */
s = ResSizeFile( file );
if( !buffer ) {
#ifdef USE_SH_POOLS
alloc_buffer = (char *)MemAllocPtr( gResmgrMemPool, s, 0 );
#else
alloc_buffer = (char *)MemMalloc( s, filename );
#endif
if( !alloc_buffer ) {
SAY_ERROR( RES_ERR_NO_MEMORY, filename );
ResCloseFile( file );
if( size )
*size = 0;
return( NULL );
}
}
else
alloc_buffer = buffer;
check = ResReadFile( file, alloc_buffer, s );
ResCloseFile( file );
if( check < 0 ) /* error reading file */
{
#ifdef USE_SH_POOLS
MemFreePtr( alloc_buffer );
#else
MemFree( alloc_buffer );
#endif
alloc_buffer = NULL;
}
if( size )
*size = check;
return( alloc_buffer );
}
/* =======================================================
FUNCTION: ResUnloadFile
PURPOSE: Unloads a file that was allocated via
ResLoadFile. This function is here for
two purposes, 1) provide a balance to
the API for ResLoadFile, and 2) to provide
a placeholder should ResLoadFile be expanded
to allow some sort of caching.
PARAMETERS: Memory pointer that was returned from
ResLoadFile.
RETURNS: None.
======================================================= */
RES_EXPORT void ResUnloadFile( char * buffer )
{
#if( RES_DEBUG_PARAMS )
if( !buffer ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResUnloadFile" );
return;
}
#endif /* RES_DEBUG_PARAMS */
#ifdef USE_SH_POOLS
MemFreePtr( buffer );
#else
MemFree( buffer );
#endif
}
/* =======================================================
FUNCTION: ResCloseFile
PURPOSE: Close a previously opened file.
PARAMETERS: File int.
RETURNS: TRUE (pass) / FALSE (fail)
======================================================= */
RES_EXPORT int ResCloseFile( int file )
{
HASH_ENTRY * entry;
char filename[_MAX_PATH],
dirpath[_MAX_PATH];
long size;
int retval = 1;
#if( RES_DEBUG_PARAMS )
if( file < 0 || file >= MAX_FILE_HANDLES ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResCloseFile" );
return( FALSE );
}
if( FILE_HANDLES[ file ].os_handle == -1 ) {
SAY_ERROR( RES_ERR_ILLEGAL_FILE_HANDLE, "ResCloseFile" );
return( FALSE );
}
#endif /* RES_DEBUG_PARAMS */
#if (RES_MULTITHREAD)
REQUEST_LOCK(GLOCK);
#endif
IF_LOG( LOG( "close (%s):\n", FILE_HANDLES[ file ].filename ));
SHOULD_I_CALL_WITH( CALLBACK_CLOSE_FILE, file, retval );
if( !FILE_HANDLES[file].zip ) {
/* if the file has been written to, recheck the size */
if( FILE_HANDLES[file].csize == (unsigned int)WRITTEN_TO_FLAG ) {
/* flush to disk */
_commit( FILE_HANDLES[file].os_handle );
/* go to the end of the file */
size = lseek( FILE_HANDLES[file].os_handle, 0, SEEK_END );
split_path( FILE_HANDLES[file].filename, filename, dirpath );
#if( !RES_USE_FLAT_MODEL )
entry = hash_find( dirpath, GLOBAL_HASH_TABLE );
if( entry ) {
entry = hash_find( filename, (HASH_TABLE *)entry -> dir );
if( entry )
entry -> size = size;
else {
SAY_ERROR( RES_ERR_UNKNOWN, "set size" );
}
}
else {
SAY_ERROR( RES_ERR_UNKNOWN, "set size" );
}
#else /* flat model */
entry = hash_find( filename, GLOBAL_HASH_TABLE );
if( entry )
entry -> size = size;
else {
SAY_ERROR( RES_ERR_UNKNOWN, "set size" );
}
#endif /* !RES_USE_FLAT_MODEL */
}
if( !FILE_HANDLES[ file ].seek_start ) /* don't close an archive */
_close( FILE_HANDLES[ file ].os_handle );
#ifdef USE_SH_POOLS
MemFreePtr( FILE_HANDLES[ file ].filename );
#else
MemFree( FILE_HANDLES[ file ].filename );
#endif
FILE_HANDLES[ file ].filename = NULL;
FILE_HANDLES[ file ].os_handle = -1;
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return( TRUE );
}
else
{
#ifdef USE_SH_POOLS
MemFreePtr( FILE_HANDLES[file].zip );
MemFreePtr( FILE_HANDLES[file].filename );
#else
MemFree( FILE_HANDLES[file].zip );
MemFree( FILE_HANDLES[file].filename );
#endif
FILE_HANDLES[ file ].zip = NULL;
FILE_HANDLES[ file ].filename = NULL;
FILE_HANDLES[ file ].os_handle = -1;
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return( TRUE );
}
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return( FALSE );
}
/* =======================================================
FUNCTION: ResWriteFile
PURPOSE: Write to a file via the Resource Manager.
PARAMETERS: File int, ptr to a buffer to get
data from, number of bytes to write.
RETURNS: Number of bytes actually written.
======================================================= */
RES_EXPORT size_t ResWriteFile( int handle, const void * buffer, size_t count )
{
FILE_ENTRY * file;
int check;
int retval = 1;
#if( RES_DEBUG_PARAMS )
if( handle < 0 || handle >= MAX_FILE_HANDLES || !buffer ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResWriteFile" );
return( 0 );
}
#endif /* RES_DEBUG_PARAMS */
#if (RES_MULTITHREAD)
REQUEST_LOCK(GLOCK);
#endif
file = &FILE_HANDLES[ handle ];
if( file -> os_handle == -1 ) {
SAY_ERROR( RES_ERR_ILLEGAL_FILE_HANDLE, "ResWriteFile" );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return(0);
}
if( !(file -> mode & (_O_CREAT | _O_APPEND | _O_RDWR | _O_WRONLY))) {
SAY_ERROR( RES_ERR_PROBLEM_WRITING, file -> filename );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return(0);
}
SHOULD_I_CALL_WITH( CALLBACK_WRITE_FILE, handle, retval );
/* Set a bit so we know to reestablish the file size on ResCloseFile() */
/* Use the csize field since we no this is not used for files we can write to */
file -> csize = (unsigned int)WRITTEN_TO_FLAG;
IF_LOG( LOG( "write (%s): (%d bytes)\n", file -> filename, count ));
check = _write( file -> os_handle, buffer, count );
if( check < 0 )
ResCheckMedia( file -> device );
else
file -> current_pos += count;
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return( check );
}
/* =======================================================
FUNCTION: ResDeleteFile
PURPOSE: Remove a file from the r/w medium.
PARAMETERS: Filename.
RETURNS: TRUE (pass) / FALSE (fail)
======================================================= */
RES_EXPORT int ResDeleteFile( const char * name )
{
HASH_ENTRY * entry;
HASH_TABLE * table;
int check;
#if( RES_DEBUG_PARAMS )
if( !name ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResDeleteFile" );
return( FALSE );
}
#endif
#if (RES_MULTITHREAD)
REQUEST_LOCK(GLOCK);
#endif
IF_LOG( LOG( "delete: %s\n", name ));
#if( !RES_USE_FLAT_MODEL )
/* find both the entry & the table it resides in */
entry = hash_find_table( name, &table );
#else
entry = hash_find( name, GLOBAL_HASH_TABLE );
table = GLOBAL_HASH_TABLE;
#endif
if( !entry ) {
SAY_ERROR( RES_ERR_FILE_NOT_FOUND, name );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return( FALSE );
}
if( entry -> file_position == -1 ) {
chmod( entry -> name, _S_IWRITE );
check = remove( entry -> name );
if( check == -1 ) {
SAY_ERROR( RES_ERR_CANT_DELETE_FILE, name );
}
/* don't return yet, remove file from hash
table even if delete at os level fails */
}
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK);
#endif
return( hash_delete( entry, table ));
}
/* =============================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -