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 <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 <unordered_map>
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 7987 : PositionHolder::PositionHolder(const Reference<XSeekable> &rxSeekable)
58 : : mxSeekable(rxSeekable)
59 7987 : , mnPosition(rxSeekable->getPosition())
60 : {
61 7987 : }
62 :
63 15974 : PositionHolder::~PositionHolder() try
64 : {
65 7987 : mxSeekable->seek(mnPosition);
66 : }
67 0 : catch (...)
68 : {
69 7987 : }
70 :
71 : } // anonymous namespace
72 :
73 : typedef struct
74 129 : {
75 : tools::SvRef<SotStorage> ref;
76 179 : } SotStorageRefWrapper;
77 :
78 : typedef struct
79 126 : {
80 : tools::SvRef<SotStorageStream> ref;
81 668 : } SotStorageStreamRefWrapper;
82 :
83 : namespace
84 : {
85 :
86 162 : 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 162 : if (rPath.startsWith("/") && rPath.getLength() >= 2)
91 0 : return rPath.copy(1);
92 162 : return rPath;
93 : }
94 :
95 : }
96 :
97 : namespace
98 : {
99 :
100 302 : const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs)
101 : {
102 302 : if (lhs.isEmpty())
103 244 : return rhs;
104 58 : return lhs + "/" + rhs;
105 : }
106 :
107 668 : 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 std::unordered_map<rtl::OUString, std::size_t, rtl::OUStringHash> NameMap_t;
122 : typedef std::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 29 : struct OLEStorageImpl
141 : {
142 : OLEStorageImpl();
143 :
144 : void initialize(SvStream *pStream);
145 :
146 : tools::SvRef<SotStorageStream> getStream(const rtl::OUString &rPath);
147 : tools::SvRef<SotStorageStream> getStream(std::size_t nId);
148 :
149 : private:
150 : void traverse(const tools::SvRef<SotStorage> &rStorage, const rtl::OUString &rPath);
151 :
152 : tools::SvRef<SotStorageStream> 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 126 : OLEStreamData::OLEStreamData(const rtl::OString &rName)
163 : : stream()
164 126 : , name(rName)
165 : {
166 126 : }
167 :
168 29 : OLEStorageImpl::OLEStorageImpl()
169 : : mxRootStorage()
170 : , maStorageMap()
171 : , maStreams()
172 : , maNameMap()
173 29 : , mbInitialized(false)
174 : {
175 29 : }
176 :
177 29 : void OLEStorageImpl::initialize(SvStream *const pStream)
178 : {
179 29 : if (!pStream)
180 29 : return;
181 :
182 29 : mxRootStorage.ref = new SotStorage(pStream, true);
183 :
184 29 : traverse(mxRootStorage.ref, "");
185 :
186 29 : mbInitialized = true;
187 : }
188 :
189 98 : tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const rtl::OUString &rPath)
190 : {
191 98 : const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
192 98 : 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 98 : if (maNameMap.end() == aIt)
198 8 : return tools::SvRef<SotStorageStream>();
199 :
200 90 : if (!maStreams[aIt->second].stream.ref.Is())
201 63 : maStreams[aIt->second].stream.ref = createStream(aPath);
202 :
203 90 : return maStreams[aIt->second].stream.ref;
204 : }
205 :
206 2 : tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const std::size_t nId)
207 : {
208 2 : if (!maStreams[nId].stream.ref.Is())
209 2 : maStreams[nId].stream.ref = createStream(rtl::OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
210 :
211 2 : return maStreams[nId].stream.ref;
212 : }
213 :
214 79 : void OLEStorageImpl::traverse(const tools::SvRef<SotStorage> &rStorage, const rtl::OUString &rPath)
215 : {
216 79 : SvStorageInfoList infos;
217 :
218 79 : rStorage->FillInfoList(&infos);
219 :
220 255 : for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt)
221 : {
222 176 : if (aIt->IsStream())
223 : {
224 126 : maStreams.push_back(OLEStreamData(rtl::OUStringToOString(concatPath(rPath, aIt->GetName()), RTL_TEXTENCODING_UTF8)));
225 126 : maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1;
226 : }
227 50 : else if (aIt->IsStorage())
228 : {
229 50 : const rtl::OUString aPath = concatPath(rPath, aIt->GetName());
230 100 : SotStorageRefWrapper xStorage;
231 50 : xStorage.ref = rStorage->OpenSotStorage(aIt->GetName(), STREAM_STD_READ);
232 50 : maStorageMap[aPath] = xStorage;
233 :
234 : // deep-first traversal
235 100 : traverse(xStorage.ref, aPath);
236 : }
237 : else
238 : {
239 : SAL_WARN("writerperfect", "OLEStorageImpl::traverse: invalid storage entry, neither stream nor file");
240 : }
241 79 : }
242 79 : }
243 :
244 65 : tools::SvRef<SotStorageStream> OLEStorageImpl::createStream(const rtl::OUString &rPath)
245 : {
246 65 : const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/'));
247 :
248 65 : if (-1 == nDelim)
249 49 : return mxRootStorage.ref->OpenSotStream(rPath, STREAM_STD_READ);
250 :
251 16 : const rtl::OUString aDir = rPath.copy(0, nDelim);
252 32 : const rtl::OUString aName = rPath.copy(nDelim + 1);
253 :
254 16 : const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
255 :
256 16 : if (maStorageMap.end() == aIt)
257 0 : return 0;
258 :
259 32 : return aIt->second.ref->OpenSotStream(aName, STREAM_STD_READ);
260 : }
261 :
262 : }
263 :
264 : namespace
265 : {
266 :
267 5505 : 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 190 : struct ZipStorageImpl
287 : {
288 : explicit 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 1835 : ZipStreamData::ZipStreamData(const rtl::OString &rName)
314 : : xStream()
315 1835 : , aName(rName)
316 : {
317 1835 : }
318 :
319 190 : ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer)
320 : : mxContainer(rxContainer)
321 : , maStreams()
322 : , maNameMap()
323 190 : , mbInitialized(false)
324 : {
325 : assert(mxContainer.is());
326 190 : }
327 :
328 190 : void ZipStorageImpl::initialize()
329 : {
330 190 : traverse(mxContainer);
331 :
332 190 : mbInitialized = true;
333 190 : }
334 :
335 64 : Reference<XInputStream> ZipStorageImpl::getStream(const rtl::OUString &rPath)
336 : {
337 64 : const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
338 64 : 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 64 : if (maNameMap.end() == aIt)
344 25 : return Reference<XInputStream>();
345 :
346 39 : if (!maStreams[aIt->second].xStream.is())
347 38 : maStreams[aIt->second].xStream = createStream(aPath);
348 :
349 39 : return maStreams[aIt->second].xStream;
350 : }
351 :
352 11 : Reference<XInputStream> ZipStorageImpl::getStream(const std::size_t nId)
353 : {
354 11 : if (!maStreams[nId].xStream.is())
355 11 : maStreams[nId].xStream = createStream(rtl::OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
356 :
357 11 : return maStreams[nId].xStream;
358 : }
359 :
360 190 : void ZipStorageImpl::traverse(const Reference<container::XNameAccess> &rxContainer)
361 : {
362 190 : const Sequence<rtl::OUString> lNames = rxContainer->getElementNames();
363 :
364 190 : maStreams.reserve(lNames.getLength());
365 :
366 2949 : for (sal_Int32 n = 0; n < lNames.getLength(); ++n)
367 : {
368 2759 : if (!lNames[n].endsWith("/")) // skip dirs
369 : {
370 1835 : maStreams.push_back(ZipStreamData(rtl::OUStringToOString(lNames[n], RTL_TEXTENCODING_UTF8)));
371 1835 : maNameMap[lNames[n]] = maStreams.size() - 1;
372 : }
373 190 : }
374 190 : }
375 :
376 49 : Reference<XInputStream> ZipStorageImpl::createStream(const rtl::OUString &rPath)
377 : {
378 49 : Reference<XInputStream> xStream;
379 :
380 : try
381 : {
382 49 : const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
383 98 : const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
384 :
385 49 : if (xSeekable.is())
386 0 : xStream = xInputStream;
387 : else
388 98 : xStream.set(new comphelper::OSeekableInputWrapper(xInputStream, comphelper::getProcessComponentContext()));
389 : }
390 0 : catch (const Exception &)
391 : {
392 : // nothing needed
393 : }
394 :
395 49 : return xStream;
396 : }
397 :
398 : }
399 :
400 : class WPXSvInputStreamImpl
401 : {
402 : public :
403 : explicit 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 : static librevenge::RVNGInputStream *createWPXStream(const tools::SvRef<SotStorageStream> &rxStorage);
429 : static 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 6029 : 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 6029 : mnReadBufferPos(0)
458 : {
459 6029 : if (!xStream.is() || !mxStream.is())
460 0 : mnLength = 0;
461 : else
462 : {
463 6029 : if (!mxSeekable.is())
464 0 : mnLength = 0;
465 : else
466 : {
467 : try
468 : {
469 6029 : mnLength = mxSeekable->getLength();
470 6029 : if (0 < mxSeekable->getPosition())
471 129 : 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 6029 : }
481 :
482 6028 : WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
483 : {
484 6028 : }
485 :
486 12009 : const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
487 : {
488 12009 : numBytesRead = 0;
489 :
490 12009 : if (numBytes == 0 || isEnd())
491 9 : return 0;
492 :
493 12000 : numBytesRead = mxStream->readSomeBytes(maData, numBytes);
494 12000 : if (numBytesRead == 0)
495 0 : return 0;
496 :
497 12000 : return reinterpret_cast<const unsigned char *>(maData.getConstArray());
498 : }
499 :
500 1658288 : long WPXSvInputStreamImpl::tell()
501 : {
502 1658288 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
503 0 : return -1L;
504 : else
505 : {
506 1658288 : sal_Int64 tmpPosition = mxSeekable->getPosition();
507 1658288 : if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
508 0 : return -1L;
509 1658288 : return (long)tmpPosition;
510 : }
511 : }
512 :
513 44970 : int WPXSvInputStreamImpl::seek(long offset)
514 : {
515 44970 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
516 0 : return -1;
517 :
518 44970 : sal_Int64 tmpPosition = mxSeekable->getPosition();
519 44970 : if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
520 0 : return -1;
521 :
522 : try
523 : {
524 44970 : mxSeekable->seek(offset);
525 44970 : return 0;
526 : }
527 0 : catch (...)
528 : {
529 : SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
530 0 : return -1;
531 : }
532 : }
533 :
534 29886998 : bool WPXSvInputStreamImpl::isEnd()
535 : {
536 29886998 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
537 0 : return true;
538 29886998 : return (mxSeekable->getPosition() >= mnLength);
539 : }
540 :
541 5798 : bool WPXSvInputStreamImpl::isStructured()
542 : {
543 5798 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
544 0 : return false;
545 :
546 5798 : PositionHolder pos(mxSeekable);
547 5798 : mxSeekable->seek(0);
548 :
549 5798 : if (isOLE())
550 103 : return true;
551 :
552 5695 : mxSeekable->seek(0);
553 :
554 5695 : return isZip();
555 : }
556 :
557 383 : unsigned WPXSvInputStreamImpl::subStreamCount()
558 : {
559 383 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
560 0 : return 0;
561 :
562 383 : PositionHolder pos(mxSeekable);
563 383 : mxSeekable->seek(0);
564 :
565 383 : if (isOLE())
566 : {
567 18 : ensureOLEIsInitialized();
568 :
569 18 : return mpOLEStorage->maStreams.size();
570 : }
571 :
572 365 : mxSeekable->seek(0);
573 :
574 365 : if (isZip())
575 : {
576 364 : ensureZipIsInitialized();
577 :
578 364 : return mpZipStorage->maStreams.size();
579 : }
580 :
581 1 : return 0;
582 : }
583 :
584 1456 : const char *WPXSvInputStreamImpl::subStreamName(const unsigned id)
585 : {
586 1456 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
587 0 : return 0;
588 :
589 1456 : PositionHolder pos(mxSeekable);
590 1456 : mxSeekable->seek(0);
591 :
592 1456 : if (isOLE())
593 : {
594 32 : ensureOLEIsInitialized();
595 :
596 32 : if (mpOLEStorage->maStreams.size() <= id)
597 0 : return 0;
598 :
599 32 : return mpOLEStorage->maStreams[id].name.getStr();
600 : }
601 :
602 1424 : mxSeekable->seek(0);
603 :
604 1424 : if (isZip())
605 : {
606 1423 : ensureZipIsInitialized();
607 :
608 1423 : if (mpZipStorage->maStreams.size() <= id)
609 0 : return 0;
610 :
611 1423 : return mpZipStorage->maStreams[id].aName.getStr();
612 : }
613 :
614 1 : return 0;
615 : }
616 :
617 171 : bool WPXSvInputStreamImpl::existsSubStream(const char *const name)
618 : {
619 171 : if (!name)
620 0 : return false;
621 :
622 171 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
623 0 : return false;
624 :
625 171 : PositionHolder pos(mxSeekable);
626 171 : mxSeekable->seek(0);
627 :
628 342 : const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
629 :
630 171 : if (isOLE())
631 : {
632 2 : ensureOLEIsInitialized();
633 2 : return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
634 : }
635 :
636 169 : mxSeekable->seek(0);
637 :
638 169 : if (isZip())
639 : {
640 168 : ensureZipIsInitialized();
641 168 : return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
642 : }
643 :
644 172 : return false;
645 : }
646 :
647 163 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name)
648 : {
649 163 : if (!name)
650 0 : return 0;
651 :
652 163 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
653 0 : return 0;
654 :
655 163 : PositionHolder pos(mxSeekable);
656 163 : mxSeekable->seek(0);
657 :
658 326 : const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
659 :
660 163 : if (isOLE())
661 : {
662 98 : ensureOLEIsInitialized();
663 98 : return createWPXStream(mpOLEStorage->getStream(aName));
664 : }
665 :
666 65 : mxSeekable->seek(0);
667 :
668 65 : if (isZip())
669 : {
670 64 : ensureZipIsInitialized();
671 :
672 : try
673 : {
674 64 : return createWPXStream(mpZipStorage->getStream(aName));
675 : }
676 0 : catch (const Exception &)
677 : {
678 : // nothing needed
679 : }
680 : }
681 :
682 164 : return 0;
683 : }
684 :
685 16 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
686 : {
687 16 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
688 0 : return 0;
689 :
690 16 : PositionHolder pos(mxSeekable);
691 16 : mxSeekable->seek(0);
692 :
693 16 : if (isOLE())
694 : {
695 3 : ensureOLEIsInitialized();
696 :
697 3 : if (mpOLEStorage->maStreams.size() <= id)
698 1 : return 0;
699 :
700 2 : return createWPXStream(mpOLEStorage->getStream(id));
701 : }
702 :
703 13 : mxSeekable->seek(0);
704 :
705 13 : if (isZip())
706 : {
707 12 : ensureZipIsInitialized();
708 :
709 12 : if (mpZipStorage->maStreams.size() <= id)
710 1 : return 0;
711 :
712 : try
713 : {
714 11 : return createWPXStream(mpZipStorage->getStream(id));
715 : }
716 0 : catch (const Exception &)
717 : {
718 : // nothing needed
719 : }
720 : }
721 1 : return 0;
722 : }
723 :
724 47458 : void WPXSvInputStreamImpl::invalidateReadBuffer()
725 : {
726 47458 : if (mpReadBuffer)
727 : {
728 6433 : seek((long) tell() + (long)mnReadBufferPos - (long)mnReadBufferLength);
729 6433 : mpReadBuffer = 0;
730 6433 : mnReadBufferPos = 0;
731 6433 : mnReadBufferLength = 0;
732 : }
733 47458 : }
734 :
735 100 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const tools::SvRef<SotStorageStream> &rxStorage)
736 : {
737 100 : if (rxStorage.Is())
738 : {
739 92 : Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper(rxStorage));
740 92 : return new WPXSvInputStream(xContents);
741 : }
742 8 : return 0;
743 : }
744 :
745 75 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream> &rxStream)
746 : {
747 75 : if (rxStream.is())
748 50 : return new WPXSvInputStream(rxStream);
749 : else
750 25 : return 0;
751 : }
752 :
753 7987 : bool WPXSvInputStreamImpl::isOLE()
754 : {
755 7987 : if (!mbCheckedOLE)
756 : {
757 : assert(0 == mxSeekable->getPosition());
758 :
759 5614 : boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream));
760 5614 : if (pStream && SotStorage::IsOLEStorage(pStream.get()))
761 29 : mpOLEStorage.reset(new OLEStorageImpl());
762 :
763 5614 : mbCheckedOLE = true;
764 : }
765 :
766 7987 : return bool(mpOLEStorage);
767 : }
768 :
769 7731 : bool WPXSvInputStreamImpl::isZip()
770 : {
771 7731 : if (!mbCheckedZip)
772 : {
773 : assert(0 == mxSeekable->getPosition());
774 :
775 : try
776 : {
777 5585 : Sequence<Any> aArgs(1);
778 5585 : aArgs[0] <<= mxStream;
779 :
780 11170 : const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW);
781 : const Reference<packages::zip::XZipFileAccess2> xZip(
782 11170 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
783 5775 : UNO_QUERY_THROW);
784 5775 : mpZipStorage.reset(new ZipStorageImpl(xZip));
785 : }
786 5395 : catch (const Exception &)
787 : {
788 : // ignore
789 : }
790 :
791 5585 : mbCheckedZip = true;
792 : }
793 :
794 7731 : return bool(mpZipStorage);
795 : }
796 :
797 153 : void WPXSvInputStreamImpl::ensureOLEIsInitialized()
798 : {
799 : assert(mpOLEStorage);
800 :
801 153 : if (!mpOLEStorage->mbInitialized)
802 29 : mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
803 153 : }
804 :
805 2031 : void WPXSvInputStreamImpl::ensureZipIsInitialized()
806 : {
807 : assert(mpZipStorage);
808 :
809 2031 : if (!mpZipStorage->mbInitialized)
810 190 : mpZipStorage->initialize();
811 2031 : }
812 :
813 6029 : WPXSvInputStream::WPXSvInputStream(Reference< XInputStream > xStream) :
814 6029 : mpImpl(new WPXSvInputStreamImpl(xStream))
815 : {
816 6029 : }
817 :
818 12298 : WPXSvInputStream::~WPXSvInputStream()
819 : {
820 6028 : if (mpImpl)
821 6028 : delete mpImpl;
822 6270 : }
823 :
824 : #define BUFFER_MAX 65536
825 :
826 28852068 : const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
827 : {
828 28852068 : numBytesRead = 0;
829 :
830 28852068 : if (numBytes == 0 || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
831 35 : return 0;
832 :
833 28852033 : if (mpImpl->mpReadBuffer)
834 : {
835 28840958 : if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
836 : {
837 28840024 : const unsigned char *pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
838 28840024 : mpImpl->mnReadBufferPos += numBytes;
839 28840024 : numBytesRead = numBytes;
840 28840024 : return pTmp;
841 : }
842 :
843 934 : mpImpl->invalidateReadBuffer();
844 : }
845 :
846 12009 : unsigned long curpos = (unsigned long) mpImpl->tell();
847 12009 : if (curpos == (unsigned long)-1) // returned ERROR
848 0 : return 0;
849 :
850 24018 : if ((curpos + numBytes < curpos) /*overflow*/ ||
851 12009 : (curpos + numBytes >= (sal_uInt64)mpImpl->mnLength)) /*reading more than available*/
852 : {
853 608 : numBytes = mpImpl->mnLength - curpos;
854 : }
855 :
856 12009 : if (numBytes < BUFFER_MAX)
857 : {
858 11987 : if (BUFFER_MAX < mpImpl->mnLength - curpos)
859 955 : mpImpl->mnReadBufferLength = BUFFER_MAX;
860 : else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
861 11032 : mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
862 : }
863 : else
864 22 : mpImpl->mnReadBufferLength = numBytes;
865 :
866 12009 : unsigned long tmpNumBytes(0);
867 12009 : mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes);
868 12009 : if (tmpNumBytes != mpImpl->mnReadBufferLength)
869 0 : mpImpl->mnReadBufferLength = tmpNumBytes;
870 :
871 12009 : mpImpl->mnReadBufferPos = 0;
872 12009 : if (!mpImpl->mnReadBufferLength)
873 9 : return 0;
874 :
875 12000 : numBytesRead = numBytes;
876 :
877 12000 : mpImpl->mnReadBufferPos += numBytesRead;
878 12000 : return mpImpl->mpReadBuffer;
879 : }
880 :
881 1352628 : long WPXSvInputStream::tell()
882 : {
883 1352628 : long retVal = mpImpl->tell();
884 1352628 : return retVal - (long)mpImpl->mnReadBufferLength + (long)mpImpl->mnReadBufferPos;
885 : }
886 :
887 117163 : int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
888 : {
889 117163 : sal_Int64 tmpOffset = offset;
890 117163 : if (seekType == librevenge::RVNG_SEEK_CUR)
891 798 : tmpOffset += tell();
892 117163 : if (seekType == librevenge::RVNG_SEEK_END)
893 7593 : tmpOffset += mpImpl->mnLength;
894 :
895 117163 : int retVal = 0;
896 117163 : if (tmpOffset < 0)
897 : {
898 3 : tmpOffset = 0;
899 3 : retVal = -1;
900 : }
901 117163 : if (tmpOffset > mpImpl->mnLength)
902 : {
903 16 : tmpOffset = mpImpl->mnLength;
904 16 : retVal = -1;
905 : }
906 :
907 117163 : if (tmpOffset < mpImpl->tell() && (unsigned long)tmpOffset >= (unsigned long)mpImpl->tell() - mpImpl->mnReadBufferLength)
908 : {
909 78626 : mpImpl->mnReadBufferPos = (unsigned long)(tmpOffset + (long) mpImpl->mnReadBufferLength - (long) mpImpl->tell());
910 78626 : return retVal;
911 : }
912 :
913 38537 : mpImpl->invalidateReadBuffer();
914 :
915 38537 : if (mpImpl->seek(tmpOffset))
916 0 : return -1;
917 38537 : return retVal;
918 : }
919 :
920 29874998 : bool WPXSvInputStream::isEnd()
921 : {
922 29874998 : return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
923 : }
924 :
925 5798 : bool WPXSvInputStream::isStructured()
926 : {
927 5798 : mpImpl->invalidateReadBuffer();
928 5798 : return mpImpl->isStructured();
929 : }
930 :
931 383 : unsigned WPXSvInputStream::subStreamCount()
932 : {
933 383 : mpImpl->invalidateReadBuffer();
934 383 : return mpImpl->subStreamCount();
935 : }
936 :
937 1456 : const char *WPXSvInputStream::subStreamName(const unsigned id)
938 : {
939 1456 : mpImpl->invalidateReadBuffer();
940 1456 : return mpImpl->subStreamName(id);
941 : }
942 :
943 171 : bool WPXSvInputStream::existsSubStream(const char *const name)
944 : {
945 171 : mpImpl->invalidateReadBuffer();
946 171 : return mpImpl->existsSubStream(name);
947 : }
948 :
949 163 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamByName(const char *name)
950 : {
951 163 : mpImpl->invalidateReadBuffer();
952 163 : return mpImpl->getSubStreamByName(name);
953 : }
954 :
955 16 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamById(const unsigned id)
956 : {
957 16 : mpImpl->invalidateReadBuffer();
958 16 : return mpImpl->getSubStreamById(id);
959 : }
960 :
961 : }
962 :
963 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|