xref: /aoo41x/main/svl/source/misc/strmadpt.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 
31 #include <functional> // needed under Solaris when including <algorithm>...
32 
33 #include <algorithm>
34 #include <limits>
35 #include <set>
36 #include <rtl/alloc.h>
37 #include <rtl/memory.h>
38 #include <svl/instrm.hxx>
39 #include <svl/outstrm.hxx>
40 #include <svl/strmadpt.hxx>
41 
42 using namespace com::sun::star;
43 
44 //============================================================================
45 class SvDataPipe_Impl
46 {
47 public:
48 	enum SeekResult { SEEK_BEFORE_MARKED, SEEK_OK, SEEK_PAST_END };
49 
50 private:
51 	struct Page
52 	{
53 		Page * m_pPrev;
54 		Page * m_pNext;
55 		sal_Int8 * m_pStart;
56 		sal_Int8 * m_pRead;
57 		sal_Int8 * m_pEnd;
58 		sal_uInt32 m_nOffset;
59 		sal_Int8 m_aBuffer[1];
60 	};
61 
62 	std::multiset< sal_uInt32 > m_aMarks;
63 	Page * m_pFirstPage;
64 	Page * m_pReadPage;
65 	Page * m_pWritePage;
66 	sal_Int8 * m_pReadBuffer;
67 	sal_uInt32 m_nReadBufferSize;
68 	sal_uInt32 m_nReadBufferFilled;
69 	sal_uInt32 m_nPageSize;
70 	sal_uInt32 m_nMinPages;
71 	sal_uInt32 m_nMaxPages;
72 	sal_uInt32 m_nPages;
73 	bool m_bEOF;
74 
75 	bool remove(Page * pPage);
76 
77 public:
78 	inline SvDataPipe_Impl(sal_uInt32 nThePageSize = 1000,
79 						   sal_uInt32 nTheMinPages = 100,
80 						   sal_uInt32 nTheMaxPages
81 						       = std::numeric_limits< sal_uInt32 >::max());
82 
83 	~SvDataPipe_Impl();
84 
85 	inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize);
86 
87 	sal_uInt32 read();
88 
89 	void clearReadBuffer() { m_pReadBuffer = 0; }
90 
91 	sal_uInt32 write(sal_Int8 const * pBuffer, sal_uInt32 nSize);
92 
93 	void setEOF() { m_bEOF = true; }
94 
95 	inline bool isEOF() const;
96 
97 	bool addMark(sal_uInt32 nPosition);
98 
99 	bool removeMark(sal_uInt32 nPosition);
100 
101 	inline sal_uInt32 getReadPosition() const;
102 
103 	SeekResult setReadPosition(sal_uInt32 nPosition);
104 };
105 
106 SvDataPipe_Impl::SvDataPipe_Impl(sal_uInt32 nThePageSize,
107 								 sal_uInt32 nTheMinPages,
108 								 sal_uInt32 nTheMaxPages):
109 	m_pFirstPage(0),
110 	m_pReadPage(0),
111 	m_pWritePage(0),
112 	m_pReadBuffer(0),
113 	m_nPageSize(std::min< sal_uInt32 >(
114 		            std::max< sal_uInt32 >(nThePageSize, sal_uInt32(1)),
115 					sal_uInt32(std::numeric_limits< sal_uInt32 >::max()
116 							       - sizeof (Page) + 1))),
117 	m_nMinPages(std::max< sal_uInt32 >(nTheMinPages, sal_uInt32(1))),
118 	m_nMaxPages(std::max< sal_uInt32 >(nTheMaxPages, sal_uInt32(1))),
119 	m_nPages(0),
120 	m_bEOF(false)
121 {}
122 
123 inline void SvDataPipe_Impl::setReadBuffer(sal_Int8 * pBuffer,
124 										   sal_uInt32 nSize)
125 {
126 	m_pReadBuffer = pBuffer;
127 	m_nReadBufferSize = nSize;
128 	m_nReadBufferFilled = 0;
129 }
130 
131 inline bool SvDataPipe_Impl::isEOF() const
132 {
133 	return m_bEOF && m_pReadPage == m_pWritePage
134 	       && (!m_pReadPage || m_pReadPage->m_pRead == m_pReadPage->m_pEnd);
135 }
136 
137 inline sal_uInt32 SvDataPipe_Impl::getReadPosition() const
138 {
139 	return m_pReadPage == 0 ? 0 :
140 		                      m_pReadPage->m_nOffset
141 		                          + (m_pReadPage->m_pRead
142 									     - m_pReadPage->m_aBuffer);
143 }
144 
145 //============================================================================
146 //
147 //  SvOutputStreamOpenLockBytes
148 //
149 //============================================================================
150 
151 TYPEINIT1(SvOutputStreamOpenLockBytes, SvOpenLockBytes)
152 
153 //============================================================================
154 // virtual
155 ErrCode SvOutputStreamOpenLockBytes::ReadAt(sal_uLong, void *, sal_uLong, sal_uLong *)
156 	const
157 {
158 	return ERRCODE_IO_CANTREAD;
159 }
160 
161 //============================================================================
162 // virtual
163 ErrCode SvOutputStreamOpenLockBytes::WriteAt(sal_uLong nPos, void const * pBuffer,
164 											 sal_uLong nCount, sal_uLong * pWritten)
165 {
166 	if (nPos != m_nPosition)
167 		return ERRCODE_IO_CANTWRITE;
168 	return FillAppend(pBuffer, nCount, pWritten);
169 }
170 
171 //============================================================================
172 // virtual
173 ErrCode SvOutputStreamOpenLockBytes::Flush() const
174 {
175 	if (!m_xOutputStream.is())
176 		return ERRCODE_IO_CANTWRITE;
177 	try
178 	{
179 		m_xOutputStream->flush();
180 	}
181 	catch (io::IOException)
182 	{
183 		return ERRCODE_IO_CANTWRITE;
184 	}
185 	return ERRCODE_NONE;
186 }
187 
188 //============================================================================
189 // virtual
190 ErrCode SvOutputStreamOpenLockBytes::SetSize(sal_uLong)
191 {
192 	return ERRCODE_IO_NOTSUPPORTED;
193 }
194 
195 //============================================================================
196 // virtual
197 ErrCode SvOutputStreamOpenLockBytes::Stat(SvLockBytesStat * pStat,
198 										  SvLockBytesStatFlag) const
199 {
200 	if (pStat)
201 		pStat->nSize = m_nPosition;
202 	return ERRCODE_NONE;
203 }
204 
205 //============================================================================
206 // virtual
207 ErrCode SvOutputStreamOpenLockBytes::FillAppend(void const * pBuffer,
208 												sal_uLong nCount,
209 												sal_uLong * pWritten)
210 {
211 	if (!m_xOutputStream.is())
212 		return ERRCODE_IO_CANTWRITE;
213 	if (nCount > 0
214 		&& nCount > std::numeric_limits< sal_uLong >::max() - m_nPosition)
215 	{
216 		nCount = std::numeric_limits< sal_uLong >::max() - m_nPosition;
217 		if (nCount == 0)
218 			return ERRCODE_IO_CANTWRITE;
219 	}
220 	try
221 	{
222 		m_xOutputStream->
223 			writeBytes(uno::Sequence< sal_Int8 >(
224 				           static_cast< sal_Int8 const * >(pBuffer), nCount));
225 	}
226 	catch (io::IOException)
227 	{
228 		return ERRCODE_IO_CANTWRITE;
229 	}
230 	m_nPosition += nCount;
231 	if (pWritten)
232 		*pWritten = nCount;
233 	return ERRCODE_NONE;
234 }
235 
236 //============================================================================
237 // virtual
238 sal_uLong SvOutputStreamOpenLockBytes::Tell() const
239 {
240 	return m_nPosition;
241 }
242 
243 //============================================================================
244 // virtual
245 sal_uLong SvOutputStreamOpenLockBytes::Seek(sal_uLong)
246 {
247 	return m_nPosition;
248 }
249 
250 //============================================================================
251 // virtual
252 void SvOutputStreamOpenLockBytes::Terminate()
253 {
254 	if (m_xOutputStream.is())
255 		try
256 		{
257 			m_xOutputStream->closeOutput();
258 		}
259 		catch (io::IOException) {}
260 }
261 
262 //============================================================================
263 //
264 //  SvLockBytesInputStream
265 //
266 //============================================================================
267 
268 // virtual
269 uno::Any SAL_CALL SvLockBytesInputStream::queryInterface(uno::Type const &
270 														     rType)
271 	throw (uno::RuntimeException)
272 {
273 	uno::Any
274 		aReturn(cppu::queryInterface(rType,
275 									 static_cast< io::XInputStream * >(this),
276 									 static_cast< io::XSeekable * >(this)));
277 	return aReturn.hasValue() ? aReturn : OWeakObject::queryInterface(rType);
278 }
279 
280 //============================================================================
281 // virtual
282 void SAL_CALL SvLockBytesInputStream::acquire()	throw ()
283 {
284 	OWeakObject::acquire();
285 }
286 
287 //============================================================================
288 // virtual
289 void SAL_CALL SvLockBytesInputStream::release() throw ()
290 {
291 	OWeakObject::release();
292 }
293 
294 //============================================================================
295 // virtual
296 sal_Int32 SAL_CALL
297 SvLockBytesInputStream::readBytes(uno::Sequence< sal_Int8 > & rData,
298 								  sal_Int32 nBytesToRead)
299 	throw (io::IOException, uno::RuntimeException)
300 {
301     OSL_ASSERT(m_nPosition >= 0);
302 	if (!m_xLockBytes.Is())
303 		throw io::NotConnectedException();
304 	if (
305          nBytesToRead < 0 ||
306          (
307           static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE &&
308           nBytesToRead > 0
309          )
310        )
311     {
312 		throw io::IOException();
313     }
314 	rData.realloc(nBytesToRead);
315 	sal_Int32 nSize = 0;
316 	while (nSize < nBytesToRead)
317 	{
318 		sal_Size nCount;
319 		ErrCode nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(
320                                                   m_nPosition),
321 											  rData.getArray() + nSize,
322 											  nBytesToRead - nSize, &nCount);
323 		if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING)
324 			throw io::IOException();
325 		m_nPosition += nCount;
326 		nSize += nCount;
327 		if (nError == ERRCODE_NONE && nCount == 0)
328 			break;
329 	}
330 	rData.realloc(nSize);
331 	return nSize;
332 }
333 
334 //============================================================================
335 // virtual
336 sal_Int32 SAL_CALL
337 SvLockBytesInputStream::readSomeBytes(uno::Sequence< sal_Int8 > & rData,
338 									  sal_Int32 nMaxBytesToRead)
339 	throw (io::IOException, uno::RuntimeException)
340 {
341     OSL_ASSERT(m_nPosition >= 0);
342 	if (!m_xLockBytes.Is())
343 		throw io::NotConnectedException();
344 	if (static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE
345 		&& nMaxBytesToRead > 0)
346 		throw io::IOException();
347 	rData.realloc(nMaxBytesToRead);
348 	sal_Size nCount = 0;
349 	if (nMaxBytesToRead > 0)
350 	{
351 		ErrCode nError;
352 		do
353 		{
354 			nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(m_nPosition),
355 										  rData.getArray(),
356 										  nMaxBytesToRead < 0 ?
357 										      0 : nMaxBytesToRead,
358 										  &nCount);
359 			if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING)
360 				throw io::IOException();
361 			m_nPosition += nCount;
362 		}
363 		while (nCount == 0 && nError == ERRCODE_IO_PENDING);
364 	}
365 	rData.realloc(sal_Int32(nCount));
366 	return sal_Int32(nCount);
367 }
368 
369 //============================================================================
370 // virtual
371 void SAL_CALL SvLockBytesInputStream::skipBytes(sal_Int32 nBytesToSkip)
372 	throw (io::IOException, uno::RuntimeException)
373 {
374 	if (!m_xLockBytes.Is())
375 		throw io::NotConnectedException();
376 	if (nBytesToSkip < 0)
377 		throw io::IOException();
378 	if (nBytesToSkip > SAL_MAX_INT64 - m_nPosition)
379 		throw io::BufferSizeExceededException();
380 	m_nPosition += nBytesToSkip;
381 }
382 
383 //============================================================================
384 // virtual
385 sal_Int32 SAL_CALL SvLockBytesInputStream::available()
386 	throw (io::IOException, uno::RuntimeException)
387 {
388     OSL_ASSERT(m_nPosition >= 0);
389 	if (!m_xLockBytes.Is())
390 		throw io::NotConnectedException();
391 	SvLockBytesStat aStat;
392 	if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE)
393 		throw io::IOException();
394 	return aStat.nSize <= static_cast<sal_uInt64>(m_nPosition) ?
395 		       0 :
396            static_cast<sal_Size>(aStat.nSize - m_nPosition) <=
397                    static_cast<sal_uInt32>(SAL_MAX_INT32) ?
398                static_cast<sal_Int32>(aStat.nSize - m_nPosition) :
399                SAL_MAX_INT32;
400 }
401 
402 //============================================================================
403 // virtual
404 void SAL_CALL SvLockBytesInputStream::closeInput()
405 	throw (io::IOException, uno::RuntimeException)
406 {
407 	if (!m_xLockBytes.Is())
408 		throw io::NotConnectedException();
409 	m_xLockBytes = 0;
410 }
411 
412 //============================================================================
413 // virtual
414 void SAL_CALL SvLockBytesInputStream::seek(sal_Int64 nLocation)
415 	throw (lang::IllegalArgumentException, io::IOException,
416 		   uno::RuntimeException)
417 {
418 	if (nLocation < 0)
419 		throw lang::IllegalArgumentException();
420 	if (!m_xLockBytes.Is())
421 		throw io::NotConnectedException();
422 	m_nPosition = nLocation;
423 }
424 
425 //============================================================================
426 // virtual
427 sal_Int64 SAL_CALL SvLockBytesInputStream::getPosition()
428 	throw (io::IOException, uno::RuntimeException)
429 {
430 	if (!m_xLockBytes.Is())
431 		throw io::NotConnectedException();
432 	return m_nPosition;
433 }
434 
435 //============================================================================
436 // virtual
437 sal_Int64 SAL_CALL SvLockBytesInputStream::getLength()
438 	throw (io::IOException, uno::RuntimeException)
439 {
440 	if (!m_xLockBytes.Is())
441 		throw io::NotConnectedException();
442 	SvLockBytesStat aStat;
443 	if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE)
444 		throw io::IOException();
445 #if SAL_TYPES_SIZEOFPOINTER > 4 // avoid warnings if sal_Size < sal_Int64
446     if (aStat.nSize > static_cast<sal_uInt64>(SAL_MAX_INT64))
447 		throw io::IOException();
448 #endif
449 	return aStat.nSize;
450 }
451 
452 //============================================================================
453 //
454 //  SvInputStream
455 //
456 //============================================================================
457 
458 bool SvInputStream::open()
459 {
460 	if (GetError() != ERRCODE_NONE)
461 		return false;
462 	if (!(m_xSeekable.is() || m_pPipe))
463 	{
464 		if (!m_xStream.is())
465 		{
466 			SetError(ERRCODE_IO_INVALIDDEVICE);
467 			return false;
468 		}
469 		m_xSeekable
470 			= uno::Reference< io::XSeekable >(m_xStream, uno::UNO_QUERY);
471 		if (!m_xSeekable.is())
472 			m_pPipe = new SvDataPipe_Impl;
473 	}
474 	return true;
475 }
476 
477 //============================================================================
478 // virtual
479 sal_uLong SvInputStream::GetData(void * pData, sal_uLong nSize)
480 {
481 	if (!open())
482 	{
483 		SetError(ERRCODE_IO_CANTREAD);
484 		return 0;
485 	}
486 	sal_uInt32 nRead = 0;
487 	if (m_xSeekable.is())
488 	{
489 		if (m_nSeekedFrom != STREAM_SEEK_TO_END)
490 		{
491 			try
492 			{
493 				m_xSeekable->seek(m_nSeekedFrom);
494 			}
495 			catch (io::IOException)
496 			{
497 				SetError(ERRCODE_IO_CANTREAD);
498 				return 0;
499 			}
500 			m_nSeekedFrom = STREAM_SEEK_TO_END;
501 		}
502 		for (;;)
503 		{
504 			sal_Int32 nRemain
505 				= sal_Int32(
506 					std::min(sal_uLong(nSize - nRead),
507 							 sal_uLong(std::numeric_limits< sal_Int32 >::max())));
508 			if (nRemain == 0)
509 				break;
510 			uno::Sequence< sal_Int8 > aBuffer;
511 			sal_Int32 nCount;
512 			try
513 			{
514 				nCount = m_xStream->readBytes(aBuffer, nRemain);
515 			}
516 			catch (io::IOException)
517 			{
518 				SetError(ERRCODE_IO_CANTREAD);
519 				return nRead;
520 			}
521 			rtl_copyMemory(static_cast< sal_Int8 * >(pData) + nRead,
522 						   aBuffer.getConstArray(), sal_uInt32(nCount));
523 			nRead += nCount;
524 			if (nCount < nRemain)
525 				break;
526 		}
527 	}
528 	else
529 	{
530 		if (m_nSeekedFrom != STREAM_SEEK_TO_END)
531 		{
532 			SetError(ERRCODE_IO_CANTREAD);
533 			return 0;
534 		}
535 		m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize);
536 		nRead = m_pPipe->read();
537 		if (nRead < nSize && !m_pPipe->isEOF())
538 			for (;;)
539 			{
540 				sal_Int32 nRemain
541 					= sal_Int32(
542 						std::min(
543 							sal_uLong(nSize - nRead),
544 							sal_uLong(std::numeric_limits< sal_Int32 >::max())));
545 				if (nRemain == 0)
546 					break;
547 				uno::Sequence< sal_Int8 > aBuffer;
548 				sal_Int32 nCount;
549 				try
550 				{
551 					nCount = m_xStream->readBytes(aBuffer, nRemain);
552 				}
553 				catch (io::IOException)
554 				{
555 					SetError(ERRCODE_IO_CANTREAD);
556 					break;
557 				}
558 				m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount));
559 				nRead += m_pPipe->read();
560 				if (nCount < nRemain)
561 				{
562 					m_xStream->closeInput();
563 					m_pPipe->setEOF();
564 					break;
565 				}
566 			}
567 		m_pPipe->clearReadBuffer();
568 	}
569 	return nRead;
570 }
571 
572 //============================================================================
573 // virtual
574 sal_uLong SvInputStream::PutData(void const *, sal_uLong)
575 {
576 	SetError(ERRCODE_IO_NOTSUPPORTED);
577 	return 0;
578 }
579 
580 //============================================================================
581 // virtual
582 void SvInputStream::FlushData()
583 {}
584 
585 //============================================================================
586 // virtual
587 sal_uLong SvInputStream::SeekPos(sal_uLong nPos)
588 {
589 	if (open())
590 	{
591 		if (nPos == STREAM_SEEK_TO_END)
592 		{
593 			if (m_nSeekedFrom == STREAM_SEEK_TO_END)
594 			{
595 				if (m_xSeekable.is())
596 					try
597 					{
598 						sal_Int64 nLength = m_xSeekable->getLength();
599                         OSL_ASSERT(nLength >= 0);
600 						if (static_cast<sal_uInt64>(nLength)
601                             < STREAM_SEEK_TO_END)
602 						{
603 							m_nSeekedFrom = Tell();
604 							return sal_uLong(nLength);
605 						}
606 					}
607 					catch (io::IOException) {}
608 				else
609 					return Tell(); //@@@
610 			}
611 			else
612 				return Tell();
613 		}
614 		else if (nPos == m_nSeekedFrom)
615 		{
616 			m_nSeekedFrom = STREAM_SEEK_TO_END;
617 			return nPos;
618 		}
619 		else if (m_xSeekable.is())
620 			try
621 			{
622 				m_xSeekable->seek(nPos);
623 				m_nSeekedFrom = STREAM_SEEK_TO_END;
624 				return nPos;
625 			}
626 			catch (io::IOException) {}
627 		else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK)
628 		{
629 			m_nSeekedFrom = STREAM_SEEK_TO_END;
630 			return nPos;
631 		}
632 	}
633 	SetError(ERRCODE_IO_CANTSEEK);
634 	return Tell();
635 }
636 
637 //============================================================================
638 // virtual
639 void SvInputStream::SetSize(sal_uLong)
640 {
641 	SetError(ERRCODE_IO_NOTSUPPORTED);
642 }
643 
644 //============================================================================
645 SvInputStream::SvInputStream(
646 		com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
647 				const &
648 			rTheStream):
649 	m_xStream(rTheStream),
650 	m_pPipe(0),
651 	m_nSeekedFrom(STREAM_SEEK_TO_END)
652 {
653 	SetBufferSize(0);
654 }
655 
656 //============================================================================
657 // virtual
658 SvInputStream::~SvInputStream()
659 {
660 	if (m_xStream.is())
661 		try
662 		{
663 			m_xStream->closeInput();
664 		}
665 		catch (io::IOException) {}
666 	delete m_pPipe;
667 }
668 
669 //============================================================================
670 // virtual
671 sal_uInt16 SvInputStream::IsA() const
672 {
673 	return 0;
674 }
675 
676 //============================================================================
677 // virtual
678 void SvInputStream::AddMark(sal_uLong nPos)
679 {
680 	if (open() && m_pPipe)
681 		m_pPipe->addMark(nPos);
682 }
683 
684 //============================================================================
685 // virtual
686 void SvInputStream::RemoveMark(sal_uLong nPos)
687 {
688 	if (open() && m_pPipe)
689 		m_pPipe->removeMark(nPos);
690 }
691 
692 //============================================================================
693 //
694 //  SvOutputStream
695 //
696 //============================================================================
697 
698 // virtual
699 sal_uLong SvOutputStream::GetData(void *, sal_uLong)
700 {
701 	SetError(ERRCODE_IO_NOTSUPPORTED);
702 	return 0;
703 }
704 
705 //============================================================================
706 // virtual
707 sal_uLong SvOutputStream::PutData(void const * pData, sal_uLong nSize)
708 {
709 	if (!m_xStream.is())
710 	{
711 		SetError(ERRCODE_IO_CANTWRITE);
712 		return 0;
713 	}
714 	sal_uLong nWritten = 0;
715 	for (;;)
716 	{
717 		sal_Int32 nRemain
718 			= sal_Int32(
719 				std::min(sal_uLong(nSize - nWritten),
720 						 sal_uLong(std::numeric_limits< sal_Int32 >::max())));
721 		if (nRemain == 0)
722 			break;
723 		try
724 		{
725 			m_xStream->writeBytes(uno::Sequence< sal_Int8 >(
726 				                      static_cast<const sal_Int8 * >(pData)
727 									      + nWritten,
728 									  nRemain));
729 		}
730 		catch (io::IOException)
731 		{
732 			SetError(ERRCODE_IO_CANTWRITE);
733 			break;
734 		}
735 		nWritten += nRemain;
736 	}
737 	return nWritten;
738 }
739 
740 //============================================================================
741 // virtual
742 sal_uLong SvOutputStream::SeekPos(sal_uLong)
743 {
744 	SetError(ERRCODE_IO_NOTSUPPORTED);
745 	return 0;
746 }
747 
748 //============================================================================
749 // virtual
750 void SvOutputStream::FlushData()
751 {
752 	if (!m_xStream.is())
753 	{
754 		SetError(ERRCODE_IO_INVALIDDEVICE);
755 		return;
756 	}
757 	try
758 	{
759 		m_xStream->flush();
760 	}
761 	catch (io::IOException) {}
762 }
763 
764 //============================================================================
765 // virtual
766 void SvOutputStream::SetSize(sal_uLong)
767 {
768 	SetError(ERRCODE_IO_NOTSUPPORTED);
769 }
770 
771 //============================================================================
772 SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const &
773 							       rTheStream):
774 	m_xStream(rTheStream)
775 {
776 	SetBufferSize(0);
777 }
778 
779 //============================================================================
780 // virtual
781 SvOutputStream::~SvOutputStream()
782 {
783 	if (m_xStream.is())
784 		try
785 		{
786 			m_xStream->closeOutput();
787 		}
788 		catch (io::IOException) {}
789 }
790 
791 //============================================================================
792 // virtual
793 sal_uInt16 SvOutputStream::IsA() const
794 {
795 	return 0;
796 }
797 
798 //============================================================================
799 //
800 //  SvDataPipe_Impl
801 //
802 //============================================================================
803 
804 bool SvDataPipe_Impl::remove(Page * pPage)
805 {
806 	if (
807         pPage != m_pFirstPage ||
808         m_pReadPage == m_pFirstPage ||
809         (
810          !m_aMarks.empty() &&
811          *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize
812         )
813        )
814     {
815 		return false;
816     }
817 
818 	m_pFirstPage = m_pFirstPage->m_pNext;
819 
820 	if (m_nPages <= m_nMinPages)
821 		return true;
822 
823 	pPage->m_pPrev->m_pNext = pPage->m_pNext;
824 	pPage->m_pNext->m_pPrev = pPage->m_pPrev;
825 	rtl_freeMemory(pPage);
826 	--m_nPages;
827 
828 	return true;
829 }
830 
831 //============================================================================
832 SvDataPipe_Impl::~SvDataPipe_Impl()
833 {
834 	if (m_pFirstPage != 0)
835 		for (Page * pPage = m_pFirstPage;;)
836 		{
837 			Page * pNext = pPage->m_pNext;
838 			rtl_freeMemory(pPage);
839 			if (pNext == m_pFirstPage)
840 				break;
841 			pPage = pNext;
842 		}
843 }
844 
845 //============================================================================
846 sal_uInt32 SvDataPipe_Impl::read()
847 {
848 	if (m_pReadBuffer == 0 || m_nReadBufferSize == 0 || m_pReadPage == 0)
849 		return 0;
850 
851 	sal_uInt32 nSize = m_nReadBufferSize;
852 	sal_uInt32 nRemain = m_nReadBufferSize - m_nReadBufferFilled;
853 
854 	m_pReadBuffer += m_nReadBufferFilled;
855 	m_nReadBufferSize -= m_nReadBufferFilled;
856 	m_nReadBufferFilled = 0;
857 
858 	while (nRemain > 0)
859 	{
860 		sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd
861 												    - m_pReadPage->m_pRead),
862 									 nRemain);
863 		rtl_copyMemory(m_pReadBuffer, m_pReadPage->m_pRead, nBlock);
864 		m_pReadPage->m_pRead += nBlock;
865 		m_pReadBuffer += nBlock;
866 		m_nReadBufferSize -= nBlock;
867 		m_nReadBufferFilled = 0;
868 		nRemain -= nBlock;
869 
870 		if (m_pReadPage == m_pWritePage)
871 			break;
872 
873 		if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd)
874 		{
875 			Page * pRemove = m_pReadPage;
876 			m_pReadPage = pRemove->m_pNext;
877 			remove(pRemove);
878 		}
879 	}
880 
881 	return nSize - nRemain;
882 }
883 
884 //============================================================================
885 sal_uInt32 SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize)
886 {
887 	if (nSize == 0)
888 		return 0;
889 
890 	if (m_pWritePage == 0)
891 	{
892 		m_pFirstPage
893 			= static_cast< Page * >(rtl_allocateMemory(sizeof (Page)
894 													       + m_nPageSize
895 													       - 1));
896 		m_pFirstPage->m_pPrev = m_pFirstPage;
897 		m_pFirstPage->m_pNext = m_pFirstPage;
898 		m_pFirstPage->m_pStart = m_pFirstPage->m_aBuffer;
899 		m_pFirstPage->m_pRead = m_pFirstPage->m_aBuffer;
900 		m_pFirstPage->m_pEnd = m_pFirstPage->m_aBuffer;
901 		m_pFirstPage->m_nOffset = 0;
902 		m_pReadPage = m_pFirstPage;
903 		m_pWritePage = m_pFirstPage;
904 		++m_nPages;
905 	}
906 
907 	sal_uInt32 nRemain = nSize;
908 
909 	if (m_pReadBuffer != 0 && m_pReadPage == m_pWritePage
910 		&& m_pReadPage->m_pRead == m_pWritePage->m_pEnd)
911 	{
912 		sal_uInt32 nBlock = std::min(nRemain,
913 									 sal_uInt32(m_nReadBufferSize
914 												    - m_nReadBufferFilled));
915 		sal_uInt32 nPosition = m_pWritePage->m_nOffset
916 			                       + (m_pWritePage->m_pEnd
917 									      - m_pWritePage->m_aBuffer);
918 		if (!m_aMarks.empty())
919 			nBlock = *m_aMarks.begin() > nPosition ?
920 				         std::min(nBlock, sal_uInt32(*m_aMarks.begin()
921 													     - nPosition)) :
922 			             0;
923 
924 		if (nBlock > 0)
925 		{
926 			rtl_copyMemory(m_pReadBuffer + m_nReadBufferFilled, pBuffer,
927 						   nBlock);
928 			m_nReadBufferFilled += nBlock;
929 			nRemain -= nBlock;
930 
931 			nPosition += nBlock;
932 			m_pWritePage->m_nOffset = (nPosition / m_nPageSize) * m_nPageSize;
933 			m_pWritePage->m_pStart = m_pWritePage->m_aBuffer
934 				                         + nPosition % m_nPageSize;
935 			m_pWritePage->m_pRead = m_pWritePage->m_pStart;
936 			m_pWritePage->m_pEnd = m_pWritePage->m_pStart;
937 		}
938 	}
939 
940 	if (nRemain > 0)
941 		for (;;)
942 		{
943 			sal_uInt32 nBlock
944 				= std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize
945 									      - m_pWritePage->m_pEnd),
946 						   nRemain);
947 			rtl_copyMemory(m_pWritePage->m_pEnd, pBuffer, nBlock);
948 			m_pWritePage->m_pEnd += nBlock;
949 			pBuffer += nBlock;
950 			nRemain -= nBlock;
951 
952 			if (nRemain == 0)
953 				break;
954 
955 			if (m_pWritePage->m_pNext == m_pFirstPage)
956 			{
957 				if (m_nPages == m_nMaxPages)
958 					break;
959 
960 				Page * pNew
961 					= static_cast< Page * >(rtl_allocateMemory(
962 						                        sizeof (Page) + m_nPageSize
963 												    - 1));
964 				pNew->m_pPrev = m_pWritePage;
965 				pNew->m_pNext = m_pWritePage->m_pNext;
966 
967 				m_pWritePage->m_pNext->m_pPrev = pNew;
968 				m_pWritePage->m_pNext = pNew;
969 				++m_nPages;
970 			}
971 
972 			m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset
973 				                                   + m_nPageSize;
974 			m_pWritePage = m_pWritePage->m_pNext;
975 			m_pWritePage->m_pStart = m_pWritePage->m_aBuffer;
976 			m_pWritePage->m_pRead = m_pWritePage->m_aBuffer;
977 			m_pWritePage->m_pEnd = m_pWritePage->m_aBuffer;
978 		}
979 
980 	return nSize - nRemain;
981 }
982 
983 //============================================================================
984 bool SvDataPipe_Impl::addMark(sal_uInt32 nPosition)
985 {
986 	if (m_pFirstPage != 0 && m_pFirstPage->m_nOffset > nPosition)
987 		return false;
988 	m_aMarks.insert(nPosition);
989 	return true;
990 }
991 
992 //============================================================================
993 bool SvDataPipe_Impl::removeMark(sal_uInt32 nPosition)
994 {
995 	std::multiset< sal_uInt32 >::iterator t = m_aMarks.find(nPosition);
996 	if (t == m_aMarks.end())
997 		return false;
998 	m_aMarks.erase(t);
999 	while (remove(m_pFirstPage)) ;
1000 	return true;
1001 }
1002 
1003 //============================================================================
1004 SvDataPipe_Impl::SeekResult SvDataPipe_Impl::setReadPosition(sal_uInt32
1005 															     nPosition)
1006 {
1007 	if (m_pFirstPage == 0)
1008 		return nPosition == 0 ? SEEK_OK : SEEK_PAST_END;
1009 
1010 	if (nPosition
1011 		    <= m_pReadPage->m_nOffset
1012 		           + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer))
1013 	{
1014 		if (nPosition
1015 			    < m_pFirstPage->m_nOffset
1016 			          + (m_pFirstPage->m_pStart - m_pFirstPage->m_aBuffer))
1017 			return SEEK_BEFORE_MARKED;
1018 
1019 		while (nPosition < m_pReadPage->m_nOffset)
1020 		{
1021 			m_pReadPage->m_pRead = m_pReadPage->m_pStart;
1022 			m_pReadPage = m_pReadPage->m_pPrev;
1023 		}
1024 	}
1025 	else
1026 	{
1027 		if (nPosition
1028 			    > m_pWritePage->m_nOffset
1029 			          + (m_pWritePage->m_pEnd - m_pWritePage->m_aBuffer))
1030 			return SEEK_PAST_END;
1031 
1032 		while (m_pReadPage != m_pWritePage
1033 			   && nPosition >= m_pReadPage->m_nOffset + m_nPageSize)
1034 		{
1035 			Page * pRemove = m_pReadPage;
1036 			m_pReadPage = pRemove->m_pNext;
1037 			remove(pRemove);
1038 		}
1039 	}
1040 
1041 	m_pReadPage->m_pRead = m_pReadPage->m_aBuffer
1042 		                       + (nPosition - m_pReadPage->m_nOffset);
1043 	return SEEK_OK;
1044 }
1045 
1046