490 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			490 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //-----------------------------------------------------------------------------
 | |
| // Torque Game Engine
 | |
| // Copyright (C) GarageGames.com, Inc.
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| #ifndef _RESMANAGER_H_
 | |
| #define _RESMANAGER_H_
 | |
| 
 | |
| #ifndef _PLATFORM_H_
 | |
| #include "platform/platform.h"
 | |
| #endif
 | |
| #ifndef _TVECTOR_H_
 | |
| #include "core/tVector.h"
 | |
| #endif
 | |
| #ifndef _STRINGTABLE_H_
 | |
| #include "core/stringTable.h"
 | |
| #endif
 | |
| 
 | |
| #ifndef _FILESTREAM_H_
 | |
| #include "core/fileStream.h"
 | |
| #endif
 | |
| #ifndef _ZIPSUBSTREAM_H_
 | |
| #include "core/zipSubStream.h"
 | |
| #endif
 | |
| #ifndef _ZIPAGGREGATE_H_
 | |
| #include "core/zipAggregate.h"
 | |
| #endif
 | |
| #ifndef _ZIPHEADERS_H_
 | |
| #include "core/zipHeaders.h"
 | |
| #endif
 | |
| #ifndef _CRC_H_
 | |
| #include "core/crc.h"
 | |
| #endif
 | |
| 
 | |
| class Stream;
 | |
| class FileStream;
 | |
| class ZipSubRStream;
 | |
| class ResManager;
 | |
| class FindMatch;
 | |
| 
 | |
| extern ResManager *ResourceManager;
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| class ResourceObject;
 | |
| 
 | |
| /// The base class for all resources.
 | |
| ///
 | |
| /// This must be subclassed to implement a resource that can be managed.
 | |
| ///
 | |
| /// Creating a new resource type is very simple. First, you need a function
 | |
| /// which can create a new instance of the resource given a stream:
 | |
| ///
 | |
| /// @code
 | |
| /// ResourceInstance* constructBitmapBMP(Stream &stream)
 | |
| /// {
 | |
| ///    GBitmap *bmp = new GBitmap;
 | |
| ///    if(bmp->readMSBmp(stream))
 | |
| ///       return bmp;
 | |
| ///    else
 | |
| ///    {
 | |
| ///       delete bmp;
 | |
| ///       return NULL;
 | |
| ///    }
 | |
| /// }
 | |
| /// @endcode
 | |
| ///
 | |
| /// Then you need to register the extension of your resource type with the resource manager:
 | |
| ///
 | |
| /// @code
 | |
| /// ResourceManager->registerExtension(".bmp", constructBitmapBMP);
 | |
| /// @endcode
 | |
| ///
 | |
| /// And, of course, you need to provide a subclass of ResourceInstance:
 | |
| ///
 | |
| /// @code
 | |
| /// class GBitmap : ResourceInstance {
 | |
| ///    ... whatever you need for your resource goes in here ...
 | |
| /// }
 | |
| /// @endcode
 | |
| ///
 | |
| /// ResourceInstance imposes very few requirements on you as the resource type
 | |
| /// implementor. All you "have" to provide is a destructor to deallocate whatever
 | |
| /// storage your resource might allocate. The ResourceManager will ensure that
 | |
| /// there is only one instance of the ResourceInstance for each file, and that it
 | |
| /// is only destroyed when no more references to it remain.
 | |
| ///
 | |
| /// @see TerrainFile, GBitmap, AudioBuffer for more examples.
 | |
| class ResourceInstance
 | |
| {
 | |
| private:
 | |
| public:
 | |
|    /// Pointer to the ResourceObject that stores all our book-keeping data.
 | |
|    ResourceObject *mSourceResource;
 | |
| 
 | |
|    ResourceInstance() { mSourceResource = NULL; }
 | |
|    virtual ~ResourceInstance() {}
 | |
| };
 | |
| 
 | |
| 
 | |
| typedef ResourceInstance* (*RESOURCE_CREATE_FN)(Stream &stream);
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| #define InvalidCRC 0xFFFFFFFF
 | |
| 
 | |
| /// Wrapper around a ResourceInstance.
 | |
| ///
 | |
| /// This contains all the book-keeping data used by ResDictionary and ResManager.
 | |
| ///
 | |
| /// @see ResManager
 | |
| class ResourceObject
 | |
| {
 | |
|    friend class ResDictionary;
 | |
|    friend class ResManager;
 | |
| 
 | |
|    /// @name List Book-keeping
 | |
|    /// @{
 | |
| 
 | |
|    ///
 | |
|    ResourceObject *prev, *next;
 | |
| 
 | |
|    ResourceObject *nextEntry;    ///< This is used by ResDictionary for its hash table.
 | |
| 
 | |
|    ResourceObject *nextResource;
 | |
|    ResourceObject *prevResource;
 | |
|    /// @}
 | |
| 
 | |
| public:
 | |
|    enum Flags
 | |
|    {
 | |
|       VolumeBlock   = BIT(0),
 | |
|       File          = BIT(1),
 | |
|       Added         = BIT(2),
 | |
|    };
 | |
|    S32 flags;  ///< Set from Flags.
 | |
| 
 | |
|    StringTableEntry path;     ///< Resource path.
 | |
|    StringTableEntry name;     ///< Resource name.
 | |
| 
 | |
|    /// @name ZIP Archive
 | |
|    /// If the resource is stored in a zip file, these members are populated.
 | |
|    /// @{
 | |
| 
 | |
|    ///
 | |
|    StringTableEntry zipPath;  ///< Path of zip file.
 | |
|    StringTableEntry zipName;  ///< Name of zip file.
 | |
| 
 | |
|    S32 fileOffset;            ///< Offset of data in zip file.
 | |
|    S32 fileSize;              ///< Size on disk of resource block.
 | |
|    S32 compressedFileSize;    ///< Actual size of resource data.
 | |
|    /// @}
 | |
| 
 | |
|    ResourceInstance *mInstance;  ///< Pointer to actual object instance. If the object is not loaded,
 | |
|                                  ///  this may be NULL or garbage.
 | |
|    S32 lockCount;                ///< Lock count; used to control load/unload of resource from memory.
 | |
|    U32 crc;                      ///< CRC of resource.
 | |
| 
 | |
|    ResourceObject();
 | |
|    ~ResourceObject() { unlink(); }
 | |
| 
 | |
|    void destruct();
 | |
| 
 | |
|    /// @name List Management
 | |
|    /// @{
 | |
| 
 | |
|    ///
 | |
|    ResourceObject* getNext() const { return next; }
 | |
|    void unlink();
 | |
|    void linkAfter(ResourceObject* res);
 | |
|    /// @}
 | |
| 
 | |
|    /// Get some information about file times.
 | |
|    ///
 | |
|    /// @param  createTime  Pointer to a FileTime structure to fill with information about when this object was
 | |
|    ///                     created.
 | |
|    /// @param  modifyTime  Pointer to a FileTime structure to fill with information about when this object was
 | |
|    ///                     modified.
 | |
|    void getFileTimes(FileTime *createTime, FileTime *modifyTime);
 | |
| };
 | |
| 
 | |
| 
 | |
| inline void ResourceObject::unlink()
 | |
| {
 | |
|    if (next)
 | |
|       next->prev = prev;
 | |
|    if (prev)
 | |
|       prev->next = next;
 | |
|    next = prev = 0;
 | |
| }
 | |
| 
 | |
| inline void ResourceObject::linkAfter(ResourceObject* res)
 | |
| {
 | |
|    unlink();
 | |
|    prev = res;
 | |
|    if ((next = res->next) != 0)
 | |
|       next->prev = this;
 | |
|    res->next = this;
 | |
| }
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| /// Wrapper class around a ResourceInstance subclass.
 | |
| ///
 | |
| /// @code
 | |
| ///    // Loading a resource...
 | |
| ///    Resource<TerrainFile> terrRes;
 | |
| ///
 | |
| ///    terrRes = ResourceManager->load(fileName);
 | |
| ///    if(!bool(terrRes))
 | |
| ///       Con::errorf(ConsoleLogEntry::General, "Terraformer::terrainFile - invalid terrain file '%s'.", fileName);
 | |
| /// @endcode
 | |
| ///
 | |
| /// When the Resource<> is destroyed, it frees the lock on the resource.
 | |
| ///
 | |
| /// @see ResManager
 | |
| template <class T> class Resource
 | |
| {
 | |
| private:
 | |
|    ResourceObject *obj;  ///< Actual resource object
 | |
| 
 | |
|    // ***WARNING***
 | |
|    // Using a faster lock that bypasses the resource manger.
 | |
|    // void _lock() { if (obj) obj->rm->lockResource( obj ); }
 | |
|    void _lock();   ///< Increments the lock count on this object
 | |
|    void _unlock(); ///< Decrements the lock count on this object
 | |
| 
 | |
| public:
 | |
|    /// If assigned a ResourceObject, it's assumed to already have
 | |
|    /// been locked, lock count is incremented only for copies or
 | |
|    /// assignment from another Resource.
 | |
|    Resource() : obj(NULL) { ; }
 | |
|    Resource(ResourceObject *p) : obj(p) { ; }
 | |
|    Resource(const Resource &res) : obj(res.obj) { _lock(); }
 | |
|    ~Resource() { unlock(); }  ///< Decrements the lock count on this object, and if the lock count is 0 afterwards,
 | |
|                               ///< adds the object to the timeoutList for deletion on execution of purge().
 | |
| 
 | |
|    const char *getFilePath() const { return (obj ? obj->path : NULL); } ///< Returns the path of the file (without the actual name)
 | |
|    const char *getFileName() const { return (obj ? obj->name : NULL); } ///< Returns the actual file name (without the path)
 | |
| 
 | |
|    Resource& operator= (ResourceObject *p) { _unlock(); obj = p; return *this; }
 | |
|    Resource& operator= (const Resource &r) { _unlock(); obj = r.obj; _lock(); return *this; }
 | |
| 
 | |
|    U32 getCRC() { return (obj ? obj->crc : 0); }
 | |
|    bool isNull()   const { return ((obj == NULL) || (obj->mInstance == NULL)); }
 | |
|    operator bool() const { return ((obj != NULL) && (obj->mInstance != NULL)); }
 | |
|    T* operator->()   { return (T*)obj->mInstance; }
 | |
|    T& operator*()    { return *((T*)obj->mInstance); }
 | |
|    operator T*() const    { return (obj) ? (T*)obj->mInstance : (T*)NULL; }
 | |
|    const T* operator->() const  { return (const T*)obj->mInstance; }
 | |
|    const T& operator*() const   { return *((const T*)obj->mInstance); }
 | |
|    operator const T*() const    { return (obj) ? (const T*)obj->mInstance :  (const T*)NULL; }
 | |
|    void unlock();
 | |
|    void purge();
 | |
| };
 | |
| 
 | |
| #define INVALID_ID ((U32)(~0))
 | |
| 
 | |
| //----------------------------------------------------------------------------
 | |
| /// Resource Dictionary.
 | |
| ///
 | |
| /// Maps of names and object IDs to objects.
 | |
| ///
 | |
| /// Provides fast lookup for name->object, id->object and
 | |
| /// for fast removal of an object given a pointer to it.
 | |
| ///
 | |
| /// @see ResManager
 | |
| class ResDictionary
 | |
| {
 | |
|    /// @name Hash Table
 | |
|    /// @{
 | |
| 
 | |
|    enum { DefaultTableSize = 1029 };
 | |
| 
 | |
|    ResourceObject **hashTable;
 | |
|    S32 entryCount;
 | |
|    S32 hashTableSize;
 | |
|    DataChunker memPool;
 | |
|    S32 hash(StringTableEntry path, StringTableEntry name);
 | |
|    S32 hash(ResourceObject *obj) { return hash(obj->path, obj->name); }
 | |
|    /// @}
 | |
| 
 | |
| public:
 | |
|    ResDictionary();
 | |
|    ~ResDictionary();
 | |
| 
 | |
|    /// Add a ResourceObject to the dictionary.
 | |
|    void insert(ResourceObject *obj, StringTableEntry path, StringTableEntry file);
 | |
| 
 | |
|    /// @name Find
 | |
|    /// These functions search the hash table for an individual resource.  If the resource has
 | |
|    /// already been loaded, it will find the resource and return its object.  If not,
 | |
|    /// it will return NULL.
 | |
|    /// @{
 | |
| 
 | |
|    ResourceObject* find(StringTableEntry path, StringTableEntry file);
 | |
|    ResourceObject* find(StringTableEntry path, StringTableEntry file, StringTableEntry filePath, StringTableEntry fileName);
 | |
|    ResourceObject* find(StringTableEntry path, StringTableEntry file, U32 flags);
 | |
|    /// @}
 | |
| 
 | |
|    /// Move a previously added resource object to be in the list after everything that matches the specified mask.
 | |
|    void pushBehind(ResourceObject *obj, S32 mask);
 | |
| 
 | |
|    /// Remove a resource object from the dictionary.
 | |
|    void remove(ResourceObject *obj);
 | |
| };
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| /// A virtual file system for the storage and retrieval of ResourceObjects.
 | |
| ///
 | |
| /// Basic resource manager behavior:
 | |
| ///  - Set the mod path.
 | |
| ///      - ResManager scans directory tree under listed base directories
 | |
| ///      - Any volume (.zip) file in the root directory of a mod is scanned
 | |
| ///        for resources.
 | |
| ///      - Any files currently in the resource manager become memory resources.
 | |
| ///      - They can be "reattached" to the first file that matches the file name.
 | |
| ///
 | |
| /// All classes which wish to be handled by the resource manager need:
 | |
| ///    -# To be derived from ResourceInstance.
 | |
| ///    -# To register a creation function and file extension with the manager.
 | |
| ///
 | |
| /// @nosubgrouping
 | |
| class ResManager
 | |
| {
 | |
| private:
 | |
|    /// Path to which we will write data.
 | |
|    ///
 | |
|    /// This is used when, for instance, we download files from a server.
 | |
|    char writeablePath[1024];
 | |
| 
 | |
|    /// Primary path from which we load data.
 | |
|    char primaryPath[1024];
 | |
| 
 | |
|    /// List of secondary paths to search.
 | |
|    char* pathList;
 | |
| 
 | |
|    ResourceObject timeoutList;
 | |
|    ResourceObject resourceList;
 | |
| 
 | |
|    ResDictionary dictionary;
 | |
| 
 | |
|    bool echoFileNames;
 | |
| 
 | |
|    bool isIgnoredSubdirectoryName(const char *name) const;
 | |
| 
 | |
|    /// Scan a zip file for resources.
 | |
|    bool scanZip(ResourceObject *zipObject);
 | |
| 
 | |
|    /// Create a ResourceObject from the given file.
 | |
|    ResourceObject* createResource(StringTableEntry path, StringTableEntry file);
 | |
| 
 | |
|    /// Create a ResourceObject from the given file in a zip file.
 | |
|    ResourceObject* createZipResource(StringTableEntry path, StringTableEntry file, StringTableEntry zipPath, StringTableEntry zipFle);
 | |
| 
 | |
|    void searchPath(const char *pathStart);
 | |
|    bool setModZip(const char* path);
 | |
| 
 | |
|    struct RegisteredExtension
 | |
|    {
 | |
|       StringTableEntry     mExtension;
 | |
|       RESOURCE_CREATE_FN   mCreateFn;
 | |
|       RegisteredExtension  *next;
 | |
|    };
 | |
| 
 | |
|    Vector<char *> mMissingFileList;                ///< List of missing files.
 | |
|    bool mLoggingMissingFiles;                      ///< Are there any missing files?
 | |
|    void fileIsMissing(const char *fileName);       ///< Called when a file is missing.
 | |
| 
 | |
|    RegisteredExtension *registeredList;
 | |
| 
 | |
|    static char *smExcludedDirectories;
 | |
|    ResManager();
 | |
| public:
 | |
|    RESOURCE_CREATE_FN getCreateFunction( const char *name );
 | |
| 
 | |
|    ~ResManager();
 | |
|    /// @name Global Control
 | |
|    /// These are called to initialize/destroy the resource manager at runtime.
 | |
|    /// @{
 | |
| 
 | |
|    static void create();
 | |
|    static void destroy();
 | |
| 
 | |
|    /// Load the excluded directories from the resource manager pref and
 | |
|    /// stuff it into the platform layer.
 | |
|    static void initExcludedDirectories();
 | |
| 
 | |
|    ///@}
 | |
| 
 | |
|    void setFileNameEcho(bool on);                     ///< Sets whether or not to echo filenames that have been accessed by means of openStream
 | |
|    void setModPaths(U32 numPaths, const char **dirs); ///< Sets the path for the current game mod
 | |
|    const char* getModPaths();                         ///< Gets the path for the current game mod
 | |
| 
 | |
|    void setMissingFileLogging(bool log);              ///< Should we log missing files?
 | |
|    bool getMissingFileList(Vector<char *> &list);     ///< Gets which files are missing
 | |
|    void clearMissingFileList();                       ///< Clears the missing file list
 | |
| 
 | |
|    /// Tells the resource manager what to do with a resource that it loads
 | |
|    void registerExtension(const char *extension, RESOURCE_CREATE_FN create_fn);
 | |
| 
 | |
|    S32 getSize(const char* filename);                 ///< Gets the size of the file
 | |
|    const char* getFullPath(const char * filename, char * path, U32 pathLen);  ///< Gets the full path of the file
 | |
|    const char* getModPathOf(const char* fileName);    ///< Gets the path of the file local to the mod
 | |
|    const char* getPathOf(const char * filename);      ///< Gets the path of the file from the base directory
 | |
|    const char* getBasePath();                         ///< Gets the base path
 | |
| 
 | |
|    ResourceObject* load(const char * fileName, bool computeCRC = false);   ///< loads an instance of an object
 | |
|    Stream*  openStream(const char * fileName);        ///< Opens a stream for an object
 | |
|    Stream*  openStream(ResourceObject *object);       ///< Opens a stream for an object
 | |
|    void     closeStream(Stream *stream);              ///< Closes the stream
 | |
| 
 | |
|    /// Decrements the lock count of an object.  If the lock count is zero post-decrement,
 | |
|    /// the object is added to the timeoutList for deletion upon call of flush.
 | |
|    void unlock( ResourceObject* );
 | |
| 
 | |
|    /// Add a new resource instance
 | |
|    bool add(const char* name, ResourceInstance *addInstance, bool extraLock = false);
 | |
| 
 | |
|    /// Searches the hash list for the filename and returns it's object if found, otherwise NULL
 | |
|    ResourceObject* find(const char * fileName);
 | |
|    /// Loads a new instance of an object by means of a filename
 | |
|    ResourceInstance* loadInstance(const char *fileName, bool computeCRC = false);
 | |
|    /// Loads a new instance of an object by means of a resource object
 | |
|    ResourceInstance* loadInstance(ResourceObject *object, bool computeCRC = false);
 | |
| 
 | |
|    /// Searches the hash list for the filename and returns it's object if found, otherwise NULL
 | |
|    ResourceObject* find(const char * fileName, U32 flags);
 | |
| 
 | |
|    /// Finds a resource object with given expression
 | |
|    ResourceObject* findMatch(const char *expression, const char **fn, ResourceObject *start = NULL);
 | |
| 
 | |
|    /// Finds a resource object with given expressions, seperated by " "
 | |
|    ResourceObject* findMatchMultiExprs(const char *multiExpression, const char **fn, ResourceObject *start = NULL);
 | |
| 
 | |
|    void purge();                                      ///< Goes through the timeoutList and deletes it all.  BURN!!!
 | |
|    void purge( ResourceObject *obj );                 ///< Deletes one resource object.
 | |
|    void freeResource(ResourceObject *resObject);      ///< Frees a resource!
 | |
|    void serialize(VectorPtr<const char *> &filenames);///< Sorts the resource objects
 | |
| 
 | |
|    S32  findMatches( FindMatch *pFM );                ///< Finds multiple matches to an expression.
 | |
|    bool findFile( const char *name );                 ///< Checks to see if a file exists.
 | |
| 
 | |
|    /// Computes the CRC of a file.
 | |
|    ///
 | |
|    /// By passing a different crcInitialVal, you can take the CRC of multiple files.
 | |
|    bool getCrc(const char * fileName, U32 & crcVal, const U32 crcInitialVal = INITIAL_CRC_VALUE );
 | |
| 
 | |
|    void setWriteablePath(const char *path);           ///< Sets the writable path for a file to the one given.
 | |
|    bool isValidWriteFileName(const char *fn);         ///< Checks to see if the given path is valid for writing.
 | |
| 
 | |
|    /// Opens a file for writing!
 | |
|    bool openFileForWrite(FileStream &fs, const char *fileName, U32 accessMode = 1);
 | |
| 
 | |
| #ifdef TORQUE_DEBUG
 | |
|    void dumpLoadedResources();                        ///< Dumps all loaded resources to the console.
 | |
| #endif
 | |
| };
 | |
| 
 | |
| template<class T> inline void Resource<T>::unlock()
 | |
| {
 | |
|    if (obj) {
 | |
|       ResourceManager->unlock( obj );
 | |
|       obj=NULL;
 | |
|    }
 | |
| }
 | |
| 
 | |
| template<class T> inline void Resource<T>::purge()
 | |
| {
 | |
|    if (obj) {
 | |
|       ResourceManager->unlock( obj );
 | |
|       if (obj->lockCount == 0)
 | |
|          ResourceManager->purge(obj);
 | |
|       obj = NULL;
 | |
|    }
 | |
| }
 | |
| template <class T> inline void Resource<T>::_lock()
 | |
| {
 | |
|    if (obj)
 | |
|       obj->lockCount++;
 | |
| }
 | |
| 
 | |
| template <class T> inline void Resource<T>::_unlock()
 | |
| {
 | |
|    if (obj)
 | |
|       ResourceManager->unlock( obj );
 | |
| }
 | |
| 
 | |
| #endif //_RESMANAGER_H_
 | 
