📄 resmgr.c
字号:
char filename[_MAX_PATH];
int retval = 1;
int handle;
int dir_index;
struct _finddata_t data; /* used to dummy-up a hash entry */
char tmp[LREC_SIZE];
local_file_hdr lrec;
IF_LOG( LOG( "open (%s):\n", name ));
#if( RES_DEBUG_PARAMS )
if( !name ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResOpenFile" );
return( -1 );
}
#endif
#if (RES_MULTITHREAD)
REQUEST_LOCK(GLOCK);
#endif
/* get the next available file handle */
handle = get_handle();
if( handle == -1 ) { /* none left */
SAY_ERROR( RES_ERR_TOO_MANY_FILES, "ResOpenFile" );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
file = &FILE_HANDLES[ handle ];
/* ----------------------------------------------------
Find the hash entry for the given filename. If we
are building a hierarchical model, we need to search
all of the tables in the order of our search path
(hash_find_table), otherwise, we just need to search
our main hash table (hash_find).
If filename coercion is being used, the filename
string is scanned for the occurence of a backslash.
If there is one, the code forces a fullpath name
conversion on this string in-case it is a relative
pathname (eg; ..\windows\foo.c).
---------------------------------------------------- */
#if( !RES_USE_FLAT_MODEL )
entry = hash_find_table( name, &table );
#else /* flat model */
entry = hash_find( name, GLOBAL_HASH_TABLE );
#endif
if( !entry ) { /* NOT FOUND */
/* if the user is trying to create a file on the harddrive,
this is ok. */
if( !(mode & _O_CREAT)) {
SAY_ERROR( RES_ERR_FILE_NOT_FOUND, name );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
else {
/* CREATING A FILE */
/* In this case, we need to make sure that the directory is already 'added'
to the resource manager if we are using hierarchical model. If we are
using the flat model, we just need to create a dummy hash_entry for the
file. The file size member of the hash entry structure will be set
in ResFileClose. */
IF_LOG( LOG( "creating file: %s\n", name ));
#if( !RES_USE_FLAT_MODEL )
if( strchr( name, ASCII_BACKSLASH )) {
split_path( name, filename, dirpath );
entry = hash_find( dirpath, GLOBAL_HASH_TABLE );
}
else {/* current directory */
strcpy( filename, name );
strcpy( dirpath, GLOBAL_CURRENT_PATH );
entry = hash_find( GLOBAL_CURRENT_PATH, GLOBAL_HASH_TABLE );
}
if( !entry || !entry -> dir ) { /* directory is not already added */
SAY_ERROR( RES_ERR_UNKNOWN_WRITE_TO, name );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
else {
table = (HASH_TABLE *)entry -> dir;
}
#else /* flat model */
if( strchr( name, ASCII_BACKSLASH ))
split_path( name, filename, dirpath );
else /* current directory */
strcpy( filename, name );
table = GLOBAL_HASH_TABLE;
#endif /* !RES_USE_FLAT_MODEL */
strcpy( data.name, filename );
data.attrib = (unsigned int)FORCE_BIT;
data.time_create = 0;
data.time_access = 0;
data.size = 0;
entry = hash_add( &data, table );
if( !entry ) {
SAY_ERROR( RES_ERR_UNKNOWN, "ResOpen - create" );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
for( dir_index = 0; dir_index <= GLOBAL_SEARCH_INDEX; dir_index++ ) {
if( !stricmp( dirpath, GLOBAL_SEARCH_PATH[ dir_index ] )) {
entry -> directory = dir_index;
entry -> volume = (char)(toupper(dirpath[0]) - 'A');
break;
}
}
if( dir_index > GLOBAL_SEARCH_INDEX ) {
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
entry -> archive = -1;
}
}
/* Make sure the user isn't trying to write to an archive file.
Someday this may be possible, but not for a while. */
if( entry -> archive != -1 ) {
int check;
check = (_O_CREAT | _O_APPEND | _O_RDWR | _O_WRONLY);
check &= mode;
if( check ) {/* don't known why had to do it broken out like this - ask MSVC */
SAY_ERROR( RES_ERR_CANT_WRITE_ARCHIVE, name );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
}
/* Initialize some common data */
file -> current_pos = 0;
file -> current_filbuf_pos = 0;
/* Is this a loose file (not in an archive?) */
if( entry -> archive == -1 ) {
/* may seem redundant but there are too many pathological cases otherwise */
if( mode & _O_CREAT )
res_fullpath( filename, name, _MAX_PATH ); /* regardless of coercion state */
else
sprintf( filename, "%s%s", GLOBAL_SEARCH_PATH[ entry -> directory ], entry -> name );
/* there is actually a third parameter to open() (MSVC just doesn't admit it)
octal 666 ensures that stack-crap won't accidently create this file as
read-only. Thank to Roger Fujii for this fix! */
file -> os_handle = _open( filename, mode, 0x1b6 /* choked on O666 and O666L */ );
if( file -> os_handle == -1 ) {
if( errno == EACCES )
{SAY_ERROR( RES_ERR_FILE_SHARING, filename );}
else
{SAY_ERROR( RES_ERR_FILE_NOT_FOUND, filename );}
ResCheckMedia( entry -> volume );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
file -> seek_start = 0;
file -> size = entry -> size;
file -> csize = 0;
file -> attrib = entry -> attrib;
file -> mode = mode;
file -> location = -1;
file -> zip = NULL;
file -> filename = MemStrDup( filename );
file -> device = entry -> volume;
SHOULD_I_CALL_WITH( CALLBACK_OPEN_FILE, handle, retval );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( handle );
}
else { /* in an archive */
/* using the handle, search the list for the structure */
for( list = ARCHIVE_LIST; list; list = list -> next ) {
archive = (ARCHIVE *)list -> node;
if( archive -> os_handle == entry -> archive )
break;
}
if( !list ) {
SAY_ERROR( RES_ERR_UNKNOWN, " " ); /* archive handle in hash entry is incorrect (or archive detached) */
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
sprintf( filename, "%s%s", GLOBAL_SEARCH_PATH[ entry -> directory ], entry -> name );
lseek( archive -> os_handle, entry -> file_position + SIGNATURE_SIZE, SEEK_SET );
_read( archive -> os_handle, tmp, LREC_SIZE );
process_local_file_hdr( &lrec, tmp ); /* return PK-type error code */
file -> seek_start = lseek( archive -> os_handle, lrec.filename_length + lrec.extra_field_length, SEEK_CUR );
switch( entry -> method ) {
case STORED: {
file -> os_handle = archive -> os_handle;
//file -> seek_start = entry -> file_position;
file -> csize = 0;
file -> size = entry -> size;
file -> filename = MemStrDup( filename );
file -> mode = mode;
file -> device = entry -> volume;
file -> zip = NULL; /* only used if we need to deflate */
SHOULD_I_CALL_WITH( CALLBACK_OPEN_FILE, handle, retval );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( handle );
break;
}
case DEFLATED: {
COMPRESSED_FILE * zip;
#ifdef USE_SH_POOLS
zip = (COMPRESSED_FILE *)MemAllocPtr( gResmgrMemPool, sizeof(COMPRESSED_FILE) + (entry -> size), 0 );
#else
zip = (COMPRESSED_FILE *)MemMalloc( sizeof(COMPRESSED_FILE) + (entry -> size), "Inflate" );
#endif
if( !zip ) {
SAY_ERROR( RES_ERR_NO_MEMORY, "Inflate" );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return(-1);
}
file -> os_handle = archive -> os_handle;
//file -> seek_start = entry -> file_position;
file -> csize = entry -> csize;
file -> size = entry -> size;
file -> filename = MemStrDup( filename );
file -> mode = mode;
file -> device = entry -> volume;
#ifdef USE_SH_POOLS
zip -> slide = (uch *)MemAllocPtr( gResmgrMemPool, UNZIP_SLIDE_SIZE + INPUTBUFSIZE, 0 ); /* glob temporary allocations */
#else
zip -> slide = (uch *)MemMalloc( UNZIP_SLIDE_SIZE + INPUTBUFSIZE, "deflate" ); /* glob temporary allocations */
#endif
zip -> in_buffer = (uch *)zip -> slide + UNZIP_SLIDE_SIZE;
zip -> in_ptr = (uch *)zip -> in_buffer;
zip -> in_count = 0;
zip -> in_size = file -> csize > INPUTBUFSIZE ? INPUTBUFSIZE : file -> csize;
zip -> csize = file -> csize;
zip -> out_buffer = (char *)zip + sizeof(COMPRESSED_FILE);
zip -> out_count = 0;
zip -> archive = archive;
file -> zip = zip; /* Future use: I may add incremental deflation */
inflate( zip );
#ifdef USE_SH_POOLS
MemFreePtr( zip -> slide ); /* Free temporary allocations */
#else
MemFree( zip -> slide ); /* Free temporary allocations */
#endif
SHOULD_I_CALL_WITH( CALLBACK_OPEN_FILE, handle, retval );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( handle );
break;
}
default:
SAY_ERROR( RES_ERR_UNSUPPORTED_COMPRESSION, entry -> name );
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
break;
}
}
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( -1 );
}
/* =======================================================
FUNCTION: ResSizeFile
PURPOSE: Determine the size of a file
PARAMETERS: File handle.
RETURNS: Size of the file in bytes.
======================================================= */
RES_EXPORT int ResSizeFile( int file )
{
#if( RES_DEBUG_PARAMS )
if( file < 0 || file >= MAX_FILE_HANDLES ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResSizeFile" );
return( -1 );
}
if( FILE_HANDLES[ file ].os_handle == -1 ) {
SAY_ERROR( RES_ERR_ILLEGAL_FILE_HANDLE, "ResSizeFile" );
return( -1 );
}
#endif /* RES_DEBUG_PARAMS */
return( FILE_HANDLES[ file ].size );
}
/* =======================================================
FUNCTION: ResReadFile
PURPOSE: Read from a file via the Resource Manager.
PARAMETERS: File int, ptr to a buffer to place
data, number of bytes to read.
RETURNS: Number of bytes actually read, -1 in case
of an error.
======================================================= */
RES_EXPORT int ResReadFile( int handle, void * buffer, size_t count )
{
FILE_ENTRY * file;
int len;
int retval = 1;
#if( RES_DEBUG_PARAMS )
if( !buffer || handle < 0 || handle > MAX_FILE_HANDLES ) {
SAY_ERROR( RES_ERR_INCORRECT_PARAMETER, "ResReadFile" );
return( -1 );
}
#endif /* RES_DEBUG_PARAMS */
#if (RES_MULTITHREAD)
REQUEST_LOCK(GLOCK); /* GFG */
#endif
file = &FILE_HANDLES[ handle ];
if( file -> os_handle == -1 ) {
SAY_ERROR( RES_ERR_ILLEGAL_FILE_HANDLE, "ResReadFile" );
return( -1 );
}
IF_LOG( LOG( "read (%s): (%d bytes)\n", file -> filename, count ));
SHOULD_I_CALL_WITH( CALLBACK_READ_FILE, handle, retval );
if( file -> current_pos >= file -> size )
{
#if (RES_MULTITHREAD)
RELEASE_LOCK(GLOCK); /* GFG */
#endif
return( 0 ); /* GFG NOV 18 was return (-1) */
}
if( !file -> zip ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -