]> git.tdb.fi Git - libs/datafile.git/blob - source/packcollection.h
Add an intelligent packed collection class
[libs/datafile.git] / source / packcollection.h
1 #ifndef MSP_DATAFILE_PACKCOLLECTION_H_
2 #define MSP_DATAFILE_PACKCOLLECTION_H_
3
4 #include "collection.h"
5 #include "objectloader.h"
6
7 namespace Msp {
8 namespace DataFile {
9
10 /**
11 A collection class that loads data from pack files.  As opposed to plain
12 collection files, pack files are composed from a number of logical files.  They
13 also contain a directory with a list of objects contained in the pack and which
14 logical files they are in.  This allows the pack to be loaded in a piecewise
15 manner instead of all at once.
16
17 It's possible for a pack file to contain plain collection files as well.  When
18 an object from such a file is requested, the entire sub-collection it is stored
19 in is loaded.
20 */
21 class PackCollection: public Collection
22 {
23 private:
24         class File;
25         struct Object;
26
27         typedef std::map<std::string, const Object *> ObjectMap;
28
29         class Pack
30         {
31         public:
32                 class Loader: public ObjectLoader<Pack>
33                 {
34                 public:
35                         Loader(Pack &);
36                 private:
37                         void file(const std::string &);
38                 };
39
40         private:
41                 std::string filename;
42                 unsigned base_offset;
43                 std::list<File> files;
44
45         public:
46                 Pack(const std::string &);
47
48                 const std::string &get_filename() const { return filename; }
49                 unsigned get_base_offset() const { return base_offset; }
50
51                 void collect_objects(ObjectMap &) const;
52         };
53
54         class File
55         {
56         public:
57                 class Loader: public ObjectLoader<File>
58                 {
59                 public:
60                         Loader(File &);
61                 private:
62                         virtual void finish();
63                         void object(const std::string &, const std::string &);
64                 };
65
66         private:
67                 const Pack &pack;
68                 std::string filename;
69                 unsigned offset;
70                 unsigned length;
71                 bool collection;
72                 std::list<Object> objects;
73                 bool loaded;
74
75         public:
76                 File(const Pack &, const std::string &);
77
78                 RefPtr<IO::Base> open() const;
79                 const std::string &get_filename() const { return filename; }
80                 std::string get_full_name() const;
81                 bool is_collection() const { return collection; }
82
83                 void set_loaded();
84                 bool is_loaded() const { return loaded; }
85
86                 void collect_objects(ObjectMap &) const;
87         };
88
89         class Object
90         {
91         private:
92                 File &file;
93                 std::string name;
94                 std::string keyword;
95
96         public:
97                 Object(File &, const std::string &, const std::string &);
98
99                 File &get_file() const { return file; }
100                 const std::string &get_name() const { return name; }
101                 const std::string &get_keyword() const { return keyword; }
102         };
103
104         std::list<Pack> packs;
105         ObjectMap objects;
106
107 public:
108         /** Adds a pack file to the collection.  The directory is read immediately,
109         and packed objects are loaded as they are needed. */
110         void add_pack_file(const std::string &);
111
112 protected:
113         template<typename T>
114         CollectionItemType<T> &add_type()
115         {
116                 return Collection::add_type<T>().creator(&PackCollection::create<T>);
117         }
118
119 private:
120         template<typename T>
121         T *create(const std::string &name)
122         {
123                 ObjectMap::iterator i = objects.find(name);
124                 if(i==objects.end())
125                         return 0;
126
127                 File &file = i->second->get_file();
128                 if(file.is_loaded())
129                         return 0;
130                 file.set_loaded();
131
132                 RefPtr<IO::Base> in = file.open();
133                 Parser parser(*in, file.get_full_name());
134                 if(file.is_collection())
135                 {
136                         Loader ldr(*this);
137                         ldr.load(parser);
138                         return 0;
139                 }
140                 else
141                 {
142                         RefPtr<T> item = new T;
143                         ItemLoader<T> ldr(*item, *this);
144                         ldr.load(parser);
145                         return item.release();
146                 }
147         }
148 };
149
150 } // namespace DataFile
151 } // namespace Msp
152
153 #endif