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