1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
28 #include <com/sun/star/io/XInputStream.hpp>
29 #include <com/sun/star/io/XSeekable.hpp>
31 #include <osl/diagnose.h>
32 #include <rtl/alloc.h>
33 #include <cppuhelper/queryinterface.hxx>
34 #include <svl/instrm.hxx>
35 #include <svl/outstrm.hxx>
37 #include <strmadpt.hxx>
39 using namespace com::sun::star
;
44 enum SeekResult
{ SEEK_BEFORE_MARKED
, SEEK_OK
, SEEK_PAST_END
};
55 sal_Int8 m_aBuffer
[1];
58 std::multiset
< sal_uInt32
> m_aMarks
;
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
;
71 bool remove(Page
* pPage
);
74 inline SvDataPipe_Impl(sal_uInt32 nThePageSize
= 1000,
75 sal_uInt32 nTheMinPages
= 100,
76 sal_uInt32 nTheMaxPages
77 = std::numeric_limits
< sal_uInt32
>::max());
81 inline void setReadBuffer(sal_Int8
* pBuffer
, sal_uInt32 nSize
);
85 void clearReadBuffer() { m_pReadBuffer
= 0; }
87 sal_uInt32
write(sal_Int8
const * pBuffer
, sal_uInt32 nSize
);
89 void setEOF() { m_bEOF
= true; }
91 inline bool isEOF() const;
93 SeekResult
setReadPosition(sal_uInt32 nPosition
);
96 SvDataPipe_Impl::SvDataPipe_Impl(sal_uInt32 nThePageSize
,
97 sal_uInt32 nTheMinPages
,
98 sal_uInt32 nTheMaxPages
)
103 , m_nReadBufferSize( 0 )
104 , m_nReadBufferFilled( 0 )
105 , m_nPageSize(std::min
< sal_uInt32
>(
106 std::max
< sal_uInt32
>(nThePageSize
, sal_uInt32(1)),
107 sal_uInt32(std::numeric_limits
< sal_uInt32
>::max()
108 - sizeof (Page
) + 1)))
109 , m_nMinPages(std::max
< sal_uInt32
>(nTheMinPages
, sal_uInt32(1)))
110 , m_nMaxPages(std::max
< sal_uInt32
>(nTheMaxPages
, sal_uInt32(1)))
115 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8
* pBuffer
,
118 m_pReadBuffer
= pBuffer
;
119 m_nReadBufferSize
= nSize
;
120 m_nReadBufferFilled
= 0;
123 inline bool SvDataPipe_Impl::isEOF() const
125 return m_bEOF
&& m_pReadPage
== m_pWritePage
126 && (!m_pReadPage
|| m_pReadPage
->m_pRead
== m_pReadPage
->m_pEnd
);
129 // SvOutputStreamOpenLockBytes
132 TYPEINIT1(SvOutputStreamOpenLockBytes
, SvOpenLockBytes
)
135 ErrCode
SvOutputStreamOpenLockBytes::ReadAt(sal_uInt64
, void *, sal_uLong
, sal_uLong
*)
138 return ERRCODE_IO_CANTREAD
;
142 ErrCode
SvOutputStreamOpenLockBytes::WriteAt(sal_uInt64
const nPos
, void const * pBuffer
,
143 sal_uLong nCount
, sal_uLong
* pWritten
)
145 if (nPos
!= m_nPosition
)
146 return ERRCODE_IO_CANTWRITE
;
147 return FillAppend(pBuffer
, nCount
, pWritten
);
151 ErrCode
SvOutputStreamOpenLockBytes::Flush() const
153 if (!m_xOutputStream
.is())
154 return ERRCODE_IO_CANTWRITE
;
157 m_xOutputStream
->flush();
159 catch (const io::IOException
&)
161 return ERRCODE_IO_CANTWRITE
;
167 ErrCode
SvOutputStreamOpenLockBytes::SetSize(sal_uInt64
)
169 return ERRCODE_IO_NOTSUPPORTED
;
173 ErrCode
SvOutputStreamOpenLockBytes::Stat(SvLockBytesStat
* pStat
,
174 SvLockBytesStatFlag
) const
177 pStat
->nSize
= m_nPosition
;
182 ErrCode
SvOutputStreamOpenLockBytes::FillAppend(void const * pBuffer
,
184 sal_uLong
* pWritten
)
186 if (!m_xOutputStream
.is())
187 return ERRCODE_IO_CANTWRITE
;
189 && nCount
> std::numeric_limits
< sal_uLong
>::max() - m_nPosition
)
191 nCount
= std::numeric_limits
< sal_uLong
>::max() - m_nPosition
;
193 return ERRCODE_IO_CANTWRITE
;
198 writeBytes(uno::Sequence
< sal_Int8
>(
199 static_cast< sal_Int8
const * >(pBuffer
), nCount
));
201 catch (const io::IOException
&)
203 return ERRCODE_IO_CANTWRITE
;
205 m_nPosition
+= nCount
;
212 sal_uInt64
SvOutputStreamOpenLockBytes::Tell() const
218 sal_uInt64
SvOutputStreamOpenLockBytes::Seek(sal_uInt64
)
224 void SvOutputStreamOpenLockBytes::Terminate()
226 if (m_xOutputStream
.is())
230 m_xOutputStream
->closeOutput();
232 catch (const io::IOException
&)
242 bool SvInputStream::open()
244 if (GetError() != ERRCODE_NONE
)
246 if (!(m_xSeekable
.is() || m_pPipe
))
250 SetError(ERRCODE_IO_INVALIDDEVICE
);
254 = uno::Reference
< io::XSeekable
>(m_xStream
, uno::UNO_QUERY
);
255 if (!m_xSeekable
.is())
256 m_pPipe
= new SvDataPipe_Impl
;
262 sal_uLong
SvInputStream::GetData(void * pData
, sal_uLong nSize
)
266 SetError(ERRCODE_IO_CANTREAD
);
269 // check if a truncated STREAM_SEEK_TO_END was passed
270 assert(m_nSeekedFrom
!= SAL_MAX_UINT32
);
271 sal_uInt32 nRead
= 0;
272 if (m_xSeekable
.is())
274 if (m_nSeekedFrom
!= STREAM_SEEK_TO_END
)
278 m_xSeekable
->seek(m_nSeekedFrom
);
280 catch (const io::IOException
&)
282 SetError(ERRCODE_IO_CANTREAD
);
285 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
291 std::min(sal_uLong(nSize
- nRead
),
292 sal_uLong(std::numeric_limits
< sal_Int32
>::max())));
295 uno::Sequence
< sal_Int8
> aBuffer
;
299 nCount
= m_xStream
->readBytes(aBuffer
, nRemain
);
301 catch (const io::IOException
&)
303 SetError(ERRCODE_IO_CANTREAD
);
306 memcpy(static_cast< sal_Int8
* >(pData
) + nRead
,
307 aBuffer
.getConstArray(), sal_uInt32(nCount
));
309 if (nCount
< nRemain
)
315 if (m_nSeekedFrom
!= STREAM_SEEK_TO_END
)
317 SetError(ERRCODE_IO_CANTREAD
);
320 m_pPipe
->setReadBuffer(static_cast< sal_Int8
* >(pData
), nSize
);
321 nRead
= m_pPipe
->read();
322 if (nRead
< nSize
&& !m_pPipe
->isEOF())
328 sal_uLong(nSize
- nRead
),
329 sal_uLong(std::numeric_limits
< sal_Int32
>::max())));
332 uno::Sequence
< sal_Int8
> aBuffer
;
336 nCount
= m_xStream
->readBytes(aBuffer
, nRemain
);
338 catch (const io::IOException
&)
340 SetError(ERRCODE_IO_CANTREAD
);
343 m_pPipe
->write(aBuffer
.getConstArray(), sal_uInt32(nCount
));
344 nRead
+= m_pPipe
->read();
345 if (nCount
< nRemain
)
347 m_xStream
->closeInput();
352 m_pPipe
->clearReadBuffer();
358 sal_uLong
SvInputStream::PutData(void const *, sal_uLong
)
360 SetError(ERRCODE_IO_NOTSUPPORTED
);
365 void SvInputStream::FlushData()
369 sal_uInt64
SvInputStream::SeekPos(sal_uInt64
const nPos
)
371 // check if a truncated STREAM_SEEK_TO_END was passed
372 assert(nPos
!= SAL_MAX_UINT32
);
375 if (nPos
== STREAM_SEEK_TO_END
)
377 if (m_nSeekedFrom
== STREAM_SEEK_TO_END
)
379 if (m_xSeekable
.is())
382 sal_Int64 nLength
= m_xSeekable
->getLength();
383 OSL_ASSERT(nLength
>= 0);
384 if (static_cast<sal_uInt64
>(nLength
)
385 < STREAM_SEEK_TO_END
)
387 m_nSeekedFrom
= Tell();
388 return sal_uLong(nLength
);
391 catch (const io::IOException
&)
400 else if (nPos
== m_nSeekedFrom
)
402 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
405 else if (m_xSeekable
.is())
409 m_xSeekable
->seek(nPos
);
410 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
413 catch (const io::IOException
&)
417 else if (m_pPipe
->setReadPosition(nPos
) == SvDataPipe_Impl::SEEK_OK
)
419 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
422 else if ( nPos
> Tell() )
424 // Read out the bytes
425 sal_Int32 nRead
= nPos
- Tell();
426 uno::Sequence
< sal_Int8
> aBuffer
;
427 m_xStream
->readBytes( aBuffer
, nRead
);
430 else if ( nPos
== Tell() )
433 SetError(ERRCODE_IO_CANTSEEK
);
438 void SvInputStream::SetSize(sal_uInt64
)
440 SetError(ERRCODE_IO_NOTSUPPORTED
);
443 SvInputStream::SvInputStream(
444 com::sun::star::uno::Reference
< com::sun::star::io::XInputStream
>
447 m_xStream(rTheStream
),
449 m_nSeekedFrom(STREAM_SEEK_TO_END
)
455 SvInputStream::~SvInputStream()
461 m_xStream
->closeInput();
463 catch (const io::IOException
&)
473 sal_uLong
SvOutputStream::GetData(void *, sal_uLong
)
475 SetError(ERRCODE_IO_NOTSUPPORTED
);
480 sal_uLong
SvOutputStream::PutData(void const * pData
, sal_uLong nSize
)
484 SetError(ERRCODE_IO_CANTWRITE
);
487 sal_uLong nWritten
= 0;
492 std::min(sal_uLong(nSize
- nWritten
),
493 sal_uLong(std::numeric_limits
< sal_Int32
>::max())));
498 m_xStream
->writeBytes(uno::Sequence
< sal_Int8
>(
499 static_cast<const sal_Int8
* >(pData
)
503 catch (const io::IOException
&)
505 SetError(ERRCODE_IO_CANTWRITE
);
514 sal_uInt64
SvOutputStream::SeekPos(sal_uInt64
)
516 SetError(ERRCODE_IO_NOTSUPPORTED
);
521 void SvOutputStream::FlushData()
525 SetError(ERRCODE_IO_INVALIDDEVICE
);
532 catch (const io::IOException
&)
538 void SvOutputStream::SetSize(sal_uInt64
)
540 SetError(ERRCODE_IO_NOTSUPPORTED
);
543 SvOutputStream::SvOutputStream(uno::Reference
< io::XOutputStream
> const &
545 m_xStream(rTheStream
)
551 SvOutputStream::~SvOutputStream()
557 m_xStream
->closeOutput();
559 catch (const io::IOException
&)
569 bool SvDataPipe_Impl::remove(Page
* pPage
)
572 pPage
!= m_pFirstPage
||
573 m_pReadPage
== m_pFirstPage
||
576 *m_aMarks
.begin() < m_pFirstPage
->m_nOffset
+ m_nPageSize
583 m_pFirstPage
= m_pFirstPage
->m_pNext
;
585 if (m_nPages
<= m_nMinPages
)
588 pPage
->m_pPrev
->m_pNext
= pPage
->m_pNext
;
589 pPage
->m_pNext
->m_pPrev
= pPage
->m_pPrev
;
590 rtl_freeMemory(pPage
);
596 SvDataPipe_Impl::~SvDataPipe_Impl()
598 if (m_pFirstPage
!= 0)
599 for (Page
* pPage
= m_pFirstPage
;;)
601 Page
* pNext
= pPage
->m_pNext
;
602 rtl_freeMemory(pPage
);
603 if (pNext
== m_pFirstPage
)
609 sal_uInt32
SvDataPipe_Impl::read()
611 if (m_pReadBuffer
== 0 || m_nReadBufferSize
== 0 || m_pReadPage
== 0)
614 sal_uInt32 nSize
= m_nReadBufferSize
;
615 sal_uInt32 nRemain
= m_nReadBufferSize
- m_nReadBufferFilled
;
617 m_pReadBuffer
+= m_nReadBufferFilled
;
618 m_nReadBufferSize
-= m_nReadBufferFilled
;
619 m_nReadBufferFilled
= 0;
623 sal_uInt32 nBlock
= std::min(sal_uInt32(m_pReadPage
->m_pEnd
624 - m_pReadPage
->m_pRead
),
626 memcpy(m_pReadBuffer
, m_pReadPage
->m_pRead
, nBlock
);
627 m_pReadPage
->m_pRead
+= nBlock
;
628 m_pReadBuffer
+= nBlock
;
629 m_nReadBufferSize
-= nBlock
;
630 m_nReadBufferFilled
= 0;
633 if (m_pReadPage
== m_pWritePage
)
636 if (m_pReadPage
->m_pRead
== m_pReadPage
->m_pEnd
)
638 Page
* pRemove
= m_pReadPage
;
639 m_pReadPage
= pRemove
->m_pNext
;
644 return nSize
- nRemain
;
647 sal_uInt32
SvDataPipe_Impl::write(sal_Int8
const * pBuffer
, sal_uInt32 nSize
)
652 if (m_pWritePage
== 0)
655 = static_cast< Page
* >(rtl_allocateMemory(sizeof (Page
)
658 m_pFirstPage
->m_pPrev
= m_pFirstPage
;
659 m_pFirstPage
->m_pNext
= m_pFirstPage
;
660 m_pFirstPage
->m_pStart
= m_pFirstPage
->m_aBuffer
;
661 m_pFirstPage
->m_pRead
= m_pFirstPage
->m_aBuffer
;
662 m_pFirstPage
->m_pEnd
= m_pFirstPage
->m_aBuffer
;
663 m_pFirstPage
->m_nOffset
= 0;
664 m_pReadPage
= m_pFirstPage
;
665 m_pWritePage
= m_pFirstPage
;
669 sal_uInt32 nRemain
= nSize
;
671 if (m_pReadBuffer
!= 0 && m_pReadPage
== m_pWritePage
672 && m_pReadPage
->m_pRead
== m_pWritePage
->m_pEnd
)
674 sal_uInt32 nBlock
= std::min(nRemain
,
675 sal_uInt32(m_nReadBufferSize
676 - m_nReadBufferFilled
));
677 sal_uInt32 nPosition
= m_pWritePage
->m_nOffset
678 + (m_pWritePage
->m_pEnd
679 - m_pWritePage
->m_aBuffer
);
680 if (!m_aMarks
.empty())
681 nBlock
= *m_aMarks
.begin() > nPosition
?
682 std::min(nBlock
, sal_uInt32(*m_aMarks
.begin()
688 memcpy(m_pReadBuffer
+ m_nReadBufferFilled
, pBuffer
,
690 m_nReadBufferFilled
+= nBlock
;
694 m_pWritePage
->m_nOffset
= (nPosition
/ m_nPageSize
) * m_nPageSize
;
695 m_pWritePage
->m_pStart
= m_pWritePage
->m_aBuffer
696 + nPosition
% m_nPageSize
;
697 m_pWritePage
->m_pRead
= m_pWritePage
->m_pStart
;
698 m_pWritePage
->m_pEnd
= m_pWritePage
->m_pStart
;
706 = std::min(sal_uInt32(m_pWritePage
->m_aBuffer
+ m_nPageSize
707 - m_pWritePage
->m_pEnd
),
709 memcpy(m_pWritePage
->m_pEnd
, pBuffer
, nBlock
);
710 m_pWritePage
->m_pEnd
+= nBlock
;
717 if (m_pWritePage
->m_pNext
== m_pFirstPage
)
719 if (m_nPages
== m_nMaxPages
)
723 = static_cast< Page
* >(rtl_allocateMemory(
724 sizeof (Page
) + m_nPageSize
726 pNew
->m_pPrev
= m_pWritePage
;
727 pNew
->m_pNext
= m_pWritePage
->m_pNext
;
729 m_pWritePage
->m_pNext
->m_pPrev
= pNew
;
730 m_pWritePage
->m_pNext
= pNew
;
734 m_pWritePage
->m_pNext
->m_nOffset
= m_pWritePage
->m_nOffset
736 m_pWritePage
= m_pWritePage
->m_pNext
;
737 m_pWritePage
->m_pStart
= m_pWritePage
->m_aBuffer
;
738 m_pWritePage
->m_pRead
= m_pWritePage
->m_aBuffer
;
739 m_pWritePage
->m_pEnd
= m_pWritePage
->m_aBuffer
;
742 return nSize
- nRemain
;
745 SvDataPipe_Impl::SeekResult
SvDataPipe_Impl::setReadPosition(sal_uInt32
748 if (m_pFirstPage
== 0)
749 return nPosition
== 0 ? SEEK_OK
: SEEK_PAST_END
;
752 <= m_pReadPage
->m_nOffset
753 + (m_pReadPage
->m_pRead
- m_pReadPage
->m_aBuffer
))
756 < m_pFirstPage
->m_nOffset
757 + (m_pFirstPage
->m_pStart
- m_pFirstPage
->m_aBuffer
))
758 return SEEK_BEFORE_MARKED
;
760 while (nPosition
< m_pReadPage
->m_nOffset
)
762 m_pReadPage
->m_pRead
= m_pReadPage
->m_pStart
;
763 m_pReadPage
= m_pReadPage
->m_pPrev
;
769 > m_pWritePage
->m_nOffset
770 + (m_pWritePage
->m_pEnd
- m_pWritePage
->m_aBuffer
))
771 return SEEK_PAST_END
;
773 while (m_pReadPage
!= m_pWritePage
774 && nPosition
>= m_pReadPage
->m_nOffset
+ m_nPageSize
)
776 Page
* pRemove
= m_pReadPage
;
777 m_pReadPage
= pRemove
->m_pNext
;
782 m_pReadPage
->m_pRead
= m_pReadPage
->m_aBuffer
783 + (nPosition
- m_pReadPage
->m_nOffset
);
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */