einstein/cpp-source/resources.h

413 lines
13 KiB
C++

#ifndef __RESOURCES_H__
#define __RESOURCES_H__
/** \file resources.h
* Classes for resources loading and unloading.
*/
#include <string>
#include <fstream>
#include <list>
#include <map>
#include <vector>
#include "visitor.h"
#include "buffer.h"
typedef std::list<std::wstring> 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<DirectoryEntry> 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<std::wstring, DirectoryEntry> 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<ResVariant*> 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<std::wstring, Resource*> ResourcesMap;
/// List of resources.
typedef std::list<Resource*> ResourcesList;
/// Map group names to resources list.
typedef std::map<std::wstring, ResourcesList> ResourcesListMap;
/// List of resource files.
typedef std::vector<ResourceFile*> 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<Resource*> &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