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/IOException.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/io/XOutputStream.hpp>
31 #include <com/sun/star/io/XSeekable.hpp>
33 #include <osl/diagnose.h>
34 #include <rtl/alloc.h>
35 #include <cppuhelper/queryinterface.hxx>
36 #include <svl/instrm.hxx>
37 #include <svl/outstrm.hxx>
39 using namespace com::sun::star
;
44 enum SeekResult
{ SEEK_BEFORE_MARKED
, SEEK_OK
, SEEK_PAST_END
};
55 sal_Int8 m_aBuffer
[1];
57 static const sal_uInt32 m_nPageSize
= 1000;
59 std::multiset
< sal_uInt32
> m_aMarks
;
63 sal_Int8
* m_pReadBuffer
;
64 sal_uInt32 m_nReadBufferSize
;
65 sal_uInt32 m_nReadBufferFilled
;
69 void remove(Page
* pPage
);
72 inline SvDataPipe_Impl();
76 inline void setReadBuffer(sal_Int8
* pBuffer
, sal_uInt32 nSize
);
80 void clearReadBuffer() { m_pReadBuffer
= nullptr; }
82 void write(sal_Int8
const * pBuffer
, sal_uInt32 nSize
);
84 void setEOF() { m_bEOF
= true; }
86 inline bool isEOF() const;
88 SeekResult
setReadPosition(sal_uInt32 nPosition
);
91 SvDataPipe_Impl::SvDataPipe_Impl()
92 : m_pFirstPage( nullptr )
93 , m_pReadPage( nullptr )
94 , m_pWritePage( nullptr )
95 , m_pReadBuffer( nullptr )
96 , m_nReadBufferSize( 0 )
97 , m_nReadBufferFilled( 0 )
102 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8
* pBuffer
,
105 m_pReadBuffer
= pBuffer
;
106 m_nReadBufferSize
= nSize
;
107 m_nReadBufferFilled
= 0;
110 inline bool SvDataPipe_Impl::isEOF() const
112 return m_bEOF
&& m_pReadPage
== m_pWritePage
113 && (!m_pReadPage
|| m_pReadPage
->m_pRead
== m_pReadPage
->m_pEnd
);
120 bool SvInputStream::open()
122 if (GetError() != ERRCODE_NONE
)
124 if (!(m_xSeekable
.is() || m_pPipe
))
128 SetError(ERRCODE_IO_INVALIDDEVICE
);
131 m_xSeekable
.set(m_xStream
, uno::UNO_QUERY
);
132 if (!m_xSeekable
.is())
133 m_pPipe
.reset( new SvDataPipe_Impl
);
139 std::size_t SvInputStream::GetData(void * pData
, std::size_t const nSize
)
143 SetError(ERRCODE_IO_CANTREAD
);
146 // check if a truncated STREAM_SEEK_TO_END was passed
147 assert(m_nSeekedFrom
!= SAL_MAX_UINT32
);
148 sal_uInt32 nRead
= 0;
149 if (m_xSeekable
.is())
151 if (m_nSeekedFrom
!= STREAM_SEEK_TO_END
)
155 m_xSeekable
->seek(m_nSeekedFrom
);
157 catch (const io::IOException
&)
159 SetError(ERRCODE_IO_CANTREAD
);
162 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
168 std::min(std::size_t(nSize
- nRead
),
169 std::size_t(std::numeric_limits
<sal_Int32
>::max())));
172 uno::Sequence
< sal_Int8
> aBuffer
;
176 nCount
= m_xStream
->readBytes(aBuffer
, nRemain
);
178 catch (const io::IOException
&)
180 SetError(ERRCODE_IO_CANTREAD
);
183 memcpy(static_cast< sal_Int8
* >(pData
) + nRead
,
184 aBuffer
.getConstArray(), sal_uInt32(nCount
));
186 if (nCount
< nRemain
)
192 if (m_nSeekedFrom
!= STREAM_SEEK_TO_END
)
194 SetError(ERRCODE_IO_CANTREAD
);
197 m_pPipe
->setReadBuffer(static_cast< sal_Int8
* >(pData
), nSize
);
198 nRead
= m_pPipe
->read();
199 if (nRead
< nSize
&& !m_pPipe
->isEOF())
205 std::size_t(nSize
- nRead
),
206 std::size_t(std::numeric_limits
<sal_Int32
>::max())));
209 uno::Sequence
< sal_Int8
> aBuffer
;
213 nCount
= m_xStream
->readBytes(aBuffer
, nRemain
);
215 catch (const io::IOException
&)
217 SetError(ERRCODE_IO_CANTREAD
);
220 m_pPipe
->write(aBuffer
.getConstArray(), sal_uInt32(nCount
));
221 nRead
+= m_pPipe
->read();
222 if (nCount
< nRemain
)
224 m_xStream
->closeInput();
229 m_pPipe
->clearReadBuffer();
235 std::size_t SvInputStream::PutData(void const *, std::size_t)
237 SetError(ERRCODE_IO_NOTSUPPORTED
);
242 void SvInputStream::FlushData()
246 sal_uInt64
SvInputStream::SeekPos(sal_uInt64
const nPos
)
248 // check if a truncated STREAM_SEEK_TO_END was passed
249 assert(nPos
!= SAL_MAX_UINT32
);
252 if (nPos
== STREAM_SEEK_TO_END
)
254 if (m_nSeekedFrom
== STREAM_SEEK_TO_END
)
256 if (m_xSeekable
.is())
259 sal_Int64 nLength
= m_xSeekable
->getLength();
260 OSL_ASSERT(nLength
>= 0);
261 if (static_cast<sal_uInt64
>(nLength
)
262 < STREAM_SEEK_TO_END
)
264 m_nSeekedFrom
= Tell();
265 return sal_uInt64(nLength
);
268 catch (const io::IOException
&)
277 else if (nPos
== m_nSeekedFrom
)
279 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
282 else if (m_xSeekable
.is())
286 m_xSeekable
->seek(nPos
);
287 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
290 catch (const io::IOException
&)
294 else if (m_pPipe
->setReadPosition(nPos
) == SvDataPipe_Impl::SEEK_OK
)
296 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
299 else if ( nPos
> Tell() )
301 // Read out the bytes
302 sal_Int32 nRead
= nPos
- Tell();
303 uno::Sequence
< sal_Int8
> aBuffer
;
304 m_xStream
->readBytes( aBuffer
, nRead
);
307 else if ( nPos
== Tell() )
310 SetError(ERRCODE_IO_CANTSEEK
);
315 void SvInputStream::SetSize(sal_uInt64
)
317 SetError(ERRCODE_IO_NOTSUPPORTED
);
320 SvInputStream::SvInputStream( css::uno::Reference
< css::io::XInputStream
> const & rTheStream
):
321 m_xStream(rTheStream
),
322 m_nSeekedFrom(STREAM_SEEK_TO_END
)
328 SvInputStream::~SvInputStream()
334 m_xStream
->closeInput();
336 catch (const io::IOException
&)
345 std::size_t SvOutputStream::GetData(void *, std::size_t)
347 SetError(ERRCODE_IO_NOTSUPPORTED
);
352 std::size_t SvOutputStream::PutData(void const * pData
, std::size_t nSize
)
356 SetError(ERRCODE_IO_CANTWRITE
);
359 std::size_t nWritten
= 0;
364 std::min(std::size_t(nSize
- nWritten
),
365 std::size_t(std::numeric_limits
<sal_Int32
>::max())));
370 m_xStream
->writeBytes(uno::Sequence
< sal_Int8
>(
371 static_cast<const sal_Int8
* >(pData
)
375 catch (const io::IOException
&)
377 SetError(ERRCODE_IO_CANTWRITE
);
386 sal_uInt64
SvOutputStream::SeekPos(sal_uInt64
)
388 SetError(ERRCODE_IO_NOTSUPPORTED
);
393 void SvOutputStream::FlushData()
397 SetError(ERRCODE_IO_INVALIDDEVICE
);
404 catch (const io::IOException
&)
410 void SvOutputStream::SetSize(sal_uInt64
)
412 SetError(ERRCODE_IO_NOTSUPPORTED
);
415 SvOutputStream::SvOutputStream(uno::Reference
< io::XOutputStream
> const &
417 m_xStream(rTheStream
)
423 SvOutputStream::~SvOutputStream()
429 m_xStream
->closeOutput();
431 catch (const io::IOException
&)
441 void SvDataPipe_Impl::remove(Page
* pPage
)
444 pPage
!= m_pFirstPage
||
445 m_pReadPage
== m_pFirstPage
||
448 *m_aMarks
.begin() < m_pFirstPage
->m_nOffset
+ m_nPageSize
455 m_pFirstPage
= m_pFirstPage
->m_pNext
;
457 if (m_nPages
<= 100) // min pages
460 pPage
->m_pPrev
->m_pNext
= pPage
->m_pNext
;
461 pPage
->m_pNext
->m_pPrev
= pPage
->m_pPrev
;
466 SvDataPipe_Impl::~SvDataPipe_Impl()
468 if (m_pFirstPage
!= nullptr)
469 for (Page
* pPage
= m_pFirstPage
;;)
471 Page
* pNext
= pPage
->m_pNext
;
473 if (pNext
== m_pFirstPage
)
479 sal_uInt32
SvDataPipe_Impl::read()
481 if (m_pReadBuffer
== nullptr || m_nReadBufferSize
== 0 || m_pReadPage
== nullptr)
484 sal_uInt32 nSize
= m_nReadBufferSize
;
485 sal_uInt32 nRemain
= m_nReadBufferSize
- m_nReadBufferFilled
;
487 m_pReadBuffer
+= m_nReadBufferFilled
;
488 m_nReadBufferSize
-= m_nReadBufferFilled
;
489 m_nReadBufferFilled
= 0;
493 sal_uInt32 nBlock
= std::min(sal_uInt32(m_pReadPage
->m_pEnd
494 - m_pReadPage
->m_pRead
),
496 memcpy(m_pReadBuffer
, m_pReadPage
->m_pRead
, nBlock
);
497 m_pReadPage
->m_pRead
+= nBlock
;
498 m_pReadBuffer
+= nBlock
;
499 m_nReadBufferSize
-= nBlock
;
500 m_nReadBufferFilled
= 0;
503 if (m_pReadPage
== m_pWritePage
)
506 if (m_pReadPage
->m_pRead
== m_pReadPage
->m_pEnd
)
508 Page
* pRemove
= m_pReadPage
;
509 m_pReadPage
= pRemove
->m_pNext
;
514 return nSize
- nRemain
;
517 void SvDataPipe_Impl::write(sal_Int8
const * pBuffer
, sal_uInt32 nSize
)
522 if (m_pWritePage
== nullptr)
525 = static_cast< Page
* >(std::malloc(sizeof (Page
)
528 m_pFirstPage
->m_pPrev
= m_pFirstPage
;
529 m_pFirstPage
->m_pNext
= m_pFirstPage
;
530 m_pFirstPage
->m_pStart
= m_pFirstPage
->m_aBuffer
;
531 m_pFirstPage
->m_pRead
= m_pFirstPage
->m_aBuffer
;
532 m_pFirstPage
->m_pEnd
= m_pFirstPage
->m_aBuffer
;
533 m_pFirstPage
->m_nOffset
= 0;
534 m_pReadPage
= m_pFirstPage
;
535 m_pWritePage
= m_pFirstPage
;
539 sal_uInt32 nRemain
= nSize
;
541 if (m_pReadBuffer
!= nullptr && m_pReadPage
== m_pWritePage
542 && m_pReadPage
->m_pRead
== m_pWritePage
->m_pEnd
)
544 sal_uInt32 nBlock
= std::min(nRemain
,
545 sal_uInt32(m_nReadBufferSize
546 - m_nReadBufferFilled
));
547 sal_uInt32 nPosition
= m_pWritePage
->m_nOffset
548 + (m_pWritePage
->m_pEnd
549 - m_pWritePage
->m_aBuffer
);
550 if (!m_aMarks
.empty())
551 nBlock
= *m_aMarks
.begin() > nPosition
?
552 std::min(nBlock
, sal_uInt32(*m_aMarks
.begin()
558 memcpy(m_pReadBuffer
+ m_nReadBufferFilled
, pBuffer
,
560 m_nReadBufferFilled
+= nBlock
;
564 m_pWritePage
->m_nOffset
= (nPosition
/ m_nPageSize
) * m_nPageSize
;
565 m_pWritePage
->m_pStart
= m_pWritePage
->m_aBuffer
566 + nPosition
% m_nPageSize
;
567 m_pWritePage
->m_pRead
= m_pWritePage
->m_pStart
;
568 m_pWritePage
->m_pEnd
= m_pWritePage
->m_pStart
;
578 = std::min(sal_uInt32(m_pWritePage
->m_aBuffer
+ m_nPageSize
579 - m_pWritePage
->m_pEnd
),
581 memcpy(m_pWritePage
->m_pEnd
, pBuffer
, nBlock
);
582 m_pWritePage
->m_pEnd
+= nBlock
;
589 if (m_pWritePage
->m_pNext
== m_pFirstPage
)
591 if (m_nPages
== std::numeric_limits
< sal_uInt32
>::max())
595 = static_cast< Page
* >(std::malloc(
596 sizeof (Page
) + m_nPageSize
598 pNew
->m_pPrev
= m_pWritePage
;
599 pNew
->m_pNext
= m_pWritePage
->m_pNext
;
601 m_pWritePage
->m_pNext
->m_pPrev
= pNew
;
602 m_pWritePage
->m_pNext
= pNew
;
606 m_pWritePage
->m_pNext
->m_nOffset
= m_pWritePage
->m_nOffset
608 m_pWritePage
= m_pWritePage
->m_pNext
;
609 m_pWritePage
->m_pStart
= m_pWritePage
->m_aBuffer
;
610 m_pWritePage
->m_pRead
= m_pWritePage
->m_aBuffer
;
611 m_pWritePage
->m_pEnd
= m_pWritePage
->m_aBuffer
;
615 SvDataPipe_Impl::SeekResult
SvDataPipe_Impl::setReadPosition(sal_uInt32
618 if (m_pFirstPage
== nullptr)
619 return nPosition
== 0 ? SEEK_OK
: SEEK_PAST_END
;
622 <= m_pReadPage
->m_nOffset
623 + (m_pReadPage
->m_pRead
- m_pReadPage
->m_aBuffer
))
626 < m_pFirstPage
->m_nOffset
627 + (m_pFirstPage
->m_pStart
- m_pFirstPage
->m_aBuffer
))
628 return SEEK_BEFORE_MARKED
;
630 while (nPosition
< m_pReadPage
->m_nOffset
)
632 m_pReadPage
->m_pRead
= m_pReadPage
->m_pStart
;
633 m_pReadPage
= m_pReadPage
->m_pPrev
;
639 > m_pWritePage
->m_nOffset
640 + (m_pWritePage
->m_pEnd
- m_pWritePage
->m_aBuffer
))
641 return SEEK_PAST_END
;
643 while (m_pReadPage
!= m_pWritePage
644 && nPosition
>= m_pReadPage
->m_nOffset
+ m_nPageSize
)
646 Page
* pRemove
= m_pReadPage
;
647 m_pReadPage
= pRemove
->m_pNext
;
652 m_pReadPage
->m_pRead
= m_pReadPage
->m_aBuffer
653 + (nPosition
- m_pReadPage
->m_nOffset
);
657 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */