/src/libe-book/src/lib/SoftBookResourceDir.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* |
3 | | * This file is part of the libe-book project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #include <cassert> |
11 | | #include <string> |
12 | | #include <unordered_map> |
13 | | |
14 | | #include <boost/optional.hpp> |
15 | | |
16 | | #include "libebook_utils.h" |
17 | | #include "EBOOKMemoryStream.h" |
18 | | #include "SoftBookHeader.h" |
19 | | #include "SoftBookResourceDir.h" |
20 | | |
21 | | using boost::optional; |
22 | | using std::shared_ptr; |
23 | | |
24 | | using std::string; |
25 | | |
26 | | namespace libebook |
27 | | { |
28 | | |
29 | | namespace |
30 | | { |
31 | | |
32 | | template<class Selector> |
33 | | class ResourceStream : public librevenge::RVNGInputStream |
34 | | { |
35 | | public: |
36 | | ResourceStream(shared_ptr<librevenge::RVNGInputStream> strm, shared_ptr<SoftBookResourceDirImpl> resourceDir); |
37 | | |
38 | | bool isStructured() override; |
39 | | unsigned subStreamCount() override; |
40 | | const char *subStreamName(unsigned id) override; |
41 | | bool existsSubStream(const char *name) override; |
42 | | librevenge::RVNGInputStream *getSubStreamByName(const char *name) override; |
43 | | RVNGInputStream *getSubStreamById(unsigned id) override; |
44 | | |
45 | | const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead) override; |
46 | | int seek(long offset, librevenge::RVNG_SEEK_TYPE seekType) override; |
47 | | long tell() override; |
48 | | bool isEnd() override; |
49 | | |
50 | | private: |
51 | | const shared_ptr<librevenge::RVNGInputStream> m_stream; |
52 | | const shared_ptr<SoftBookResourceDirImpl> m_resourceDir; |
53 | | }; |
54 | | |
55 | | struct NameSelector |
56 | | { |
57 | | static librevenge::RVNGInputStream *getStream(shared_ptr<SoftBookResourceDirImpl> resourceDir, const char *name); |
58 | | }; |
59 | | |
60 | | struct TypeSelector |
61 | | { |
62 | | static librevenge::RVNGInputStream *getStream(shared_ptr<SoftBookResourceDirImpl> resourceDir, const char *name); |
63 | | }; |
64 | | |
65 | | } |
66 | | |
67 | | class SoftBookResourceDirImpl |
68 | | { |
69 | | // -Weffc++ |
70 | | SoftBookResourceDirImpl(const SoftBookResourceDirImpl &other); |
71 | | SoftBookResourceDirImpl &operator=(const SoftBookResourceDirImpl &other); |
72 | | |
73 | | struct ResourceInfo |
74 | | { |
75 | | ResourceInfo(); |
76 | | |
77 | | unsigned offset; |
78 | | unsigned length; |
79 | | optional<string> type; |
80 | | }; |
81 | | |
82 | | typedef std::unordered_map<string, ResourceInfo> ResourceMap_t; |
83 | | typedef std::unordered_map<string, ResourceMap_t::const_iterator> TypeMap_t; |
84 | | |
85 | | public: |
86 | | SoftBookResourceDirImpl(librevenge::RVNGInputStream *input, unsigned files, unsigned version); |
87 | | |
88 | | librevenge::RVNGInputStream *getDirStream() const; |
89 | | |
90 | | librevenge::RVNGInputStream *getResourceByName(const char *name) const; |
91 | | librevenge::RVNGInputStream *getResourceByType(const char *type) const; |
92 | | |
93 | | private: |
94 | | ResourceMap_t::const_iterator findResourceByType(const char *type) const; |
95 | | |
96 | | librevenge::RVNGInputStream *createStream(const ResourceInfo &info) const; |
97 | | |
98 | | private: |
99 | | librevenge::RVNGInputStream *m_stream; |
100 | | unsigned m_start; |
101 | | unsigned m_length; |
102 | | mutable ResourceMap_t m_resourceMap; |
103 | | mutable TypeMap_t m_typeMap; |
104 | | }; |
105 | | |
106 | | namespace |
107 | | { |
108 | | |
109 | | string readFileType(librevenge::RVNGInputStream *const input) |
110 | 580k | { |
111 | 580k | const unsigned char *const data = readNBytes(input, 4); |
112 | 580k | const string fileName(data, data + ((0 == data[3]) ? 3 : 4)); |
113 | 580k | return fileName; |
114 | 580k | } |
115 | | |
116 | | librevenge::RVNGInputStream *NameSelector::getStream(const shared_ptr<SoftBookResourceDirImpl> resourceDir, const char *const name) |
117 | 0 | { |
118 | 0 | return resourceDir->getResourceByName(name); |
119 | 0 | } |
120 | | |
121 | | librevenge::RVNGInputStream *TypeSelector::getStream(const shared_ptr<SoftBookResourceDirImpl> resourceDir, const char *const name) |
122 | 227 | { |
123 | 227 | return resourceDir->getResourceByType(name); |
124 | 227 | } |
125 | | |
126 | | template<class Selector> |
127 | | ResourceStream<Selector>::ResourceStream(const shared_ptr<librevenge::RVNGInputStream> strm, const shared_ptr<SoftBookResourceDirImpl> resourceDir) |
128 | 226 | : m_stream(strm) |
129 | 226 | , m_resourceDir(resourceDir) |
130 | 226 | { |
131 | 226 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::ResourceStream(std::__1::shared_ptr<librevenge::RVNGInputStream>, std::__1::shared_ptr<libebook::SoftBookResourceDirImpl>) SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::ResourceStream(std::__1::shared_ptr<librevenge::RVNGInputStream>, std::__1::shared_ptr<libebook::SoftBookResourceDirImpl>) Line | Count | Source | 128 | 226 | : m_stream(strm) | 129 | 226 | , m_resourceDir(resourceDir) | 130 | 226 | { | 131 | 226 | } |
|
132 | | |
133 | | template<class Selector> |
134 | | bool ResourceStream<Selector>::isStructured() |
135 | 0 | { |
136 | 0 | return true; |
137 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::isStructured() Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::isStructured() |
138 | | |
139 | | template<class Selector> |
140 | | unsigned ResourceStream<Selector>::subStreamCount() |
141 | 0 | { |
142 | | // TODO: implement me |
143 | 0 | return 0; |
144 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::subStreamCount() Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::subStreamCount() |
145 | | |
146 | | template<class Selector> |
147 | | const char *ResourceStream<Selector>::subStreamName(const unsigned id) |
148 | 0 | { |
149 | | // TODO: implement me |
150 | 0 | (void) id; |
151 | 0 | return nullptr; |
152 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::subStreamName(unsigned int) Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::subStreamName(unsigned int) |
153 | | |
154 | | template<class Selector> |
155 | | bool ResourceStream<Selector>::existsSubStream(const char *const name) |
156 | 0 | { |
157 | | // TODO: implement me |
158 | 0 | (void) name; |
159 | 0 | return true; |
160 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::existsSubStream(char const*) Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::existsSubStream(char const*) |
161 | | |
162 | | template<class Selector> |
163 | | librevenge::RVNGInputStream *ResourceStream<Selector>::getSubStreamByName(const char *const name) |
164 | 227 | { |
165 | 227 | return Selector::getStream(m_resourceDir, name); |
166 | 227 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::getSubStreamByName(char const*) SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::getSubStreamByName(char const*) Line | Count | Source | 164 | 227 | { | 165 | 227 | return Selector::getStream(m_resourceDir, name); | 166 | 227 | } |
|
167 | | |
168 | | template<class Selector> |
169 | | librevenge::RVNGInputStream *ResourceStream<Selector>::getSubStreamById(const unsigned id) |
170 | 0 | { |
171 | | // TODO: implement me |
172 | 0 | (void) id; |
173 | 0 | return nullptr; |
174 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::getSubStreamById(unsigned int) Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::getSubStreamById(unsigned int) |
175 | | |
176 | | template<class Selector> |
177 | | const unsigned char *ResourceStream<Selector>::read(const unsigned long numBytes, unsigned long &numBytesRead) |
178 | 0 | { |
179 | 0 | return m_stream->read(numBytes, numBytesRead); |
180 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::read(unsigned long, unsigned long&) Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::read(unsigned long, unsigned long&) |
181 | | |
182 | | template<class Selector> |
183 | | int ResourceStream<Selector>::seek(const long offset, const librevenge::RVNG_SEEK_TYPE seekType) |
184 | 0 | { |
185 | 0 | return m_stream->seek(offset, seekType); |
186 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::seek(long, librevenge::RVNG_SEEK_TYPE) Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::seek(long, librevenge::RVNG_SEEK_TYPE) |
187 | | |
188 | | template<class Selector> |
189 | | long ResourceStream<Selector>::tell() |
190 | 0 | { |
191 | 0 | return m_stream->tell(); |
192 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::tell() Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::tell() |
193 | | |
194 | | template<class Selector> |
195 | | bool ResourceStream<Selector>::isEnd() |
196 | 0 | { |
197 | 0 | return m_stream->isEnd(); |
198 | 0 | } Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::NameSelector>::isEnd() Unexecuted instantiation: SoftBookResourceDir.cpp:libebook::(anonymous namespace)::ResourceStream<libebook::(anonymous namespace)::TypeSelector>::isEnd() |
199 | | |
200 | | } |
201 | | |
202 | | SoftBookResourceDir::SoftBookResourceDir(librevenge::RVNGInputStream *const input, const SoftBookHeader &header) |
203 | 947 | : m_impl() |
204 | 947 | { |
205 | 947 | input->seek((long) header.getTOCOffset(), librevenge::RVNG_SEEK_SET); |
206 | 947 | m_impl.reset(new SoftBookResourceDirImpl(input, header.getFileCount(), header.getVersion())); |
207 | 947 | } |
208 | | |
209 | | shared_ptr<librevenge::RVNGInputStream> SoftBookResourceDir::getNameStream() const |
210 | 0 | { |
211 | 0 | const shared_ptr<librevenge::RVNGInputStream> strm(m_impl->getDirStream()); |
212 | 0 | const shared_ptr<librevenge::RVNGInputStream> resource(new ResourceStream<NameSelector>(strm, m_impl)); |
213 | 0 | return resource; |
214 | 0 | } |
215 | | |
216 | | shared_ptr<librevenge::RVNGInputStream> SoftBookResourceDir::getTypeStream() const |
217 | 298 | { |
218 | 298 | const shared_ptr<librevenge::RVNGInputStream> strm(m_impl->getDirStream()); |
219 | 298 | const shared_ptr<librevenge::RVNGInputStream> resource(new ResourceStream<TypeSelector>(strm, m_impl)); |
220 | 298 | return resource; |
221 | 298 | } |
222 | | |
223 | | SoftBookResourceDirImpl::ResourceInfo::ResourceInfo() |
224 | 336k | : offset(0) |
225 | 336k | , length(0) |
226 | 336k | , type() |
227 | 336k | { |
228 | 336k | } |
229 | | |
230 | | SoftBookResourceDirImpl::SoftBookResourceDirImpl(librevenge::RVNGInputStream *const input, const unsigned files, const unsigned version) |
231 | 947 | : m_stream(input) |
232 | 947 | , m_start(0) |
233 | 947 | , m_length(0) |
234 | 947 | , m_resourceMap() |
235 | 947 | , m_typeMap() |
236 | 947 | { |
237 | 947 | m_start = static_cast<unsigned>(input->tell()); |
238 | 947 | unsigned headerLength = 0; |
239 | | |
240 | 947 | switch (version) |
241 | 947 | { |
242 | 251 | case 1 : |
243 | 251 | headerLength = 10; |
244 | 251 | break; |
245 | 696 | case 2 : |
246 | 696 | headerLength = 20; |
247 | 696 | break; |
248 | 0 | default : |
249 | 0 | EBOOK_DEBUG_MSG(("unknown version %d\n", version)); |
250 | 0 | throw GenericException(); |
251 | 947 | } |
252 | | |
253 | 947 | const unsigned tocLength = headerLength * files; |
254 | 947 | unsigned fileOffset = m_start + tocLength; |
255 | 947 | m_length = tocLength; |
256 | | |
257 | 337k | for (unsigned i = 0; i != files; ++i) |
258 | 336k | { |
259 | 336k | const string fileName = readFileType(input); |
260 | 336k | ResourceInfo info; |
261 | | |
262 | 336k | switch (version) |
263 | 336k | { |
264 | 92.9k | case 1 : |
265 | 92.9k | skip(input, 2); |
266 | 92.9k | info.length = readU32(input, true); |
267 | 92.9k | break; |
268 | 243k | case 2 : |
269 | 243k | skip(input, 4); |
270 | 243k | info.length = readU32(input, true); |
271 | 243k | info.type = readFileType(input); |
272 | 243k | skip(input, 4); |
273 | 243k | break; |
274 | 0 | default : |
275 | 0 | throw GenericException(); |
276 | 336k | } |
277 | | |
278 | 336k | info.length += headerLength; |
279 | 336k | info.offset = fileOffset; |
280 | 336k | fileOffset += info.length; |
281 | 336k | m_length += info.length; |
282 | | |
283 | 336k | const ResourceMap_t::const_iterator it = m_resourceMap.insert(ResourceMap_t::value_type(fileName, info)).first; |
284 | 336k | if (info.type) |
285 | 243k | m_typeMap.insert(TypeMap_t::value_type(get(info.type), it)); |
286 | 336k | } |
287 | 947 | } |
288 | | |
289 | | librevenge::RVNGInputStream *SoftBookResourceDirImpl::getDirStream() const |
290 | 298 | { |
291 | 298 | m_stream->seek((long) m_start, librevenge::RVNG_SEEK_SET); |
292 | 298 | const unsigned char *const data = readNBytes(m_stream, m_length); |
293 | 298 | return new EBOOKMemoryStream(data, m_length); |
294 | 298 | } |
295 | | |
296 | | librevenge::RVNGInputStream *SoftBookResourceDirImpl::getResourceByName(const char *const name) const |
297 | 0 | { |
298 | 0 | librevenge::RVNGInputStream *resource = nullptr; |
299 | |
|
300 | 0 | ResourceMap_t::const_iterator it = m_resourceMap.find(name); |
301 | 0 | if (m_resourceMap.end() != it) |
302 | 0 | resource = createStream(it->second); |
303 | |
|
304 | 0 | return resource; |
305 | 0 | } |
306 | | |
307 | | librevenge::RVNGInputStream *SoftBookResourceDirImpl::getResourceByType(const char *const type) const |
308 | 227 | { |
309 | 227 | TypeMap_t::const_iterator it = m_typeMap.find(type); |
310 | 227 | if (m_typeMap.end() == it) |
311 | 60 | { |
312 | 60 | const ResourceMap_t::const_iterator resIt = findResourceByType(type); |
313 | 60 | it = m_typeMap.insert(TypeMap_t::value_type(type, resIt)).first; |
314 | 60 | } |
315 | 227 | assert(m_typeMap.end() != it); |
316 | | |
317 | 227 | librevenge::RVNGInputStream *resource = nullptr; |
318 | 227 | if (m_resourceMap.end() != it->second) |
319 | 167 | resource = createStream(it->second->second); |
320 | | |
321 | 227 | return resource; |
322 | 227 | } |
323 | | |
324 | | SoftBookResourceDirImpl::ResourceMap_t::const_iterator SoftBookResourceDirImpl::findResourceByType(const char *const type) const |
325 | 60 | { |
326 | 60 | auto it = m_resourceMap.begin(); |
327 | | |
328 | 190 | for (; m_resourceMap.end() != it; ++it) |
329 | 130 | { |
330 | 130 | ResourceInfo &info = it->second; |
331 | 130 | if (!info.type) |
332 | 28 | { |
333 | | // sniff the content |
334 | 28 | m_stream->seek((long) info.offset, librevenge::RVNG_SEEK_SET); |
335 | 28 | if (1 == readU16(m_stream)) |
336 | 3 | info.type = readFileType(m_stream); |
337 | 25 | else |
338 | 25 | info.type = string(); |
339 | 28 | } |
340 | | |
341 | 130 | assert(info.type); |
342 | | |
343 | 130 | if (type == get(info.type)) |
344 | 0 | break; |
345 | 130 | } |
346 | | |
347 | 60 | return it; |
348 | 60 | } |
349 | | |
350 | | librevenge::RVNGInputStream *SoftBookResourceDirImpl::createStream(const ResourceInfo &info) const |
351 | 167 | { |
352 | 167 | m_stream->seek((long) info.offset, librevenge::RVNG_SEEK_SET); |
353 | 167 | const unsigned char *const data = readNBytes(m_stream, info.length); |
354 | 167 | return new EBOOKMemoryStream(data, info.length); |
355 | 167 | } |
356 | | |
357 | | } |
358 | | |
359 | | /* vim:set shiftwidth=2 softtabstop=2 expandtab: */ |