xref: /trunk/main/svl/source/misc/strmadpt.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 
31 #include <functional> // needed under Solaris when including <algorithm>...
32 
33 #include <algorithm>
34 #include <limits>
35 #include <set>
36 #include <rtl/alloc.h>
37 #include <rtl/memory.h>
38 #include <svl/instrm.hxx>
39 #include <svl/outstrm.hxx>
40 #include <svl/strmadpt.hxx>
41 
42 using namespace com::sun::star;
43 
44 //============================================================================
45 class SvDataPipe_Impl
46 {
47 public:
48     enum SeekResult { SEEK_BEFORE_MARKED, SEEK_OK, SEEK_PAST_END };
49 
50 private:
51     struct Page
52     {
53         Page * m_pPrev;
54         Page * m_pNext;
55         sal_Int8 * m_pStart;
56         sal_Int8 * m_pRead;
57         sal_Int8 * m_pEnd;
58         sal_uInt32 m_nOffset;
59         sal_Int8 m_aBuffer[1];
60     };
61 
62     std::multiset< sal_uInt32 > m_aMarks;
63     Page * m_pFirstPage;
64     Page * m_pReadPage;
65     Page * m_pWritePage;
66     sal_Int8 * m_pReadBuffer;
67     sal_uInt32 m_nReadBufferSize;
68     sal_uInt32 m_nReadBufferFilled;
69     sal_uInt32 m_nPageSize;
70     sal_uInt32 m_nMinPages;
71     sal_uInt32 m_nMaxPages;
72     sal_uInt32 m_nPages;
73     bool m_bEOF;
74 
75     bool remove(Page * pPage);
76 
77 public:
78     inline SvDataPipe_Impl(sal_uInt32 nThePageSize = 1000,
79                            sal_uInt32 nTheMinPages = 100,
80                            sal_uInt32 nTheMaxPages
81                                = std::numeric_limits< sal_uInt32 >::max());
82 
83     ~SvDataPipe_Impl();
84 
85     inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize);
86 
87     sal_uInt32 read();
88 
89     void clearReadBuffer() { m_pReadBuffer = 0; }
90 
91     sal_uInt32 write(sal_Int8 const * pBuffer, sal_uInt32 nSize);
92 
93     void setEOF() { m_bEOF = true; }
94 
95     inline bool isEOF() const;
96 
97     bool addMark(sal_uInt32 nPosition);
98 
99     bool removeMark(sal_uInt32 nPosition);
100 
101     inline sal_uInt32 getReadPosition() const;
102 
103     SeekResult setReadPosition(sal_uInt32 nPosition);
104 };
105 
106 SvDataPipe_Impl::SvDataPipe_Impl(sal_uInt32 nThePageSize,
107                                  sal_uInt32 nTheMinPages,
108                                  sal_uInt32 nTheMaxPages):
109     m_pFirstPage(0),
110     m_pReadPage(0),
111     m_pWritePage(0),
112     m_pReadBuffer(0),
113     m_nPageSize(std::min< sal_uInt32 >(
114                     std::max< sal_uInt32 >(nThePageSize, sal_uInt32(1)),
115                     sal_uInt32(std::numeric_limits< sal_uInt32 >::max()
116                                    - sizeof (Page) + 1))),
117     m_nMinPages(std::max< sal_uInt32 >(nTheMinPages, sal_uInt32(1))),
118     m_nMaxPages(std::max< sal_uInt32 >(nTheMaxPages, sal_uInt32(1))),
119     m_nPages(0),
120     m_bEOF(false)
121 {}
122 
123 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8 * pBuffer,
124                                            sal_uInt32 nSize)
125 {
126     m_pReadBuffer = pBuffer;
127     m_nReadBufferSize = nSize;
128     m_nReadBufferFilled = 0;
129 }
130 
131 inline bool SvDataPipe_Impl::isEOF() const
132 {
133     return m_bEOF && m_pReadPage == m_pWritePage
134            && (!m_pReadPage || m_pReadPage->m_pRead == m_pReadPage->m_pEnd);
135 }
136 
137 inline sal_uInt32 SvDataPipe_Impl::getReadPosition() const
138 {
139     return m_pReadPage == 0 ? 0 :
140                               m_pReadPage->m_nOffset
141                                   + (m_pReadPage->m_pRead
142                                          - m_pReadPage->m_aBuffer);
143 }
144 
145 //============================================================================
146 //
147 //  SvOutputStreamOpenLockBytes
148 //
149 //============================================================================
150 
151 TYPEINIT1(SvOutputStreamOpenLockBytes, SvOpenLockBytes)
152 
153 //============================================================================
154 // virtual
155 ErrCode SvOutputStreamOpenLockBytes::ReadAt(sal_uLong, void *, sal_uLong, sal_uLong *)
156     const
157 {
158     return ERRCODE_IO_CANTREAD;
159 }
160 
161 //============================================================================
162 // virtual
163 ErrCode SvOutputStreamOpenLockBytes::WriteAt(sal_uLong nPos, void const * pBuffer,
164                                              sal_uLong nCount, sal_uLong * pWritten)
165 {
166     if (nPos != m_nPosition)
167         return ERRCODE_IO_CANTWRITE;
168     return FillAppend(pBuffer, nCount, pWritten);
169 }
170 
171 //============================================================================
172 // virtual
173 ErrCode SvOutputStreamOpenLockBytes::Flush() const
174 {
175     if (!m_xOutputStream.is())
176         return ERRCODE_IO_CANTWRITE;
177     try
178     {
179         m_xOutputStream->flush();
180     }
181     catch (io::IOException)
182     {
183         return ERRCODE_IO_CANTWRITE;
184     }
185     return ERRCODE_NONE;
186 }
187 
188 //============================================================================
189 // virtual
190 ErrCode SvOutputStreamOpenLockBytes::SetSize(sal_uLong)
191 {
192     return ERRCODE_IO_NOTSUPPORTED;
193 }
194 
195 //============================================================================
196 // virtual
197 ErrCode SvOutputStreamOpenLockBytes::Stat(SvLockBytesStat * pStat,
198                                           SvLockBytesStatFlag) const
199 {
200     if (pStat)
201         pStat->nSize = m_nPosition;
202     return ERRCODE_NONE;
203 }
204 
205 //============================================================================
206 // virtual
207 ErrCode SvOutputStreamOpenLockBytes::FillAppend(void const * pBuffer,
208                                                 sal_uLong nCount,
209                                                 sal_uLong * pWritten)
210 {
211     if (!m_xOutputStream.is())
212         return ERRCODE_IO_CANTWRITE;
213     if (nCount > 0
214         && nCount > std::numeric_limits< sal_uLong >::max() - m_nPosition)
215     {
216         nCount = std::numeric_limits< sal_uLong >::max() - m_nPosition;
217         if (nCount == 0)
218             return ERRCODE_IO_CANTWRITE;
219     }
220     try
221     {
222         m_xOutputStream->
223             writeBytes(uno::Sequence< sal_Int8 >(
224                            static_cast< sal_Int8 const * >(pBuffer), nCount));
225     }
226     catch (io::IOException)
227     {
228         return ERRCODE_IO_CANTWRITE;
229     }
230     m_nPosition += nCount;
231     if (pWritten)
232         *pWritten = nCount;
233     return ERRCODE_NONE;
234 }
235 
236 //============================================================================
237 // virtual
238 sal_uLong SvOutputStreamOpenLockBytes::Tell() const
239 {
240     return m_nPosition;
241 }
242 
243 //============================================================================
244 // virtual
245 sal_uLong SvOutputStreamOpenLockBytes::Seek(sal_uLong)
246 {
247     return m_nPosition;
248 }
249 
250 //============================================================================
251 // virtual
252 void SvOutputStreamOpenLockBytes::Terminate()
253 {
254     if (m_xOutputStream.is())
255         try
256         {
257             m_xOutputStream->closeOutput();
258         }
259         catch (io::IOException) {}
260 }
261 
262 //============================================================================
263 //
264 //  SvLockBytesInputStream
265 //
266 //============================================================================
267 
268 // virtual
269 uno::Any SAL_CALL SvLockBytesInputStream::queryInterface(uno::Type const &
270                                                              rType)
271     throw (uno::RuntimeException)
272 {
273     uno::Any
274         aReturn(cppu::queryInterface(rType,
275                                      static_cast< io::XInputStream * >(this),
276                                      static_cast< io::XSeekable * >(this)));
277     return aReturn.hasValue() ? aReturn : OWeakObject::queryInterface(rType);
278 }
279 
280 //============================================================================
281 // virtual
282 void SAL_CALL SvLockBytesInputStream::acquire() throw ()
283 {
284     OWeakObject::acquire();
285 }
286 
287 //============================================================================
288 // virtual
289 void SAL_CALL SvLockBytesInputStream::release() throw ()
290 {
291     OWeakObject::release();
292 }
293 
294 //============================================================================
295 // virtual
296 sal_Int32 SAL_CALL
297 SvLockBytesInputStream::readBytes(uno::Sequence< sal_Int8 > & rData,
298                                   sal_Int32 nBytesToRead)
299     throw (io::IOException, uno::RuntimeException)
300 {
301     OSL_ASSERT(m_nPosition >= 0);
302     if (!m_xLockBytes.Is())
303         throw io::NotConnectedException();
304     if (
305          nBytesToRead < 0 ||
306          (
307           static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE &&
308           nBytesToRead > 0
309          )
310        )
311     {
312         throw io::IOException();
313     }
314     rData.realloc(nBytesToRead);
315     sal_Int32 nSize = 0;
316     while (nSize < nBytesToRead)
317     {
318         sal_Size nCount;
319         ErrCode nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(
320                                                   m_nPosition),
321                                               rData.getArray() + nSize,
322                                               nBytesToRead - nSize, &nCount);
323         if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING)
324             throw io::IOException();
325         m_nPosition += nCount;
326         nSize += nCount;
327         if (nError == ERRCODE_NONE && nCount == 0)
328             break;
329     }
330     rData.realloc(nSize);
331     return nSize;
332 }
333 
334 //============================================================================
335 // virtual
336 sal_Int32 SAL_CALL
337 SvLockBytesInputStream::readSomeBytes(uno::Sequence< sal_Int8 > & rData,
338                                       sal_Int32 nMaxBytesToRead)
339     throw (io::IOException, uno::RuntimeException)
340 {
341     OSL_ASSERT(m_nPosition >= 0);
342     if (!m_xLockBytes.Is())
343         throw io::NotConnectedException();
344     if (static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE
345         && nMaxBytesToRead > 0)
346         throw io::IOException();
347     rData.realloc(nMaxBytesToRead);
348     sal_Size nCount = 0;
349     if (nMaxBytesToRead > 0)
350     {
351         ErrCode nError;
352         do
353         {
354             nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(m_nPosition),
355                                           rData.getArray(),
356                                           nMaxBytesToRead < 0 ?
357                                               0 : nMaxBytesToRead,
358                                           &nCount);
359             if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING)
360                 throw io::IOException();
361             m_nPosition += nCount;
362         }
363         while (nCount == 0 && nError == ERRCODE_IO_PENDING);
364     }
365     rData.realloc(sal_Int32(nCount));
366     return sal_Int32(nCount);
367 }
368 
369 //============================================================================
370 // virtual
371 void SAL_CALL SvLockBytesInputStream::skipBytes(sal_Int32 nBytesToSkip)
372     throw (io::IOException, uno::RuntimeException)
373 {
374     if (!m_xLockBytes.Is())
375         throw io::NotConnectedException();
376     if (nBytesToSkip < 0)
377         throw io::IOException();
378     if (nBytesToSkip > SAL_MAX_INT64 - m_nPosition)
379         throw io::BufferSizeExceededException();
380     m_nPosition += nBytesToSkip;
381 }
382 
383 //============================================================================
384 // virtual
385 sal_Int32 SAL_CALL SvLockBytesInputStream::available()
386     throw (io::IOException, uno::RuntimeException)
387 {
388     OSL_ASSERT(m_nPosition >= 0);
389     if (!m_xLockBytes.Is())
390         throw io::NotConnectedException();
391     SvLockBytesStat aStat;
392     if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE)
393         throw io::IOException();
394     return aStat.nSize <= static_cast<sal_uInt64>(m_nPosition) ?
395                0 :
396            static_cast<sal_Size>(aStat.nSize - m_nPosition) <=
397                    static_cast<sal_uInt32>(SAL_MAX_INT32) ?
398                static_cast<sal_Int32>(aStat.nSize - m_nPosition) :
399                SAL_MAX_INT32;
400 }
401 
402 //============================================================================
403 // virtual
404 void SAL_CALL SvLockBytesInputStream::closeInput()
405     throw (io::IOException, uno::RuntimeException)
406 {
407     if (!m_xLockBytes.Is())
408         throw io::NotConnectedException();
409     m_xLockBytes = 0;
410 }
411 
412 //============================================================================
413 // virtual
414 void SAL_CALL SvLockBytesInputStream::seek(sal_Int64 nLocation)
415     throw (lang::IllegalArgumentException, io::IOException,
416            uno::RuntimeException)
417 {
418     if (nLocation < 0)
419         throw lang::IllegalArgumentException();
420     if (!m_xLockBytes.Is())
421         throw io::NotConnectedException();
422     m_nPosition = nLocation;
423 }
424 
425 //============================================================================
426 // virtual
427 sal_Int64 SAL_CALL SvLockBytesInputStream::getPosition()
428     throw (io::IOException, uno::RuntimeException)
429 {
430     if (!m_xLockBytes.Is())
431         throw io::NotConnectedException();
432     return m_nPosition;
433 }
434 
435 //============================================================================
436 // virtual
437 sal_Int64 SAL_CALL SvLockBytesInputStream::getLength()
438     throw (io::IOException, uno::RuntimeException)
439 {
440     if (!m_xLockBytes.Is())
441         throw io::NotConnectedException();
442     SvLockBytesStat aStat;
443     if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE)
444         throw io::IOException();
445 #if SAL_TYPES_SIZEOFPOINTER > 4 // avoid warnings if sal_Size < sal_Int64
446     if (aStat.nSize > static_cast<sal_uInt64>(SAL_MAX_INT64))
447         throw io::IOException();
448 #endif
449     return aStat.nSize;
450 }
451 
452 //============================================================================
453 //
454 //  SvInputStream
455 //
456 //============================================================================
457 
458 bool SvInputStream::open()
459 {
460     if (GetError() != ERRCODE_NONE)
461         return false;
462     if (!(m_xSeekable.is() || m_pPipe))
463     {
464         if (!m_xStream.is())
465         {
466             SetError(ERRCODE_IO_INVALIDDEVICE);
467             return false;
468         }
469         m_xSeekable
470             = uno::Reference< io::XSeekable >(m_xStream, uno::UNO_QUERY);
471         if (!m_xSeekable.is())
472             m_pPipe = new SvDataPipe_Impl;
473     }
474     return true;
475 }
476 
477 //============================================================================
478 // virtual
479 sal_uLong SvInputStream::GetData(void * pData, sal_uLong nSize)
480 {
481     if (!open())
482     {
483         SetError(ERRCODE_IO_CANTREAD);
484         return 0;
485     }
486     sal_uInt32 nRead = 0;
487     if (m_xSeekable.is())
488     {
489         if (m_nSeekedFrom != STREAM_SEEK_TO_END)
490         {
491             try
492             {
493                 m_xSeekable->seek(m_nSeekedFrom);
494             }
495             catch (io::IOException)
496             {
497                 SetError(ERRCODE_IO_CANTREAD);
498                 return 0;
499             }
500             m_nSeekedFrom = STREAM_SEEK_TO_END;
501         }
502         for (;;)
503         {
504             sal_Int32 nRemain
505                 = sal_Int32(
506                     std::min(sal_uLong(nSize - nRead),
507                              sal_uLong(std::numeric_limits< sal_Int32 >::max())));
508             if (nRemain == 0)
509                 break;
510             uno::Sequence< sal_Int8 > aBuffer;
511             sal_Int32 nCount;
512             try
513             {
514                 nCount = m_xStream->readBytes(aBuffer, nRemain);
515             }
516             catch (io::IOException)
517             {
518                 SetError(ERRCODE_IO_CANTREAD);
519                 return nRead;
520             }
521             rtl_copyMemory(static_cast< sal_Int8 * >(pData) + nRead,
522                            aBuffer.getConstArray(), sal_uInt32(nCount));
523             nRead += nCount;
524             if (nCount < nRemain)
525                 break;
526         }
527     }
528     else
529     {
530         if (m_nSeekedFrom != STREAM_SEEK_TO_END)
531         {
532             SetError(ERRCODE_IO_CANTREAD);
533             return 0;
534         }
535         m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
536         nRead = m_pPipe->read();
537         if (nRead < nSize && !m_pPipe->isEOF())
538             for (;;)
539             {
540                 sal_Int32 nRemain
541                     = sal_Int32(
542                         std::min(
543                             sal_uLong(nSize - nRead),
544                             sal_uLong(std::numeric_limits< sal_Int32 >::max())));
545                 if (nRemain == 0)
546                     break;
547                 uno::Sequence< sal_Int8 > aBuffer;
548                 sal_Int32 nCount;
549                 try
550                 {
551                     nCount = m_xStream->readBytes(aBuffer, nRemain);
552                 }
553                 catch (io::IOException)
554                 {
555                     SetError(ERRCODE_IO_CANTREAD);
556                     break;
557                 }
558                 m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
559                 nRead += m_pPipe->read();
560                 if (nCount < nRemain)
561                 {
562                     m_xStream->closeInput();
563                     m_pPipe->setEOF();
564                     break;
565                 }
566             }
567         m_pPipe->clearReadBuffer();
568     }
569     return nRead;
570 }
571 
572 //============================================================================
573 // virtual
574 sal_uLong SvInputStream::PutData(void const *, sal_uLong)
575 {
576     SetError(ERRCODE_IO_NOTSUPPORTED);
577     return 0;
578 }
579 
580 //============================================================================
581 // virtual
582 void SvInputStream::FlushData()
583 {}
584 
585 //============================================================================
586 // virtual
587 sal_uLong SvInputStream::SeekPos(sal_uLong nPos)
588 {
589     if (open())
590     {
591         if (nPos == STREAM_SEEK_TO_END)
592         {
593             if (m_nSeekedFrom == STREAM_SEEK_TO_END)
594             {
595                 if (m_xSeekable.is())
596                     try
597                     {
598                         sal_Int64 nLength = m_xSeekable->getLength();
599                         OSL_ASSERT(nLength >= 0);
600                         if (static_cast<sal_uInt64>(nLength)
601                             < STREAM_SEEK_TO_END)
602                         {
603                             m_nSeekedFrom = Tell();
604                             return sal_uLong(nLength);
605                         }
606                     }
607                     catch (io::IOException) {}
608                 else
609                     return Tell(); //@@@
610             }
611             else
612                 return Tell();
613         }
614         else if (nPos == m_nSeekedFrom)
615         {
616             m_nSeekedFrom = STREAM_SEEK_TO_END;
617             return nPos;
618         }
619         else if (m_xSeekable.is())
620             try
621             {
622                 m_xSeekable->seek(nPos);
623                 m_nSeekedFrom = STREAM_SEEK_TO_END;
624                 return nPos;
625             }
626             catch (io::IOException) {}
627         else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
628         {
629             m_nSeekedFrom = STREAM_SEEK_TO_END;
630             return nPos;
631         }
632     }
633     SetError(ERRCODE_IO_CANTSEEK);
634     return Tell();
635 }
636 
637 //============================================================================
638 // virtual
639 void SvInputStream::SetSize(sal_uLong)
640 {
641     SetError(ERRCODE_IO_NOTSUPPORTED);
642 }
643 
644 //============================================================================
645 SvInputStream::SvInputStream(
646         com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
647                 const &
648             rTheStream):
649     m_xStream(rTheStream),
650     m_pPipe(0),
651     m_nSeekedFrom(STREAM_SEEK_TO_END)
652 {
653     SetBufferSize(0);
654 }
655 
656 //============================================================================
657 // virtual
658 SvInputStream::~SvInputStream()
659 {
660     if (m_xStream.is())
661         try
662         {
663             m_xStream->closeInput();
664         }
665         catch (io::IOException) {}
666     delete m_pPipe;
667 }
668 
669 //============================================================================
670 // virtual
671 sal_uInt16 SvInputStream::IsA() const
672 {
673     return 0;
674 }
675 
676 //============================================================================
677 // virtual
678 void SvInputStream::AddMark(sal_uLong nPos)
679 {
680     if (open() && m_pPipe)
681         m_pPipe->addMark(nPos);
682 }
683 
684 //============================================================================
685 // virtual
686 void SvInputStream::RemoveMark(sal_uLong nPos)
687 {
688     if (open() && m_pPipe)
689         m_pPipe->removeMark(nPos);
690 }
691 
692 //============================================================================
693 //
694 //  SvOutputStream
695 //
696 //============================================================================
697 
698 // virtual
699 sal_uLong SvOutputStream::GetData(void *, sal_uLong)
700 {
701     SetError(ERRCODE_IO_NOTSUPPORTED);
702     return 0;
703 }
704 
705 //============================================================================
706 // virtual
707 sal_uLong SvOutputStream::PutData(void const * pData, sal_uLong nSize)
708 {
709     if (!m_xStream.is())
710     {
711         SetError(ERRCODE_IO_CANTWRITE);
712         return 0;
713     }
714     sal_uLong nWritten = 0;
715     for (;;)
716     {
717         sal_Int32 nRemain
718             = sal_Int32(
719                 std::min(sal_uLong(nSize - nWritten),
720                          sal_uLong(std::numeric_limits< sal_Int32 >::max())));
721         if (nRemain == 0)
722             break;
723         try
724         {
725             m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
726                                       static_cast<const sal_Int8 * >(pData)
727                                           + nWritten,
728                                       nRemain));
729         }
730         catch (io::IOException)
731         {
732             SetError(ERRCODE_IO_CANTWRITE);
733             break;
734         }
735         nWritten += nRemain;
736     }
737     return nWritten;
738 }
739 
740 //============================================================================
741 // virtual
742 sal_uLong SvOutputStream::SeekPos(sal_uLong)
743 {
744     SetError(ERRCODE_IO_NOTSUPPORTED);
745     return 0;
746 }
747 
748 //============================================================================
749 // virtual
750 void SvOutputStream::FlushData()
751 {
752     if (!m_xStream.is())
753     {
754         SetError(ERRCODE_IO_INVALIDDEVICE);
755         return;
756     }
757     try
758     {
759         m_xStream->flush();
760     }
761     catch (io::IOException) {}
762 }
763 
764 //============================================================================
765 // virtual
766 void SvOutputStream::SetSize(sal_uLong)
767 {
768     SetError(ERRCODE_IO_NOTSUPPORTED);
769 }
770 
771 //============================================================================
772 SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const &
773                                    rTheStream):
774     m_xStream(rTheStream)
775 {
776     SetBufferSize(0);
777 }
778 
779 //============================================================================
780 // virtual
781 SvOutputStream::~SvOutputStream()
782 {
783     if (m_xStream.is())
784         try
785         {
786             m_xStream->closeOutput();
787         }
788         catch (io::IOException) {}
789 }
790 
791 //============================================================================
792 // virtual
793 sal_uInt16 SvOutputStream::IsA() const
794 {
795     return 0;
796 }
797 
798 //============================================================================
799 //
800 //  SvDataPipe_Impl
801 //
802 //============================================================================
803 
804 bool SvDataPipe_Impl::remove(Page * pPage)
805 {
806     if (
807         pPage != m_pFirstPage ||
808         m_pReadPage == m_pFirstPage ||
809         (
810          !m_aMarks.empty() &&
811          *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize
812         )
813        )
814     {
815         return false;
816     }
817 
818     m_pFirstPage = m_pFirstPage->m_pNext;
819 
820     if (m_nPages <= m_nMinPages)
821         return true;
822 
823     pPage->m_pPrev->m_pNext = pPage->m_pNext;
824     pPage->m_pNext->m_pPrev = pPage->m_pPrev;
825     rtl_freeMemory(pPage);
826     --m_nPages;
827 
828     return true;
829 }
830 
831 //============================================================================
832 SvDataPipe_Impl::~SvDataPipe_Impl()
833 {
834     if (m_pFirstPage != 0)
835         for (Page * pPage = m_pFirstPage;;)
836         {
837             Page * pNext = pPage->m_pNext;
838             rtl_freeMemory(pPage);
839             if (pNext == m_pFirstPage)
840                 break;
841             pPage = pNext;
842         }
843 }
844 
845 //============================================================================
846 sal_uInt32 SvDataPipe_Impl::read()
847 {
848     if (m_pReadBuffer == 0 || m_nReadBufferSize == 0 || m_pReadPage == 0)
849         return 0;
850 
851     sal_uInt32 nSize = m_nReadBufferSize;
852     sal_uInt32 nRemain = m_nReadBufferSize - m_nReadBufferFilled;
853 
854     m_pReadBuffer += m_nReadBufferFilled;
855     m_nReadBufferSize -= m_nReadBufferFilled;
856     m_nReadBufferFilled = 0;
857 
858     while (nRemain > 0)
859     {
860         sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
861                                                     - m_pReadPage->m_pRead),
862                                      nRemain);
863         rtl_copyMemory(m_pReadBuffer, m_pReadPage->m_pRead, nBlock);
864         m_pReadPage->m_pRead += nBlock;
865         m_pReadBuffer += nBlock;
866         m_nReadBufferSize -= nBlock;
867         m_nReadBufferFilled = 0;
868         nRemain -= nBlock;
869 
870         if (m_pReadPage == m_pWritePage)
871             break;
872 
873         if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd)
874         {
875             Page * pRemove = m_pReadPage;
876             m_pReadPage = pRemove->m_pNext;
877             remove(pRemove);
878         }
879     }
880 
881     return nSize - nRemain;
882 }
883 
884 //============================================================================
885 sal_uInt32 SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
886 {
887     if (nSize == 0)
888         return 0;
889 
890     if (m_pWritePage == 0)
891     {
892         m_pFirstPage
893             = static_cast< Page * >(rtl_allocateMemory(sizeof (Page)
894                                                            + m_nPageSize
895                                                            - 1));
896         m_pFirstPage->m_pPrev = m_pFirstPage;
897         m_pFirstPage->m_pNext = m_pFirstPage;
898         m_pFirstPage->m_pStart = m_pFirstPage->m_aBuffer;
899         m_pFirstPage->m_pRead = m_pFirstPage->m_aBuffer;
900         m_pFirstPage->m_pEnd = m_pFirstPage->m_aBuffer;
901         m_pFirstPage->m_nOffset = 0;
902         m_pReadPage = m_pFirstPage;
903         m_pWritePage = m_pFirstPage;
904         ++m_nPages;
905     }
906 
907     sal_uInt32 nRemain = nSize;
908 
909     if (m_pReadBuffer != 0 && m_pReadPage == m_pWritePage
910         && m_pReadPage->m_pRead == m_pWritePage->m_pEnd)
911     {
912         sal_uInt32 nBlock = std::min(nRemain,
913                                      sal_uInt32(m_nReadBufferSize
914                                                     - m_nReadBufferFilled));
915         sal_uInt32 nPosition = m_pWritePage->m_nOffset
916                                    + (m_pWritePage->m_pEnd
917                                           - m_pWritePage->m_aBuffer);
918         if (!m_aMarks.empty())
919             nBlock = *m_aMarks.begin() > nPosition ?
920                          std::min(nBlock, sal_uInt32(*m_aMarks.begin()
921                                                          - nPosition)) :
922                          0;
923 
924         if (nBlock > 0)
925         {
926             rtl_copyMemory(m_pReadBuffer + m_nReadBufferFilled, pBuffer,
927                            nBlock);
928             m_nReadBufferFilled += nBlock;
929             nRemain -= nBlock;
930 
931             nPosition += nBlock;
932             m_pWritePage->m_nOffset = (nPosition / m_nPageSize) * m_nPageSize;
933             m_pWritePage->m_pStart = m_pWritePage->m_aBuffer
934                                          + nPosition % m_nPageSize;
935             m_pWritePage->m_pRead = m_pWritePage->m_pStart;
936             m_pWritePage->m_pEnd = m_pWritePage->m_pStart;
937         }
938     }
939 
940     if (nRemain > 0)
941         for (;;)
942         {
943             sal_uInt32 nBlock
944                 = std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize
945                                           - m_pWritePage->m_pEnd),
946                            nRemain);
947             rtl_copyMemory(m_pWritePage->m_pEnd, pBuffer, nBlock);
948             m_pWritePage->m_pEnd += nBlock;
949             pBuffer += nBlock;
950             nRemain -= nBlock;
951 
952             if (nRemain == 0)
953                 break;
954 
955             if (m_pWritePage->m_pNext == m_pFirstPage)
956             {
957                 if (m_nPages == m_nMaxPages)
958                     break;
959 
960                 Page * pNew
961                     = static_cast< Page * >(rtl_allocateMemory(
962                                                 sizeof (Page) + m_nPageSize
963                                                     - 1));
964                 pNew->m_pPrev = m_pWritePage;
965                 pNew->m_pNext = m_pWritePage->m_pNext;
966 
967                 m_pWritePage->m_pNext->m_pPrev = pNew;
968                 m_pWritePage->m_pNext = pNew;
969                 ++m_nPages;
970             }
971 
972             m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset
973                                                    + m_nPageSize;
974             m_pWritePage = m_pWritePage->m_pNext;
975             m_pWritePage->m_pStart = m_pWritePage->m_aBuffer;
976             m_pWritePage->m_pRead = m_pWritePage->m_aBuffer;
977             m_pWritePage->m_pEnd = m_pWritePage->m_aBuffer;
978         }
979 
980     return nSize - nRemain;
981 }
982 
983 //============================================================================
984 bool SvDataPipe_Impl::addMark(sal_uInt32 nPosition)
985 {
986     if (m_pFirstPage != 0 && m_pFirstPage->m_nOffset > nPosition)
987         return false;
988     m_aMarks.insert(nPosition);
989     return true;
990 }
991 
992 //============================================================================
993 bool SvDataPipe_Impl::removeMark(sal_uInt32 nPosition)
994 {
995     std::multiset< sal_uInt32 >::iterator t = m_aMarks.find(nPosition);
996     if (t == m_aMarks.end())
997         return false;
998     m_aMarks.erase(t);
999     while (remove(m_pFirstPage)) ;
1000     return true;
1001 }
1002 
1003 //============================================================================
1004 SvDataPipe_Impl::SeekResult SvDataPipe_Impl::setReadPosition(sal_uInt32
1005                                                                  nPosition)
1006 {
1007     if (m_pFirstPage == 0)
1008         return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
1009 
1010     if (nPosition
1011             <= m_pReadPage->m_nOffset
1012                    + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer))
1013     {
1014         if (nPosition
1015                 < m_pFirstPage->m_nOffset
1016                       + (m_pFirstPage->m_pStart - m_pFirstPage->m_aBuffer))
1017             return SEEK_BEFORE_MARKED;
1018 
1019         while (nPosition < m_pReadPage->m_nOffset)
1020         {
1021             m_pReadPage->m_pRead = m_pReadPage->m_pStart;
1022             m_pReadPage = m_pReadPage->m_pPrev;
1023         }
1024     }
1025     else
1026     {
1027         if (nPosition
1028                 > m_pWritePage->m_nOffset
1029                       + (m_pWritePage->m_pEnd - m_pWritePage->m_aBuffer))
1030             return SEEK_PAST_END;
1031 
1032         while (m_pReadPage != m_pWritePage
1033                && nPosition >= m_pReadPage->m_nOffset + m_nPageSize)
1034         {
1035             Page * pRemove = m_pReadPage;
1036             m_pReadPage = pRemove->m_pNext;
1037             remove(pRemove);
1038         }
1039     }
1040 
1041     m_pReadPage->m_pRead = m_pReadPage->m_aBuffer
1042                                + (nPosition - m_pReadPage->m_nOffset);
1043     return SEEK_OK;
1044 }
1045 
1046