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