Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice 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 <writerperfect/WPXSvInputStream.hxx>
11 :
12 : #include <com/sun/star/packages/zip/XZipFileAccess2.hpp>
13 : #include <com/sun/star/uno/Any.hxx>
14 :
15 : #include <comphelper/processfactory.hxx>
16 : #include <comphelper/seekableinput.hxx>
17 :
18 : #include <rtl/string.hxx>
19 :
20 : #include <sot/storage.hxx>
21 :
22 : #include <tools/stream.hxx>
23 : #include <unotools/streamwrap.hxx>
24 : #include <unotools/ucbstreamhelper.hxx>
25 :
26 : #include <limits>
27 : #include <vector>
28 :
29 : #include <boost/noncopyable.hpp>
30 : #include <boost/scoped_ptr.hpp>
31 : #include <boost/unordered_map.hpp>
32 :
33 : namespace writerperfect
34 : {
35 :
36 : using namespace ::com::sun::star::uno;
37 : using namespace ::com::sun::star::io;
38 :
39 : namespace container = com::sun::star::container;
40 : namespace lang = com::sun::star::lang;
41 : namespace packages = com::sun::star::packages;
42 :
43 : namespace
44 : {
45 :
46 : class PositionHolder : boost::noncopyable
47 : {
48 : public:
49 : explicit PositionHolder(const Reference<XSeekable> &rxSeekable);
50 : ~PositionHolder();
51 :
52 : private:
53 : const Reference<XSeekable> mxSeekable;
54 : const sal_uInt64 mnPosition;
55 : };
56 :
57 1066 : PositionHolder::PositionHolder(const Reference<XSeekable> &rxSeekable)
58 : : mxSeekable(rxSeekable)
59 1066 : , mnPosition(rxSeekable->getPosition())
60 : {
61 1066 : }
62 :
63 2132 : PositionHolder::~PositionHolder() try
64 : {
65 1066 : mxSeekable->seek(mnPosition);
66 1066 : }
67 0 : catch (...)
68 : {
69 1066 : }
70 :
71 : } // anonymous namespace
72 :
73 : typedef struct
74 258 : {
75 : SotStorageRef ref;
76 358 : } SotStorageRefWrapper;
77 :
78 : typedef struct
79 252 : {
80 : SotStorageStreamRef ref;
81 1336 : } SotStorageStreamRefWrapper;
82 :
83 : namespace
84 : {
85 :
86 216 : rtl::OUString lcl_normalizeSubStreamPath(const rtl::OUString &rPath)
87 : {
88 : // accept paths which begin by '/'
89 : // TODO: maybe this should to a full normalization
90 216 : if (rPath.startsWith("/") && rPath.getLength() >= 2)
91 0 : return rPath.copy(1);
92 216 : return rPath;
93 : }
94 :
95 : }
96 :
97 : namespace
98 : {
99 :
100 604 : const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs)
101 : {
102 604 : if (lhs.isEmpty())
103 488 : return rhs;
104 116 : return lhs + "/" + rhs;
105 : }
106 :
107 1336 : struct OLEStreamData
108 : {
109 : explicit OLEStreamData(const rtl::OString &rName);
110 :
111 : SotStorageStreamRefWrapper stream;
112 :
113 : /** Name of the stream.
114 : *
115 : * This is not @c rtl::OUString, because we need to be able to
116 : * produce const char* from it.
117 : */
118 : rtl::OString name;
119 : };
120 :
121 : typedef boost::unordered_map<rtl::OUString, std::size_t, rtl::OUStringHash> NameMap_t;
122 : typedef boost::unordered_map<rtl::OUString, SotStorageRefWrapper, rtl::OUStringHash> OLEStorageMap_t;
123 :
124 : /** Representation of an OLE2 storage.
125 : *
126 : * This class tries to bring a bit of sanity to use of SotStorage with
127 : * respect to the needs of @c librevenge::RVNGInputStream API. It
128 : * holds all nested storages for the whole lifetime (more precisely,
129 : * since initialization, which is performed by calling @c
130 : * initialize()), thus ensuring that no created stream is destroyed
131 : * just because its parent storage went out of scope. It also holds a
132 : * bidirectional map of stream names to their indexes (index of a
133 : * stream is determined by deep-first traversal), which is also
134 : * populated during initialization (member variables @c maStreams and
135 : * @c maNameMap).
136 : *
137 : * Streams are created on demand (and saved, for the same reason as
138 : * storages).
139 : */
140 58 : struct OLEStorageImpl
141 : {
142 : OLEStorageImpl();
143 :
144 : void initialize(SvStream *pStream);
145 :
146 : SotStorageStreamRef getStream(const rtl::OUString &rPath);
147 : SotStorageStreamRef getStream(std::size_t nId);
148 :
149 : private:
150 : void traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath);
151 :
152 : SotStorageStreamRef createStream(const rtl::OUString &rPath);
153 :
154 : public:
155 : SotStorageRefWrapper mxRootStorage; //< root storage of the OLE2
156 : OLEStorageMap_t maStorageMap; //< map of all sub storages by name
157 : ::std::vector< OLEStreamData > maStreams; //< list of streams and their names
158 : NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
159 : bool mbInitialized;
160 : };
161 :
162 252 : OLEStreamData::OLEStreamData(const rtl::OString &rName)
163 : : stream()
164 252 : , name(rName)
165 : {
166 252 : }
167 :
168 58 : OLEStorageImpl::OLEStorageImpl()
169 : : mxRootStorage()
170 : , maStorageMap()
171 : , maStreams()
172 : , maNameMap()
173 58 : , mbInitialized(false)
174 : {
175 58 : }
176 :
177 58 : void OLEStorageImpl::initialize(SvStream *const pStream)
178 : {
179 58 : if (!pStream)
180 58 : return;
181 :
182 58 : mxRootStorage.ref = new SotStorage(pStream, true);
183 :
184 58 : traverse(mxRootStorage.ref, "");
185 :
186 58 : mbInitialized = true;
187 : }
188 :
189 166 : SotStorageStreamRef OLEStorageImpl::getStream(const rtl::OUString &rPath)
190 : {
191 166 : const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
192 166 : NameMap_t::iterator aIt = maNameMap.find(aPath);
193 :
194 : // For the while don't return stream in this situation.
195 : // Later, given how libcdr's zip stream implementation behaves,
196 : // return the first stream in the storage if there is one.
197 166 : if (maNameMap.end() == aIt)
198 12 : return SotStorageStreamRef();
199 :
200 154 : if (!maStreams[aIt->second].stream.ref.Is())
201 116 : maStreams[aIt->second].stream.ref = createStream(aPath);
202 :
203 154 : return maStreams[aIt->second].stream.ref;
204 : }
205 :
206 4 : SotStorageStreamRef OLEStorageImpl::getStream(const std::size_t nId)
207 : {
208 4 : if (!maStreams[nId].stream.ref.Is())
209 4 : maStreams[nId].stream.ref = createStream(rtl::OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
210 :
211 4 : return maStreams[nId].stream.ref;
212 : }
213 :
214 158 : void OLEStorageImpl::traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath)
215 : {
216 158 : SvStorageInfoList infos;
217 :
218 158 : rStorage->FillInfoList(&infos);
219 :
220 510 : for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt)
221 : {
222 352 : if (aIt->IsStream())
223 : {
224 252 : maStreams.push_back(OLEStreamData(rtl::OUStringToOString(concatPath(rPath, aIt->GetName()), RTL_TEXTENCODING_UTF8)));
225 252 : maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1;
226 : }
227 100 : else if (aIt->IsStorage())
228 : {
229 100 : const rtl::OUString aPath = concatPath(rPath, aIt->GetName());
230 200 : SotStorageRefWrapper xStorage;
231 100 : xStorage.ref = rStorage->OpenSotStorage(aIt->GetName(), STREAM_STD_READ);
232 100 : maStorageMap[aPath] = xStorage;
233 :
234 : // deep-first traversal
235 200 : traverse(xStorage.ref, aPath);
236 : }
237 : else
238 : {
239 : assert(false);
240 : }
241 158 : }
242 158 : }
243 :
244 120 : SotStorageStreamRef OLEStorageImpl::createStream(const rtl::OUString &rPath)
245 : {
246 120 : const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/'));
247 :
248 120 : if (-1 == nDelim)
249 88 : return mxRootStorage.ref->OpenSotStream(rPath, STREAM_STD_READ);
250 :
251 32 : const rtl::OUString aDir = rPath.copy(0, nDelim);
252 64 : const rtl::OUString aName = rPath.copy(nDelim + 1);
253 :
254 32 : const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
255 :
256 32 : if (maStorageMap.end() == aIt)
257 0 : return 0;
258 :
259 64 : return aIt->second.ref->OpenSotStream(aName, STREAM_STD_READ);
260 : }
261 :
262 : }
263 :
264 : namespace
265 : {
266 :
267 966 : struct ZipStreamData
268 : {
269 : explicit ZipStreamData(const rtl::OString &rName);
270 :
271 : Reference<XInputStream> xStream;
272 :
273 : /** Name of the stream.
274 : *
275 : * This is not @c rtl::OUString, because we need to be able to
276 : * produce const char* from it.
277 : */
278 : rtl::OString aName;
279 : };
280 :
281 : /** Representation of a Zip storage.
282 : *
283 : * This is quite similar to OLEStorageImpl, except that we do not need
284 : * to keep all storages (folders) open.
285 : */
286 28 : struct ZipStorageImpl
287 : {
288 : ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer);
289 :
290 : /** Initialize for access.
291 : *
292 : * This creates a bidirectional map of stream names to their
293 : * indexes (index of a stream is determined by deep-first
294 : * traversal).
295 : */
296 : void initialize();
297 :
298 : Reference<XInputStream> getStream(const rtl::OUString &rPath);
299 : Reference<XInputStream> getStream(std::size_t nId);
300 :
301 : private:
302 : void traverse(const Reference<container::XNameAccess> &rxEnum);
303 :
304 : Reference<XInputStream> createStream(const rtl::OUString &rPath);
305 :
306 : public:
307 : Reference<container::XNameAccess> mxContainer; //< root of the Zip
308 : ::std::vector< ZipStreamData > maStreams; //< list of streams and their names
309 : NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
310 : bool mbInitialized;
311 : };
312 :
313 322 : ZipStreamData::ZipStreamData(const rtl::OString &rName)
314 : : xStream()
315 322 : , aName(rName)
316 : {
317 322 : }
318 :
319 28 : ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer)
320 : : mxContainer(rxContainer)
321 : , maStreams()
322 : , maNameMap()
323 28 : , mbInitialized(false)
324 : {
325 : assert(mxContainer.is());
326 28 : }
327 :
328 28 : void ZipStorageImpl::initialize()
329 : {
330 28 : traverse(mxContainer);
331 :
332 28 : mbInitialized = true;
333 28 : }
334 :
335 50 : Reference<XInputStream> ZipStorageImpl::getStream(const rtl::OUString &rPath)
336 : {
337 50 : const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
338 50 : NameMap_t::iterator aIt = maNameMap.find(aPath);
339 :
340 : // For the while don't return stream in this situation.
341 : // Later, given how libcdr's zip stream implementation behaves,
342 : // return the first stream in the storage if there is one.
343 50 : if (maNameMap.end() == aIt)
344 6 : return Reference<XInputStream>();
345 :
346 44 : if (!maStreams[aIt->second].xStream.is())
347 32 : maStreams[aIt->second].xStream = createStream(aPath);
348 :
349 44 : return maStreams[aIt->second].xStream;
350 : }
351 :
352 22 : Reference<XInputStream> ZipStorageImpl::getStream(const std::size_t nId)
353 : {
354 22 : if (!maStreams[nId].xStream.is())
355 22 : maStreams[nId].xStream = createStream(rtl::OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
356 :
357 22 : return maStreams[nId].xStream;
358 : }
359 :
360 28 : void ZipStorageImpl::traverse(const Reference<container::XNameAccess> &rxContainer)
361 : {
362 28 : const Sequence<rtl::OUString> lNames = rxContainer->getElementNames();
363 :
364 28 : maStreams.reserve(lNames.getLength());
365 :
366 406 : for (sal_Int32 n = 0; n < lNames.getLength(); ++n)
367 : {
368 378 : if (!lNames[n].endsWithAsciiL("/", 1)) // skip dirs
369 : {
370 322 : maStreams.push_back(ZipStreamData(rtl::OUStringToOString(lNames[n], RTL_TEXTENCODING_UTF8)));
371 322 : maNameMap[lNames[n]] = maStreams.size() - 1;
372 : }
373 28 : }
374 28 : }
375 :
376 54 : Reference<XInputStream> ZipStorageImpl::createStream(const rtl::OUString &rPath)
377 : {
378 54 : Reference<XInputStream> xStream;
379 :
380 : try
381 : {
382 54 : const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
383 108 : const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
384 :
385 54 : if (xSeekable.is())
386 0 : xStream = xInputStream;
387 : else
388 108 : xStream.set(new comphelper::OSeekableInputWrapper(xInputStream, comphelper::getProcessComponentContext()));
389 : }
390 0 : catch (const Exception &)
391 : {
392 : // nothing needed
393 : }
394 :
395 54 : return xStream;
396 : }
397 :
398 : }
399 :
400 : class WPXSvInputStreamImpl
401 : {
402 : public :
403 : WPXSvInputStreamImpl(::com::sun::star::uno::Reference<
404 : ::com::sun::star::io::XInputStream > xStream);
405 : ~WPXSvInputStreamImpl();
406 :
407 : bool isStructured();
408 : unsigned subStreamCount();
409 : const char *subStreamName(unsigned id);
410 : bool existsSubStream(const char *name);
411 : librevenge::RVNGInputStream *getSubStreamByName(const char *name);
412 : librevenge::RVNGInputStream *getSubStreamById(unsigned id);
413 :
414 : const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead);
415 : int seek(long offset);
416 : long tell();
417 : bool isEnd();
418 :
419 : void invalidateReadBuffer();
420 :
421 : private:
422 : bool isOLE();
423 : void ensureOLEIsInitialized();
424 :
425 : bool isZip();
426 : void ensureZipIsInitialized();
427 :
428 : librevenge::RVNGInputStream *createWPXStream(const SotStorageStreamRef &rxStorage);
429 : librevenge::RVNGInputStream *createWPXStream(const Reference<XInputStream> &rxStream);
430 :
431 : private:
432 : ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > mxStream;
433 : ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > mxSeekable;
434 : ::com::sun::star::uno::Sequence< sal_Int8 > maData;
435 : boost::scoped_ptr< OLEStorageImpl > mpOLEStorage;
436 : boost::scoped_ptr< ZipStorageImpl > mpZipStorage;
437 : bool mbCheckedOLE;
438 : bool mbCheckedZip;
439 : public:
440 : sal_Int64 mnLength;
441 : const unsigned char *mpReadBuffer;
442 : unsigned long mnReadBufferLength;
443 : unsigned long mnReadBufferPos;
444 : };
445 :
446 698 : WPXSvInputStreamImpl::WPXSvInputStreamImpl(Reference< XInputStream > xStream) :
447 : mxStream(xStream),
448 : mxSeekable(xStream, UNO_QUERY),
449 : maData(0),
450 : mpOLEStorage(0),
451 : mpZipStorage(0),
452 : mbCheckedOLE(false),
453 : mbCheckedZip(false),
454 : mnLength(0),
455 : mpReadBuffer(0),
456 : mnReadBufferLength(0),
457 698 : mnReadBufferPos(0)
458 : {
459 698 : if (!xStream.is() || !mxStream.is())
460 0 : mnLength = 0;
461 : else
462 : {
463 698 : if (!mxSeekable.is())
464 0 : mnLength = 0;
465 : else
466 : {
467 : try
468 : {
469 698 : mnLength = mxSeekable->getLength();
470 698 : if (0 < mxSeekable->getPosition())
471 234 : mxSeekable->seek(0);
472 : }
473 0 : catch (...)
474 : {
475 : SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
476 0 : mnLength = 0;
477 : }
478 : }
479 : }
480 698 : }
481 :
482 696 : WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
483 : {
484 696 : }
485 :
486 1156 : const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
487 : {
488 1156 : numBytesRead = 0;
489 :
490 1156 : if (numBytes == 0 || isEnd())
491 14 : return 0;
492 :
493 1142 : numBytesRead = mxStream->readSomeBytes(maData, numBytes);
494 1142 : if (numBytesRead == 0)
495 0 : return 0;
496 :
497 1142 : return (const unsigned char *)maData.getConstArray();
498 : }
499 :
500 2886676 : long WPXSvInputStreamImpl::tell()
501 : {
502 2886676 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
503 0 : return -1L;
504 : else
505 : {
506 2886676 : sal_Int64 tmpPosition = mxSeekable->getPosition();
507 2886676 : if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
508 0 : return -1L;
509 2886676 : return (long)tmpPosition;
510 : }
511 : }
512 :
513 3734 : int WPXSvInputStreamImpl::seek(long offset)
514 : {
515 3734 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
516 0 : return -1;
517 :
518 3734 : sal_Int64 tmpPosition = mxSeekable->getPosition();
519 3734 : if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
520 0 : return -1;
521 :
522 : try
523 : {
524 3734 : mxSeekable->seek(offset);
525 3734 : return 0;
526 : }
527 0 : catch (...)
528 : {
529 : SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
530 0 : return -1;
531 : }
532 : }
533 :
534 5744186 : bool WPXSvInputStreamImpl::isEnd()
535 : {
536 5744186 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
537 0 : return true;
538 5744186 : return (mxSeekable->getPosition() >= mnLength);
539 : }
540 :
541 624 : bool WPXSvInputStreamImpl::isStructured()
542 : {
543 624 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
544 0 : return false;
545 :
546 624 : PositionHolder pos(mxSeekable);
547 624 : mxSeekable->seek(0);
548 :
549 624 : if (isOLE())
550 192 : return true;
551 :
552 432 : mxSeekable->seek(0);
553 :
554 432 : return isZip();
555 : }
556 :
557 64 : unsigned WPXSvInputStreamImpl::subStreamCount()
558 : {
559 64 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
560 0 : return 0;
561 :
562 64 : PositionHolder pos(mxSeekable);
563 64 : mxSeekable->seek(0);
564 :
565 64 : if (isOLE())
566 : {
567 36 : ensureOLEIsInitialized();
568 :
569 36 : return mpOLEStorage->maStreams.size();
570 : }
571 :
572 28 : mxSeekable->seek(0);
573 :
574 28 : if (isZip())
575 : {
576 26 : ensureZipIsInitialized();
577 :
578 26 : return mpZipStorage->maStreams.size();
579 : }
580 :
581 2 : return 0;
582 : }
583 :
584 68 : const char *WPXSvInputStreamImpl::subStreamName(const unsigned id)
585 : {
586 68 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
587 0 : return 0;
588 :
589 68 : PositionHolder pos(mxSeekable);
590 68 : mxSeekable->seek(0);
591 :
592 68 : if (isOLE())
593 : {
594 64 : ensureOLEIsInitialized();
595 :
596 64 : if (mpOLEStorage->maStreams.size() <= id)
597 0 : return 0;
598 :
599 64 : return mpOLEStorage->maStreams[id].name.getStr();
600 : }
601 :
602 4 : mxSeekable->seek(0);
603 :
604 4 : if (isZip())
605 : {
606 2 : ensureZipIsInitialized();
607 :
608 2 : if (mpZipStorage->maStreams.size() <= id)
609 0 : return 0;
610 :
611 2 : return mpZipStorage->maStreams[id].aName.getStr();
612 : }
613 :
614 2 : return 0;
615 : }
616 :
617 60 : bool WPXSvInputStreamImpl::existsSubStream(const char *const name)
618 : {
619 60 : if (!name)
620 0 : return false;
621 :
622 60 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
623 0 : return false;
624 :
625 60 : PositionHolder pos(mxSeekable);
626 60 : mxSeekable->seek(0);
627 :
628 120 : const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
629 :
630 60 : if (isOLE())
631 : {
632 4 : ensureOLEIsInitialized();
633 4 : return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
634 : }
635 :
636 56 : mxSeekable->seek(0);
637 :
638 56 : if (isZip())
639 : {
640 54 : ensureZipIsInitialized();
641 54 : return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
642 : }
643 :
644 62 : return false;
645 : }
646 :
647 218 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name)
648 : {
649 218 : if (!name)
650 0 : return 0;
651 :
652 218 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
653 0 : return 0;
654 :
655 218 : PositionHolder pos(mxSeekable);
656 218 : mxSeekable->seek(0);
657 :
658 436 : const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
659 :
660 218 : if (isOLE())
661 : {
662 166 : ensureOLEIsInitialized();
663 166 : return createWPXStream(mpOLEStorage->getStream(aName));
664 : }
665 :
666 52 : mxSeekable->seek(0);
667 :
668 52 : if (isZip())
669 : {
670 50 : ensureZipIsInitialized();
671 :
672 : try
673 : {
674 50 : return createWPXStream(mpZipStorage->getStream(aName));
675 : }
676 0 : catch (const Exception &)
677 : {
678 : // nothing needed
679 : }
680 : }
681 :
682 220 : return 0;
683 : }
684 :
685 32 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
686 : {
687 32 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
688 0 : return 0;
689 :
690 32 : PositionHolder pos(mxSeekable);
691 32 : mxSeekable->seek(0);
692 :
693 32 : if (isOLE())
694 : {
695 6 : ensureOLEIsInitialized();
696 :
697 6 : if (mpOLEStorage->maStreams.size() <= id)
698 2 : return 0;
699 :
700 4 : return createWPXStream(mpOLEStorage->getStream(id));
701 : }
702 :
703 26 : mxSeekable->seek(0);
704 :
705 26 : if (isZip())
706 : {
707 24 : ensureZipIsInitialized();
708 :
709 24 : if (mpZipStorage->maStreams.size() <= id)
710 2 : return 0;
711 :
712 : try
713 : {
714 22 : return createWPXStream(mpZipStorage->getStream(id));
715 : }
716 0 : catch (const Exception &)
717 : {
718 : // nothing needed
719 : }
720 : }
721 2 : return 0;
722 : }
723 :
724 4258 : void WPXSvInputStreamImpl::invalidateReadBuffer()
725 : {
726 4258 : if (mpReadBuffer)
727 : {
728 654 : seek((long) tell() + (long)mnReadBufferPos - (long)mnReadBufferLength);
729 654 : mpReadBuffer = 0;
730 654 : mnReadBufferPos = 0;
731 654 : mnReadBufferLength = 0;
732 : }
733 4258 : }
734 :
735 170 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const SotStorageStreamRef &rxStorage)
736 : {
737 170 : if (rxStorage.Is())
738 : {
739 158 : Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper(rxStorage));
740 158 : return new WPXSvInputStream(xContents);
741 : }
742 12 : return 0;
743 : }
744 :
745 72 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream> &rxStream)
746 : {
747 72 : if (rxStream.is())
748 66 : return new WPXSvInputStream(rxStream);
749 : else
750 6 : return 0;
751 : }
752 :
753 1066 : bool WPXSvInputStreamImpl::isOLE()
754 : {
755 1066 : if (!mbCheckedOLE)
756 : {
757 : assert(0 == mxSeekable->getPosition());
758 :
759 446 : boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream));
760 446 : if (pStream && SotStorage::IsOLEStorage(pStream.get()))
761 58 : mpOLEStorage.reset(new OLEStorageImpl());
762 :
763 446 : mbCheckedOLE = true;
764 : }
765 :
766 1066 : return bool(mpOLEStorage);
767 : }
768 :
769 598 : bool WPXSvInputStreamImpl::isZip()
770 : {
771 598 : if (!mbCheckedZip)
772 : {
773 : assert(0 == mxSeekable->getPosition());
774 :
775 : try
776 : {
777 388 : Sequence<Any> aArgs(1);
778 388 : aArgs[0] <<= mxStream;
779 :
780 776 : const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW);
781 : const Reference<packages::zip::XZipFileAccess2> xZip(
782 776 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
783 416 : UNO_QUERY_THROW);
784 416 : mpZipStorage.reset(new ZipStorageImpl(xZip));
785 : }
786 360 : catch (const Exception &)
787 : {
788 : // ignore
789 : }
790 :
791 388 : mbCheckedZip = true;
792 : }
793 :
794 598 : return bool(mpZipStorage);
795 : }
796 :
797 276 : void WPXSvInputStreamImpl::ensureOLEIsInitialized()
798 : {
799 : assert(mpOLEStorage);
800 :
801 276 : if (!mpOLEStorage->mbInitialized)
802 58 : mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
803 276 : }
804 :
805 156 : void WPXSvInputStreamImpl::ensureZipIsInitialized()
806 : {
807 : assert(mpZipStorage);
808 :
809 156 : if (!mpZipStorage->mbInitialized)
810 28 : mpZipStorage->initialize();
811 156 : }
812 :
813 698 : WPXSvInputStream::WPXSvInputStream(Reference< XInputStream > xStream) :
814 698 : mpImpl(new WPXSvInputStreamImpl(xStream))
815 : {
816 698 : }
817 :
818 1652 : WPXSvInputStream::~WPXSvInputStream()
819 : {
820 696 : if (mpImpl)
821 696 : delete mpImpl;
822 956 : }
823 :
824 : #define BUFFER_MAX 65536
825 :
826 3784816 : const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
827 : {
828 3784816 : numBytesRead = 0;
829 :
830 3784816 : if (numBytes == 0 || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
831 70 : return 0;
832 :
833 3784746 : if (mpImpl->mpReadBuffer)
834 : {
835 3783702 : if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
836 : {
837 3783590 : const unsigned char *pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
838 3783590 : mpImpl->mnReadBufferPos += numBytes;
839 3783590 : numBytesRead = numBytes;
840 3783590 : return pTmp;
841 : }
842 :
843 112 : mpImpl->invalidateReadBuffer();
844 : }
845 :
846 1156 : unsigned long curpos = (unsigned long) mpImpl->tell();
847 1156 : if (curpos == (unsigned long)-1) // returned ERROR
848 0 : return 0;
849 :
850 2312 : if ((curpos + numBytes < curpos) /*overflow*/ ||
851 1156 : (curpos + numBytes >= (sal_uInt64)mpImpl->mnLength)) /*reading more than available*/
852 : {
853 68 : numBytes = mpImpl->mnLength - curpos;
854 : }
855 :
856 1156 : if (numBytes < BUFFER_MAX)
857 : {
858 1136 : if (BUFFER_MAX < mpImpl->mnLength - curpos)
859 194 : mpImpl->mnReadBufferLength = BUFFER_MAX;
860 : else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
861 942 : mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
862 : }
863 : else
864 20 : mpImpl->mnReadBufferLength = numBytes;
865 :
866 1156 : unsigned long tmpNumBytes(0);
867 1156 : mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes);
868 1156 : if (tmpNumBytes != mpImpl->mnReadBufferLength)
869 0 : mpImpl->mnReadBufferLength = tmpNumBytes;
870 :
871 1156 : mpImpl->mnReadBufferPos = 0;
872 1156 : if (!mpImpl->mnReadBufferLength)
873 14 : return 0;
874 :
875 1142 : numBytesRead = numBytes;
876 :
877 1142 : mpImpl->mnReadBufferPos += numBytesRead;
878 1142 : return mpImpl->mpReadBuffer;
879 : }
880 :
881 2545750 : long WPXSvInputStream::tell()
882 : {
883 2545750 : long retVal = mpImpl->tell();
884 2545750 : return retVal - (long)mpImpl->mnReadBufferLength + (long)mpImpl->mnReadBufferPos;
885 : }
886 :
887 114756 : int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
888 : {
889 114756 : sal_Int64 tmpOffset = offset;
890 114756 : if (seekType == librevenge::RVNG_SEEK_CUR)
891 992 : tmpOffset += tell();
892 114756 : if (seekType == librevenge::RVNG_SEEK_END)
893 520 : tmpOffset += mpImpl->mnLength;
894 :
895 114756 : int retVal = 0;
896 114756 : if (tmpOffset < 0)
897 : {
898 6 : tmpOffset = 0;
899 6 : retVal = -1;
900 : }
901 114756 : if (tmpOffset > mpImpl->mnLength)
902 : {
903 30 : tmpOffset = mpImpl->mnLength;
904 30 : retVal = -1;
905 : }
906 :
907 114756 : if (tmpOffset < mpImpl->tell() && (unsigned long)tmpOffset >= (unsigned long)mpImpl->tell() - mpImpl->mnReadBufferLength)
908 : {
909 111676 : mpImpl->mnReadBufferPos = (unsigned long)(tmpOffset + (long) mpImpl->mnReadBufferLength - (long) mpImpl->tell());
910 111676 : return retVal;
911 : }
912 :
913 3080 : mpImpl->invalidateReadBuffer();
914 :
915 3080 : if (mpImpl->seek(tmpOffset))
916 0 : return -1;
917 3080 : return retVal;
918 : }
919 :
920 5743044 : bool WPXSvInputStream::isEnd()
921 : {
922 5743044 : return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
923 : }
924 :
925 624 : bool WPXSvInputStream::isStructured()
926 : {
927 624 : mpImpl->invalidateReadBuffer();
928 624 : return mpImpl->isStructured();
929 : }
930 :
931 64 : unsigned WPXSvInputStream::subStreamCount()
932 : {
933 64 : mpImpl->invalidateReadBuffer();
934 64 : return mpImpl->subStreamCount();
935 : }
936 :
937 68 : const char *WPXSvInputStream::subStreamName(const unsigned id)
938 : {
939 68 : mpImpl->invalidateReadBuffer();
940 68 : return mpImpl->subStreamName(id);
941 : }
942 :
943 60 : bool WPXSvInputStream::existsSubStream(const char *const name)
944 : {
945 60 : mpImpl->invalidateReadBuffer();
946 60 : return mpImpl->existsSubStream(name);
947 : }
948 :
949 218 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamByName(const char *name)
950 : {
951 218 : mpImpl->invalidateReadBuffer();
952 218 : return mpImpl->getSubStreamByName(name);
953 : }
954 :
955 32 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamById(const unsigned id)
956 : {
957 32 : mpImpl->invalidateReadBuffer();
958 32 : return mpImpl->getSubStreamById(id);
959 : }
960 :
961 : }
962 :
963 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|