]> git.tdb.fi Git - libs/datafile.git/blob - source/packsource.cpp
Cosmetic changes
[libs/datafile.git] / source / packsource.cpp
1 #include <msp/io/slice.h>
2 #include <msp/strings/format.h>
3 #include <msp/strings/regex.h>
4 #include "collection.h"
5 #include "packsource.h"
6
7 using namespace std;
8
9 namespace {
10
11 void delete_io(Msp::IO::Base *io)
12 {
13         delete io;
14 }
15
16 }
17
18 namespace Msp {
19 namespace DataFile {
20
21 void PackSource::add_pack_file(const string &fn)
22 {
23         add_pack_file(fn, string());
24 }
25
26 void PackSource::add_pack_file(const string &fn, const string &filter)
27 {
28         add_pack(0, fn, filter);
29 }
30
31 void PackSource::add_pack_io(IO::Seekable &io, const string &fn)
32 {
33         add_pack(&io, fn, string());
34 }
35
36 void PackSource::add_pack_io(IO::Seekable &io, const string &fn, const string &filter)
37 {
38         add_pack(&io, fn, filter);
39 }
40
41 void PackSource::add_pack(IO::Seekable *io, const string &fn, const string &filter)
42 {
43         Pack *pack = 0;
44         for(list<Pack>::iterator i=packs.begin(); (!pack && i!=packs.end()); ++i)
45                 if(i->get_filename()==fn || (io && i->get_io()==io))
46                         pack = &*i;
47         if(!pack)
48         {
49                 packs.push_back(Pack(io, fn));
50                 pack = &packs.back();
51                 if(io)
52                 {
53                         DataFile::Parser parser(*io, fn);
54                         Pack::Loader loader(*pack);
55                         loader.load(parser);
56                 }
57                 else
58                         DataFile::load(*pack, fn);
59         }
60
61         FileMap pack_files;
62         pack->collect_files(pack_files, filter);
63         for(FileMap::const_iterator i=pack_files.begin(); i!=pack_files.end(); ++i)
64         {
65                 files[i->first] = i->second;
66                 i->second->collect_objects(objects);
67         }
68 }
69
70 list<PackSource::FileInfo> PackSource::list_files() const
71 {
72         list<FileInfo> result;
73         for(FileMap::const_iterator i=files.begin(); i!=files.end(); ++i)
74                 result.push_back(i->second->get_info());
75         return result;
76 }
77
78 bool PackSource::is_loadable(const CollectionItemTypeBase &type, const string &name) const
79 {
80         ObjectMap::const_iterator i = objects.find(name);
81         if(i==objects.end())
82                 return false;
83
84         // If the object has a keyword, it must match that of the type
85         if(!i->second->get_keyword().empty() && i->second->get_keyword()!=type.get_keyword())
86                 return false;
87
88         return true;
89 }
90
91 CollectionSource::NameList PackSource::get_names(const CollectionItemTypeBase &type) const
92 {
93         NameList names;
94         for(ObjectMap::const_iterator i=objects.begin(); i!=objects.end(); ++i)
95         {
96                 if(!i->second->get_keyword().empty())
97                 {
98                         if(i->second->get_keyword()!=type.get_keyword())
99                                 continue;
100                 }
101                 else if(!type.match_name(i->first))
102                         continue;
103
104                 names.push_back(i->first);
105         }
106
107         return names;
108 }
109
110 void PackSource::load(Collection &coll, const CollectionItemTypeBase &type, const string &name) const
111 {
112         ObjectMap::const_iterator i = objects.find(name);
113         if(i==objects.end())
114                 return;
115
116         File &file = i->second->get_file();
117
118         RefPtr<IO::Base> in = file.open();
119         Parser parser(*in, file.get_full_name());
120         if(file.is_collection())
121         {
122                 Collection::Loader ldr(coll);
123                 ldr.load(parser);
124         }
125         else
126                 type.load_item(coll, parser, name);
127 }
128
129 IO::Seekable *PackSource::open(const string &fn) const
130 {
131         FileMap::const_iterator i = files.find(fn);
132         if(i!=files.end())
133                 return i->second->open().release();
134
135         return 0;
136 }
137
138
139 PackSource::Pack::Pack(IO::Seekable *i, const string &fn):
140         filename(fn),
141         io(i),
142         base_offset(0)
143 { }
144
145 void PackSource::Pack::collect_files(FileMap &fm, const string &filter) const
146 {
147         if(filter.empty())
148         {
149                 for(list<File>::const_iterator i=files.begin(); i!=files.end(); ++i)
150                         fm[i->get_filename()] = &*i;
151         }
152         else
153         {
154                 Regex re(filter);
155                 for(list<File>::const_iterator i=files.begin(); i!=files.end(); ++i)
156                         if(re.match(i->get_filename()))
157                                 fm[i->get_filename()] = &*i;
158         }
159 }
160
161
162 PackSource::File::File(const Pack &p, const string &fn):
163         pack(p),
164         filename(fn),
165         offset(0),
166         length(0),
167         collection(false)
168 { }
169
170 RefPtr<IO::Seekable> PackSource::File::open() const
171 {
172         if(pack.get_io())
173                 // TODO Performance may be poor without buffering
174                 return new IO::Slice(*pack.get_io(), pack.get_base_offset()+offset, length);
175         else
176         {
177                 IO::BufferedFile *io_file = new IO::BufferedFile(pack.get_filename());
178                 IO::Slice *io_slice = new IO::Slice(*io_file, pack.get_base_offset()+offset, length);
179                 io_slice->signal_deleted.connect(sigc::bind(sigc::ptr_fun(delete_io), io_file));
180                 return io_slice;
181         }
182 }
183
184 PackSource::FileInfo PackSource::File::get_info() const
185 {
186         FileInfo info;
187         info.name = filename;
188         info.size = length;
189         return info;
190 }
191
192 string PackSource::File::get_full_name() const
193 {
194         return format("%s/%s", pack.get_filename(), filename);
195 }
196
197 void PackSource::File::collect_objects(ObjectMap &objs) const
198 {
199         for(list<Object>::const_iterator i=objects.begin(); i!=objects.end(); ++i)
200                 objs[i->get_name()] = &*i;
201 }
202
203
204 PackSource::Object::Object(File &f, const string &n, const string &k):
205         file(f),
206         name(n),
207         keyword(k)
208 { }
209
210
211 PackSource::Pack::Loader::Loader(Pack &p):
212         ObjectLoader<Pack>(p)
213 {
214         add("file",        &Loader::file);
215         add("base_offset", &Pack::base_offset);
216 }
217
218 void PackSource::Pack::Loader::file(const string &fn)
219 {
220         obj.files.push_back(File(obj, fn));
221         load_sub(obj.files.back());
222 }
223
224
225 PackSource::File::Loader::Loader(File &f):
226         ObjectLoader<File>(f)
227 {
228         add("object", &Loader::object);
229         add("slice",  &File::offset, &File::length);
230 }
231
232 void PackSource::File::Loader::finish()
233 {
234         if(!obj.collection)
235         {
236                 PackSource::Object ob(obj, obj.filename, string());
237                 obj.objects.push_back(ob);
238         }
239 }
240
241 void PackSource::File::Loader::object(const string &name, const string &kwd)
242 {
243         obj.objects.push_back(PackSource::Object(obj, name, kwd));
244         obj.collection = true;
245 }
246
247 } // namespace DataFile
248 } // namespace Msp