LibreOffice Module svl (master) 1
strmadpt.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <algorithm>
22#include <limits>
23#include <set>
24#include <string.h>
25
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>
34#include <utility>
35
36using namespace com::sun::star;
37
39{
40public:
42
43private:
44 struct Page
45 {
51 sal_uInt32 m_nOffset;
53 };
54 static const sal_uInt32 m_nPageSize = 1000;
55
56 std::multiset< sal_uInt32 > m_aMarks;
63 sal_uInt32 m_nPages;
64 bool m_bEOF;
65
66 void remove(Page * pPage);
67
68public:
69 inline SvDataPipe_Impl();
70
72
73 inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize);
74
75 sal_uInt32 read();
76
77 void clearReadBuffer() { m_pReadBuffer = nullptr; }
78
79 void write(sal_Int8 const * pBuffer, sal_uInt32 nSize);
80
81 void setEOF() { m_bEOF = true; }
82
83 inline bool isEOF() const;
84
85 SeekResult setReadPosition(sal_uInt32 nPosition);
86};
87
89 : m_pFirstPage( nullptr )
90 , m_pReadPage( nullptr )
91 , m_pWritePage( nullptr )
92 , m_pReadBuffer( nullptr )
93 , m_nReadBufferSize( 0 )
94 , m_nReadBufferFilled( 0 )
95 , m_nPages( 0 )
96 , m_bEOF( false )
97{}
98
100 sal_uInt32 nSize)
101{
102 m_pReadBuffer = pBuffer;
103 m_nReadBufferSize = nSize;
105}
106
107inline bool SvDataPipe_Impl::isEOF() const
108{
109 return m_bEOF && m_pReadPage == m_pWritePage
111}
112
113
114
115// SvInputStream
116
118{
119 if (GetError() != ERRCODE_NONE)
120 return false;
121 if (!(m_xSeekable.is() || m_pPipe))
122 {
123 if (!m_xStream.is())
124 {
126 return false;
127 }
128 m_xSeekable.set(m_xStream, uno::UNO_QUERY);
129 if (!m_xSeekable.is())
130 m_pPipe.reset( new SvDataPipe_Impl );
131 }
132 return true;
133}
134
135// virtual
136std::size_t SvInputStream::GetData(void * pData, std::size_t const nSize)
137{
138 if (!open())
139 {
141 return 0;
142 }
143 // check if a truncated STREAM_SEEK_TO_END was passed
144 assert(m_nSeekedFrom != SAL_MAX_UINT32);
145 sal_uInt32 nRead = 0;
146 if (m_xSeekable.is())
147 {
149 {
150 try
151 {
153 }
154 catch (const io::IOException&)
155 {
157 return 0;
158 }
160 }
161 for (;;)
162 {
163 sal_Int32 nRemain
164 = sal_Int32(
165 std::min(std::size_t(nSize - nRead),
166 std::size_t(std::numeric_limits<sal_Int32>::max())));
167 if (nRemain == 0)
168 break;
169 uno::Sequence< sal_Int8 > aBuffer;
170 sal_Int32 nCount;
171 try
172 {
173 nCount = m_xStream->readBytes(aBuffer, nRemain);
174 }
175 catch (const io::IOException&)
176 {
178 return nRead;
179 }
180 memcpy(static_cast< sal_Int8 * >(pData) + nRead,
181 aBuffer.getConstArray(), sal_uInt32(nCount));
182 nRead += nCount;
183 if (nCount < nRemain)
184 break;
185 }
186 }
187 else
188 {
190 {
192 return 0;
193 }
194 m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
195 nRead = m_pPipe->read();
196 if (nRead < nSize && !m_pPipe->isEOF())
197 for (;;)
198 {
199 sal_Int32 nRemain
200 = sal_Int32(
201 std::min(
202 std::size_t(nSize - nRead),
203 std::size_t(std::numeric_limits<sal_Int32>::max())));
204 if (nRemain == 0)
205 break;
206 uno::Sequence< sal_Int8 > aBuffer;
207 sal_Int32 nCount;
208 try
209 {
210 nCount = m_xStream->readBytes(aBuffer, nRemain);
211 }
212 catch (const io::IOException&)
213 {
215 break;
216 }
217 m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
218 nRead += m_pPipe->read();
219 if (nCount < nRemain)
220 {
221 m_xStream->closeInput();
222 m_pPipe->setEOF();
223 break;
224 }
225 }
226 m_pPipe->clearReadBuffer();
227 }
228 return nRead;
229}
230
231// virtual
232std::size_t SvInputStream::PutData(void const *, std::size_t)
233{
235 return 0;
236}
237
238// virtual
240{}
241
242// virtual
243sal_uInt64 SvInputStream::SeekPos(sal_uInt64 const nPos)
244{
245 // check if a truncated STREAM_SEEK_TO_END was passed
246 assert(nPos != SAL_MAX_UINT32);
247 if (open())
248 {
250 {
252 {
253 if (m_xSeekable.is())
254 try
255 {
256 sal_Int64 nLength = m_xSeekable->getLength();
257 OSL_ASSERT(nLength >= 0);
260 {
262 return sal_uInt64(nLength);
263 }
264 }
265 catch (const io::IOException&)
266 {
267 }
268 else
269 return Tell(); //@@@
270 }
271 else
272 return Tell();
273 }
274 else if (nPos == m_nSeekedFrom)
275 {
277 return nPos;
278 }
279 else if (m_xSeekable.is())
280 {
281 try
282 {
283 m_xSeekable->seek(nPos);
285 return nPos;
286 }
287 catch (const io::IOException&)
288 {
289 }
290 }
291 else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
292 {
294 return nPos;
295 }
296 else if ( nPos > Tell() )
297 {
298 // Read out the bytes
299 sal_Int32 nRead = nPos - Tell();
300 uno::Sequence< sal_Int8 > aBuffer;
301 m_xStream->readBytes( aBuffer, nRead );
302 return nPos;
303 }
304 else if ( nPos == Tell() )
305 return nPos;
306 }
308 return Tell();
309}
310
311// virtual
313{
315}
316
317SvInputStream::SvInputStream( css::uno::Reference< css::io::XInputStream > xTheStream):
318 m_xStream(std::move(xTheStream)),
319 m_nSeekedFrom(STREAM_SEEK_TO_END)
320{
321 SetBufferSize(0);
322}
323
324// virtual
326{
327 if (m_xStream.is())
328 {
329 try
330 {
331 m_xStream->closeInput();
332 }
333 catch (const io::IOException&)
334 {
335 }
336 }
337}
338
339// SvOutputStream
340
341// virtual
342std::size_t SvOutputStream::GetData(void *, std::size_t)
343{
345 return 0;
346}
347
348// virtual
349std::size_t SvOutputStream::PutData(void const * pData, std::size_t nSize)
350{
351 if (!m_xStream.is())
352 {
354 return 0;
355 }
356 std::size_t nWritten = 0;
357 for (;;)
358 {
359 sal_Int32 nRemain
360 = sal_Int32(
361 std::min(std::size_t(nSize - nWritten),
362 std::size_t(std::numeric_limits<sal_Int32>::max())));
363 if (nRemain == 0)
364 break;
365 try
366 {
367 m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
368 static_cast<const sal_Int8 * >(pData)
369 + nWritten,
370 nRemain));
371 }
372 catch (const io::IOException&)
373 {
375 break;
376 }
377 nWritten += nRemain;
378 }
379 return nWritten;
380}
381
382// virtual
383sal_uInt64 SvOutputStream::SeekPos(sal_uInt64)
384{
386 return 0;
387}
388
389// virtual
391{
392 if (!m_xStream.is())
393 {
395 return;
396 }
397 try
398 {
399 m_xStream->flush();
400 }
401 catch (const io::IOException&)
402 {
403 }
404}
405
406// virtual
408{
410}
411
412SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > xTheStream):
413 m_xStream(std::move(xTheStream))
414{
415 SetBufferSize(0);
416}
417
418// virtual
420{
421 if (m_xStream.is())
422 {
423 try
424 {
425 m_xStream->closeOutput();
426 }
427 catch (const io::IOException&)
428 {
429 }
430 }
431}
432
433
434// SvDataPipe_Impl
435
436
438{
439 if (
440 pPage != m_pFirstPage ||
442 (
443 !m_aMarks.empty() &&
445 )
446 )
447 {
448 return;
449 }
450
452
453 if (m_nPages <= 100) // min pages
454 return;
455
456 pPage->m_pPrev->m_pNext = pPage->m_pNext;
457 pPage->m_pNext->m_pPrev = pPage->m_pPrev;
458 std::free(pPage);
459 --m_nPages;
460}
461
463{
464 if (m_pFirstPage != nullptr)
465 for (Page * pPage = m_pFirstPage;;)
466 {
467 Page * pNext = pPage->m_pNext;
468 std::free(pPage);
469 if (pNext == m_pFirstPage)
470 break;
471 pPage = pNext;
472 }
473}
474
476{
477 if (m_pReadBuffer == nullptr || m_nReadBufferSize == 0 || m_pReadPage == nullptr)
478 return 0;
479
480 sal_uInt32 nSize = m_nReadBufferSize;
481 sal_uInt32 nRemain = m_nReadBufferSize - m_nReadBufferFilled;
482
486
487 while (nRemain > 0)
488 {
489 sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
491 nRemain);
492 memcpy(m_pReadBuffer, m_pReadPage->m_pRead, nBlock);
493 m_pReadPage->m_pRead += nBlock;
494 m_pReadBuffer += nBlock;
495 m_nReadBufferSize -= nBlock;
497 nRemain -= nBlock;
498
500 break;
501
503 {
504 Page * pRemove = m_pReadPage;
505 m_pReadPage = pRemove->m_pNext;
506 remove(pRemove);
507 }
508 }
509
510 return nSize - nRemain;
511}
512
513void SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
514{
515 if (nSize == 0)
516 return;
517
518 if (m_pWritePage == nullptr)
519 {
521 = static_cast< Page * >(std::malloc(sizeof (Page)
523 - 1));
532 ++m_nPages;
533 }
534
535 sal_uInt32 nRemain = nSize;
536
537 if (m_pReadBuffer != nullptr && m_pReadPage == m_pWritePage
539 {
540 sal_uInt32 nBlock = std::min(nRemain,
541 sal_uInt32(m_nReadBufferSize
543 sal_uInt32 nPosition = m_pWritePage->m_nOffset
546 if (!m_aMarks.empty())
547 nBlock = *m_aMarks.begin() > nPosition ?
548 std::min(nBlock, sal_uInt32(*m_aMarks.begin()
549 - nPosition)) :
550 0;
551
552 if (nBlock > 0)
553 {
554 memcpy(m_pReadBuffer + m_nReadBufferFilled, pBuffer,
555 nBlock);
556 m_nReadBufferFilled += nBlock;
557 nRemain -= nBlock;
558
559 nPosition += nBlock;
562 + nPosition % m_nPageSize;
565 }
566 }
567
568 if (nRemain <= 0)
569 return;
570
571 for (;;)
572 {
573 sal_uInt32 nBlock
574 = std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize
576 nRemain);
577 memcpy(m_pWritePage->m_pEnd, pBuffer, nBlock);
578 m_pWritePage->m_pEnd += nBlock;
579 pBuffer += nBlock;
580 nRemain -= nBlock;
581
582 if (nRemain == 0)
583 break;
584
586 {
587 if (m_nPages == std::numeric_limits< sal_uInt32 >::max())
588 break;
589
590 Page * pNew
591 = static_cast< Page * >(std::malloc(
592 sizeof (Page) + m_nPageSize
593 - 1));
594 pNew->m_pPrev = m_pWritePage;
596
598 m_pWritePage->m_pNext = pNew;
599 ++m_nPages;
600 }
601
603 + m_nPageSize;
608 }
609}
610
612 nPosition)
613{
614 if (m_pFirstPage == nullptr)
615 return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
616
617 if (nPosition
620 {
621 if (nPosition
624 return SEEK_BEFORE_MARKED;
625
626 while (nPosition < m_pReadPage->m_nOffset)
627 {
630 }
631 }
632 else
633 {
634 if (nPosition
637 return SEEK_PAST_END;
638
639 while (m_pReadPage != m_pWritePage
640 && nPosition >= m_pReadPage->m_nOffset + m_nPageSize)
641 {
642 Page * pRemove = m_pReadPage;
643 m_pReadPage = pRemove->m_pNext;
644 remove(pRemove);
645 }
646 }
647
649 + (nPosition - m_pReadPage->m_nOffset);
650 return SEEK_OK;
651}
652
653/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt32 m_nReadBufferFilled
Definition: strmadpt.cxx:62
void remove(Page *pPage)
Definition: strmadpt.cxx:437
sal_Int8 * m_pReadBuffer
Definition: strmadpt.cxx:60
void write(sal_Int8 const *pBuffer, sal_uInt32 nSize)
Definition: strmadpt.cxx:513
std::multiset< sal_uInt32 > m_aMarks
Definition: strmadpt.cxx:56
sal_uInt32 m_nReadBufferSize
Definition: strmadpt.cxx:61
sal_uInt32 read()
Definition: strmadpt.cxx:475
Page * m_pReadPage
Definition: strmadpt.cxx:58
SeekResult setReadPosition(sal_uInt32 nPosition)
Definition: strmadpt.cxx:611
Page * m_pWritePage
Definition: strmadpt.cxx:59
static const sal_uInt32 m_nPageSize
Definition: strmadpt.cxx:54
Page * m_pFirstPage
Definition: strmadpt.cxx:57
sal_uInt32 m_nPages
Definition: strmadpt.cxx:63
bool isEOF() const
Definition: strmadpt.cxx:107
void clearReadBuffer()
Definition: strmadpt.cxx:77
void setReadBuffer(sal_Int8 *pBuffer, sal_uInt32 nSize)
Definition: strmadpt.cxx:99
css::uno::Reference< css::io::XInputStream > m_xStream
Definition: instrm.hxx:38
SvInputStream(css::uno::Reference< css::io::XInputStream > xTheStream)
Definition: strmadpt.cxx:317
SVL_DLLPRIVATE bool open()
Definition: strmadpt.cxx:117
css::uno::Reference< css::io::XSeekable > m_xSeekable
Definition: instrm.hxx:39
virtual SVL_DLLPRIVATE std::size_t PutData(void const *, std::size_t) override
Definition: strmadpt.cxx:232
virtual ~SvInputStream() override
Definition: strmadpt.cxx:325
sal_uInt64 m_nSeekedFrom
Definition: instrm.hxx:41
std::unique_ptr< SvDataPipe_Impl > m_pPipe
Definition: instrm.hxx:40
virtual SVL_DLLPRIVATE std::size_t GetData(void *pData, std::size_t nSize) override
Definition: strmadpt.cxx:136
virtual SVL_DLLPRIVATE sal_uInt64 SeekPos(sal_uInt64 nPos) override
Definition: strmadpt.cxx:243
virtual SVL_DLLPRIVATE void SetSize(sal_uInt64) override
Definition: strmadpt.cxx:312
virtual SVL_DLLPRIVATE void FlushData() override
Definition: strmadpt.cxx:239
SvOutputStream(css::uno::Reference< css::io::XOutputStream > xTheStream)
Definition: strmadpt.cxx:412
virtual SVL_DLLPRIVATE void FlushData() override
Definition: strmadpt.cxx:390
virtual ~SvOutputStream() override
Definition: strmadpt.cxx:419
virtual SVL_DLLPRIVATE std::size_t PutData(void const *pData, std::size_t nSize) override
Definition: strmadpt.cxx:349
virtual SVL_DLLPRIVATE sal_uInt64 SeekPos(sal_uInt64) override
Definition: strmadpt.cxx:383
css::uno::Reference< css::io::XOutputStream > m_xStream
Definition: outstrm.hxx:34
virtual SVL_DLLPRIVATE std::size_t GetData(void *, std::size_t) override
Definition: strmadpt.cxx:342
virtual SVL_DLLPRIVATE void SetSize(sal_uInt64) override
Definition: strmadpt.cxx:407
sal_uInt64 Tell() const
void SetBufferSize(sal_uInt16 m_nBufSize)
void SetError(ErrCode nErrorCode)
ErrCode GetError() const
int nCount
#define ERRCODE_IO_INVALIDDEVICE
#define ERRCODE_IO_CANTREAD
#define ERRCODE_IO_CANTSEEK
#define ERRCODE_IO_CANTWRITE
#define ERRCODE_IO_NOTSUPPORTED
#define ERRCODE_NONE
sal_uInt16 nPos
std::unique_ptr< sal_Int32[]> pData
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
#define STREAM_SEEK_TO_END
sal_uInt32 m_nOffset
Definition: strmadpt.cxx:51
sal_Int8 * m_pRead
Definition: strmadpt.cxx:49
sal_Int8 * m_pStart
Definition: strmadpt.cxx:48
sal_Int8 m_aBuffer[1]
Definition: strmadpt.cxx:52
signed char sal_Int8
#define SAL_MAX_UINT32
Reference< XStream > m_xStream
std::unique_ptr< char[]> aBuffer
sal_Int32 nLength