bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / misc / strmadpt.cxx
blobdf8b901706eec3f70995d918df4bac5737c3157c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <functional>
23 #include <algorithm>
24 #include <limits>
25 #include <set>
26 #include <string.h>
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;
41 class SvDataPipe_Impl
43 public:
44 enum SeekResult { SEEK_BEFORE_MARKED, SEEK_OK, SEEK_PAST_END };
46 private:
47 struct Page
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];
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;
71 bool remove(Page * pPage);
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());
79 ~SvDataPipe_Impl();
81 inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize);
83 sal_uInt32 read();
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)
99 : m_pFirstPage( 0 )
100 , m_pReadPage( 0 )
101 , m_pWritePage( 0 )
102 , m_pReadBuffer( 0 )
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)))
111 , m_nPages( 0 )
112 , m_bEOF( false )
115 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8 * pBuffer,
116 sal_uInt32 nSize)
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)
134 // virtual
135 ErrCode SvOutputStreamOpenLockBytes::ReadAt(sal_uInt64, void *, sal_uLong, sal_uLong*)
136 const
138 return ERRCODE_IO_CANTREAD;
141 // virtual
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);
150 // virtual
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;
163 return ERRCODE_NONE;
166 // virtual
167 ErrCode SvOutputStreamOpenLockBytes::SetSize(sal_uInt64)
169 return ERRCODE_IO_NOTSUPPORTED;
172 // virtual
173 ErrCode SvOutputStreamOpenLockBytes::Stat(SvLockBytesStat * pStat,
174 SvLockBytesStatFlag) const
176 if (pStat)
177 pStat->nSize = m_nPosition;
178 return ERRCODE_NONE;
181 // virtual
182 ErrCode SvOutputStreamOpenLockBytes::FillAppend(void const * pBuffer,
183 sal_uLong nCount,
184 sal_uLong * pWritten)
186 if (!m_xOutputStream.is())
187 return ERRCODE_IO_CANTWRITE;
188 if (nCount > 0
189 && nCount > std::numeric_limits< sal_uLong >::max() - m_nPosition)
191 nCount = std::numeric_limits< sal_uLong >::max() - m_nPosition;
192 if (nCount == 0)
193 return ERRCODE_IO_CANTWRITE;
197 m_xOutputStream->
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;
206 if (pWritten)
207 *pWritten = nCount;
208 return ERRCODE_NONE;
211 // virtual
212 sal_uInt64 SvOutputStreamOpenLockBytes::Tell() const
214 return m_nPosition;
217 // virtual
218 sal_uInt64 SvOutputStreamOpenLockBytes::Seek(sal_uInt64)
220 return m_nPosition;
223 // virtual
224 void SvOutputStreamOpenLockBytes::Terminate()
226 if (m_xOutputStream.is())
230 m_xOutputStream->closeOutput();
232 catch (const io::IOException&)
239 // SvInputStream
242 bool SvInputStream::open()
244 if (GetError() != ERRCODE_NONE)
245 return false;
246 if (!(m_xSeekable.is() || m_pPipe))
248 if (!m_xStream.is())
250 SetError(ERRCODE_IO_INVALIDDEVICE);
251 return false;
253 m_xSeekable
254 = uno::Reference< io::XSeekable >(m_xStream, uno::UNO_QUERY);
255 if (!m_xSeekable.is())
256 m_pPipe = new SvDataPipe_Impl;
258 return true;
261 // virtual
262 sal_uLong SvInputStream::GetData(void * pData, sal_uLong nSize)
264 if (!open())
266 SetError(ERRCODE_IO_CANTREAD);
267 return 0;
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);
283 return 0;
285 m_nSeekedFrom = STREAM_SEEK_TO_END;
287 for (;;)
289 sal_Int32 nRemain
290 = sal_Int32(
291 std::min(sal_uLong(nSize - nRead),
292 sal_uLong(std::numeric_limits< sal_Int32 >::max())));
293 if (nRemain == 0)
294 break;
295 uno::Sequence< sal_Int8 > aBuffer;
296 sal_Int32 nCount;
299 nCount = m_xStream->readBytes(aBuffer, nRemain);
301 catch (const io::IOException&)
303 SetError(ERRCODE_IO_CANTREAD);
304 return nRead;
306 memcpy(static_cast< sal_Int8 * >(pData) + nRead,
307 aBuffer.getConstArray(), sal_uInt32(nCount));
308 nRead += nCount;
309 if (nCount < nRemain)
310 break;
313 else
315 if (m_nSeekedFrom != STREAM_SEEK_TO_END)
317 SetError(ERRCODE_IO_CANTREAD);
318 return 0;
320 m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
321 nRead = m_pPipe->read();
322 if (nRead < nSize && !m_pPipe->isEOF())
323 for (;;)
325 sal_Int32 nRemain
326 = sal_Int32(
327 std::min(
328 sal_uLong(nSize - nRead),
329 sal_uLong(std::numeric_limits< sal_Int32 >::max())));
330 if (nRemain == 0)
331 break;
332 uno::Sequence< sal_Int8 > aBuffer;
333 sal_Int32 nCount;
336 nCount = m_xStream->readBytes(aBuffer, nRemain);
338 catch (const io::IOException&)
340 SetError(ERRCODE_IO_CANTREAD);
341 break;
343 m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
344 nRead += m_pPipe->read();
345 if (nCount < nRemain)
347 m_xStream->closeInput();
348 m_pPipe->setEOF();
349 break;
352 m_pPipe->clearReadBuffer();
354 return nRead;
357 // virtual
358 sal_uLong SvInputStream::PutData(void const *, sal_uLong)
360 SetError(ERRCODE_IO_NOTSUPPORTED);
361 return 0;
364 // virtual
365 void SvInputStream::FlushData()
368 // virtual
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);
373 if (open())
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&)
394 else
395 return Tell(); //@@@
397 else
398 return Tell();
400 else if (nPos == m_nSeekedFrom)
402 m_nSeekedFrom = STREAM_SEEK_TO_END;
403 return nPos;
405 else if (m_xSeekable.is())
409 m_xSeekable->seek(nPos);
410 m_nSeekedFrom = STREAM_SEEK_TO_END;
411 return nPos;
413 catch (const io::IOException&)
417 else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
419 m_nSeekedFrom = STREAM_SEEK_TO_END;
420 return nPos;
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 );
428 return nPos;
430 else if ( nPos == Tell() )
431 return nPos;
433 SetError(ERRCODE_IO_CANTSEEK);
434 return Tell();
437 // virtual
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 >
445 const &
446 rTheStream):
447 m_xStream(rTheStream),
448 m_pPipe(0),
449 m_nSeekedFrom(STREAM_SEEK_TO_END)
451 SetBufferSize(0);
454 // virtual
455 SvInputStream::~SvInputStream()
457 if (m_xStream.is())
461 m_xStream->closeInput();
463 catch (const io::IOException&)
467 delete m_pPipe;
470 // SvOutputStream
472 // virtual
473 sal_uLong SvOutputStream::GetData(void *, sal_uLong)
475 SetError(ERRCODE_IO_NOTSUPPORTED);
476 return 0;
479 // virtual
480 sal_uLong SvOutputStream::PutData(void const * pData, sal_uLong nSize)
482 if (!m_xStream.is())
484 SetError(ERRCODE_IO_CANTWRITE);
485 return 0;
487 sal_uLong nWritten = 0;
488 for (;;)
490 sal_Int32 nRemain
491 = sal_Int32(
492 std::min(sal_uLong(nSize - nWritten),
493 sal_uLong(std::numeric_limits< sal_Int32 >::max())));
494 if (nRemain == 0)
495 break;
498 m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
499 static_cast<const sal_Int8 * >(pData)
500 + nWritten,
501 nRemain));
503 catch (const io::IOException&)
505 SetError(ERRCODE_IO_CANTWRITE);
506 break;
508 nWritten += nRemain;
510 return nWritten;
513 // virtual
514 sal_uInt64 SvOutputStream::SeekPos(sal_uInt64)
516 SetError(ERRCODE_IO_NOTSUPPORTED);
517 return 0;
520 // virtual
521 void SvOutputStream::FlushData()
523 if (!m_xStream.is())
525 SetError(ERRCODE_IO_INVALIDDEVICE);
526 return;
530 m_xStream->flush();
532 catch (const io::IOException&)
537 // virtual
538 void SvOutputStream::SetSize(sal_uInt64)
540 SetError(ERRCODE_IO_NOTSUPPORTED);
543 SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const &
544 rTheStream):
545 m_xStream(rTheStream)
547 SetBufferSize(0);
550 // virtual
551 SvOutputStream::~SvOutputStream()
553 if (m_xStream.is())
557 m_xStream->closeOutput();
559 catch (const io::IOException&)
566 // SvDataPipe_Impl
569 bool SvDataPipe_Impl::remove(Page * pPage)
571 if (
572 pPage != m_pFirstPage ||
573 m_pReadPage == m_pFirstPage ||
575 !m_aMarks.empty() &&
576 *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize
580 return false;
583 m_pFirstPage = m_pFirstPage->m_pNext;
585 if (m_nPages <= m_nMinPages)
586 return true;
588 pPage->m_pPrev->m_pNext = pPage->m_pNext;
589 pPage->m_pNext->m_pPrev = pPage->m_pPrev;
590 rtl_freeMemory(pPage);
591 --m_nPages;
593 return true;
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)
604 break;
605 pPage = pNext;
609 sal_uInt32 SvDataPipe_Impl::read()
611 if (m_pReadBuffer == 0 || m_nReadBufferSize == 0 || m_pReadPage == 0)
612 return 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;
621 while (nRemain > 0)
623 sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
624 - m_pReadPage->m_pRead),
625 nRemain);
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;
631 nRemain -= nBlock;
633 if (m_pReadPage == m_pWritePage)
634 break;
636 if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd)
638 Page * pRemove = m_pReadPage;
639 m_pReadPage = pRemove->m_pNext;
640 remove(pRemove);
644 return nSize - nRemain;
647 sal_uInt32 SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
649 if (nSize == 0)
650 return 0;
652 if (m_pWritePage == 0)
654 m_pFirstPage
655 = static_cast< Page * >(rtl_allocateMemory(sizeof (Page)
656 + m_nPageSize
657 - 1));
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;
666 ++m_nPages;
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()
683 - nPosition)) :
686 if (nBlock > 0)
688 memcpy(m_pReadBuffer + m_nReadBufferFilled, pBuffer,
689 nBlock);
690 m_nReadBufferFilled += nBlock;
691 nRemain -= nBlock;
693 nPosition += 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;
702 if (nRemain > 0)
703 for (;;)
705 sal_uInt32 nBlock
706 = std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize
707 - m_pWritePage->m_pEnd),
708 nRemain);
709 memcpy(m_pWritePage->m_pEnd, pBuffer, nBlock);
710 m_pWritePage->m_pEnd += nBlock;
711 pBuffer += nBlock;
712 nRemain -= nBlock;
714 if (nRemain == 0)
715 break;
717 if (m_pWritePage->m_pNext == m_pFirstPage)
719 if (m_nPages == m_nMaxPages)
720 break;
722 Page * pNew
723 = static_cast< Page * >(rtl_allocateMemory(
724 sizeof (Page) + m_nPageSize
725 - 1));
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;
731 ++m_nPages;
734 m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset
735 + m_nPageSize;
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
746 nPosition)
748 if (m_pFirstPage == 0)
749 return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
751 if (nPosition
752 <= m_pReadPage->m_nOffset
753 + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer))
755 if (nPosition
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;
766 else
768 if (nPosition
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;
778 remove(pRemove);
782 m_pReadPage->m_pRead = m_pReadPage->m_aBuffer
783 + (nPosition - m_pReadPage->m_nOffset);
784 return SEEK_OK;
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */