Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/io/source/stm/omark.cxx
Line
Count
Source
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 <map>
22
#include <memory>
23
#include <optional>
24
25
#include <com/sun/star/io/BufferSizeExceededException.hpp>
26
#include <com/sun/star/io/NotConnectedException.hpp>
27
#include <com/sun/star/io/XMarkableStream.hpp>
28
#include <com/sun/star/io/XOutputStream.hpp>
29
#include <com/sun/star/io/XInputStream.hpp>
30
#include <com/sun/star/io/XActiveDataSource.hpp>
31
#include <com/sun/star/io/XActiveDataSink.hpp>
32
#include <com/sun/star/io/XConnectable.hpp>
33
#include <com/sun/star/lang/IllegalArgumentException.hpp>
34
#include <com/sun/star/lang/XServiceInfo.hpp>
35
#include <com/sun/star/uno/XComponentContext.hpp>
36
37
#include <cppuhelper/weak.hxx>
38
#include <cppuhelper/implbase.hxx>
39
#include <cppuhelper/supportsservice.hxx>
40
41
#include <osl/diagnose.h>
42
#include <mutex>
43
44
using namespace ::cppu;
45
using namespace ::com::sun::star::io;
46
using namespace ::com::sun::star::uno;
47
using namespace ::com::sun::star::lang;
48
49
#include "streamhelper.hxx"
50
51
namespace io_stm {
52
53
namespace {
54
55
/***********************
56
*
57
* OMarkableOutputStream.
58
*
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.
61
*
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.
65
*
66
**********************/
67
class OMarkableOutputStream :
68
    public WeakImplHelper< XOutputStream ,
69
                            XActiveDataSource ,
70
                            XMarkableStream ,
71
                            XConnectable,
72
                            XServiceInfo
73
                          >
74
{
75
public:
76
    OMarkableOutputStream(  );
77
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;
82
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;
89
90
public: // XActiveDataSource
91
    virtual void SAL_CALL setOutputStream(const Reference < XOutputStream > & aStream) override;
92
    virtual Reference < XOutputStream > SAL_CALL getOutputStream() override;
93
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;
99
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;
104
105
private:
106
    // helper methods
107
    /// @throws NotConnectedException
108
    /// @throws BufferSizeExceededException
109
    void checkMarksAndFlush();
110
111
    Reference< XConnectable > m_succ;
112
    Reference< XConnectable > m_pred;
113
114
    Reference< XOutputStream >  m_output;
115
    bool m_bValidStream;
116
117
    MemRingBuffer m_aRingBuffer;
118
    std::map<sal_Int32,sal_Int32,std::less< sal_Int32 > > m_mapMarks;
119
    sal_Int32 m_nCurrentPos;
120
    sal_Int32 m_nCurrentMark;
121
122
    std::mutex m_mutex;
123
};
124
125
}
126
127
OMarkableOutputStream::OMarkableOutputStream( )
128
0
    : m_bValidStream(false)
129
0
    , m_nCurrentPos(0)
130
0
    , m_nCurrentMark(0)
131
0
{
132
0
}
133
134
// XOutputStream
135
void OMarkableOutputStream::writeBytes(const Sequence< sal_Int8 >& aData)
136
0
{
137
0
    std::unique_lock guard( m_mutex );
138
139
0
    if( !m_bValidStream ) {
140
0
        throw NotConnectedException();
141
0
    }
142
0
    if( m_mapMarks.empty() && ( m_aRingBuffer.getSize() == 0 ) ) {
143
        // no mark and  buffer active, simple write through
144
0
        m_output->writeBytes( aData );
145
0
    }
146
0
    else {
147
        // new data must be buffered
148
0
        m_aRingBuffer.writeAt( m_nCurrentPos , aData );
149
0
        m_nCurrentPos += aData.getLength();
150
0
        checkMarksAndFlush();
151
0
    }
152
153
0
}
154
155
void OMarkableOutputStream::flush()
156
0
{
157
0
    Reference< XOutputStream > output;
158
0
    {
159
0
        std::unique_lock guard( m_mutex );
160
0
        output = m_output;
161
0
    }
162
163
    // Markable cannot flush buffered data, because the data may get rewritten,
164
    // however one can forward the flush to the chained stream to give it
165
    // a chance to write data buffered in the chained stream.
166
0
    if( output.is() )
167
0
    {
168
0
        output->flush();
169
0
    }
170
0
}
171
172
void OMarkableOutputStream::closeOutput()
173
0
{
174
0
    if( !m_bValidStream ) {
175
0
        throw NotConnectedException();
176
0
    }
177
0
    std::unique_lock guard( m_mutex );
178
    // all marks must be cleared and all
179
180
0
    m_mapMarks.clear();
181
0
    m_nCurrentPos = m_aRingBuffer.getSize();
182
0
    checkMarksAndFlush();
183
184
0
    m_output->closeOutput();
185
186
0
    setOutputStream( Reference< XOutputStream > () );
187
0
    setPredecessor( Reference < XConnectable >() );
188
0
    setSuccessor( Reference< XConnectable > () );
189
190
0
}
191
192
193
sal_Int32 OMarkableOutputStream::createMark()
194
0
{
195
0
    std::unique_lock guard( m_mutex );
196
0
    sal_Int32 nMark = m_nCurrentMark;
197
198
0
    m_mapMarks[nMark] = m_nCurrentPos;
199
200
0
    m_nCurrentMark ++;
201
0
    return nMark;
202
0
}
203
204
void OMarkableOutputStream::deleteMark(sal_Int32 Mark)
205
0
{
206
0
    std::unique_lock guard( m_mutex );
207
0
    std::map<sal_Int32,sal_Int32,std::less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
208
209
0
    if( ii == m_mapMarks.end() ) {
210
0
        throw IllegalArgumentException(
211
0
            "MarkableOutputStream::deleteMark unknown mark (" + OUString::number(Mark) + ")",
212
0
            *this, 0);
213
0
    }
214
0
    m_mapMarks.erase( ii );
215
0
    checkMarksAndFlush();
216
0
}
217
218
void OMarkableOutputStream::jumpToMark(sal_Int32 nMark)
219
0
{
220
0
    std::unique_lock guard( m_mutex );
221
0
    std::map<sal_Int32,sal_Int32,std::less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
222
223
0
    if( ii == m_mapMarks.end() ) {
224
0
        throw IllegalArgumentException(
225
0
            "MarkableOutputStream::jumpToMark unknown mark (" + OUString::number(nMark) + ")",
226
0
            *this, 0);
227
0
    }
228
0
    m_nCurrentPos = (*ii).second;
229
0
}
230
231
void OMarkableOutputStream::jumpToFurthest()
232
0
{
233
0
    std::unique_lock guard( m_mutex );
234
0
    m_nCurrentPos = m_aRingBuffer.getSize();
235
0
    checkMarksAndFlush();
236
0
}
237
238
sal_Int32 OMarkableOutputStream::offsetToMark(sal_Int32 nMark)
239
0
{
240
241
0
    std::unique_lock guard( m_mutex );
242
0
    std::map<sal_Int32,sal_Int32,std::less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
243
244
0
    if( ii == m_mapMarks.end() )
245
0
    {
246
0
        throw IllegalArgumentException(
247
0
            "MarkableOutputStream::offsetToMark unknown mark (" + OUString::number(nMark) + ")",
248
0
            *this, 0);
249
0
    }
250
0
    return m_nCurrentPos - (*ii).second;
251
0
}
252
253
254
// XActiveDataSource2
255
void OMarkableOutputStream::setOutputStream(const Reference < XOutputStream >& aStream)
256
0
{
257
0
    if( m_output != aStream ) {
258
0
        m_output = aStream;
259
260
0
        Reference < XConnectable > succ( m_output , UNO_QUERY );
261
0
        setSuccessor( succ );
262
0
    }
263
0
    m_bValidStream = m_output.is();
264
0
}
265
266
Reference< XOutputStream > OMarkableOutputStream::getOutputStream()
267
0
{
268
0
    return m_output;
269
0
}
270
271
272
void OMarkableOutputStream::setSuccessor( const Reference< XConnectable > &r )
273
0
{
274
     /// if the references match, nothing needs to be done
275
0
     if( m_succ != r ) {
276
         /// store the reference for later use
277
0
         m_succ = r;
278
279
0
         if( m_succ.is() ) {
280
0
              m_succ->setPredecessor( Reference < XConnectable > (
281
0
                  static_cast< XConnectable *  >(this) ) );
282
0
         }
283
0
     }
284
0
}
285
Reference <XConnectable > OMarkableOutputStream::getSuccessor()
286
0
{
287
0
    return m_succ;
288
0
}
289
290
291
// XDataSource
292
void OMarkableOutputStream::setPredecessor( const Reference< XConnectable > &r )
293
0
{
294
0
    if( r != m_pred ) {
295
0
        m_pred = r;
296
0
        if( m_pred.is() ) {
297
0
            m_pred->setSuccessor( Reference < XConnectable > (
298
0
                static_cast< XConnectable *  >(this ) ) );
299
0
        }
300
0
    }
301
0
}
302
Reference < XConnectable > OMarkableOutputStream::getPredecessor()
303
0
{
304
0
    return m_pred;
305
0
}
306
307
308
// private methods
309
310
void OMarkableOutputStream::checkMarksAndFlush()
311
0
{
312
    // find the smallest mark
313
0
    sal_Int32 nNextFound = m_nCurrentPos;
314
0
    for (auto const& mark : m_mapMarks)
315
0
    {
316
0
        if( mark.second <= nNextFound )  {
317
0
            nNextFound = mark.second;
318
0
        }
319
0
    }
320
321
0
    if( nNextFound ) {
322
        // some data must be released !
323
0
        m_nCurrentPos -= nNextFound;
324
0
        for (auto & mark : m_mapMarks)
325
0
        {
326
0
            mark.second -= nNextFound;
327
0
        }
328
329
0
        Sequence<sal_Int8> seq(nNextFound);
330
0
        m_aRingBuffer.readAt( 0 , seq , nNextFound );
331
0
        m_aRingBuffer.forgetFromStart( nNextFound );
332
333
        // now write data through to streams
334
0
        m_output->writeBytes( seq );
335
0
    }
336
0
    else {
337
        // nothing to do. There is a mark or the current cursor position, that prevents
338
        // releasing data !
339
0
    }
340
0
}
341
342
343
// XServiceInfo
344
OUString OMarkableOutputStream::getImplementationName()
345
0
{
346
0
    return u"com.sun.star.comp.io.stm.MarkableOutputStream"_ustr;
347
0
}
348
349
// XServiceInfo
350
sal_Bool OMarkableOutputStream::supportsService(const OUString& ServiceName)
351
0
{
352
0
    return cppu::supportsService(this, ServiceName);
353
0
}
354
355
// XServiceInfo
356
Sequence< OUString > OMarkableOutputStream::getSupportedServiceNames()
357
0
{
358
0
    return { u"com.sun.star.io.MarkableOutputStream"_ustr };
359
0
}
360
361
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
362
io_OMarkableOutputStream_get_implementation(
363
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
364
0
{
365
0
    return cppu::acquire(new OMarkableOutputStream());
366
0
}
367
368
369
// XMarkableInputStream
370
371
namespace {
372
373
class OMarkableInputStream :
374
    public WeakImplHelper
375
    <
376
             XInputStream,
377
             XActiveDataSink,
378
             XMarkableStream,
379
             XConnectable,
380
             XServiceInfo
381
    >
382
{
383
public:
384
    OMarkableInputStream(  );
385
386
387
public: // XInputStream
388
    virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override ;
389
    virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
390
    virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
391
392
    virtual sal_Int32 SAL_CALL available() override;
393
    virtual void SAL_CALL closeInput() override;
394
395
public: // XMarkable
396
    virtual sal_Int32 SAL_CALL createMark() override;
397
    virtual void SAL_CALL deleteMark(sal_Int32 Mark) override;
398
    virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override;
399
    virtual void SAL_CALL jumpToFurthest() override;
400
    virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override;
401
402
public: // XActiveDataSink
403
    virtual void SAL_CALL setInputStream(const Reference < XInputStream > & aStream) override;
404
    virtual Reference < XInputStream > SAL_CALL getInputStream() override;
405
406
public: // XConnectable
407
    virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor) override;
408
    virtual Reference < XConnectable > SAL_CALL getPredecessor() override;
409
    virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor) override;
410
    virtual Reference < XConnectable > SAL_CALL getSuccessor() override;
411
412
public: // XServiceInfo
413
    OUString                     SAL_CALL getImplementationName() override;
414
    Sequence< OUString >         SAL_CALL getSupportedServiceNames() override;
415
    sal_Bool                         SAL_CALL  supportsService(const OUString& ServiceName) override;
416
417
private:
418
    void checkMarksAndFlush();
419
420
    Reference < XConnectable >  m_succ;
421
    Reference < XConnectable >  m_pred;
422
423
    Reference< XInputStream > m_input;
424
    bool m_bValidStream;
425
426
    std::optional<MemRingBuffer> m_oBuffer;
427
    std::map<sal_Int32,sal_Int32,std::less< sal_Int32 > > m_mapMarks;
428
    sal_Int32 m_nCurrentPos;
429
    sal_Int32 m_nCurrentMark;
430
431
    std::mutex m_mutex;
432
};
433
434
}
435
436
OMarkableInputStream::OMarkableInputStream()
437
0
    : m_bValidStream(false)
438
0
    , m_nCurrentPos(0)
439
0
    , m_nCurrentMark(0)
440
0
{
441
0
    m_oBuffer.emplace();
442
0
}
443
444
445
// XInputStream
446
447
sal_Int32 OMarkableInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
448
0
{
449
0
    std::unique_lock guard( m_mutex );
450
451
0
    if( !m_bValidStream ) {
452
0
        throw NotConnectedException(
453
0
            u"MarkableInputStream::readBytes NotConnectedException"_ustr,
454
0
            *this );
455
0
    }
456
457
0
    sal_Int32 nBytesRead;
458
0
    if( m_mapMarks.empty() && ! m_oBuffer->getSize() ) {
459
        // normal read !
460
0
        nBytesRead = m_input->readBytes( aData, nBytesToRead );
461
0
    }
462
0
    else {
463
        // read from buffer
464
0
        sal_Int32 nRead;
465
466
        // read enough bytes into buffer
467
0
        if( m_oBuffer->getSize() - m_nCurrentPos < nBytesToRead  ) {
468
0
            sal_Int32 nToRead = nBytesToRead - ( m_oBuffer->getSize() - m_nCurrentPos );
469
0
            nRead = m_input->readBytes( aData , nToRead );
470
471
0
            OSL_ASSERT( aData.getLength() == nRead );
472
473
0
            m_oBuffer->writeAt( m_oBuffer->getSize() , aData );
474
475
0
            if( nRead < nToRead ) {
476
0
                nBytesToRead = nBytesToRead - (nToRead-nRead);
477
0
            }
478
0
        }
479
480
0
        OSL_ASSERT( m_oBuffer->getSize() - m_nCurrentPos >= nBytesToRead  );
481
482
0
        m_oBuffer->readAt( m_nCurrentPos , aData , nBytesToRead );
483
484
0
        m_nCurrentPos += nBytesToRead;
485
0
        nBytesRead = nBytesToRead;
486
0
    }
487
488
0
    return nBytesRead;
489
0
}
490
491
492
sal_Int32 OMarkableInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
493
0
{
494
0
    std::unique_lock guard( m_mutex );
495
496
0
    if( !m_bValidStream )    {
497
0
        throw NotConnectedException(
498
0
            u"MarkableInputStream::readSomeBytes NotConnectedException"_ustr,
499
0
            *this );
500
0
    }
501
502
0
    sal_Int32 nBytesRead;
503
0
    if( m_mapMarks.empty() && ! m_oBuffer->getSize() ) {
504
        // normal read !
505
0
        nBytesRead = m_input->readSomeBytes( aData, nMaxBytesToRead );
506
0
    }
507
0
    else {
508
        // read from buffer
509
0
        sal_Int32 nRead = 0;
510
0
        sal_Int32 nInBuffer = m_oBuffer->getSize() - m_nCurrentPos;
511
0
        sal_Int32 nAdditionalBytesToRead = std::min<sal_Int32>(nMaxBytesToRead-nInBuffer,m_input->available());
512
0
        nAdditionalBytesToRead = std::max<sal_Int32>(0 , nAdditionalBytesToRead );
513
514
        // read enough bytes into buffer
515
0
        if( 0 == nInBuffer ) {
516
0
            nRead = m_input->readSomeBytes( aData , nMaxBytesToRead );
517
0
        }
518
0
        else if( nAdditionalBytesToRead ) {
519
0
            nRead = m_input->readBytes( aData , nAdditionalBytesToRead );
520
0
        }
521
522
0
        if( nRead ) {
523
0
            aData.realloc( nRead );
524
0
            m_oBuffer->writeAt( m_oBuffer->getSize() , aData );
525
0
        }
526
527
0
        nBytesRead = std::min( nMaxBytesToRead , nInBuffer + nRead );
528
529
        // now take everything from buffer !
530
0
        m_oBuffer->readAt( m_nCurrentPos , aData , nBytesRead );
531
532
0
        m_nCurrentPos += nBytesRead;
533
0
    }
534
535
0
    return nBytesRead;
536
537
538
0
}
539
540
541
void OMarkableInputStream::skipBytes(sal_Int32 nBytesToSkip)
542
0
{
543
0
    if ( nBytesToSkip < 0 )
544
0
        throw BufferSizeExceededException(
545
0
            u"precondition not met: XInputStream::skipBytes: non-negative integer required!"_ustr,
546
0
            *this
547
0
        );
548
549
    // this method is blocking
550
0
    Sequence<sal_Int8> seqDummy( nBytesToSkip );
551
0
    readBytes( seqDummy , nBytesToSkip );
552
0
}
553
554
sal_Int32 OMarkableInputStream::available()
555
0
{
556
0
    std::unique_lock guard( m_mutex );
557
558
0
    if( !m_bValidStream )    {
559
0
        throw NotConnectedException(
560
0
            u"MarkableInputStream::available NotConnectedException"_ustr,
561
0
            *this );
562
0
    }
563
564
0
    sal_Int32 nAvail = m_input->available() + ( m_oBuffer->getSize() - m_nCurrentPos );
565
0
    return nAvail;
566
0
}
567
568
569
void OMarkableInputStream::closeInput()
570
0
{
571
0
    std::unique_lock guard( m_mutex );
572
573
0
    if( !m_bValidStream ) {
574
0
        throw NotConnectedException(
575
0
            u"MarkableInputStream::closeInput NotConnectedException"_ustr,
576
0
            *this );
577
0
    }
578
579
0
    m_input->closeInput();
580
581
0
    m_input.clear();
582
0
    if( m_pred )
583
0
        m_pred.clear();
584
0
    if( m_succ )
585
0
        m_succ.clear();
586
0
    m_bValidStream = false;
587
0
    m_oBuffer.reset();
588
0
    m_nCurrentPos = 0;
589
0
    m_nCurrentMark = 0;
590
0
}
591
592
// XMarkable
593
594
sal_Int32 OMarkableInputStream::createMark()
595
0
{
596
0
    std::unique_lock guard( m_mutex );
597
0
    sal_Int32 nMark = m_nCurrentMark;
598
599
0
    m_mapMarks[nMark] = m_nCurrentPos;
600
601
0
    m_nCurrentMark ++;
602
0
    return nMark;
603
0
}
604
605
void OMarkableInputStream::deleteMark(sal_Int32 Mark)
606
0
{
607
0
    std::unique_lock guard( m_mutex );
608
0
    std::map<sal_Int32,sal_Int32,std::less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
609
610
0
    if( ii == m_mapMarks.end() ) {
611
0
        throw IllegalArgumentException(
612
0
            "MarkableInputStream::deleteMark unknown mark (" + OUString::number(Mark) + ")",
613
0
            *this , 0 );
614
0
    }
615
0
    m_mapMarks.erase( ii );
616
0
    checkMarksAndFlush();
617
0
}
618
619
void OMarkableInputStream::jumpToMark(sal_Int32 nMark)
620
0
{
621
0
    std::unique_lock guard( m_mutex );
622
0
    std::map<sal_Int32,sal_Int32,std::less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
623
624
0
    if( ii == m_mapMarks.end() )
625
0
    {
626
0
        throw IllegalArgumentException(
627
0
            "MarkableInputStream::jumpToMark unknown mark (" + OUString::number(nMark) + ")",
628
0
            *this , 0 );
629
0
    }
630
0
    m_nCurrentPos = (*ii).second;
631
0
}
632
633
void OMarkableInputStream::jumpToFurthest()
634
0
{
635
0
    std::unique_lock guard( m_mutex );
636
0
    m_nCurrentPos = m_oBuffer->getSize();
637
0
    checkMarksAndFlush();
638
0
}
639
640
sal_Int32 OMarkableInputStream::offsetToMark(sal_Int32 nMark)
641
0
{
642
0
    std::unique_lock guard( m_mutex );
643
0
    std::map<sal_Int32,sal_Int32,std::less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
644
645
0
    if( ii == m_mapMarks.end() )
646
0
    {
647
0
        throw IllegalArgumentException(
648
0
            "MarkableInputStream::offsetToMark unknown mark (" + OUString::number(nMark) + ")",
649
0
            *this, 0 );
650
0
    }
651
0
    return m_nCurrentPos - (*ii).second;
652
0
}
653
654
655
// XActiveDataSource
656
void OMarkableInputStream::setInputStream(const Reference< XInputStream > & aStream)
657
0
{
658
0
    Reference < XConnectable > pred;
659
0
    {
660
0
        std::unique_lock guard( m_mutex );
661
0
        if( m_input == aStream )
662
0
            return;
663
664
0
        m_input = aStream;
665
0
        m_bValidStream = m_input.is();
666
0
        pred.set( m_input , UNO_QUERY );
667
0
    }
668
0
    setPredecessor( pred );
669
0
}
670
671
Reference< XInputStream > OMarkableInputStream::getInputStream()
672
0
{
673
0
    std::unique_lock guard( m_mutex );
674
0
    return m_input;
675
0
}
676
677
678
// XDataSink
679
void OMarkableInputStream::setSuccessor( const Reference< XConnectable > &r )
680
0
{
681
0
    {
682
0
        std::unique_lock guard( m_mutex );
683
        /// if the references match, nothing needs to be done
684
0
        if( m_succ == r )
685
0
            return;
686
687
        /// store the reference for later use
688
0
        m_succ = r;
689
0
    }
690
0
    if( r ) {
691
        /// set this instance as the sink !
692
0
        r->setPredecessor( Reference< XConnectable > ( static_cast< XConnectable * >(this) ) );
693
0
    }
694
0
}
695
696
Reference < XConnectable >  OMarkableInputStream::getSuccessor()
697
0
{
698
0
    std::unique_lock guard( m_mutex );
699
0
    return m_succ;
700
0
}
701
702
703
// XDataSource
704
void OMarkableInputStream::setPredecessor( const Reference < XConnectable >  &r )
705
0
{
706
0
    {
707
0
        std::unique_lock guard( m_mutex );
708
0
        if( r == m_pred )
709
0
            return;
710
0
        m_pred = r;
711
0
    }
712
0
    if( r ) {
713
0
        r->setSuccessor( Reference< XConnectable > (
714
0
            static_cast< XConnectable * >(this) ) );
715
0
    }
716
0
}
717
718
Reference< XConnectable >  OMarkableInputStream::getPredecessor()
719
0
{
720
0
    std::unique_lock guard( m_mutex );
721
0
    return m_pred;
722
0
}
723
724
725
void OMarkableInputStream::checkMarksAndFlush()
726
0
{
727
    // find the smallest mark
728
0
    sal_Int32 nNextFound = m_nCurrentPos;
729
0
    for (auto const& mark : m_mapMarks)
730
0
    {
731
0
        if( mark.second <= nNextFound )  {
732
0
            nNextFound = mark.second;
733
0
        }
734
0
    }
735
736
0
    if( nNextFound ) {
737
        // some data must be released !
738
0
        m_nCurrentPos -= nNextFound;
739
0
        for (auto & mark : m_mapMarks)
740
0
        {
741
0
            mark.second -= nNextFound;
742
0
        }
743
744
0
        m_oBuffer->forgetFromStart( nNextFound );
745
746
0
    }
747
0
    else {
748
        // nothing to do. There is a mark or the current cursor position, that prevents
749
        // releasing data !
750
0
    }
751
0
}
752
753
// XServiceInfo
754
OUString OMarkableInputStream::getImplementationName()
755
0
{
756
0
    return u"com.sun.star.comp.io.stm.MarkableInputStream"_ustr;
757
0
}
758
759
// XServiceInfo
760
sal_Bool OMarkableInputStream::supportsService(const OUString& ServiceName)
761
0
{
762
0
    return cppu::supportsService(this, ServiceName);
763
0
}
764
765
// XServiceInfo
766
Sequence< OUString > OMarkableInputStream::getSupportedServiceNames()
767
0
{
768
0
    return { u"com.sun.star.io.MarkableInputStream"_ustr };
769
0
}
770
771
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
772
io_OMarkableInputStream_get_implementation(
773
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
774
0
{
775
0
    return cppu::acquire(new OMarkableInputStream());
776
0
}
777
778
}
779
780
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */