Coverage Report

Created: 2026-02-14 09:37

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