xref: /AOO41X/main/svl/source/misc/strmadpt.cxx (revision 40df464ee80f942fd2baf5effc726656f4be12a0)
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     throw (uno::RuntimeException)
268 {
269     uno::Any
270         aReturn(cppu::queryInterface(rType,
271                                      static_cast< io::XInputStream * >(this),
272                                      static_cast< io::XSeekable * >(this)));
273     return aReturn.hasValue() ? aReturn : OWeakObject::queryInterface(rType);
274 }
275 
276 //============================================================================
277 // virtual
acquire()278 void SAL_CALL SvLockBytesInputStream::acquire() throw ()
279 {
280     OWeakObject::acquire();
281 }
282 
283 //============================================================================
284 // virtual
release()285 void SAL_CALL SvLockBytesInputStream::release() throw ()
286 {
287     OWeakObject::release();
288 }
289 
290 //============================================================================
291 // virtual
292 sal_Int32 SAL_CALL
readBytes(uno::Sequence<sal_Int8> & rData,sal_Int32 nBytesToRead)293 SvLockBytesInputStream::readBytes(uno::Sequence< sal_Int8 > & rData,
294                                   sal_Int32 nBytesToRead)
295     throw (io::IOException, uno::RuntimeException)
296 {
297     OSL_ASSERT(m_nPosition >= 0);
298     if (!m_xLockBytes.Is())
299         throw io::NotConnectedException();
300     if (
301          nBytesToRead < 0 ||
302          (
303           static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE &&
304           nBytesToRead > 0
305          )
306        )
307     {
308         throw io::IOException();
309     }
310     rData.realloc(nBytesToRead);
311     sal_Int32 nSize = 0;
312     while (nSize < nBytesToRead)
313     {
314         sal_Size nCount;
315         ErrCode nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(
316                                                   m_nPosition),
317                                               rData.getArray() + nSize,
318                                               nBytesToRead - nSize, &nCount);
319         if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING)
320             throw io::IOException();
321         m_nPosition += nCount;
322         nSize += nCount;
323         if (nError == ERRCODE_NONE && nCount == 0)
324             break;
325     }
326     rData.realloc(nSize);
327     return nSize;
328 }
329 
330 //============================================================================
331 // virtual
332 sal_Int32 SAL_CALL
readSomeBytes(uno::Sequence<sal_Int8> & rData,sal_Int32 nMaxBytesToRead)333 SvLockBytesInputStream::readSomeBytes(uno::Sequence< sal_Int8 > & rData,
334                                       sal_Int32 nMaxBytesToRead)
335     throw (io::IOException, uno::RuntimeException)
336 {
337     OSL_ASSERT(m_nPosition >= 0);
338     if (!m_xLockBytes.Is())
339         throw io::NotConnectedException();
340     if (static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE
341         && nMaxBytesToRead > 0)
342         throw io::IOException();
343     rData.realloc(nMaxBytesToRead);
344     sal_Size nCount = 0;
345     if (nMaxBytesToRead > 0)
346     {
347         ErrCode nError;
348         do
349         {
350             nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(m_nPosition),
351                                           rData.getArray(),
352                                           nMaxBytesToRead < 0 ?
353                                               0 : nMaxBytesToRead,
354                                           &nCount);
355             if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING)
356                 throw io::IOException();
357             m_nPosition += nCount;
358         }
359         while (nCount == 0 && nError == ERRCODE_IO_PENDING);
360     }
361     rData.realloc(sal_Int32(nCount));
362     return sal_Int32(nCount);
363 }
364 
365 //============================================================================
366 // virtual
skipBytes(sal_Int32 nBytesToSkip)367 void SAL_CALL SvLockBytesInputStream::skipBytes(sal_Int32 nBytesToSkip)
368     throw (io::IOException, uno::RuntimeException)
369 {
370     if (!m_xLockBytes.Is())
371         throw io::NotConnectedException();
372     if (nBytesToSkip < 0)
373         throw io::IOException();
374     if (nBytesToSkip > SAL_MAX_INT64 - m_nPosition)
375         throw io::BufferSizeExceededException();
376     m_nPosition += nBytesToSkip;
377 }
378 
379 //============================================================================
380 // virtual
available()381 sal_Int32 SAL_CALL SvLockBytesInputStream::available()
382     throw (io::IOException, uno::RuntimeException)
383 {
384     OSL_ASSERT(m_nPosition >= 0);
385     if (!m_xLockBytes.Is())
386         throw io::NotConnectedException();
387     SvLockBytesStat aStat;
388     if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE)
389         throw io::IOException();
390     return aStat.nSize <= static_cast<sal_uInt64>(m_nPosition) ?
391                0 :
392            static_cast<sal_Size>(aStat.nSize - m_nPosition) <=
393                    static_cast<sal_uInt32>(SAL_MAX_INT32) ?
394                static_cast<sal_Int32>(aStat.nSize - m_nPosition) :
395                SAL_MAX_INT32;
396 }
397 
398 //============================================================================
399 // virtual
closeInput()400 void SAL_CALL SvLockBytesInputStream::closeInput()
401     throw (io::IOException, uno::RuntimeException)
402 {
403     if (!m_xLockBytes.Is())
404         throw io::NotConnectedException();
405     m_xLockBytes = 0;
406 }
407 
408 //============================================================================
409 // virtual
seek(sal_Int64 nLocation)410 void SAL_CALL SvLockBytesInputStream::seek(sal_Int64 nLocation)
411     throw (lang::IllegalArgumentException, io::IOException,
412            uno::RuntimeException)
413 {
414     if (nLocation < 0)
415         throw lang::IllegalArgumentException();
416     if (!m_xLockBytes.Is())
417         throw io::NotConnectedException();
418     m_nPosition = nLocation;
419 }
420 
421 //============================================================================
422 // virtual
getPosition()423 sal_Int64 SAL_CALL SvLockBytesInputStream::getPosition()
424     throw (io::IOException, uno::RuntimeException)
425 {
426     if (!m_xLockBytes.Is())
427         throw io::NotConnectedException();
428     return m_nPosition;
429 }
430 
431 //============================================================================
432 // virtual
getLength()433 sal_Int64 SAL_CALL SvLockBytesInputStream::getLength()
434     throw (io::IOException, uno::RuntimeException)
435 {
436     if (!m_xLockBytes.Is())
437         throw io::NotConnectedException();
438     SvLockBytesStat aStat;
439     if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE)
440         throw io::IOException();
441 #if SAL_TYPES_SIZEOFPOINTER > 4 // avoid warnings if sal_Size < sal_Int64
442     if (aStat.nSize > static_cast<sal_uInt64>(SAL_MAX_INT64))
443         throw io::IOException();
444 #endif
445     return aStat.nSize;
446 }
447 
448 //============================================================================
449 //
450 //  SvInputStream
451 //
452 //============================================================================
453 
open()454 bool SvInputStream::open()
455 {
456     if (GetError() != ERRCODE_NONE)
457         return false;
458     if (!(m_xSeekable.is() || m_pPipe))
459     {
460         if (!m_xStream.is())
461         {
462             SetError(ERRCODE_IO_INVALIDDEVICE);
463             return false;
464         }
465         m_xSeekable
466             = uno::Reference< io::XSeekable >(m_xStream, uno::UNO_QUERY);
467         if (!m_xSeekable.is())
468             m_pPipe = new SvDataPipe_Impl;
469     }
470     return true;
471 }
472 
473 //============================================================================
474 // virtual
GetData(void * pData,sal_uLong nSize)475 sal_uLong SvInputStream::GetData(void * pData, sal_uLong nSize)
476 {
477     if (!open())
478     {
479         SetError(ERRCODE_IO_CANTREAD);
480         return 0;
481     }
482     sal_uInt32 nRead = 0;
483     if (m_xSeekable.is())
484     {
485         if (m_nSeekedFrom != STREAM_SEEK_TO_END)
486         {
487             try
488             {
489                 m_xSeekable->seek(m_nSeekedFrom);
490             }
491             catch (io::IOException)
492             {
493                 SetError(ERRCODE_IO_CANTREAD);
494                 return 0;
495             }
496             m_nSeekedFrom = STREAM_SEEK_TO_END;
497         }
498         for (;;)
499         {
500             sal_Int32 nRemain
501                 = sal_Int32(
502                     std::min(sal_uLong(nSize - nRead),
503                              sal_uLong(std::numeric_limits< sal_Int32 >::max())));
504             if (nRemain == 0)
505                 break;
506             uno::Sequence< sal_Int8 > aBuffer;
507             sal_Int32 nCount;
508             try
509             {
510                 nCount = m_xStream->readBytes(aBuffer, nRemain);
511             }
512             catch (io::IOException)
513             {
514                 SetError(ERRCODE_IO_CANTREAD);
515                 return nRead;
516             }
517             rtl_copyMemory(static_cast< sal_Int8 * >(pData) + nRead,
518                            aBuffer.getConstArray(), sal_uInt32(nCount));
519             nRead += nCount;
520             if (nCount < nRemain)
521                 break;
522         }
523     }
524     else
525     {
526         if (m_nSeekedFrom != STREAM_SEEK_TO_END)
527         {
528             SetError(ERRCODE_IO_CANTREAD);
529             return 0;
530         }
531         m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
532         nRead = m_pPipe->read();
533         if (nRead < nSize && !m_pPipe->isEOF())
534             for (;;)
535             {
536                 sal_Int32 nRemain
537                     = sal_Int32(
538                         std::min(
539                             sal_uLong(nSize - nRead),
540                             sal_uLong(std::numeric_limits< sal_Int32 >::max())));
541                 if (nRemain == 0)
542                     break;
543                 uno::Sequence< sal_Int8 > aBuffer;
544                 sal_Int32 nCount;
545                 try
546                 {
547                     nCount = m_xStream->readBytes(aBuffer, nRemain);
548                 }
549                 catch (io::IOException)
550                 {
551                     SetError(ERRCODE_IO_CANTREAD);
552                     break;
553                 }
554                 m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
555                 nRead += m_pPipe->read();
556                 if (nCount < nRemain)
557                 {
558                     m_xStream->closeInput();
559                     m_pPipe->setEOF();
560                     break;
561                 }
562             }
563         m_pPipe->clearReadBuffer();
564     }
565     return nRead;
566 }
567 
568 //============================================================================
569 // virtual
PutData(void const *,sal_uLong)570 sal_uLong SvInputStream::PutData(void const *, sal_uLong)
571 {
572     SetError(ERRCODE_IO_NOTSUPPORTED);
573     return 0;
574 }
575 
576 //============================================================================
577 // virtual
FlushData()578 void SvInputStream::FlushData()
579 {}
580 
581 //============================================================================
582 // virtual
SeekPos(sal_uLong nPos)583 sal_uLong SvInputStream::SeekPos(sal_uLong nPos)
584 {
585     if (open())
586     {
587         if (nPos == STREAM_SEEK_TO_END)
588         {
589             if (m_nSeekedFrom == STREAM_SEEK_TO_END)
590             {
591                 if (m_xSeekable.is())
592                     try
593                     {
594                         sal_Int64 nLength = m_xSeekable->getLength();
595                         OSL_ASSERT(nLength >= 0);
596                         if (static_cast<sal_uInt64>(nLength)
597                             < STREAM_SEEK_TO_END)
598                         {
599                             m_nSeekedFrom = Tell();
600                             return sal_uLong(nLength);
601                         }
602                     }
603                     catch (io::IOException) {}
604                 else
605                     return Tell(); //@@@
606             }
607             else
608                 return Tell();
609         }
610         else if (nPos == m_nSeekedFrom)
611         {
612             m_nSeekedFrom = STREAM_SEEK_TO_END;
613             return nPos;
614         }
615         else if (m_xSeekable.is())
616             try
617             {
618                 m_xSeekable->seek(nPos);
619                 m_nSeekedFrom = STREAM_SEEK_TO_END;
620                 return nPos;
621             }
622             catch (io::IOException) {}
623         else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
624         {
625             m_nSeekedFrom = STREAM_SEEK_TO_END;
626             return nPos;
627         }
628     }
629     SetError(ERRCODE_IO_CANTSEEK);
630     return Tell();
631 }
632 
633 //============================================================================
634 // virtual
SetSize(sal_uLong)635 void SvInputStream::SetSize(sal_uLong)
636 {
637     SetError(ERRCODE_IO_NOTSUPPORTED);
638 }
639 
640 //============================================================================
SvInputStream(com::sun::star::uno::Reference<com::sun::star::io::XInputStream> const & rTheStream)641 SvInputStream::SvInputStream(
642         com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
643                 const &
644             rTheStream):
645     m_xStream(rTheStream),
646     m_pPipe(0),
647     m_nSeekedFrom(STREAM_SEEK_TO_END)
648 {
649     SetBufferSize(0);
650 }
651 
652 //============================================================================
653 // virtual
~SvInputStream()654 SvInputStream::~SvInputStream()
655 {
656     if (m_xStream.is())
657         try
658         {
659             m_xStream->closeInput();
660         }
661         catch (io::IOException) {}
662     delete m_pPipe;
663 }
664 
665 //============================================================================
666 // virtual
IsA() const667 sal_uInt16 SvInputStream::IsA() const
668 {
669     return 0;
670 }
671 
672 //============================================================================
673 // virtual
AddMark(sal_uLong nPos)674 void SvInputStream::AddMark(sal_uLong nPos)
675 {
676     if (open() && m_pPipe)
677         m_pPipe->addMark(nPos);
678 }
679 
680 //============================================================================
681 // virtual
RemoveMark(sal_uLong nPos)682 void SvInputStream::RemoveMark(sal_uLong nPos)
683 {
684     if (open() && m_pPipe)
685         m_pPipe->removeMark(nPos);
686 }
687 
688 //============================================================================
689 //
690 //  SvOutputStream
691 //
692 //============================================================================
693 
694 // virtual
GetData(void *,sal_uLong)695 sal_uLong SvOutputStream::GetData(void *, sal_uLong)
696 {
697     SetError(ERRCODE_IO_NOTSUPPORTED);
698     return 0;
699 }
700 
701 //============================================================================
702 // virtual
PutData(void const * pData,sal_uLong nSize)703 sal_uLong SvOutputStream::PutData(void const * pData, sal_uLong nSize)
704 {
705     if (!m_xStream.is())
706     {
707         SetError(ERRCODE_IO_CANTWRITE);
708         return 0;
709     }
710     sal_uLong nWritten = 0;
711     for (;;)
712     {
713         sal_Int32 nRemain
714             = sal_Int32(
715                 std::min(sal_uLong(nSize - nWritten),
716                          sal_uLong(std::numeric_limits< sal_Int32 >::max())));
717         if (nRemain == 0)
718             break;
719         try
720         {
721             m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
722                                       static_cast<const sal_Int8 * >(pData)
723                                           + nWritten,
724                                       nRemain));
725         }
726         catch (io::IOException)
727         {
728             SetError(ERRCODE_IO_CANTWRITE);
729             break;
730         }
731         nWritten += nRemain;
732     }
733     return nWritten;
734 }
735 
736 //============================================================================
737 // virtual
SeekPos(sal_uLong)738 sal_uLong SvOutputStream::SeekPos(sal_uLong)
739 {
740     SetError(ERRCODE_IO_NOTSUPPORTED);
741     return 0;
742 }
743 
744 //============================================================================
745 // virtual
FlushData()746 void SvOutputStream::FlushData()
747 {
748     if (!m_xStream.is())
749     {
750         SetError(ERRCODE_IO_INVALIDDEVICE);
751         return;
752     }
753     try
754     {
755         m_xStream->flush();
756     }
757     catch (io::IOException) {}
758 }
759 
760 //============================================================================
761 // virtual
SetSize(sal_uLong)762 void SvOutputStream::SetSize(sal_uLong)
763 {
764     SetError(ERRCODE_IO_NOTSUPPORTED);
765 }
766 
767 //============================================================================
SvOutputStream(uno::Reference<io::XOutputStream> const & rTheStream)768 SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const &
769                                    rTheStream):
770     m_xStream(rTheStream)
771 {
772     SetBufferSize(0);
773 }
774 
775 //============================================================================
776 // virtual
~SvOutputStream()777 SvOutputStream::~SvOutputStream()
778 {
779     if (m_xStream.is())
780         try
781         {
782             m_xStream->closeOutput();
783         }
784         catch (io::IOException) {}
785 }
786 
787 //============================================================================
788 // virtual
IsA() const789 sal_uInt16 SvOutputStream::IsA() const
790 {
791     return 0;
792 }
793 
794 //============================================================================
795 //
796 //  SvDataPipe_Impl
797 //
798 //============================================================================
799 
remove(Page * pPage)800 bool SvDataPipe_Impl::remove(Page * pPage)
801 {
802     if (
803         pPage != m_pFirstPage ||
804         m_pReadPage == m_pFirstPage ||
805         (
806          !m_aMarks.empty() &&
807          *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize
808         )
809        )
810     {
811         return false;
812     }
813 
814     m_pFirstPage = m_pFirstPage->m_pNext;
815 
816     if (m_nPages <= m_nMinPages)
817         return true;
818 
819     pPage->m_pPrev->m_pNext = pPage->m_pNext;
820     pPage->m_pNext->m_pPrev = pPage->m_pPrev;
821     rtl_freeMemory(pPage);
822     --m_nPages;
823 
824     return true;
825 }
826 
827 //============================================================================
~SvDataPipe_Impl()828 SvDataPipe_Impl::~SvDataPipe_Impl()
829 {
830     if (m_pFirstPage != 0)
831         for (Page * pPage = m_pFirstPage;;)
832         {
833             Page * pNext = pPage->m_pNext;
834             rtl_freeMemory(pPage);
835             if (pNext == m_pFirstPage)
836                 break;
837             pPage = pNext;
838         }
839 }
840 
841 //============================================================================
read()842 sal_uInt32 SvDataPipe_Impl::read()
843 {
844     if (m_pReadBuffer == 0 || m_nReadBufferSize == 0 || m_pReadPage == 0)
845         return 0;
846 
847     sal_uInt32 nSize = m_nReadBufferSize;
848     sal_uInt32 nRemain = m_nReadBufferSize - m_nReadBufferFilled;
849 
850     m_pReadBuffer += m_nReadBufferFilled;
851     m_nReadBufferSize -= m_nReadBufferFilled;
852     m_nReadBufferFilled = 0;
853 
854     while (nRemain > 0)
855     {
856         sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
857                                                     - m_pReadPage->m_pRead),
858                                      nRemain);
859         rtl_copyMemory(m_pReadBuffer, m_pReadPage->m_pRead, nBlock);
860         m_pReadPage->m_pRead += nBlock;
861         m_pReadBuffer += nBlock;
862         m_nReadBufferSize -= nBlock;
863         m_nReadBufferFilled = 0;
864         nRemain -= nBlock;
865 
866         if (m_pReadPage == m_pWritePage)
867             break;
868 
869         if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd)
870         {
871             Page * pRemove = m_pReadPage;
872             m_pReadPage = pRemove->m_pNext;
873             remove(pRemove);
874         }
875     }
876 
877     return nSize - nRemain;
878 }
879 
880 //============================================================================
write(sal_Int8 const * pBuffer,sal_uInt32 nSize)881 sal_uInt32 SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
882 {
883     if (nSize == 0)
884         return 0;
885 
886     if (m_pWritePage == 0)
887     {
888         m_pFirstPage
889             = static_cast< Page * >(rtl_allocateMemory(sizeof (Page)
890                                                            + m_nPageSize
891                                                            - 1));
892         m_pFirstPage->m_pPrev = m_pFirstPage;
893         m_pFirstPage->m_pNext = m_pFirstPage;
894         m_pFirstPage->m_pStart = m_pFirstPage->m_aBuffer;
895         m_pFirstPage->m_pRead = m_pFirstPage->m_aBuffer;
896         m_pFirstPage->m_pEnd = m_pFirstPage->m_aBuffer;
897         m_pFirstPage->m_nOffset = 0;
898         m_pReadPage = m_pFirstPage;
899         m_pWritePage = m_pFirstPage;
900         ++m_nPages;
901     }
902 
903     sal_uInt32 nRemain = nSize;
904 
905     if (m_pReadBuffer != 0 && m_pReadPage == m_pWritePage
906         && m_pReadPage->m_pRead == m_pWritePage->m_pEnd)
907     {
908         sal_uInt32 nBlock = std::min(nRemain,
909                                      sal_uInt32(m_nReadBufferSize
910                                                     - m_nReadBufferFilled));
911         sal_uInt32 nPosition = m_pWritePage->m_nOffset
912                                    + (m_pWritePage->m_pEnd
913                                           - m_pWritePage->m_aBuffer);
914         if (!m_aMarks.empty())
915             nBlock = *m_aMarks.begin() > nPosition ?
916                          std::min(nBlock, sal_uInt32(*m_aMarks.begin()
917                                                          - nPosition)) :
918                          0;
919 
920         if (nBlock > 0)
921         {
922             rtl_copyMemory(m_pReadBuffer + m_nReadBufferFilled, pBuffer,
923                            nBlock);
924             m_nReadBufferFilled += nBlock;
925             nRemain -= nBlock;
926 
927             nPosition += nBlock;
928             m_pWritePage->m_nOffset = (nPosition / m_nPageSize) * m_nPageSize;
929             m_pWritePage->m_pStart = m_pWritePage->m_aBuffer
930                                          + nPosition % m_nPageSize;
931             m_pWritePage->m_pRead = m_pWritePage->m_pStart;
932             m_pWritePage->m_pEnd = m_pWritePage->m_pStart;
933         }
934     }
935 
936     if (nRemain > 0)
937         for (;;)
938         {
939             sal_uInt32 nBlock
940                 = std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize
941                                           - m_pWritePage->m_pEnd),
942                            nRemain);
943             rtl_copyMemory(m_pWritePage->m_pEnd, pBuffer, nBlock);
944             m_pWritePage->m_pEnd += nBlock;
945             pBuffer += nBlock;
946             nRemain -= nBlock;
947 
948             if (nRemain == 0)
949                 break;
950 
951             if (m_pWritePage->m_pNext == m_pFirstPage)
952             {
953                 if (m_nPages == m_nMaxPages)
954                     break;
955 
956                 Page * pNew
957                     = static_cast< Page * >(rtl_allocateMemory(
958                                                 sizeof (Page) + m_nPageSize
959                                                     - 1));
960                 pNew->m_pPrev = m_pWritePage;
961                 pNew->m_pNext = m_pWritePage->m_pNext;
962 
963                 m_pWritePage->m_pNext->m_pPrev = pNew;
964                 m_pWritePage->m_pNext = pNew;
965                 ++m_nPages;
966             }
967 
968             m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset
969                                                    + m_nPageSize;
970             m_pWritePage = m_pWritePage->m_pNext;
971             m_pWritePage->m_pStart = m_pWritePage->m_aBuffer;
972             m_pWritePage->m_pRead = m_pWritePage->m_aBuffer;
973             m_pWritePage->m_pEnd = m_pWritePage->m_aBuffer;
974         }
975 
976     return nSize - nRemain;
977 }
978 
979 //============================================================================
addMark(sal_uInt32 nPosition)980 bool SvDataPipe_Impl::addMark(sal_uInt32 nPosition)
981 {
982     if (m_pFirstPage != 0 && m_pFirstPage->m_nOffset > nPosition)
983         return false;
984     m_aMarks.insert(nPosition);
985     return true;
986 }
987 
988 //============================================================================
removeMark(sal_uInt32 nPosition)989 bool SvDataPipe_Impl::removeMark(sal_uInt32 nPosition)
990 {
991     std::multiset< sal_uInt32 >::iterator t = m_aMarks.find(nPosition);
992     if (t == m_aMarks.end())
993         return false;
994     m_aMarks.erase(t);
995     while (remove(m_pFirstPage)) ;
996     return true;
997 }
998 
999 //============================================================================
setReadPosition(sal_uInt32 nPosition)1000 SvDataPipe_Impl::SeekResult SvDataPipe_Impl::setReadPosition(sal_uInt32
1001                                                                  nPosition)
1002 {
1003     if (m_pFirstPage == 0)
1004         return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
1005 
1006     if (nPosition
1007             <= m_pReadPage->m_nOffset
1008                    + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer))
1009     {
1010         if (nPosition
1011                 < m_pFirstPage->m_nOffset
1012                       + (m_pFirstPage->m_pStart - m_pFirstPage->m_aBuffer))
1013             return SEEK_BEFORE_MARKED;
1014 
1015         while (nPosition < m_pReadPage->m_nOffset)
1016         {
1017             m_pReadPage->m_pRead = m_pReadPage->m_pStart;
1018             m_pReadPage = m_pReadPage->m_pPrev;
1019         }
1020     }
1021     else
1022     {
1023         if (nPosition
1024                 > m_pWritePage->m_nOffset
1025                       + (m_pWritePage->m_pEnd - m_pWritePage->m_aBuffer))
1026             return SEEK_PAST_END;
1027 
1028         while (m_pReadPage != m_pWritePage
1029                && nPosition >= m_pReadPage->m_nOffset + m_nPageSize)
1030         {
1031             Page * pRemove = m_pReadPage;
1032             m_pReadPage = pRemove->m_pNext;
1033             remove(pRemove);
1034         }
1035     }
1036 
1037     m_pReadPage->m_pRead = m_pReadPage->m_aBuffer
1038                                + (nPosition - m_pReadPage->m_nOffset);
1039     return SEEK_OK;
1040 }
1041 
1042