#ifndef __RESOURCES_H__ #define __RESOURCES_H__ /** \file resources.h * Classes for resources loading and unloading. */ #include #include #include #include #include #include "visitor.h" #include "buffer.h" typedef std::list StringList; class ResourceFile; /// Abstract interface for streamed resource access class ResourceStream { public: virtual ~ResourceStream() { }; /// Get size of resource virtual size_t getSize() = 0; /// Seek into resource. /// \param offset offset from resource start virtual void seek(long offset) = 0; /// Read data from resource into buffer. /// \param buffer buffer of size bytes. /// \param size number of bytes to read. virtual void read(char *buffer, size_t size) = 0; /// Get current position virtual long getPos() = 0; /// Return true if end of resource reached virtual bool isEof() { return (size_t)getPos() >= getSize(); }; /// Get count of bytes left virtual long getAvailable() { return (long)getSize() - getPos(); }; }; /*** * Low level resource file interface. * Never use it, use ResourcesCollection instead. ***/ class ResourceFile { private: std::ifstream stream; /// resource file input stream int priority; /// priority of resource file std::wstring name; /// resource file name Buffer *buffer; bool ownBuffer; public: /// Resource file directory entry typedef struct { std::wstring name; /// resource name long offset; /// offset from start of resource file long packedSize; /// compressed size long unpackedSize; /// uncompressed size std::wstring group; /// group name int level; /// pack level } DirectoryEntry; /// List of directory entries. typedef std::list Directory; public: /// Create resource file. Throws exception if file can't be opened. /// \param fileName the name of resource file. /// \param buffer buffer for temporary data. /// Can be shared with other resource files. ResourceFile(const std::wstring &fileName, Buffer *buffer=NULL); virtual ~ResourceFile(); public: /// Load directory listing. /// \param directory list where resource entries will be placed. void getDirectory(Directory &directory); /// Load data in preallocated buffer buf of size unpackedSize. /// \param buf buffer of unpackedSize bytes where unpacked data will /// be placed /// \param offset offset from start of resource file to packed data /// \param packedSize size of packed resource /// \param unpackedSize size of unpacked resource void load(char *buf, long offset, long packedSize, long unpackedSize, int level); /// Allocate buffer and load data. Memory returned by this /// method must be freed by free() function call. /// \param offset offset from start of resource file to packed data /// \param packedSize size of packed resource /// \param unpackedSize size of unpacked resource void* load(long offset, long packedSize, long unpackedSize, int level); /// Get priority of this resource file. int getPriority() const { return priority; }; /// Get the name of resource file. const std::wstring& getFileName() const { return name; }; /// Get file stream. std::ifstream& getStream() { return stream; }; private: /// Unpack memory buffer /// \param in buffer of inSize bytes filled with packed data /// \param inSize size of packed data /// \param out buffer of outSize bytes where unpacked data will /// be placed /// \param outSize size of unpacked data void unpack(char *in, int inSize, char *out, int outSize); }; /// Simple resource file wrapper. /// Used at boot time when ResourcesCollection /// is not available yet. class SimpleResourceFile: public ResourceFile { private: typedef std::map DirectoryMap; DirectoryMap directory; /// Directory map. public: /// Open resource file. Throws exception if file can't be opened. /// \param fileName the name of resource file. /// \param buffer buffer for temporary data. /// Can be shared with other resource files. SimpleResourceFile(const std::wstring &fileName, Buffer *buffer=NULL); public: /// Load data. Memory returned by this method should be freed /// by free() function call. /// \param name name of resource /// \param size returns size of resource virtual void* load(const std::wstring &name, int &size); /// Load data into the buffer. /// \param name name of resource /// \param buffer buffer for resource data virtual void load(const std::wstring &name, Buffer &buffer); }; /// Internationalized resource entity. class ResVariant { private: int i18nScore; ResourceFile *file; long offset; long unpackedSize; long packedSize; int refCnt; void *data; int level; public: /// Create resource variation. /// \param file reesource file /// \param score locale compability score /// \param entry entry in global resources directory ResVariant(ResourceFile *file, int score, const ResourceFile::DirectoryEntry &entry); ~ResVariant(); public: /// Return locale compability score. int getI18nScore() const { return i18nScore; }; /// Get pointer to unpacked resource data. /// Must be freed after use this delRef() void* getRef(); /// Get pointer to unpacked resource data and return resource size. /// Must be freed after use this delRef(). /// \param size returned size of resource data. void* getRef(size_t &size); /// Delete referene to data. /// \param data pointer to unpacked data. void delRef(void *data); /// Return reference counter. int getRefCount() const { return refCnt; }; /// Is data managed by this object /// \param data pointer to dataa bool isDataOwned(void *data) const { return refCnt && data == this->data; }; /// return data. /// destroy it after use with free() void* getDynData(); /// returns size of data long getSize() const { return unpackedSize; }; /// Return data in buffer /// \param buffer buffer to store data. void getData(Buffer &buffer); /// Create ResourceStream for resource. /// This may be usefull for large streams unpacked data, /// for example video and sound. /// Delete stream after use. ResourceStream* createStream(); }; /// Internationalized resources. /// Collection of localized data (ResVariant) with single name. class Resource { private: typedef std::vector Variants; Variants variants; std::wstring name; public: /// Create resource and add first entry /// \param file resource file /// \param i18nScore locale compability score /// \param entry resource entry in global directory /// \param name name of resource Resource(ResourceFile *file, int i18nScore, const ResourceFile::DirectoryEntry &entry, const std::wstring &name); ~Resource(); public: /// Add resource variant. /// \param file resource file /// \param i18nScore locale compability score /// \param entry resource entry in global directory void addVariant(ResourceFile *file, int i18nScore, const ResourceFile::DirectoryEntry &entry); /// Get number of variants. int getVariantsCount() const { return variants.size(); }; /// Geturns variant object. /// \param variant variant number. ResVariant* getVariant(int variant=0) { return variants[variant]; }; /// Load data from variant. /// Data must be freed with delRef(). /// \param variant variant number. void* getRef(int variant=0); /// Load data from variant. /// data must be freed with delRef() /// \param size size of data. /// \param variant variant number. void* getRef(int *size, int variant=0); /// Unload data /// param data pointer to data. void delRef(void *data); /// Get size of data. /// \param variant variant number. long getSize(int variant=0) { return variants[variant]->getSize(); }; /// Get name of this resource. const std::wstring& getName() const { return name; }; /// Load data into buffer. /// \param buffer buffer for data. /// \param variant variant number. void getData(Buffer &buffer, int variant=0); /// Create ResourceStream for resource. /// This may be usefull for large streams unpacked data, /// for example video and sound. /// Delete stream after use. /// \param variant variant number. ResourceStream* createStream(int variant=0); }; /// Internationalized resource files collection. /// When ResourceCollection created all resources checked against /// current locale. Resources not belonged to current locale are /// ignored, resources that can be used in current locale sorted /// by locale relevance score. /// All resources names interpeted as name[_language][_COUNTRY].extension /// where name is name of resource, language is optional two letters /// ISO language code, country is two letters ISO country code /// and extension is file extension. /// After processing resource name will be truncated to name.extension. /// By default resource with highest locale relevance score will /// be loaded. Howether, it is possible to enumerate all variants /// by using Resource class interface. /// Resource files loaded in order specified by their priority. /// Resources from file loaded later can replace resources /// loaded before it. class ResourcesCollection { private: /// Map resource names to resources. typedef std::map ResourcesMap; /// List of resources. typedef std::list ResourcesList; /// Map group names to resources list. typedef std::map ResourcesListMap; /// List of resource files. typedef std::vector ResourceFiles; ResourcesMap resources; /// Map of all available resources. ResourcesListMap groups; /// Map of all available groups. ResourceFiles files; /// List of resource files. Buffer buffer; /// Temporary buffer for resource files. public: /// Load resource files, make grouping and i18n optimizations. ResourcesCollection(StringList &directories); ~ResourcesCollection(); public: /// Returns resource entry. /// If resource not found Exception will be thrown. Resource* getResource(const std::wstring &name); /// Load resource. /// Loaded data must be freed with delRef method. void* getRef(const std::wstring &name, int &size); /// Load resource. /// Loaded data must be freed with delRef method. void* getRef(const std::wstring &name); /// Delete reference to resource. void delRef(void *data); /// Visit all group members. void forEachInGroup(const std::wstring &groupName, Visitor &visitor); /// Create ResourceStream for resource. /// This may be usefull for large streams unpacked data, /// for example video and sound. /// Delete stream after use. /// \param name name of resource. ResourceStream* createStream(const std::wstring &name); /// Load data into buffer. /// Usually you don't need this, use getRef instead. /// \param name name of resource. /// \param buffer buffer for data. void loadData(const std::wstring &name, Buffer &buffer); private: /// Open resource files. void loadResourceFiles(StringList &directories); /// Make grouping and locale processing. void processFiles(); }; /// Helper class for simple resource loading and unloading class ResDataHolder { private: void *data; size_t size; public: /// Create holder without data ResDataHolder(); /// Create holder and load data ResDataHolder(const std::wstring &name); ~ResDataHolder(); public: /// Load resource data void load(const std::wstring &name); /// Returns pointer to resource data void* getData() const { return data; }; /// Returns size of data size_t getSize() const { return size; }; }; /// Global collection of resources. /// Careated at first step at boot time stage2 extern ResourcesCollection *resources; #endif