1 #ifndef __RESOURCES_H__
2 #define __RESOURCES_H__
3 
4 /** \file resources.h
5  * Classes for resources loading and unloading.
6  */
7 
8 #include <string>
9 #include <fstream>
10 #include <list>
11 #include <map>
12 #include <vector>
13 
14 #include "visitor.h"
15 #include "buffer.h"
16 
17 typedef std::list<std::wstring> StringList;
18 
19 
20 class ResourceFile;
21 
22 
23 /// Abstract interface for streamed resource access
24 class ResourceStream
25 {
26     public:
~ResourceStream()27         virtual ~ResourceStream() { };
28 
29         /// Get size of resource
30         virtual size_t getSize() = 0;
31 
32         /// Seek into resource.
33         /// \param offset offset from resource start
34         virtual void seek(long offset) = 0;
35 
36         /// Read data from resource into buffer.
37         /// \param buffer buffer of size bytes.
38         /// \param size number of bytes to read.
39         virtual void read(char *buffer, size_t size) = 0;
40 
41         /// Get current position
42         virtual long getPos() = 0;
43 
44         /// Return true if end of resource reached
isEof()45         virtual bool isEof() { return (size_t)getPos() >= getSize(); };
46 
47         /// Get count of bytes left
getAvailable()48         virtual long getAvailable() { return (long)getSize() - getPos(); };
49 };
50 
51 
52 /***
53    * Low level resource file interface.
54    * Never use it, use ResourcesCollection instead.
55    ***/
56 class ResourceFile
57 {
58     private:
59         std::ifstream stream;           /// resource file input stream
60         int priority;                   /// priority of resource file
61         std::wstring name;              /// resource file name
62         Buffer *buffer;
63         bool ownBuffer;
64 
65     public:
66         /// Resource file directory entry
67         typedef struct {
68             std::wstring name;           /// resource name
69             long offset;                /// offset from start of resource file
70             long packedSize;            /// compressed size
71             long unpackedSize;          /// uncompressed size
72             std::wstring group;          /// group name
73             int level;                  /// pack level
74         } DirectoryEntry;
75         /// List of directory entries.
76         typedef std::list<DirectoryEntry> Directory;
77 
78     public:
79         /// Create resource file.  Throws exception if file can't be opened.
80         /// \param fileName the name of resource file.
81         /// \param buffer buffer for temporary data.
82         /// Can be shared with other resource files.
83         ResourceFile(const std::wstring &fileName, Buffer *buffer=NULL);
84         virtual ~ResourceFile();
85 
86     public:
87         /// Load directory listing.
88         /// \param directory list where resource entries will be placed.
89         void getDirectory(Directory &directory);
90 
91         /// Load data in preallocated buffer buf of size unpackedSize.
92         /// \param buf buffer of unpackedSize bytes where unpacked data will
93         /// be placed
94         /// \param offset offset from start of resource file to packed data
95         /// \param packedSize size of packed resource
96         /// \param unpackedSize size of unpacked resource
97         void load(char *buf, long offset, long packedSize,
98                 long unpackedSize, int level);
99 
100         /// Allocate buffer and load data.  Memory returned by this
101         ///  method must be freed by free() function call.
102         /// \param offset offset from start of resource file to packed data
103         /// \param packedSize size of packed resource
104         /// \param unpackedSize size of unpacked resource
105         void* load(long offset, long packedSize, long unpackedSize,
106                 int level);
107 
108         /// Get priority of this resource file.
getPriority()109         int getPriority() const { return priority; };
110 
111         /// Get the name of resource file.
getFileName()112         const std::wstring& getFileName() const { return name; };
113 
114         /// Get file stream.
getStream()115         std::ifstream& getStream() { return stream; };
116 
117     private:
118         /// Unpack memory buffer
119         /// \param in buffer of inSize bytes filled with packed data
120         /// \param inSize size of packed data
121         /// \param out buffer of outSize bytes where unpacked data will
122         /// be placed
123         /// \param outSize size of unpacked data
124         void unpack(char *in, int inSize, char *out, int outSize);
125 };
126 
127 
128 /// Simple resource file wrapper.
129 /// Used at boot time when ResourcesCollection
130 /// is not available yet.
131 class SimpleResourceFile: public ResourceFile
132 {
133     private:
134         typedef std::map<std::wstring, DirectoryEntry> DirectoryMap;
135         DirectoryMap directory;  /// Directory map.
136 
137     public:
138         /// Open resource file.  Throws exception if file can't be opened.
139         /// \param fileName the name of resource file.
140         /// \param buffer buffer for temporary data.
141         /// Can be shared with other resource files.
142         SimpleResourceFile(const std::wstring &fileName, Buffer *buffer=NULL);
143 
144     public:
145         /// Load data.  Memory returned by this method should be freed
146         /// by free() function call.
147         /// \param name name of resource
148         /// \param size returns size of resource
149         virtual void* load(const std::wstring &name, int &size);
150 
151         /// Load data into the buffer.
152         /// \param name name of resource
153         /// \param buffer buffer for resource data
154         virtual void load(const std::wstring &name, Buffer &buffer);
155 };
156 
157 
158 /// Internationalized resource entity.
159 class ResVariant
160 {
161     private:
162         int i18nScore;
163         ResourceFile *file;
164         long offset;
165         long unpackedSize;
166         long packedSize;
167         int refCnt;
168         void *data;
169         int level;
170 
171     public:
172         /// Create resource variation.
173         /// \param file reesource file
174         /// \param score locale compability score
175         /// \param entry entry in global resources directory
176         ResVariant(ResourceFile *file, int score,
177                 const ResourceFile::DirectoryEntry &entry);
178 
179         ~ResVariant();
180 
181     public:
182         /// Return locale compability score.
getI18nScore()183         int getI18nScore() const { return i18nScore; };
184 
185         /// Get pointer to unpacked resource data.
186         /// Must be freed after use this delRef()
187         void* getRef();
188 
189         /// Get pointer to unpacked resource data and return resource size.
190         /// Must be freed after use this delRef().
191         /// \param size returned size of resource data.
192         void* getRef(size_t &size);
193 
194         /// Delete referene to data.
195         /// \param data pointer to unpacked data.
196         void delRef(void *data);
197 
198         /// Return reference counter.
getRefCount()199         int getRefCount() const { return refCnt; };
200 
201         /// Is data managed by this object
202         /// \param data pointer to dataa
isDataOwned(void * data)203         bool isDataOwned(void *data) const { return refCnt && data == this->data; };
204 
205         /// return data.
206         /// destroy it after use with free()
207         void* getDynData();
208 
209         /// returns size of data
getSize()210         long getSize() const { return unpackedSize; };
211 
212         /// Return data in buffer
213         /// \param buffer buffer to store data.
214         void getData(Buffer &buffer);
215 
216         /// Create ResourceStream for resource.
217         /// This may be usefull for large streams unpacked data,
218         /// for example video and sound.
219         /// Delete stream after use.
220         ResourceStream* createStream();
221 };
222 
223 
224 /// Internationalized resources.
225 /// Collection of localized data (ResVariant) with single name.
226 class Resource
227 {
228     private:
229         typedef std::vector<ResVariant*> Variants;
230         Variants variants;
231         std::wstring name;
232 
233     public:
234         /// Create resource and add first entry
235         /// \param file resource file
236         /// \param i18nScore locale compability score
237         /// \param entry resource entry in global directory
238         /// \param name name of resource
239         Resource(ResourceFile *file, int i18nScore,
240                 const ResourceFile::DirectoryEntry &entry,
241                 const std::wstring &name);
242 
243         ~Resource();
244 
245     public:
246         /// Add resource variant.
247         /// \param file resource file
248         /// \param i18nScore locale compability score
249         /// \param entry resource entry in global directory
250         void addVariant(ResourceFile *file, int i18nScore,
251                 const ResourceFile::DirectoryEntry &entry);
252 
253         /// Get number of variants.
getVariantsCount()254         int getVariantsCount() const { return variants.size(); };
255 
256         /// Geturns variant object.
257         /// \param variant variant number.
258         ResVariant* getVariant(int variant=0) { return variants[variant]; };
259 
260         /// Load data from variant.
261         /// Data must be freed with delRef().
262         /// \param variant variant number.
263         void* getRef(int variant=0);
264 
265         /// Load data from variant.
266         /// data must be freed with delRef()
267         /// \param size size of data.
268         /// \param variant variant number.
269         void* getRef(int *size, int variant=0);
270 
271         /// Unload data
272         /// param data pointer to data.
273         void delRef(void *data);
274 
275         /// Get size of data.
276         /// \param variant variant number.
277         long getSize(int variant=0) { return variants[variant]->getSize(); };
278 
279         /// Get name of this resource.
getName()280         const std::wstring& getName() const { return name; };
281 
282         /// Load data into buffer.
283         /// \param buffer buffer for data.
284         /// \param variant variant number.
285         void getData(Buffer &buffer, int variant=0);
286 
287         /// Create ResourceStream for resource.
288         /// This may be usefull for large streams unpacked data,
289         /// for example video and sound.
290         /// Delete stream after use.
291         /// \param variant variant number.
292         ResourceStream* createStream(int variant=0);
293 };
294 
295 
296 /// Internationalized resource files collection.
297 /// When ResourceCollection created all resources checked against
298 /// current locale.  Resources not belonged to current locale are
299 /// ignored, resources that can be used in current locale sorted
300 /// by locale relevance score.
301 /// All resources names interpeted as name[_language][_COUNTRY].extension
302 /// where name is name of resource, language is optional two letters
303 /// ISO language code, country is two letters ISO country code
304 /// and extension is file extension.
305 /// After processing resource name will be truncated to name.extension.
306 /// By default resource with highest locale relevance score will
307 /// be loaded. Howether, it is possible to enumerate all variants
308 /// by using Resource class interface.
309 /// Resource files loaded in order specified by their priority.
310 /// Resources from file loaded later can replace resources
311 /// loaded before it.
312 class ResourcesCollection
313 {
314     private:
315         /// Map resource names to resources.
316         typedef std::map<std::wstring, Resource*> ResourcesMap;
317 
318         /// List of resources.
319         typedef std::list<Resource*> ResourcesList;
320 
321         /// Map group names to resources list.
322         typedef std::map<std::wstring, ResourcesList> ResourcesListMap;
323 
324         /// List of resource files.
325         typedef std::vector<ResourceFile*> ResourceFiles;
326 
327         ResourcesMap resources;    /// Map of all available resources.
328         ResourcesListMap groups;   /// Map of all available groups.
329         ResourceFiles files;       /// List of resource files.
330         Buffer buffer;             /// Temporary buffer for resource files.
331 
332     public:
333         /// Load resource files, make grouping and i18n optimizations.
334         ResourcesCollection(StringList &directories);
335         ~ResourcesCollection();
336 
337     public:
338         /// Returns resource entry.
339         /// If resource not found Exception will be thrown.
340         Resource* getResource(const std::wstring &name);
341 
342         /// Load resource.
343         /// Loaded data must be freed with delRef method.
344         void* getRef(const std::wstring &name, int &size);
345 
346         /// Load resource.
347         /// Loaded data must be freed with delRef method.
348         void* getRef(const std::wstring &name);
349 
350         /// Delete reference to resource.
351         void delRef(void *data);
352 
353         /// Visit all group members.
354         void forEachInGroup(const std::wstring &groupName,
355                 Visitor<Resource*> &visitor);
356 
357         /// Create ResourceStream for resource.
358         /// This may be usefull for large streams unpacked data,
359         /// for example video and sound.
360         /// Delete stream after use.
361         /// \param name name of resource.
362         ResourceStream* createStream(const std::wstring &name);
363 
364         /// Load data into buffer.
365         /// Usually you don't need this, use getRef instead.
366         /// \param name name of resource.
367         /// \param buffer buffer for data.
368         void loadData(const std::wstring &name, Buffer &buffer);
369 
370     private:
371         /// Open resource files.
372         void loadResourceFiles(StringList &directories);
373 
374         /// Make grouping and locale processing.
375         void processFiles();
376 };
377 
378 
379 /// Helper class for simple resource loading and unloading
380 class ResDataHolder
381 {
382     private:
383         void *data;
384         size_t size;
385 
386     public:
387         /// Create holder without data
388         ResDataHolder();
389 
390         /// Create holder and load data
391         ResDataHolder(const std::wstring &name);
392 
393         ~ResDataHolder();
394 
395     public:
396         /// Load resource data
397         void load(const std::wstring &name);
398 
399         /// Returns pointer to resource data
getData()400         void* getData() const { return data; };
401 
402         /// Returns size of data
getSize()403         size_t getSize() const { return size; };
404 };
405 
406 
407 /// Global collection of resources.
408 /// Careated at first step at boot time stage2
409 extern ResourcesCollection *resources;
410 
411 
412 #endif
413 
414