bump product version to 6.3.0.0.beta1
[LibreOffice.git] / svl / source / misc / strmadpt.cxx
blob101984e0e0683a2f7cc8e75202249e716c36ef61
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/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;
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];
57 static const sal_uInt32 m_nPageSize = 1000;
59 std::multiset< sal_uInt32 > m_aMarks;
60 Page * m_pFirstPage;
61 Page * m_pReadPage;
62 Page * m_pWritePage;
63 sal_Int8 * m_pReadBuffer;
64 sal_uInt32 m_nReadBufferSize;
65 sal_uInt32 m_nReadBufferFilled;
66 sal_uInt32 m_nPages;
67 bool m_bEOF;
69 void remove(Page * pPage);
71 public:
72 inline SvDataPipe_Impl();
74 ~SvDataPipe_Impl();
76 inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize);
78 sal_uInt32 read();
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 )
98 , m_nPages( 0 )
99 , m_bEOF( false )
102 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8 * pBuffer,
103 sal_uInt32 nSize)
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);
118 // SvInputStream
120 bool SvInputStream::open()
122 if (GetError() != ERRCODE_NONE)
123 return false;
124 if (!(m_xSeekable.is() || m_pPipe))
126 if (!m_xStream.is())
128 SetError(ERRCODE_IO_INVALIDDEVICE);
129 return false;
131 m_xSeekable.set(m_xStream, uno::UNO_QUERY);
132 if (!m_xSeekable.is())
133 m_pPipe.reset( new SvDataPipe_Impl );
135 return true;
138 // virtual
139 std::size_t SvInputStream::GetData(void * pData, std::size_t const nSize)
141 if (!open())
143 SetError(ERRCODE_IO_CANTREAD);
144 return 0;
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);
160 return 0;
162 m_nSeekedFrom = STREAM_SEEK_TO_END;
164 for (;;)
166 sal_Int32 nRemain
167 = sal_Int32(
168 std::min(std::size_t(nSize - nRead),
169 std::size_t(std::numeric_limits<sal_Int32>::max())));
170 if (nRemain == 0)
171 break;
172 uno::Sequence< sal_Int8 > aBuffer;
173 sal_Int32 nCount;
176 nCount = m_xStream->readBytes(aBuffer, nRemain);
178 catch (const io::IOException&)
180 SetError(ERRCODE_IO_CANTREAD);
181 return nRead;
183 memcpy(static_cast< sal_Int8 * >(pData) + nRead,
184 aBuffer.getConstArray(), sal_uInt32(nCount));
185 nRead += nCount;
186 if (nCount < nRemain)
187 break;
190 else
192 if (m_nSeekedFrom != STREAM_SEEK_TO_END)
194 SetError(ERRCODE_IO_CANTREAD);
195 return 0;
197 m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
198 nRead = m_pPipe->read();
199 if (nRead < nSize && !m_pPipe->isEOF())
200 for (;;)
202 sal_Int32 nRemain
203 = sal_Int32(
204 std::min(
205 std::size_t(nSize - nRead),
206 std::size_t(std::numeric_limits<sal_Int32>::max())));
207 if (nRemain == 0)
208 break;
209 uno::Sequence< sal_Int8 > aBuffer;
210 sal_Int32 nCount;
213 nCount = m_xStream->readBytes(aBuffer, nRemain);
215 catch (const io::IOException&)
217 SetError(ERRCODE_IO_CANTREAD);
218 break;
220 m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
221 nRead += m_pPipe->read();
222 if (nCount < nRemain)
224 m_xStream->closeInput();
225 m_pPipe->setEOF();
226 break;
229 m_pPipe->clearReadBuffer();
231 return nRead;
234 // virtual
235 std::size_t SvInputStream::PutData(void const *, std::size_t)
237 SetError(ERRCODE_IO_NOTSUPPORTED);
238 return 0;
241 // virtual
242 void SvInputStream::FlushData()
245 // virtual
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);
250 if (open())
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&)
271 else
272 return Tell(); //@@@
274 else
275 return Tell();
277 else if (nPos == m_nSeekedFrom)
279 m_nSeekedFrom = STREAM_SEEK_TO_END;
280 return nPos;
282 else if (m_xSeekable.is())
286 m_xSeekable->seek(nPos);
287 m_nSeekedFrom = STREAM_SEEK_TO_END;
288 return nPos;
290 catch (const io::IOException&)
294 else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
296 m_nSeekedFrom = STREAM_SEEK_TO_END;
297 return nPos;
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 );
305 return nPos;
307 else if ( nPos == Tell() )
308 return nPos;
310 SetError(ERRCODE_IO_CANTSEEK);
311 return Tell();
314 // virtual
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)
324 SetBufferSize(0);
327 // virtual
328 SvInputStream::~SvInputStream()
330 if (m_xStream.is())
334 m_xStream->closeInput();
336 catch (const io::IOException&)
342 // SvOutputStream
344 // virtual
345 std::size_t SvOutputStream::GetData(void *, std::size_t)
347 SetError(ERRCODE_IO_NOTSUPPORTED);
348 return 0;
351 // virtual
352 std::size_t SvOutputStream::PutData(void const * pData, std::size_t nSize)
354 if (!m_xStream.is())
356 SetError(ERRCODE_IO_CANTWRITE);
357 return 0;
359 std::size_t nWritten = 0;
360 for (;;)
362 sal_Int32 nRemain
363 = sal_Int32(
364 std::min(std::size_t(nSize - nWritten),
365 std::size_t(std::numeric_limits<sal_Int32>::max())));
366 if (nRemain == 0)
367 break;
370 m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
371 static_cast<const sal_Int8 * >(pData)
372 + nWritten,
373 nRemain));
375 catch (const io::IOException&)
377 SetError(ERRCODE_IO_CANTWRITE);
378 break;
380 nWritten += nRemain;
382 return nWritten;
385 // virtual
386 sal_uInt64 SvOutputStream::SeekPos(sal_uInt64)
388 SetError(ERRCODE_IO_NOTSUPPORTED);
389 return 0;
392 // virtual
393 void SvOutputStream::FlushData()
395 if (!m_xStream.is())
397 SetError(ERRCODE_IO_INVALIDDEVICE);
398 return;
402 m_xStream->flush();
404 catch (const io::IOException&)
409 // virtual
410 void SvOutputStream::SetSize(sal_uInt64)
412 SetError(ERRCODE_IO_NOTSUPPORTED);
415 SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const &
416 rTheStream):
417 m_xStream(rTheStream)
419 SetBufferSize(0);
422 // virtual
423 SvOutputStream::~SvOutputStream()
425 if (m_xStream.is())
429 m_xStream->closeOutput();
431 catch (const io::IOException&)
438 // SvDataPipe_Impl
441 void SvDataPipe_Impl::remove(Page * pPage)
443 if (
444 pPage != m_pFirstPage ||
445 m_pReadPage == m_pFirstPage ||
447 !m_aMarks.empty() &&
448 *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize
452 return;
455 m_pFirstPage = m_pFirstPage->m_pNext;
457 if (m_nPages <= 100) // min pages
458 return;
460 pPage->m_pPrev->m_pNext = pPage->m_pNext;
461 pPage->m_pNext->m_pPrev = pPage->m_pPrev;
462 std::free(pPage);
463 --m_nPages;
466 SvDataPipe_Impl::~SvDataPipe_Impl()
468 if (m_pFirstPage != nullptr)
469 for (Page * pPage = m_pFirstPage;;)
471 Page * pNext = pPage->m_pNext;
472 std::free(pPage);
473 if (pNext == m_pFirstPage)
474 break;
475 pPage = pNext;
479 sal_uInt32 SvDataPipe_Impl::read()
481 if (m_pReadBuffer == nullptr || m_nReadBufferSize == 0 || m_pReadPage == nullptr)
482 return 0;
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;
491 while (nRemain > 0)
493 sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
494 - m_pReadPage->m_pRead),
495 nRemain);
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;
501 nRemain -= nBlock;
503 if (m_pReadPage == m_pWritePage)
504 break;
506 if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd)
508 Page * pRemove = m_pReadPage;
509 m_pReadPage = pRemove->m_pNext;
510 remove(pRemove);
514 return nSize - nRemain;
517 void SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
519 if (nSize == 0)
520 return;
522 if (m_pWritePage == nullptr)
524 m_pFirstPage
525 = static_cast< Page * >(std::malloc(sizeof (Page)
526 + m_nPageSize
527 - 1));
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;
536 ++m_nPages;
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()
553 - nPosition)) :
556 if (nBlock > 0)
558 memcpy(m_pReadBuffer + m_nReadBufferFilled, pBuffer,
559 nBlock);
560 m_nReadBufferFilled += nBlock;
561 nRemain -= nBlock;
563 nPosition += 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;
572 if (nRemain <= 0)
573 return;
575 for (;;)
577 sal_uInt32 nBlock
578 = std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize
579 - m_pWritePage->m_pEnd),
580 nRemain);
581 memcpy(m_pWritePage->m_pEnd, pBuffer, nBlock);
582 m_pWritePage->m_pEnd += nBlock;
583 pBuffer += nBlock;
584 nRemain -= nBlock;
586 if (nRemain == 0)
587 break;
589 if (m_pWritePage->m_pNext == m_pFirstPage)
591 if (m_nPages == std::numeric_limits< sal_uInt32 >::max())
592 break;
594 Page * pNew
595 = static_cast< Page * >(std::malloc(
596 sizeof (Page) + m_nPageSize
597 - 1));
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;
603 ++m_nPages;
606 m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset
607 + m_nPageSize;
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
616 nPosition)
618 if (m_pFirstPage == nullptr)
619 return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
621 if (nPosition
622 <= m_pReadPage->m_nOffset
623 + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer))
625 if (nPosition
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;
636 else
638 if (nPosition
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;
648 remove(pRemove);
652 m_pReadPage->m_pRead = m_pReadPage->m_aBuffer
653 + (nPosition - m_pReadPage->m_nOffset);
654 return SEEK_OK;
657 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */