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 74 : PositionHolder::PositionHolder(const Reference<XSeekable> &rxSeekable)
52 : : mxSeekable(rxSeekable)
53 74 : , mnPosition(rxSeekable->getPosition())
54 : {
55 74 : }
56 :
57 148 : PositionHolder::~PositionHolder() try
58 : {
59 74 : mxSeekable->seek(mnPosition);
60 : }
61 0 : catch (...)
62 : {
63 74 : }
64 :
65 : } // anonymous namespace
66 :
67 : typedef struct
68 1 : {
69 : SotStorageRef ref;
70 1 : } SotStorageRefWrapper;
71 :
72 : typedef struct
73 2 : {
74 : SotStorageStreamRef ref;
75 8 : } SotStorageStreamRefWrapper;
76 :
77 : namespace
78 : {
79 :
80 2 : const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs)
81 : {
82 2 : if (lhs.isEmpty())
83 2 : return rhs;
84 0 : return lhs + "/" + rhs;
85 : }
86 :
87 8 : 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 1 : 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 2 : OLEStreamData::OLEStreamData(const rtl::OString &rName)
143 : : stream()
144 2 : , name(rName)
145 : {
146 2 : }
147 :
148 1 : OLEStorageImpl::OLEStorageImpl()
149 : : mxRootStorage()
150 : , maStorageMap()
151 : , maStreams()
152 : , maNameMap()
153 1 : , mbInitialized(false)
154 : {
155 1 : }
156 :
157 1 : void OLEStorageImpl::initialize(SvStream *const pStream)
158 : {
159 1 : if (!pStream)
160 1 : return;
161 :
162 1 : mxRootStorage.ref = new SotStorage( pStream, true );
163 :
164 1 : traverse(mxRootStorage.ref, "");
165 :
166 1 : mbInitialized = true;
167 : }
168 :
169 2 : SotStorageStreamRef OLEStorageImpl::getStream(const rtl::OUString &rPath)
170 : {
171 2 : 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 2 : if (maNameMap.end() == aIt)
177 1 : return SotStorageStreamRef();
178 :
179 1 : if (!maStreams[aIt->second].stream.ref.Is())
180 1 : maStreams[aIt->second].stream.ref = createStream(rPath);
181 :
182 1 : 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 1 : void OLEStorageImpl::traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath)
194 : {
195 1 : SvStorageInfoList infos;
196 :
197 1 : rStorage->FillInfoList(&infos);
198 :
199 3 : for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt)
200 : {
201 2 : if (aIt->IsStream())
202 : {
203 2 : maStreams.push_back(OLEStreamData(rtl::OUStringToOString(aIt->GetName(), RTL_TEXTENCODING_UTF8)));
204 2 : 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 1 : }
221 1 : }
222 :
223 1 : SotStorageStreamRef OLEStorageImpl::createStream(const rtl::OUString &rPath)
224 : {
225 1 : const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/'));
226 :
227 1 : if (-1 == nDelim)
228 1 : 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 336 : 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 10 : 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 112 : ZipStreamData::ZipStreamData(const rtl::OString &rName)
294 : : xStream()
295 112 : , aName(rName)
296 : {
297 112 : }
298 :
299 10 : ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer)
300 : : mxContainer(rxContainer)
301 : , maStreams()
302 : , maNameMap()
303 10 : , mbInitialized(false)
304 : {
305 : assert(mxContainer.is());
306 10 : }
307 :
308 10 : void ZipStorageImpl::initialize()
309 : {
310 10 : traverse(mxContainer);
311 :
312 10 : mbInitialized = true;
313 10 : }
314 :
315 42 : Reference<XInputStream> ZipStorageImpl::getStream(const rtl::OUString &rPath)
316 : {
317 42 : 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 42 : if (maNameMap.end() == aIt)
323 23 : return Reference<XInputStream>();
324 :
325 19 : if (!maStreams[aIt->second].xStream.is())
326 10 : maStreams[aIt->second].xStream = createStream(rPath);
327 :
328 19 : 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 10 : void ZipStorageImpl::traverse(const Reference<container::XNameAccess> &rxContainer)
340 : {
341 10 : const Sequence<rtl::OUString> lNames = rxContainer->getElementNames();
342 :
343 10 : maStreams.reserve(lNames.getLength());
344 :
345 149 : for (sal_Int32 n = 0; n < lNames.getLength(); ++n)
346 : {
347 139 : if (!lNames[n].endsWithAsciiL("/", 1)) // skip dirs
348 : {
349 112 : maStreams.push_back(ZipStreamData(rtl::OUStringToOString(lNames[n], RTL_TEXTENCODING_UTF8)));
350 112 : maNameMap[lNames[n]] = maStreams.size() - 1;
351 : }
352 10 : }
353 10 : }
354 :
355 10 : Reference<XInputStream> ZipStorageImpl::createStream(const rtl::OUString &rPath)
356 : {
357 10 : Reference<XInputStream> xStream;
358 :
359 : try
360 : {
361 10 : const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
362 20 : const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
363 :
364 10 : if (xSeekable.is())
365 0 : xStream = xInputStream;
366 : else
367 20 : xStream.set(new comphelper::OSeekableInputWrapper(xInputStream, comphelper::getProcessComponentContext()));
368 : }
369 0 : catch (const Exception &)
370 : {
371 : // nothing needed
372 : }
373 :
374 10 : 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 248 : 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 248 : mnReadBufferPos(0)
437 : {
438 248 : if (!xStream.is() || !mxStream.is())
439 0 : mnLength = 0;
440 : else
441 : {
442 248 : if (!mxSeekable.is())
443 0 : mnLength = 0;
444 : else
445 : {
446 : try
447 : {
448 248 : mnLength = mxSeekable->getLength();
449 : }
450 2 : catch ( ... )
451 : {
452 : SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
453 1 : mnLength = 0;
454 : }
455 : }
456 : }
457 248 : }
458 :
459 248 : WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
460 : {
461 248 : }
462 :
463 556 : const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
464 : {
465 556 : numBytesRead = 0;
466 :
467 556 : if (numBytes == 0 || isEnd())
468 4 : return 0;
469 :
470 552 : numBytesRead = mxStream->readSomeBytes (maData, numBytes);
471 552 : if (numBytesRead == 0)
472 0 : return 0;
473 :
474 552 : return (const unsigned char *)maData.getConstArray();
475 : }
476 :
477 2479261 : long WPXSvInputStreamImpl::tell()
478 : {
479 2479261 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
480 0 : return -1L;
481 : else
482 : {
483 2479261 : sal_Int64 tmpPosition = mxSeekable->getPosition();
484 2479261 : if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
485 0 : return -1L;
486 2479261 : return (long)tmpPosition;
487 : }
488 : }
489 :
490 1789 : int WPXSvInputStreamImpl::seek(long offset)
491 : {
492 1789 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
493 0 : return -1;
494 :
495 1789 : sal_Int64 tmpPosition = mxSeekable->getPosition();
496 1789 : if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
497 0 : return -1;
498 :
499 : try
500 : {
501 1789 : mxSeekable->seek(offset);
502 1789 : return 0;
503 : }
504 0 : catch (...)
505 : {
506 : SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
507 0 : return -1;
508 : }
509 : }
510 :
511 2147819 : bool WPXSvInputStreamImpl::isEnd()
512 : {
513 2147819 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
514 0 : return true;
515 2147819 : return (mxSeekable->getPosition() >= mnLength);
516 : }
517 :
518 29 : bool WPXSvInputStreamImpl::isStructured()
519 : {
520 29 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
521 0 : return false;
522 :
523 29 : PositionHolder pos(mxSeekable);
524 29 : mxSeekable->seek(0);
525 :
526 29 : if (isOLE())
527 1 : return true;
528 :
529 28 : mxSeekable->seek(0);
530 :
531 28 : 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 45 : WPXInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name)
625 : {
626 45 : if (!name)
627 0 : return 0;
628 :
629 45 : if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
630 0 : return 0;
631 :
632 45 : PositionHolder pos(mxSeekable);
633 45 : mxSeekable->seek(0);
634 :
635 90 : const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
636 :
637 45 : if (isOLE())
638 : {
639 2 : ensureOLEIsInitialized();
640 2 : return createWPXStream(mpOLEStorage->getStream(aName));
641 : }
642 :
643 43 : mxSeekable->seek(0);
644 :
645 43 : if (isZip())
646 : {
647 42 : ensureZipIsInitialized();
648 :
649 : try
650 : {
651 42 : return createWPXStream(mpZipStorage->getStream(aName));
652 : }
653 0 : catch (const Exception &)
654 : {
655 : // nothing needed
656 : }
657 : }
658 :
659 46 : 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 1597 : void WPXSvInputStreamImpl::invalidateReadBuffer()
702 : {
703 1597 : if (mpReadBuffer)
704 : {
705 343 : seek((long) tell() + (long)mnReadBufferPos - (long)mnReadBufferLength);
706 343 : mpReadBuffer = 0;
707 343 : mnReadBufferPos = 0;
708 343 : mnReadBufferLength = 0;
709 : }
710 1597 : }
711 :
712 2 : WPXInputStream *WPXSvInputStreamImpl::createWPXStream(const SotStorageStreamRef &rxStorage)
713 : {
714 2 : if (rxStorage.Is())
715 : {
716 1 : Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( rxStorage ));
717 1 : return new WPXSvInputStream( xContents );
718 : }
719 1 : return 0;
720 : }
721 :
722 42 : WPXInputStream *WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream> &rxStream)
723 : {
724 42 : if (rxStream.is())
725 19 : return new WPXSvInputStream( rxStream );
726 : else
727 23 : return 0;
728 : }
729 :
730 74 : bool WPXSvInputStreamImpl::isOLE()
731 : {
732 74 : if (!mbCheckedOLE)
733 : {
734 : assert(0 == mxSeekable->getPosition());
735 :
736 24 : boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( mxStream ));
737 24 : if (pStream && SotStorage::IsOLEStorage(pStream.get()))
738 1 : mpOLEStorage.reset(new OLEStorageImpl());
739 :
740 24 : mbCheckedOLE = true;
741 : }
742 :
743 74 : return bool(mpOLEStorage);
744 : }
745 :
746 71 : bool WPXSvInputStreamImpl::isZip()
747 : {
748 71 : if (!mbCheckedZip)
749 : {
750 : assert(0 == mxSeekable->getPosition());
751 :
752 : try
753 : {
754 23 : Sequence<Any> aArgs(1);
755 23 : aArgs[0] <<= mxStream;
756 :
757 46 : const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW);
758 : const Reference<packages::zip::XZipFileAccess2> xZip(
759 46 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
760 33 : UNO_QUERY_THROW);
761 33 : mpZipStorage.reset(new ZipStorageImpl(xZip));
762 : }
763 13 : catch (const Exception &)
764 : {
765 : // ignore
766 : }
767 :
768 23 : mbCheckedZip = true;
769 : }
770 :
771 71 : return bool(mpZipStorage);
772 : }
773 :
774 2 : void WPXSvInputStreamImpl::ensureOLEIsInitialized()
775 : {
776 : assert(mpOLEStorage);
777 :
778 2 : if (!mpOLEStorage->mbInitialized)
779 1 : mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream( mxStream ));
780 2 : }
781 :
782 42 : void WPXSvInputStreamImpl::ensureZipIsInitialized()
783 : {
784 : assert(mpZipStorage);
785 :
786 42 : if (!mpZipStorage->mbInitialized)
787 10 : mpZipStorage->initialize();
788 42 : }
789 :
790 248 : WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) :
791 248 : mpImpl(new WPXSvInputStreamImpl(xStream))
792 : {
793 248 : }
794 :
795 537 : WPXSvInputStream::~WPXSvInputStream()
796 : {
797 248 : if (mpImpl)
798 248 : delete mpImpl;
799 289 : }
800 :
801 : #define BUFFER_MAX 65536
802 :
803 946175 : const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
804 : {
805 946175 : numBytesRead = 0;
806 :
807 946175 : if (numBytes == 0 || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
808 1 : return 0;
809 :
810 946174 : if (mpImpl->mpReadBuffer)
811 : {
812 945695 : if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
813 : {
814 945618 : const unsigned char *pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
815 945618 : mpImpl->mnReadBufferPos += numBytes;
816 945618 : numBytesRead = numBytes;
817 945618 : return pTmp;
818 : }
819 :
820 77 : mpImpl->invalidateReadBuffer();
821 : }
822 :
823 556 : unsigned long curpos = (unsigned long) mpImpl->tell();
824 556 : if (curpos == (unsigned long)-1) // returned ERROR
825 0 : return 0;
826 :
827 1112 : if ((curpos + numBytes < curpos) /*overflow*/ ||
828 556 : (curpos + numBytes >= (sal_uInt64)mpImpl->mnLength)) /*reading more than available*/
829 : {
830 65 : numBytes = mpImpl->mnLength - curpos;
831 : }
832 :
833 556 : if (numBytes < BUFFER_MAX)
834 : {
835 553 : if (BUFFER_MAX < mpImpl->mnLength - curpos)
836 26 : mpImpl->mnReadBufferLength = BUFFER_MAX;
837 : else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
838 527 : mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
839 : }
840 : else
841 3 : mpImpl->mnReadBufferLength = numBytes;
842 :
843 556 : unsigned long tmpNumBytes(0);
844 556 : mpImpl->mpReadBuffer = const_cast<unsigned char*>(mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes));
845 556 : if (tmpNumBytes != mpImpl->mnReadBufferLength)
846 0 : mpImpl->mnReadBufferLength = tmpNumBytes;
847 :
848 556 : mpImpl->mnReadBufferPos = 0;
849 556 : if (!mpImpl->mnReadBufferLength)
850 4 : return 0;
851 :
852 552 : numBytesRead = numBytes;
853 :
854 552 : mpImpl->mnReadBufferPos += numBytesRead;
855 552 : return const_cast<const unsigned char *>(mpImpl->mpReadBuffer);
856 : }
857 :
858 1008846 : long WPXSvInputStream::tell()
859 : {
860 1008846 : long retVal = mpImpl->tell();
861 1008846 : return retVal - (long)mpImpl->mnReadBufferLength + (long)mpImpl->mnReadBufferPos;
862 : }
863 :
864 490617 : int WPXSvInputStream::seek(long offset, WPX_SEEK_TYPE seekType)
865 : {
866 490617 : sal_Int64 tmpOffset = offset;
867 490617 : if (seekType == WPX_SEEK_CUR)
868 467698 : tmpOffset += tell();
869 490617 : if (seekType == WPX_SEEK_END)
870 360 : tmpOffset += mpImpl->mnLength;
871 :
872 490617 : int retVal = 0;
873 490617 : if (tmpOffset < 0)
874 : {
875 15 : tmpOffset = 0;
876 15 : retVal = -1;
877 : }
878 490617 : if (tmpOffset > mpImpl->mnLength)
879 : {
880 3 : tmpOffset = mpImpl->mnLength;
881 3 : retVal = -1;
882 : }
883 :
884 490617 : if (tmpOffset < mpImpl->tell() && (unsigned long)tmpOffset >= (unsigned long)mpImpl->tell() - mpImpl->mnReadBufferLength)
885 : {
886 489171 : mpImpl->mnReadBufferPos = (unsigned long)(tmpOffset + (long) mpImpl->mnReadBufferLength - (long) mpImpl->tell());
887 489171 : return retVal;
888 : }
889 :
890 1446 : mpImpl->invalidateReadBuffer();
891 :
892 1446 : if (mpImpl->seek(tmpOffset))
893 0 : return -1;
894 1446 : return retVal;
895 : }
896 :
897 2147267 : bool WPXSvInputStream::isEnd()
898 : {
899 2147267 : return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
900 : }
901 :
902 29 : bool WPXSvInputStream::isStructured()
903 : {
904 29 : mpImpl->invalidateReadBuffer();
905 29 : 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 45 : WPXInputStream *WPXSvInputStream::getSubStreamByName(const char *name)
927 : {
928 45 : mpImpl->invalidateReadBuffer();
929 45 : 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 2147267 : bool WPXSvInputStream::atEOS()
939 : {
940 2147267 : return isEnd();
941 : }
942 :
943 29 : bool WPXSvInputStream::isOLEStream()
944 : {
945 29 : return isStructured();
946 : }
947 :
948 45 : WPXInputStream *WPXSvInputStream::getDocumentOLEStream(const char *name)
949 : {
950 45 : return getSubStreamByName(name);
951 : }
952 :
953 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|