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 .
26 #include <com/sun/star/io/IOException.hpp>
27 #include <com/sun/star/io/XInputStream.hpp>
28 #include <com/sun/star/io/XOutputStream.hpp>
29 #include <com/sun/star/io/XSeekable.hpp>
30 #include <o3tl/safeint.hxx>
31 #include <osl/diagnose.h>
32 #include <svl/instrm.hxx>
33 #include <svl/outstrm.hxx>
35 using namespace com::sun::star
;
40 enum SeekResult
{ SEEK_BEFORE_MARKED
, SEEK_OK
, SEEK_PAST_END
};
51 sal_Int8 m_aBuffer
[1];
53 static const sal_uInt32 m_nPageSize
= 1000;
55 std::multiset
< sal_uInt32
> m_aMarks
;
59 sal_Int8
* m_pReadBuffer
;
60 sal_uInt32 m_nReadBufferSize
;
61 sal_uInt32 m_nReadBufferFilled
;
65 void remove(Page
* pPage
);
68 inline SvDataPipe_Impl();
72 inline void setReadBuffer(sal_Int8
* pBuffer
, sal_uInt32 nSize
);
76 void clearReadBuffer() { m_pReadBuffer
= nullptr; }
78 void write(sal_Int8
const * pBuffer
, sal_uInt32 nSize
);
80 void setEOF() { m_bEOF
= true; }
82 inline bool isEOF() const;
84 SeekResult
setReadPosition(sal_uInt32 nPosition
);
87 SvDataPipe_Impl::SvDataPipe_Impl()
88 : m_pFirstPage( nullptr )
89 , m_pReadPage( nullptr )
90 , m_pWritePage( nullptr )
91 , m_pReadBuffer( nullptr )
92 , m_nReadBufferSize( 0 )
93 , m_nReadBufferFilled( 0 )
98 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8
* pBuffer
,
101 m_pReadBuffer
= pBuffer
;
102 m_nReadBufferSize
= nSize
;
103 m_nReadBufferFilled
= 0;
106 inline bool SvDataPipe_Impl::isEOF() const
108 return m_bEOF
&& m_pReadPage
== m_pWritePage
109 && (!m_pReadPage
|| m_pReadPage
->m_pRead
== m_pReadPage
->m_pEnd
);
116 bool SvInputStream::open()
118 if (GetError() != ERRCODE_NONE
)
120 if (!(m_xSeekable
.is() || m_pPipe
))
124 SetError(ERRCODE_IO_INVALIDDEVICE
);
127 m_xSeekable
.set(m_xStream
, uno::UNO_QUERY
);
128 if (!m_xSeekable
.is())
129 m_pPipe
.reset( new SvDataPipe_Impl
);
135 std::size_t SvInputStream::GetData(void * pData
, std::size_t const nSize
)
139 SetError(ERRCODE_IO_CANTREAD
);
142 // check if a truncated STREAM_SEEK_TO_END was passed
143 assert(m_nSeekedFrom
!= SAL_MAX_UINT32
);
144 sal_uInt32 nRead
= 0;
145 if (m_xSeekable
.is())
147 if (m_nSeekedFrom
!= STREAM_SEEK_TO_END
)
151 m_xSeekable
->seek(m_nSeekedFrom
);
153 catch (const io::IOException
&)
155 SetError(ERRCODE_IO_CANTREAD
);
158 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
164 std::min(std::size_t(nSize
- nRead
),
165 std::size_t(std::numeric_limits
<sal_Int32
>::max())));
168 uno::Sequence
< sal_Int8
> aBuffer
;
172 nCount
= m_xStream
->readBytes(aBuffer
, nRemain
);
174 catch (const io::IOException
&)
176 SetError(ERRCODE_IO_CANTREAD
);
179 memcpy(static_cast< sal_Int8
* >(pData
) + nRead
,
180 aBuffer
.getConstArray(), sal_uInt32(nCount
));
182 if (nCount
< nRemain
)
188 if (m_nSeekedFrom
!= STREAM_SEEK_TO_END
)
190 SetError(ERRCODE_IO_CANTREAD
);
193 m_pPipe
->setReadBuffer(static_cast< sal_Int8
* >(pData
), nSize
);
194 nRead
= m_pPipe
->read();
195 if (nRead
< nSize
&& !m_pPipe
->isEOF())
201 std::size_t(nSize
- nRead
),
202 std::size_t(std::numeric_limits
<sal_Int32
>::max())));
205 uno::Sequence
< sal_Int8
> aBuffer
;
209 nCount
= m_xStream
->readBytes(aBuffer
, nRemain
);
211 catch (const io::IOException
&)
213 SetError(ERRCODE_IO_CANTREAD
);
216 m_pPipe
->write(aBuffer
.getConstArray(), sal_uInt32(nCount
));
217 nRead
+= m_pPipe
->read();
218 if (nCount
< nRemain
)
220 m_xStream
->closeInput();
225 m_pPipe
->clearReadBuffer();
231 std::size_t SvInputStream::PutData(void const *, std::size_t)
233 SetError(ERRCODE_IO_NOTSUPPORTED
);
238 void SvInputStream::FlushData()
242 sal_uInt64
SvInputStream::SeekPos(sal_uInt64
const nPos
)
244 // check if a truncated STREAM_SEEK_TO_END was passed
245 assert(nPos
!= SAL_MAX_UINT32
);
248 if (nPos
== STREAM_SEEK_TO_END
)
250 if (m_nSeekedFrom
== STREAM_SEEK_TO_END
)
252 if (m_xSeekable
.is())
255 sal_Int64 nLength
= m_xSeekable
->getLength();
256 OSL_ASSERT(nLength
>= 0);
257 if (o3tl::make_unsigned(nLength
)
258 < STREAM_SEEK_TO_END
)
260 m_nSeekedFrom
= Tell();
261 return sal_uInt64(nLength
);
264 catch (const io::IOException
&)
273 else if (nPos
== m_nSeekedFrom
)
275 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
278 else if (m_xSeekable
.is())
282 m_xSeekable
->seek(nPos
);
283 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
286 catch (const io::IOException
&)
290 else if (m_pPipe
->setReadPosition(nPos
) == SvDataPipe_Impl::SEEK_OK
)
292 m_nSeekedFrom
= STREAM_SEEK_TO_END
;
295 else if ( nPos
> Tell() )
297 // Read out the bytes
298 sal_Int32 nRead
= nPos
- Tell();
299 uno::Sequence
< sal_Int8
> aBuffer
;
300 m_xStream
->readBytes( aBuffer
, nRead
);
303 else if ( nPos
== Tell() )
306 SetError(ERRCODE_IO_CANTSEEK
);
311 void SvInputStream::SetSize(sal_uInt64
)
313 SetError(ERRCODE_IO_NOTSUPPORTED
);
316 SvInputStream::SvInputStream( css::uno::Reference
< css::io::XInputStream
> const & rTheStream
):
317 m_xStream(rTheStream
),
318 m_nSeekedFrom(STREAM_SEEK_TO_END
)
324 SvInputStream::~SvInputStream()
330 m_xStream
->closeInput();
332 catch (const io::IOException
&)
341 std::size_t SvOutputStream::GetData(void *, std::size_t)
343 SetError(ERRCODE_IO_NOTSUPPORTED
);
348 std::size_t SvOutputStream::PutData(void const * pData
, std::size_t nSize
)
352 SetError(ERRCODE_IO_CANTWRITE
);
355 std::size_t nWritten
= 0;
360 std::min(std::size_t(nSize
- nWritten
),
361 std::size_t(std::numeric_limits
<sal_Int32
>::max())));
366 m_xStream
->writeBytes(uno::Sequence
< sal_Int8
>(
367 static_cast<const sal_Int8
* >(pData
)
371 catch (const io::IOException
&)
373 SetError(ERRCODE_IO_CANTWRITE
);
382 sal_uInt64
SvOutputStream::SeekPos(sal_uInt64
)
384 SetError(ERRCODE_IO_NOTSUPPORTED
);
389 void SvOutputStream::FlushData()
393 SetError(ERRCODE_IO_INVALIDDEVICE
);
400 catch (const io::IOException
&)
406 void SvOutputStream::SetSize(sal_uInt64
)
408 SetError(ERRCODE_IO_NOTSUPPORTED
);
411 SvOutputStream::SvOutputStream(uno::Reference
< io::XOutputStream
> const &
413 m_xStream(rTheStream
)
419 SvOutputStream::~SvOutputStream()
425 m_xStream
->closeOutput();
427 catch (const io::IOException
&)
437 void SvDataPipe_Impl::remove(Page
* pPage
)
440 pPage
!= m_pFirstPage
||
441 m_pReadPage
== m_pFirstPage
||
444 *m_aMarks
.begin() < m_pFirstPage
->m_nOffset
+ m_nPageSize
451 m_pFirstPage
= m_pFirstPage
->m_pNext
;
453 if (m_nPages
<= 100) // min pages
456 pPage
->m_pPrev
->m_pNext
= pPage
->m_pNext
;
457 pPage
->m_pNext
->m_pPrev
= pPage
->m_pPrev
;
462 SvDataPipe_Impl::~SvDataPipe_Impl()
464 if (m_pFirstPage
!= nullptr)
465 for (Page
* pPage
= m_pFirstPage
;;)
467 Page
* pNext
= pPage
->m_pNext
;
469 if (pNext
== m_pFirstPage
)
475 sal_uInt32
SvDataPipe_Impl::read()
477 if (m_pReadBuffer
== nullptr || m_nReadBufferSize
== 0 || m_pReadPage
== nullptr)
480 sal_uInt32 nSize
= m_nReadBufferSize
;
481 sal_uInt32 nRemain
= m_nReadBufferSize
- m_nReadBufferFilled
;
483 m_pReadBuffer
+= m_nReadBufferFilled
;
484 m_nReadBufferSize
-= m_nReadBufferFilled
;
485 m_nReadBufferFilled
= 0;
489 sal_uInt32 nBlock
= std::min(sal_uInt32(m_pReadPage
->m_pEnd
490 - m_pReadPage
->m_pRead
),
492 memcpy(m_pReadBuffer
, m_pReadPage
->m_pRead
, nBlock
);
493 m_pReadPage
->m_pRead
+= nBlock
;
494 m_pReadBuffer
+= nBlock
;
495 m_nReadBufferSize
-= nBlock
;
496 m_nReadBufferFilled
= 0;
499 if (m_pReadPage
== m_pWritePage
)
502 if (m_pReadPage
->m_pRead
== m_pReadPage
->m_pEnd
)
504 Page
* pRemove
= m_pReadPage
;
505 m_pReadPage
= pRemove
->m_pNext
;
510 return nSize
- nRemain
;
513 void SvDataPipe_Impl::write(sal_Int8
const * pBuffer
, sal_uInt32 nSize
)
518 if (m_pWritePage
== nullptr)
521 = static_cast< Page
* >(std::malloc(sizeof (Page
)
524 m_pFirstPage
->m_pPrev
= m_pFirstPage
;
525 m_pFirstPage
->m_pNext
= m_pFirstPage
;
526 m_pFirstPage
->m_pStart
= m_pFirstPage
->m_aBuffer
;
527 m_pFirstPage
->m_pRead
= m_pFirstPage
->m_aBuffer
;
528 m_pFirstPage
->m_pEnd
= m_pFirstPage
->m_aBuffer
;
529 m_pFirstPage
->m_nOffset
= 0;
530 m_pReadPage
= m_pFirstPage
;
531 m_pWritePage
= m_pFirstPage
;
535 sal_uInt32 nRemain
= nSize
;
537 if (m_pReadBuffer
!= nullptr && m_pReadPage
== m_pWritePage
538 && m_pReadPage
->m_pRead
== m_pWritePage
->m_pEnd
)
540 sal_uInt32 nBlock
= std::min(nRemain
,
541 sal_uInt32(m_nReadBufferSize
542 - m_nReadBufferFilled
));
543 sal_uInt32 nPosition
= m_pWritePage
->m_nOffset
544 + (m_pWritePage
->m_pEnd
545 - m_pWritePage
->m_aBuffer
);
546 if (!m_aMarks
.empty())
547 nBlock
= *m_aMarks
.begin() > nPosition
?
548 std::min(nBlock
, sal_uInt32(*m_aMarks
.begin()
554 memcpy(m_pReadBuffer
+ m_nReadBufferFilled
, pBuffer
,
556 m_nReadBufferFilled
+= nBlock
;
560 m_pWritePage
->m_nOffset
= (nPosition
/ m_nPageSize
) * m_nPageSize
;
561 m_pWritePage
->m_pStart
= m_pWritePage
->m_aBuffer
562 + nPosition
% m_nPageSize
;
563 m_pWritePage
->m_pRead
= m_pWritePage
->m_pStart
;
564 m_pWritePage
->m_pEnd
= m_pWritePage
->m_pStart
;
574 = std::min(sal_uInt32(m_pWritePage
->m_aBuffer
+ m_nPageSize
575 - m_pWritePage
->m_pEnd
),
577 memcpy(m_pWritePage
->m_pEnd
, pBuffer
, nBlock
);
578 m_pWritePage
->m_pEnd
+= nBlock
;
585 if (m_pWritePage
->m_pNext
== m_pFirstPage
)
587 if (m_nPages
== std::numeric_limits
< sal_uInt32
>::max())
591 = static_cast< Page
* >(std::malloc(
592 sizeof (Page
) + m_nPageSize
594 pNew
->m_pPrev
= m_pWritePage
;
595 pNew
->m_pNext
= m_pWritePage
->m_pNext
;
597 m_pWritePage
->m_pNext
->m_pPrev
= pNew
;
598 m_pWritePage
->m_pNext
= pNew
;
602 m_pWritePage
->m_pNext
->m_nOffset
= m_pWritePage
->m_nOffset
604 m_pWritePage
= m_pWritePage
->m_pNext
;
605 m_pWritePage
->m_pStart
= m_pWritePage
->m_aBuffer
;
606 m_pWritePage
->m_pRead
= m_pWritePage
->m_aBuffer
;
607 m_pWritePage
->m_pEnd
= m_pWritePage
->m_aBuffer
;
611 SvDataPipe_Impl::SeekResult
SvDataPipe_Impl::setReadPosition(sal_uInt32
614 if (m_pFirstPage
== nullptr)
615 return nPosition
== 0 ? SEEK_OK
: SEEK_PAST_END
;
618 <= m_pReadPage
->m_nOffset
619 + (m_pReadPage
->m_pRead
- m_pReadPage
->m_aBuffer
))
622 < m_pFirstPage
->m_nOffset
623 + (m_pFirstPage
->m_pStart
- m_pFirstPage
->m_aBuffer
))
624 return SEEK_BEFORE_MARKED
;
626 while (nPosition
< m_pReadPage
->m_nOffset
)
628 m_pReadPage
->m_pRead
= m_pReadPage
->m_pStart
;
629 m_pReadPage
= m_pReadPage
->m_pPrev
;
635 > m_pWritePage
->m_nOffset
636 + (m_pWritePage
->m_pEnd
- m_pWritePage
->m_aBuffer
))
637 return SEEK_PAST_END
;
639 while (m_pReadPage
!= m_pWritePage
640 && nPosition
>= m_pReadPage
->m_nOffset
+ m_nPageSize
)
642 Page
* pRemove
= m_pReadPage
;
643 m_pReadPage
= pRemove
->m_pNext
;
648 m_pReadPage
->m_pRead
= m_pReadPage
->m_aBuffer
649 + (nPosition
- m_pReadPage
->m_nOffset
);
653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */