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
35 using namespace com::sun::star;
36
37 class SvDataPipe_Impl
38 {
39 public:
40 enum SeekResult { SEEK_BEFORE_MARKED, SEEK_OK, SEEK_PAST_END };
41
42 private:
43 struct Page
44 {
45 Page * m_pPrev;
46 Page * m_pNext;
47 sal_Int8 * m_pStart;
48 sal_Int8 * m_pRead;
49 sal_Int8 * m_pEnd;
50 sal_uInt32 m_nOffset;
51 sal_Int8 m_aBuffer[1];
52 };
53 static const sal_uInt32 m_nPageSize = 1000;
54
55 std::multiset< sal_uInt32 > m_aMarks;
56 Page * m_pFirstPage;
57 Page * m_pReadPage;
58 Page * m_pWritePage;
59 sal_Int8 * m_pReadBuffer;
60 sal_uInt32 m_nReadBufferSize;
61 sal_uInt32 m_nReadBufferFilled;
62 sal_uInt32 m_nPages;
63 bool m_bEOF;
64
65 void remove(Page * pPage);
66
67 public:
68 inline SvDataPipe_Impl();
69
70 ~SvDataPipe_Impl();
71
72 inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize);
73
74 sal_uInt32 read();
75
clearReadBuffer()76 void clearReadBuffer() { m_pReadBuffer = nullptr; }
77
78 void write(sal_Int8 const * pBuffer, sal_uInt32 nSize);
79
setEOF()80 void setEOF() { m_bEOF = true; }
81
82 inline bool isEOF() const;
83
84 SeekResult setReadPosition(sal_uInt32 nPosition);
85 };
86
SvDataPipe_Impl()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 )
94 , m_nPages( 0 )
95 , m_bEOF( false )
96 {}
97
setReadBuffer(sal_Int8 * pBuffer,sal_uInt32 nSize)98 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8 * pBuffer,
99 sal_uInt32 nSize)
100 {
101 m_pReadBuffer = pBuffer;
102 m_nReadBufferSize = nSize;
103 m_nReadBufferFilled = 0;
104 }
105
isEOF() const106 inline bool SvDataPipe_Impl::isEOF() const
107 {
108 return m_bEOF && m_pReadPage == m_pWritePage
109 && (!m_pReadPage || m_pReadPage->m_pRead == m_pReadPage->m_pEnd);
110 }
111
112
113
114 // SvInputStream
115
open()116 bool SvInputStream::open()
117 {
118 if (GetError() != ERRCODE_NONE)
119 return false;
120 if (!(m_xSeekable.is() || m_pPipe))
121 {
122 if (!m_xStream.is())
123 {
124 SetError(ERRCODE_IO_INVALIDDEVICE);
125 return false;
126 }
127 m_xSeekable.set(m_xStream, uno::UNO_QUERY);
128 if (!m_xSeekable.is())
129 m_pPipe.reset( new SvDataPipe_Impl );
130 }
131 return true;
132 }
133
134 // virtual
GetData(void * pData,std::size_t const nSize)135 std::size_t SvInputStream::GetData(void * pData, std::size_t const nSize)
136 {
137 if (!open())
138 {
139 SetError(ERRCODE_IO_CANTREAD);
140 return 0;
141 }
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())
146 {
147 if (m_nSeekedFrom != STREAM_SEEK_TO_END)
148 {
149 try
150 {
151 m_xSeekable->seek(m_nSeekedFrom);
152 }
153 catch (const io::IOException&)
154 {
155 SetError(ERRCODE_IO_CANTREAD);
156 return 0;
157 }
158 m_nSeekedFrom = STREAM_SEEK_TO_END;
159 }
160 for (;;)
161 {
162 sal_Int32 nRemain
163 = sal_Int32(
164 std::min(std::size_t(nSize - nRead),
165 std::size_t(std::numeric_limits<sal_Int32>::max())));
166 if (nRemain == 0)
167 break;
168 uno::Sequence< sal_Int8 > aBuffer;
169 sal_Int32 nCount;
170 try
171 {
172 nCount = m_xStream->readBytes(aBuffer, nRemain);
173 }
174 catch (const io::IOException&)
175 {
176 SetError(ERRCODE_IO_CANTREAD);
177 return nRead;
178 }
179 memcpy(static_cast< sal_Int8 * >(pData) + nRead,
180 aBuffer.getConstArray(), sal_uInt32(nCount));
181 nRead += nCount;
182 if (nCount < nRemain)
183 break;
184 }
185 }
186 else
187 {
188 if (m_nSeekedFrom != STREAM_SEEK_TO_END)
189 {
190 SetError(ERRCODE_IO_CANTREAD);
191 return 0;
192 }
193 m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
194 nRead = m_pPipe->read();
195 if (nRead < nSize && !m_pPipe->isEOF())
196 for (;;)
197 {
198 sal_Int32 nRemain
199 = sal_Int32(
200 std::min(
201 std::size_t(nSize - nRead),
202 std::size_t(std::numeric_limits<sal_Int32>::max())));
203 if (nRemain == 0)
204 break;
205 uno::Sequence< sal_Int8 > aBuffer;
206 sal_Int32 nCount;
207 try
208 {
209 nCount = m_xStream->readBytes(aBuffer, nRemain);
210 }
211 catch (const io::IOException&)
212 {
213 SetError(ERRCODE_IO_CANTREAD);
214 break;
215 }
216 m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
217 nRead += m_pPipe->read();
218 if (nCount < nRemain)
219 {
220 m_xStream->closeInput();
221 m_pPipe->setEOF();
222 break;
223 }
224 }
225 m_pPipe->clearReadBuffer();
226 }
227 return nRead;
228 }
229
230 // virtual
PutData(void const *,std::size_t)231 std::size_t SvInputStream::PutData(void const *, std::size_t)
232 {
233 SetError(ERRCODE_IO_NOTSUPPORTED);
234 return 0;
235 }
236
237 // virtual
FlushData()238 void SvInputStream::FlushData()
239 {}
240
241 // virtual
SeekPos(sal_uInt64 const nPos)242 sal_uInt64 SvInputStream::SeekPos(sal_uInt64 const nPos)
243 {
244 // check if a truncated STREAM_SEEK_TO_END was passed
245 assert(nPos != SAL_MAX_UINT32);
246 if (open())
247 {
248 if (nPos == STREAM_SEEK_TO_END)
249 {
250 if (m_nSeekedFrom == STREAM_SEEK_TO_END)
251 {
252 if (m_xSeekable.is())
253 try
254 {
255 sal_Int64 nLength = m_xSeekable->getLength();
256 OSL_ASSERT(nLength >= 0);
257 if (o3tl::make_unsigned(nLength)
258 < STREAM_SEEK_TO_END)
259 {
260 m_nSeekedFrom = Tell();
261 return sal_uInt64(nLength);
262 }
263 }
264 catch (const io::IOException&)
265 {
266 }
267 else
268 return Tell(); //@@@
269 }
270 else
271 return Tell();
272 }
273 else if (nPos == m_nSeekedFrom)
274 {
275 m_nSeekedFrom = STREAM_SEEK_TO_END;
276 return nPos;
277 }
278 else if (m_xSeekable.is())
279 {
280 try
281 {
282 m_xSeekable->seek(nPos);
283 m_nSeekedFrom = STREAM_SEEK_TO_END;
284 return nPos;
285 }
286 catch (const io::IOException&)
287 {
288 }
289 }
290 else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
291 {
292 m_nSeekedFrom = STREAM_SEEK_TO_END;
293 return nPos;
294 }
295 else if ( nPos > Tell() )
296 {
297 // Read out the bytes
298 sal_Int32 nRead = nPos - Tell();
299 uno::Sequence< sal_Int8 > aBuffer;
300 m_xStream->readBytes( aBuffer, nRead );
301 return nPos;
302 }
303 else if ( nPos == Tell() )
304 return nPos;
305 }
306 SetError(ERRCODE_IO_CANTSEEK);
307 return Tell();
308 }
309
310 // virtual
SetSize(sal_uInt64)311 void SvInputStream::SetSize(sal_uInt64)
312 {
313 SetError(ERRCODE_IO_NOTSUPPORTED);
314 }
315
SvInputStream(css::uno::Reference<css::io::XInputStream> const & rTheStream)316 SvInputStream::SvInputStream( css::uno::Reference< css::io::XInputStream > const & rTheStream):
317 m_xStream(rTheStream),
318 m_nSeekedFrom(STREAM_SEEK_TO_END)
319 {
320 SetBufferSize(0);
321 }
322
323 // virtual
~SvInputStream()324 SvInputStream::~SvInputStream()
325 {
326 if (m_xStream.is())
327 {
328 try
329 {
330 m_xStream->closeInput();
331 }
332 catch (const io::IOException&)
333 {
334 }
335 }
336 }
337
338 // SvOutputStream
339
340 // virtual
GetData(void *,std::size_t)341 std::size_t SvOutputStream::GetData(void *, std::size_t)
342 {
343 SetError(ERRCODE_IO_NOTSUPPORTED);
344 return 0;
345 }
346
347 // virtual
PutData(void const * pData,std::size_t nSize)348 std::size_t SvOutputStream::PutData(void const * pData, std::size_t nSize)
349 {
350 if (!m_xStream.is())
351 {
352 SetError(ERRCODE_IO_CANTWRITE);
353 return 0;
354 }
355 std::size_t nWritten = 0;
356 for (;;)
357 {
358 sal_Int32 nRemain
359 = sal_Int32(
360 std::min(std::size_t(nSize - nWritten),
361 std::size_t(std::numeric_limits<sal_Int32>::max())));
362 if (nRemain == 0)
363 break;
364 try
365 {
366 m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
367 static_cast<const sal_Int8 * >(pData)
368 + nWritten,
369 nRemain));
370 }
371 catch (const io::IOException&)
372 {
373 SetError(ERRCODE_IO_CANTWRITE);
374 break;
375 }
376 nWritten += nRemain;
377 }
378 return nWritten;
379 }
380
381 // virtual
SeekPos(sal_uInt64)382 sal_uInt64 SvOutputStream::SeekPos(sal_uInt64)
383 {
384 SetError(ERRCODE_IO_NOTSUPPORTED);
385 return 0;
386 }
387
388 // virtual
FlushData()389 void SvOutputStream::FlushData()
390 {
391 if (!m_xStream.is())
392 {
393 SetError(ERRCODE_IO_INVALIDDEVICE);
394 return;
395 }
396 try
397 {
398 m_xStream->flush();
399 }
400 catch (const io::IOException&)
401 {
402 }
403 }
404
405 // virtual
SetSize(sal_uInt64)406 void SvOutputStream::SetSize(sal_uInt64)
407 {
408 SetError(ERRCODE_IO_NOTSUPPORTED);
409 }
410
SvOutputStream(uno::Reference<io::XOutputStream> const & rTheStream)411 SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const &
412 rTheStream):
413 m_xStream(rTheStream)
414 {
415 SetBufferSize(0);
416 }
417
418 // virtual
~SvOutputStream()419 SvOutputStream::~SvOutputStream()
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
remove(Page * pPage)437 void SvDataPipe_Impl::remove(Page * pPage)
438 {
439 if (
440 pPage != m_pFirstPage ||
441 m_pReadPage == m_pFirstPage ||
442 (
443 !m_aMarks.empty() &&
444 *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize
445 )
446 )
447 {
448 return;
449 }
450
451 m_pFirstPage = m_pFirstPage->m_pNext;
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
~SvDataPipe_Impl()462 SvDataPipe_Impl::~SvDataPipe_Impl()
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
read()475 sal_uInt32 SvDataPipe_Impl::read()
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
483 m_pReadBuffer += m_nReadBufferFilled;
484 m_nReadBufferSize -= m_nReadBufferFilled;
485 m_nReadBufferFilled = 0;
486
487 while (nRemain > 0)
488 {
489 sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
490 - m_pReadPage->m_pRead),
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;
496 m_nReadBufferFilled = 0;
497 nRemain -= nBlock;
498
499 if (m_pReadPage == m_pWritePage)
500 break;
501
502 if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd)
503 {
504 Page * pRemove = m_pReadPage;
505 m_pReadPage = pRemove->m_pNext;
506 remove(pRemove);
507 }
508 }
509
510 return nSize - nRemain;
511 }
512
write(sal_Int8 const * pBuffer,sal_uInt32 nSize)513 void SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
514 {
515 if (nSize == 0)
516 return;
517
518 if (m_pWritePage == nullptr)
519 {
520 m_pFirstPage
521 = static_cast< Page * >(std::malloc(sizeof (Page)
522 + m_nPageSize
523 - 1));
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;
532 ++m_nPages;
533 }
534
535 sal_uInt32 nRemain = nSize;
536
537 if (m_pReadBuffer != nullptr && m_pReadPage == m_pWritePage
538 && m_pReadPage->m_pRead == m_pWritePage->m_pEnd)
539 {
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()
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;
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;
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
575 - m_pWritePage->m_pEnd),
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
585 if (m_pWritePage->m_pNext == m_pFirstPage)
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;
595 pNew->m_pNext = m_pWritePage->m_pNext;
596
597 m_pWritePage->m_pNext->m_pPrev = pNew;
598 m_pWritePage->m_pNext = pNew;
599 ++m_nPages;
600 }
601
602 m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset
603 + m_nPageSize;
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;
608 }
609 }
610
setReadPosition(sal_uInt32 nPosition)611 SvDataPipe_Impl::SeekResult SvDataPipe_Impl::setReadPosition(sal_uInt32
612 nPosition)
613 {
614 if (m_pFirstPage == nullptr)
615 return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
616
617 if (nPosition
618 <= m_pReadPage->m_nOffset
619 + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer))
620 {
621 if (nPosition
622 < m_pFirstPage->m_nOffset
623 + (m_pFirstPage->m_pStart - m_pFirstPage->m_aBuffer))
624 return SEEK_BEFORE_MARKED;
625
626 while (nPosition < m_pReadPage->m_nOffset)
627 {
628 m_pReadPage->m_pRead = m_pReadPage->m_pStart;
629 m_pReadPage = m_pReadPage->m_pPrev;
630 }
631 }
632 else
633 {
634 if (nPosition
635 > m_pWritePage->m_nOffset
636 + (m_pWritePage->m_pEnd - m_pWritePage->m_aBuffer))
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
648 m_pReadPage->m_pRead = m_pReadPage->m_aBuffer
649 + (nPosition - m_pReadPage->m_nOffset);
650 return SEEK_OK;
651 }
652
653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
654