Bump version to 6.4-15
[LibreOffice.git] / io / source / stm / omark.cxx
blob19191e4a957b0d7df6345f5f1c8a28d54b442da4
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 <map>
22 #include <memory>
24 #include <com/sun/star/io/BufferSizeExceededException.hpp>
25 #include <com/sun/star/io/NotConnectedException.hpp>
26 #include <com/sun/star/io/XMarkableStream.hpp>
27 #include <com/sun/star/io/XOutputStream.hpp>
28 #include <com/sun/star/io/XInputStream.hpp>
29 #include <com/sun/star/io/XActiveDataSource.hpp>
30 #include <com/sun/star/io/XActiveDataSink.hpp>
31 #include <com/sun/star/io/XConnectable.hpp>
32 #include <com/sun/star/lang/IllegalArgumentException.hpp>
33 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <cppuhelper/weak.hxx>
36 #include <cppuhelper/implbase.hxx>
37 #include <cppuhelper/supportsservice.hxx>
39 #include <osl/mutex.hxx>
40 #include <osl/diagnose.h>
43 using namespace ::std;
44 using namespace ::cppu;
45 using namespace ::osl;
46 using namespace ::com::sun::star::io;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::lang;
50 #include <services.hxx>
51 #include "streamhelper.hxx"
53 namespace io_stm {
55 /***********************
57 * OMarkableOutputStream.
59 * This object allows to set marks in an outputstream. It is allowed to jump back to the marks and
60 * rewrite the same bytes.
62 * The object must buffer the data since the last mark set. Flush will not
63 * have any effect. As soon as the last mark has been removed, the object may write the data
64 * through to the chained object.
66 **********************/
67 class OMarkableOutputStream :
68 public WeakImplHelper< XOutputStream ,
69 XActiveDataSource ,
70 XMarkableStream ,
71 XConnectable,
72 XServiceInfo
75 public:
76 OMarkableOutputStream( );
78 public: // XOutputStream
79 virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override;
80 virtual void SAL_CALL flush() override;
81 virtual void SAL_CALL closeOutput() override;
83 public: // XMarkable
84 virtual sal_Int32 SAL_CALL createMark() override;
85 virtual void SAL_CALL deleteMark(sal_Int32 Mark) override;
86 virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override;
87 virtual void SAL_CALL jumpToFurthest() override;
88 virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override;
90 public: // XActiveDataSource
91 virtual void SAL_CALL setOutputStream(const Reference < XOutputStream > & aStream) override;
92 virtual Reference < XOutputStream > SAL_CALL getOutputStream() override;
94 public: // XConnectable
95 virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor) override;
96 virtual Reference < XConnectable > SAL_CALL getPredecessor() override;
97 virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor) override;
98 virtual Reference< XConnectable > SAL_CALL getSuccessor() override;
100 public: // XServiceInfo
101 OUString SAL_CALL getImplementationName() override;
102 Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
103 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
105 private:
106 // helper methods
107 /// @throws NotConnectedException
108 /// @throws BufferSizeExceededException
109 void checkMarksAndFlush();
111 Reference< XConnectable > m_succ;
112 Reference< XConnectable > m_pred;
114 Reference< XOutputStream > m_output;
115 bool m_bValidStream;
117 std::unique_ptr<MemRingBuffer> m_pBuffer;
118 map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks;
119 sal_Int32 m_nCurrentPos;
120 sal_Int32 m_nCurrentMark;
122 Mutex m_mutex;
125 OMarkableOutputStream::OMarkableOutputStream( )
126 : m_bValidStream(false)
127 , m_pBuffer( new MemRingBuffer )
128 , m_nCurrentPos(0)
129 , m_nCurrentMark(0)
133 // XOutputStream
134 void OMarkableOutputStream::writeBytes(const Sequence< sal_Int8 >& aData)
136 if( !m_bValidStream ) {
137 throw NotConnectedException();
139 if( m_mapMarks.empty() && ( m_pBuffer->getSize() == 0 ) ) {
140 // no mark and buffer active, simple write through
141 m_output->writeBytes( aData );
143 else {
144 MutexGuard guard( m_mutex );
145 // new data must be buffered
146 m_pBuffer->writeAt( m_nCurrentPos , aData );
147 m_nCurrentPos += aData.getLength();
148 checkMarksAndFlush();
153 void OMarkableOutputStream::flush()
155 Reference< XOutputStream > output;
157 MutexGuard guard( m_mutex );
158 output = m_output;
161 // Markable cannot flush buffered data, because the data may get rewritten,
162 // however one can forward the flush to the chained stream to give it
163 // a chance to write data buffered in the chained stream.
164 if( output.is() )
166 output->flush();
170 void OMarkableOutputStream::closeOutput()
172 if( !m_bValidStream ) {
173 throw NotConnectedException();
175 MutexGuard guard( m_mutex );
176 // all marks must be cleared and all
178 m_mapMarks.clear();
179 m_nCurrentPos = m_pBuffer->getSize();
180 checkMarksAndFlush();
182 m_output->closeOutput();
184 setOutputStream( Reference< XOutputStream > () );
185 setPredecessor( Reference < XConnectable >() );
186 setSuccessor( Reference< XConnectable > () );
191 sal_Int32 OMarkableOutputStream::createMark()
193 MutexGuard guard( m_mutex );
194 sal_Int32 nMark = m_nCurrentMark;
196 m_mapMarks[nMark] = m_nCurrentPos;
198 m_nCurrentMark ++;
199 return nMark;
202 void OMarkableOutputStream::deleteMark(sal_Int32 Mark)
204 MutexGuard guard( m_mutex );
205 map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
207 if( ii == m_mapMarks.end() ) {
208 throw IllegalArgumentException(
209 "MarkableOutputStream::deleteMark unknown mark (" + OUString::number(Mark) + ")",
210 *this, 0);
212 m_mapMarks.erase( ii );
213 checkMarksAndFlush();
216 void OMarkableOutputStream::jumpToMark(sal_Int32 nMark)
218 MutexGuard guard( m_mutex );
219 map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
221 if( ii == m_mapMarks.end() ) {
222 throw IllegalArgumentException(
223 "MarkableOutputStream::jumpToMark unknown mark (" + OUString::number(nMark) + ")",
224 *this, 0);
226 m_nCurrentPos = (*ii).second;
229 void OMarkableOutputStream::jumpToFurthest()
231 MutexGuard guard( m_mutex );
232 m_nCurrentPos = m_pBuffer->getSize();
233 checkMarksAndFlush();
236 sal_Int32 OMarkableOutputStream::offsetToMark(sal_Int32 nMark)
239 MutexGuard guard( m_mutex );
240 map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
242 if( ii == m_mapMarks.end() )
244 throw IllegalArgumentException(
245 "MarkableOutputStream::offsetToMark unknown mark (" + OUString::number(nMark) + ")",
246 *this, 0);
248 return m_nCurrentPos - (*ii).second;
252 // XActiveDataSource2
253 void OMarkableOutputStream::setOutputStream(const Reference < XOutputStream >& aStream)
255 if( m_output != aStream ) {
256 m_output = aStream;
258 Reference < XConnectable > succ( m_output , UNO_QUERY );
259 setSuccessor( succ );
261 m_bValidStream = m_output.is();
264 Reference< XOutputStream > OMarkableOutputStream::getOutputStream()
266 return m_output;
270 void OMarkableOutputStream::setSuccessor( const Reference< XConnectable > &r )
272 /// if the references match, nothing needs to be done
273 if( m_succ != r ) {
274 /// store the reference for later use
275 m_succ = r;
277 if( m_succ.is() ) {
278 m_succ->setPredecessor( Reference < XConnectable > (
279 static_cast< XConnectable * >(this) ) );
283 Reference <XConnectable > OMarkableOutputStream::getSuccessor()
285 return m_succ;
289 // XDataSource
290 void OMarkableOutputStream::setPredecessor( const Reference< XConnectable > &r )
292 if( r != m_pred ) {
293 m_pred = r;
294 if( m_pred.is() ) {
295 m_pred->setSuccessor( Reference < XConnectable > (
296 static_cast< XConnectable * >(this ) ) );
300 Reference < XConnectable > OMarkableOutputStream::getPredecessor()
302 return m_pred;
306 // private methods
308 void OMarkableOutputStream::checkMarksAndFlush()
310 map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
312 // find the smallest mark
313 sal_Int32 nNextFound = m_nCurrentPos;
314 for (auto const& mark : m_mapMarks)
316 if( mark.second <= nNextFound ) {
317 nNextFound = mark.second;
321 if( nNextFound ) {
322 // some data must be released !
323 m_nCurrentPos -= nNextFound;
324 for (auto & mark : m_mapMarks)
326 mark.second -= nNextFound;
329 Sequence<sal_Int8> seq(nNextFound);
330 m_pBuffer->readAt( 0 , seq , nNextFound );
331 m_pBuffer->forgetFromStart( nNextFound );
333 // now write data through to streams
334 m_output->writeBytes( seq );
336 else {
337 // nothing to do. There is a mark or the current cursor position, that prevents
338 // releasing data !
343 // XServiceInfo
344 OUString OMarkableOutputStream::getImplementationName()
346 return OMarkableOutputStream_getImplementationName();
349 // XServiceInfo
350 sal_Bool OMarkableOutputStream::supportsService(const OUString& ServiceName)
352 return cppu::supportsService(this, ServiceName);
355 // XServiceInfo
356 Sequence< OUString > OMarkableOutputStream::getSupportedServiceNames()
358 return OMarkableOutputStream_getSupportedServiceNames();
361 /*------------------------
363 * external binding
365 *------------------------*/
366 Reference< XInterface > OMarkableOutputStream_CreateInstance(
367 SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
369 OMarkableOutputStream *p = new OMarkableOutputStream( );
371 return Reference < XInterface > ( static_cast<OWeakObject *>(p) );
374 OUString OMarkableOutputStream_getImplementationName()
376 return "com.sun.star.comp.io.stm.MarkableOutputStream";
379 Sequence<OUString> OMarkableOutputStream_getSupportedServiceNames()
381 Sequence<OUString> aRet { "com.sun.star.io.MarkableOutputStream" };
383 return aRet;
387 // XMarkableInputStream
390 class OMarkableInputStream :
391 public WeakImplHelper
393 XInputStream,
394 XActiveDataSink,
395 XMarkableStream,
396 XConnectable,
397 XServiceInfo
400 public:
401 OMarkableInputStream( );
404 public: // XInputStream
405 virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override ;
406 virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
407 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
409 virtual sal_Int32 SAL_CALL available() override;
410 virtual void SAL_CALL closeInput() override;
412 public: // XMarkable
413 virtual sal_Int32 SAL_CALL createMark() override;
414 virtual void SAL_CALL deleteMark(sal_Int32 Mark) override;
415 virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override;
416 virtual void SAL_CALL jumpToFurthest() override;
417 virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override;
419 public: // XActiveDataSink
420 virtual void SAL_CALL setInputStream(const Reference < XInputStream > & aStream) override;
421 virtual Reference < XInputStream > SAL_CALL getInputStream() override;
423 public: // XConnectable
424 virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor) override;
425 virtual Reference < XConnectable > SAL_CALL getPredecessor() override;
426 virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor) override;
427 virtual Reference < XConnectable > SAL_CALL getSuccessor() override;
429 public: // XServiceInfo
430 OUString SAL_CALL getImplementationName() override;
431 Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
432 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
434 private:
435 void checkMarksAndFlush();
437 Reference < XConnectable > m_succ;
438 Reference < XConnectable > m_pred;
440 Reference< XInputStream > m_input;
441 bool m_bValidStream;
443 std::unique_ptr<MemRingBuffer> m_pBuffer;
444 map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks;
445 sal_Int32 m_nCurrentPos;
446 sal_Int32 m_nCurrentMark;
448 Mutex m_mutex;
451 OMarkableInputStream::OMarkableInputStream()
452 : m_bValidStream(false)
453 , m_nCurrentPos(0)
454 , m_nCurrentMark(0)
456 m_pBuffer.reset( new MemRingBuffer );
460 // XInputStream
462 sal_Int32 OMarkableInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
464 sal_Int32 nBytesRead;
466 if( !m_bValidStream ) {
467 throw NotConnectedException(
468 "MarkableInputStream::readBytes NotConnectedException",
469 *this );
471 MutexGuard guard( m_mutex );
472 if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
473 // normal read !
474 nBytesRead = m_input->readBytes( aData, nBytesToRead );
476 else {
477 // read from buffer
478 sal_Int32 nRead;
480 // read enough bytes into buffer
481 if( m_pBuffer->getSize() - m_nCurrentPos < nBytesToRead ) {
482 sal_Int32 nToRead = nBytesToRead - ( m_pBuffer->getSize() - m_nCurrentPos );
483 nRead = m_input->readBytes( aData , nToRead );
485 OSL_ASSERT( aData.getLength() == nRead );
487 m_pBuffer->writeAt( m_pBuffer->getSize() , aData );
489 if( nRead < nToRead ) {
490 nBytesToRead = nBytesToRead - (nToRead-nRead);
494 OSL_ASSERT( m_pBuffer->getSize() - m_nCurrentPos >= nBytesToRead );
496 m_pBuffer->readAt( m_nCurrentPos , aData , nBytesToRead );
498 m_nCurrentPos += nBytesToRead;
499 nBytesRead = nBytesToRead;
502 return nBytesRead;
506 sal_Int32 OMarkableInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
509 sal_Int32 nBytesRead;
510 if( !m_bValidStream ) {
511 throw NotConnectedException(
512 "MarkableInputStream::readSomeBytes NotConnectedException",
513 *this );
516 MutexGuard guard( m_mutex );
517 if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
518 // normal read !
519 nBytesRead = m_input->readSomeBytes( aData, nMaxBytesToRead );
521 else {
522 // read from buffer
523 sal_Int32 nRead = 0;
524 sal_Int32 nInBuffer = m_pBuffer->getSize() - m_nCurrentPos;
525 sal_Int32 nAdditionalBytesToRead = std::min<sal_Int32>(nMaxBytesToRead-nInBuffer,m_input->available());
526 nAdditionalBytesToRead = std::max<sal_Int32>(0 , nAdditionalBytesToRead );
528 // read enough bytes into buffer
529 if( 0 == nInBuffer ) {
530 nRead = m_input->readSomeBytes( aData , nMaxBytesToRead );
532 else if( nAdditionalBytesToRead ) {
533 nRead = m_input->readBytes( aData , nAdditionalBytesToRead );
536 if( nRead ) {
537 aData.realloc( nRead );
538 m_pBuffer->writeAt( m_pBuffer->getSize() , aData );
541 nBytesRead = std::min( nMaxBytesToRead , nInBuffer + nRead );
543 // now take everything from buffer !
544 m_pBuffer->readAt( m_nCurrentPos , aData , nBytesRead );
546 m_nCurrentPos += nBytesRead;
549 return nBytesRead;
555 void OMarkableInputStream::skipBytes(sal_Int32 nBytesToSkip)
557 if ( nBytesToSkip < 0 )
558 throw BufferSizeExceededException(
559 "precondition not met: XInputStream::skipBytes: non-negative integer required!",
560 *this
563 // this method is blocking
564 Sequence<sal_Int8> seqDummy( nBytesToSkip );
565 readBytes( seqDummy , nBytesToSkip );
568 sal_Int32 OMarkableInputStream::available()
570 if( !m_bValidStream ) {
571 throw NotConnectedException(
572 "MarkableInputStream::available NotConnectedException",
573 *this );
576 MutexGuard guard( m_mutex );
577 sal_Int32 nAvail = m_input->available() + ( m_pBuffer->getSize() - m_nCurrentPos );
578 return nAvail;
582 void OMarkableInputStream::closeInput()
584 if( !m_bValidStream ) {
585 throw NotConnectedException(
586 "MarkableInputStream::closeInput NotConnectedException",
587 *this );
589 MutexGuard guard( m_mutex );
591 m_input->closeInput();
593 setInputStream( Reference< XInputStream > () );
594 setPredecessor( Reference< XConnectable > () );
595 setSuccessor( Reference< XConnectable >() );
597 m_pBuffer.reset();
598 m_nCurrentPos = 0;
599 m_nCurrentMark = 0;
602 // XMarkable
604 sal_Int32 OMarkableInputStream::createMark()
606 MutexGuard guard( m_mutex );
607 sal_Int32 nMark = m_nCurrentMark;
609 m_mapMarks[nMark] = m_nCurrentPos;
611 m_nCurrentMark ++;
612 return nMark;
615 void OMarkableInputStream::deleteMark(sal_Int32 Mark)
617 MutexGuard guard( m_mutex );
618 map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
620 if( ii == m_mapMarks.end() ) {
621 throw IllegalArgumentException(
622 "MarkableInputStream::deleteMark unknown mark (" + OUString::number(Mark) + ")",
623 *this , 0 );
625 m_mapMarks.erase( ii );
626 checkMarksAndFlush();
629 void OMarkableInputStream::jumpToMark(sal_Int32 nMark)
631 MutexGuard guard( m_mutex );
632 map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
634 if( ii == m_mapMarks.end() )
636 throw IllegalArgumentException(
637 "MarkableInputStream::jumpToMark unknown mark (" + OUString::number(nMark) + ")",
638 *this , 0 );
640 m_nCurrentPos = (*ii).second;
643 void OMarkableInputStream::jumpToFurthest()
645 MutexGuard guard( m_mutex );
646 m_nCurrentPos = m_pBuffer->getSize();
647 checkMarksAndFlush();
650 sal_Int32 OMarkableInputStream::offsetToMark(sal_Int32 nMark)
652 MutexGuard guard( m_mutex );
653 map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
655 if( ii == m_mapMarks.end() )
657 throw IllegalArgumentException(
658 "MarkableInputStream::offsetToMark unknown mark (" + OUString::number(nMark) + ")",
659 *this, 0 );
661 return m_nCurrentPos - (*ii).second;
665 // XActiveDataSource
666 void OMarkableInputStream::setInputStream(const Reference< XInputStream > & aStream)
669 if( m_input != aStream ) {
670 m_input = aStream;
672 Reference < XConnectable > pred( m_input , UNO_QUERY );
673 setPredecessor( pred );
676 m_bValidStream = m_input.is();
680 Reference< XInputStream > OMarkableInputStream::getInputStream()
682 return m_input;
686 // XDataSink
687 void OMarkableInputStream::setSuccessor( const Reference< XConnectable > &r )
689 /// if the references match, nothing needs to be done
690 if( m_succ != r ) {
691 /// store the reference for later use
692 m_succ = r;
694 if( m_succ.is() ) {
695 /// set this instance as the sink !
696 m_succ->setPredecessor( Reference< XConnectable > (
697 static_cast< XConnectable * >(this) ) );
702 Reference < XConnectable > OMarkableInputStream::getSuccessor()
704 return m_succ;
708 // XDataSource
709 void OMarkableInputStream::setPredecessor( const Reference < XConnectable > &r )
711 if( r != m_pred ) {
712 m_pred = r;
713 if( m_pred.is() ) {
714 m_pred->setSuccessor( Reference< XConnectable > (
715 static_cast< XConnectable * >(this) ) );
719 Reference< XConnectable > OMarkableInputStream::getPredecessor()
721 return m_pred;
725 void OMarkableInputStream::checkMarksAndFlush()
727 map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
729 // find the smallest mark
730 sal_Int32 nNextFound = m_nCurrentPos;
731 for (auto const& mark : m_mapMarks)
733 if( mark.second <= nNextFound ) {
734 nNextFound = mark.second;
738 if( nNextFound ) {
739 // some data must be released !
740 m_nCurrentPos -= nNextFound;
741 for (auto & mark : m_mapMarks)
743 mark.second -= nNextFound;
746 m_pBuffer->forgetFromStart( nNextFound );
749 else {
750 // nothing to do. There is a mark or the current cursor position, that prevents
751 // releasing data !
755 // XServiceInfo
756 OUString OMarkableInputStream::getImplementationName()
758 return OMarkableInputStream_getImplementationName();
761 // XServiceInfo
762 sal_Bool OMarkableInputStream::supportsService(const OUString& ServiceName)
764 return cppu::supportsService(this, ServiceName);
767 // XServiceInfo
768 Sequence< OUString > OMarkableInputStream::getSupportedServiceNames()
770 return OMarkableInputStream_getSupportedServiceNames();
773 /*------------------------
775 * external binding
777 *------------------------*/
778 Reference < XInterface > OMarkableInputStream_CreateInstance(
779 SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
781 OMarkableInputStream *p = new OMarkableInputStream( );
782 return Reference< XInterface > ( static_cast<OWeakObject *>(p) );
785 OUString OMarkableInputStream_getImplementationName()
787 return "com.sun.star.comp.io.stm.MarkableInputStream";
790 Sequence<OUString> OMarkableInputStream_getSupportedServiceNames()
792 Sequence<OUString> aRet { "com.sun.star.io.MarkableInputStream" };
793 return aRet;
798 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */