⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resmgr.c

📁 空战游戏flacon源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ----------------------------------------------------------------------

    Resource Manager

	Version 2.05                   Released 03/26/97

	Written by Kevin Ray (x301)	   (c) 1996 Spectrum Holobyte

   ----------------------------------------------------------------------

      The resource manager's main function is to provide a single entry 
      point for file i/o from within an application.  Besides this
      obvious requirement, this implementation also provides these 
      added functional blocks:

            1) file extraction from archive (zip) files.
            2) virtual file system that allows easy patching of data.
            3) caching beyond the minimal i/o buffers & mscdex.
            4) asynchronous read/writes.
            5) event logging (for general debugging as well as to 
               provide a table from which to sort the contents of 
               a CD to minimize seeks).
            6) Significant debugging options.

      For the most part, all of the exported functions are syntactically
      similiar to the low-level i/o functions (io.h).  Obvious exceptions 
      to this rule are the functions for reading the contents of a 
      directory.  Since the standard dos functions _findfirst, _findnext, 
      _findclose have always been cumbersome and 'unnatural', this 
      implementation uses the metaphor used by the UNIX opendir
      command (Roger Fujii's suggestion).  For more information, look 
      at the comment above the ResOpenDirectory function.
         
      There are several compiler options that can be selected to build
      various flavors of the Resource Manager.  Debugging, obviously,
      can be included or excluded.  Within the general debugging
      category, Event Logging, Parameter Checking and use of a debug
      window can all be included or excluded.  Each of these latter
      options requires that the RES_DEBUG_VERSION be defined and
      non-zero (just use 'YES' in the header file).

      Since the bafoons at Microsoft have deemed multithreading to be
      such an awesome feature (like they invented it - it's not like 
      there aren't multithreaded operating systems on even lowly 8-bit 
      microcontrollers) this feature can be disabled.  Obviously this 
      may seem somewhat rediculous considering that asynch i/o is the 
      main feature you want threads for, but MS Visual C++ shows some 
      terribly worrisome behaviors with threads.  For instance, the 
      compiler doesn't recognize _beginthread() even with <process.h>
      included unless you have the link option /MT selected.  Why does
      the compiler care?  And there is no kill() so callbacks being
      instantiated from a thread are problematic since the callbacks
      context is always that of the thread.  Therefore, if you want
      to hide this functionality from the others using ResMgr, you
      can turn it off.

      In summary, here are the different buid options:

            debugging on or off
            multithreading on or off
            standalone version capability
            flat or hierarchical database (explained below)
            event logging
            parameter checking

      To use this library, you need to do just a few things.  Here is
      a synopsis of the functions you'll need to call and the order
      in which to call them:

         1) ResInit        initialize the resource manager

         2) ResCreatePath  give the resource manager somewhere to 
                           look for files

         3) ResAttach      (optional) open an archive file

         4) ResOpenFile,
            ResReadFile,   perform file i/o
            ResCloseFile   

         5) ResExit        shut-down the resource manager
     
	History:

	03/18/96 KBR   Created/Thieved (unzip/inflate from Fujii via gcc).
	04/01/96 KBR   Integrated unzip/inflate under virtual filesystem.
	
	TBD:  CD statistic caching (head movements, warning tracks, etc).   

   ---------------------------------------------------------------------- */
#include "lists.h"         /* list manipulation functions (+list.cpp)        */
#include "resmgr.h"        /* exported prototypes & type definitions         */
//#include "memmgr.h"
#include "omni.h"

#include <stdio.h>         /* low-level file i/o (+io.h)                     */
#include <string.h>
#include <memory.h>
#include <sys/stat.h>      /* _S_IWRITE                                      */
#include <stdarg.h>

#include <assert.h>

#if USE_WINDOWS
#  include <io.h>
#  include <direct.h>
#  include <process.h>       /* _beginthread()    MUST SET C++ OPTIONS UNDER 
                                                MSVC SETTINGS                */

#  include <windows.h>       /* all this for MessageBox (may move to debug.cpp)*/
#endif /* USE_WINDOWS */

#include "unzip.h"

#ifdef USE_SH_POOLS
#undef MemFree
#undef MemFreePtr
#undef MemMalloc
#include "Smartheap\Include\smrtheap.h"
MEM_POOL gResmgrMemPool = NULL;
#endif

#define SHOULD_I_CALL(idx,retval)       if( RES_CALLBACK[(idx)] )\
                                            retval = ( *(RES_CALLBACK[(idx)]));

#define SHOULD_I_CALL_WITH(idx,param,retval)  if( RES_CALLBACK[(idx)] )\
                                                  retval = ((*(RES_CALLBACK[(idx)]))(param));

#if( RES_STREAMING_IO )

RES_EXPORT FILE *  __cdecl _getstream( void );
RES_EXPORT FILE *  __cdecl _openfile( const char *, const char *, int, FILE * );
RES_EXPORT void    __cdecl _getbuf( FILE * );
RES_EXPORT int     __cdecl _flush( FILE * );
RES_EXPORT long    __cdecl ftell( FILE * );
RES_EXPORT long    __cdecl _ftell_lk( FILE * );

extern void __cdecl _getbuf( FILE * );
extern int  __cdecl _flush( FILE * str );

#define EINVAL                  22

#define _IOYOURBUF              0x0100
#define _INTERNAL_BUFSIZ        4096
#define _IOARCHIVE              0x00010000
#define _IOLOOSE                0x00020000
#define _SMALL_BUFSIZ           512    /* from stdio.h */
#define _INTERNAL_BUFSIZ        4096   /* from stdio.h */
#define _IOSETVBUF              0x0400 /* from file2.h */
#define _SH_DENYNO              0x40   /* from share.h */

#define anybuf(s)               ((s)->_flag & (_IOMYBUF|_IONBF|_IOYOURBUF))
#define inuse(s)                ((s)->_flag & (_IOREAD|_IOWRT|_IORW))


#define SHOULD_I_CALL(idx,retval)       if( RES_CALLBACK[(idx)] )\
                                            retval = ( *(RES_CALLBACK[(idx)]));

#define SHOULD_I_CALL_WITH(idx,param,retval)  if( RES_CALLBACK[(idx)] )\
                                                  retval = ((*(RES_CALLBACK[(idx)]))(param));
#endif /* RES_STREAMING_IO */


#define RES_INIT_DIRECTORY_SIZE         8    /* initial size for buffer used in ResCountDirectory */
                                             /* realloc'ed as needed */
                                              

/* ----------------------------------------------------------------------

      FLAT MODEL  VS.  HIERARCHICAL MODEL

   ----------------------------------------------------------------------

    There are two different implementation models that can be chosen from.  
    The first model is one in which all files are peers of one another.  
    Regardless of where the file resides, the flat model treats all files 
    as if they were to be found in a single directory.  If there happens 
    to be two files with the same name, but in two different directories, 
    the file which resides in the directory which was LAST processed is the 
    file that is entered into the database (in effect, it overrides the 
    existence of the previous file).

    The second implementation model is hierarchical.  In this model 
    directory paths are used to differentiate between identically named 
    files.  This is the only model which supports wildcarding within a 
    directory (\objects\*.3ds).  I'm not sure how usefull this model is, but 
    considering what a pain it was to implement, I hope it somehow is.  Since 
    one of the most important uses of the Resource Manager is to allow 
    projects to be 'patched' by simply copying newer data to a higher 
    priority directory, I exposed an 'override' function so    that this 
    functionality is still present in the hierarchical model.  In essence, if 
    there is a file c:\game\foo.dat and another file c:\object\foo.dat, if
    I override with a file called c:\game\patches\foo.dat I have replaced both
    \game\foo.dat AND \object\foo.dat with the file found in c:\game\patches -- 
    obviously this requires that more attention be paid to reducing these 
    complexities and avoiding possible pitfalls.

      Flat model:       Single hash table
                        All filenames are peers
                        Last file entered takes precedence
                        'Override' is automatic

      Hierarchical model: Hash table for each directory
                        Supports multiple instances of a like-named file
                        'Override' files manually by calling override

    In the flat model, files within a compressed archive are globbed right
    along within the same table as all other files.  The hierarchical model 
    will interpret any directory information within the archive file if it 
    exists, if not all files will go into their own hash table (as if all the 
    files within the archive were in the same directory).    

    The flat model is the default.
   ---------------------------------------------------------------------- */



                               
/* ----------------------------------------------------------------------

        U T I L I T Y   M A C R O S

   ---------------------------------------------------------------------- */
                        
#ifndef MAX
#  define MAX(a,b)   ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#  define MIN(a,b)   ((a) < (b) ? (a) : (b))
#endif

#define RES_STRING_SET( dst, src, ptr );    { strcpy( ptr, src );        \
                                              dst = ptr;                 \
                                              ptr += strlen(src)+1; }


#define NOTHING                  -1

#define FLAG_TEST(a,b)           ( a & b )
#define FLAG_SET(a,b)            ( a |= b )
#define FLAG_UNSET(a,b)          ( a ^= ~b )

#define HI_WORD(a)               ((a)>>16)
#define LO_WORD(a)               ((a)&0x0ffff)

#define SET_HIWORD(a,b)          { a |= ((b)<<16);   }
#define SET_LOWORD(a,b)          { a |= (b)&0x0ffff; }

#define WRITTEN_TO_FLAG          -1

#ifdef _MT
    extern void __cdecl          _unlock_file( FILE * );
    extern void __cdecl          _lock_file( FILE * );

    extern void __cdecl          _lock_fhandle( int );
    extern void __cdecl          _unlock_fhandle( int );

#   define LOCK_STREAM(a)        { _lock_file(a);   LOG( "+ %d\n", __LINE__ ); }
#   define UNLOCK_STREAM(a)      { _unlock_file(a); LOG( "- %d\n", __LINE__ ); }
#else
#   define LOCK_STREAM(a)
#   define UNLOCK_STREAM(a)
#endif



enum                                    /* compression methods                              */
{
    METHOD_STORED = 0,                  /* just stored in archive (no compression)          */
    METHOD_DEFLATED,                    /* pkzip style 'deflation'                          */
    METHOD_LOOSE                        /* loose file on harddrive                          */
};


#define EMPTY(a)                        ((a) == NOTHING)


/* ----------------------------------------------------------------------

    T Y P E   D E F I N I T I O N S

   ----------------------------------------------------------------------- */


typedef struct ASYNCH_DATA              /* created when spawning a read/write thread    */
{
    int         file;                   /* handle of file performing i/o on             */
    void      * buffer;                 /* ptr to buffer used to read to/write from     */
    size_t      size;                   /* bytes to read -or- bytes to write            */
    PFV         callback;               /* callback to issue upon completion            */

} ASYNCH_DATA;



/* ----------------------------------------------------------------------

   D E B U G   S P E C I F I C   I T E M S
   
   ---------------------------------------------------------------------- */

#if( RES_DEBUG_VERSION )

#    include "errno.h"


/* ---- DEBUG FUNCTIONS ---- */

void 
    dbg_analyze_hash( HASH_TABLE * hsh ),
    dbg_print( HASH_ENTRY * entry ),
    dbg_dir( HASH_TABLE * hsh ),
    dbg_device( DEVICE_ENTRY * dev );



STRING RES_ERR_OR_MSGS[] =
{
    "Not enough memory",                   /* Debug - Verbose Error Messages   */
    "Incorrect parameter",
    "Path not found",
	"File sharing (network error)",
    "There is no matching cd number",
    "File already closed",
    "File not found",
    "Can't attrib directory",
    "Can't attrib file",
    "Directory already exists",
    "Not a directory",
    "Could not delete",
    "Could not change directory",
    "Must create search path",
    "Could not spawn thread",
    "Could not open file",
    "Problem reading file",
    "Problem writing file",
    "System path has not been created yet",
    "Cannot interpret file/path",
    "Unknown archive",
    "Too many open files",
    "Illegal file handle",
    "Cannot delete file",
    "Cannot open archive file",
    "Corrupt archive file",
    "Unknown error",
    "Directory already in search path",
    "Destination directory not known (must add first)",
    "Cannot write to an archive",
    "Unsupported compression type",
    "Too many directories"
};

int
    RES_ERR_COUNT = sizeof( RES_ERR_OR_MSGS ) / sizeof( RES_ERR_OR_MSGS[0] );

void 
    _say_error( int error, const char * msg, int line, const char * filename );

#   define SAY_ERROR(a,b)   _say_error((a),(b), __LINE__, __FILE__ )

    int RES_DEBUG_FLAG     = TRUE;           /* run-time toggle for debugging                  */
    int RES_DEBUG_LOGGING  = FALSE;          /* are we currently logging events?               */
    int RES_DEBUG_OPEN_LOG = FALSE;          /* is a log file open?                            */

    int  RES_DEBUG_FILE     = -1;             /* file handle for logging events                 */

#if( RES_DEBUG_LOG )
#   define IF_LOG(a)               a
#   define LOG  ResDbgPrintf
#else
#   define IF_LOG(a)
#   define LOG
#endif

#   define IF_DEBUG(a)             a
#else /* RES_DEBUG_VERSION ? */
#   define IF_DEBUG(a)
#   define IF_LOG(a)
#   define LOG
#   define SAY_ERROR(a,b)          {RES_DEBUG_ERRNO=(a);}
#endif

#if( RES_DEBUG_VERSION == 0 )
#  if( RES_DEBUG_PARAMS )
#     error RES_DEBUG_VERSION must be TRUE to use RES_DEBUG_PARAMS
#  endif
#endif

#define CREATE_LOCK(a)      CreateMutex( NULL,  FALSE, a );
#define REQUEST_LOCK(a)     WaitForSingleObject(a, INFINITE);
#define RELEASE_LOCK(a)     ReleaseMutex(a);
#define DESTROY_LOCK(a)     CloseHandle(a);
   


/* ----------------------------------------------------------------------

    S T A T I C   D A T A

   ---------------------------------------------------------------------- */

#if (RES_MULTITHREAD)
static HANDLE  GLOCK=0;
#endif

HASH_TABLE                              /* For a flat model, this is the only hash table,       */
    * GLOBAL_HASH_TABLE = NULL;         /* for a hierarchical model, this is the hashed         */
                                        /* version of a root directory                          */
FILE_ENTRY
    * FILE_HANDLES = NULL;              /* Slots for open file handles                          */
                                            
PFI
   RES_CALLBACK[ NUMBER_OF_CALLBACKS ];

PRIVATE
LIST 
    * ARCHIVE_LIST = NULL;

PRIVATE
LIST
    * OPEN_DIR_LIST = NULL;

char 
    * RES_PATH[ RES_DIR_LAST ],
    * GLOBAL_SEARCH_PATH[ MAX_DIRECTORIES ];

char
    GLOBAL_INIT_PATH[ _MAX_PATH ],

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -