summaryrefslogtreecommitdiffstats
path: root/include/tools/stream.hxx
blob: 39e8dc52f65a19de56158b54379db605aa157adc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
#pragma once

#include <config_options.h>
#include <tools/toolsdllapi.h>
#include <tools/lineend.hxx>
#include <tools/long.hxx>
#include <tools/ref.hxx>
#include <vcl/errcode.hxx>
#include <rtl/string.hxx>
#include <rtl/strbuf.hxx>
#include <o3tl/typed_flags_set.hxx>
#include <memory>
#include <string_view>

class StreamData;

inline rtl_TextEncoding GetStoreCharSet( rtl_TextEncoding eEncoding )
{
    if ( eEncoding == RTL_TEXTENCODING_ISO_8859_1 )
        return RTL_TEXTENCODING_MS_1252;
    else
        return eEncoding;
}

// StreamTypes

// read, write, create,... options
enum class StreamMode {
    NONE                     = 0x0000,
    READ                     = 0x0001,  ///< allow read accesses
    WRITE                    = 0x0002,  ///< allow write accesses
// file i/o
    NOCREATE                 = 0x0004,  ///< 1 == Don't create file
    TRUNC                    = 0x0008,  ///< Truncate _existing_ file to zero length
    COPY_ON_SYMLINK          = 0x0010,  ///< copy-on-write for symlinks (Unix)
    TEMPORARY                = 0x0020,  ///< temporary file attribute (Windows-only)
// sharing options
    SHARE_DENYNONE           = 0x0100,
    SHARE_DENYREAD           = 0x0200,  // overrides denynone
    SHARE_DENYWRITE          = 0x0400,  // overrides denynone
    SHARE_DENYALL            = 0x0800,  // overrides denyread,write,none
// masks
    READWRITE                = READ | WRITE,
    STD_READ                 = READ | SHARE_DENYNONE | NOCREATE,
    STD_WRITE                = WRITE | SHARE_DENYALL,
    STD_READWRITE            = READWRITE | SHARE_DENYALL
};
namespace o3tl
{
    template<> struct typed_flags<StreamMode> : is_typed_flags<StreamMode, 0x0f3f> {};
}

#define STREAM_SEEK_TO_BEGIN            0L
#define STREAM_SEEK_TO_END              SAL_MAX_UINT64

enum class SvStreamEndian { BIG, LITTLE };

enum class SvStreamCompressFlags {
    NONE     = 0x0000,
    ZBITMAP  = 0x0001,
    NATIVE   = 0x0010,
};
namespace o3tl
{
    template<> struct typed_flags<SvStreamCompressFlags> : is_typed_flags<SvStreamCompressFlags, 0x0011> {};
}

class SvStream;

typedef SvStream& (*SvStrPtr)( SvStream& );

inline SvStream& operator<<( SvStream& rStr, SvStrPtr f );

// SvLockBytes

struct SvLockBytesStat
{
    std::size_t nSize;

    SvLockBytesStat() : nSize(0) {}
};

class TOOLS_DLLPUBLIC SvLockBytes: public SvRefBase
{
    SvStream * m_pStream;
    bool m_bOwner;
    bool m_bSync;

protected:
    void close();

public:

    SvLockBytes() : m_pStream(nullptr), m_bOwner(false), m_bSync(false) {}

    SvLockBytes(SvStream * pTheStream, bool bTheOwner = false) :
        m_pStream(pTheStream), m_bOwner(bTheOwner), m_bSync(false) {}

    virtual ~SvLockBytes() override { close(); }

    const SvStream * GetStream() const { return m_pStream; }

    void            SetSynchronMode(bool bTheSync = true) { m_bSync = bTheSync; }
    bool            IsSynchronMode() const { return m_bSync; }

    virtual ErrCode ReadAt(sal_uInt64 nPos, void * pBuffer, std::size_t nCount,
                           std::size_t * pRead) const;
    virtual ErrCode WriteAt(sal_uInt64 nPos, const void * pBuffer, std::size_t nCount,
                            std::size_t * pWritten);

    virtual ErrCode Flush() const;

    virtual ErrCode SetSize(sal_uInt64 nSize);

    virtual ErrCode Stat(SvLockBytesStat * pStat) const;
};

typedef tools::SvRef<SvLockBytes> SvLockBytesRef;

// SvStream

class TOOLS_DLLPUBLIC SvStream
{
private:
    // LockBytes Interface
    SvLockBytesRef  m_xLockBytes; ///< Default implementation
    sal_uInt64      m_nActPos;

    // buffer management
    std::unique_ptr<sal_uInt8[]>
                    m_pRWBuf;     ///< Points to read/write buffer
    sal_uInt8*      m_pBufPos;    ///< m_pRWBuf + m_nBufActualPos
    sal_uInt16      m_nBufSize;   ///< Allocated size of buffer
    sal_uInt16      m_nBufActualLen; ///< Length of used segment of buffer
                                  ///< = m_nBufSize, if EOF did not occur
    sal_uInt16      m_nBufActualPos; ///< current position in buffer (0..m_nBufSize-1)
    sal_uInt16      m_nBufFree;   ///< number of free slots in buffer to IO of type eIOMode
    bool            m_isIoRead;
    bool            m_isIoWrite;

    // Error codes, conversion, compression, ...
    bool            m_isDirty;  ///< true: Stream != buffer content
    bool            m_isSwap;
    bool            m_isEof;
    ErrCode         m_nError;
    SvStreamCompressFlags m_nCompressMode;
    LineEnd         m_eLineDelimiter;
    rtl_TextEncoding m_eStreamCharSet;

    // Encryption
    OString m_aCryptMaskKey;// aCryptMaskKey.getLength != 0  -> Encryption used
    unsigned char   m_nCryptMask;

    // Userdata
    sal_Int32       m_nVersion;   // for external use

                    SvStream ( const SvStream& rStream ) = delete;
    SvStream&       operator=( const SvStream& rStream ) = delete;

protected:
    sal_uInt64      m_nBufFilePos; ///< File position of pBuf[0]
    StreamMode      m_eStreamMode;
    bool            m_isWritable;

    virtual std::size_t GetData( void* pData, std::size_t nSize );
    virtual std::size_t PutData( const void* pData, std::size_t nSize );
    virtual sal_uInt64 SeekPos( sal_uInt64 nPos );
    virtual void    FlushData();
    virtual void    SetSize(sal_uInt64 nSize);

    SAL_DLLPRIVATE void ClearError();
    SAL_DLLPRIVATE void ClearBuffer();

    // encrypt and write in blocks
    SAL_DLLPRIVATE std::size_t CryptAndWriteBuffer( const void* pStart, std::size_t nLen );
    SAL_DLLPRIVATE void EncryptBuffer( void* pStart, std::size_t nLen ) const;

public:
                    SvStream();
                    SvStream( SvLockBytes *pLockBytes);
    virtual         ~SvStream();

    SvLockBytes*    GetLockBytes() const { return m_xLockBytes.get(); }

    ErrCode         GetError() const { return m_nError.IgnoreWarning(); }
    ErrCode const & GetErrorCode() const { return m_nError; }
    void            SetError( ErrCode nErrorCode );
    virtual void    ResetError();

    void            SetEndian( SvStreamEndian SvStreamEndian );
    SvStreamEndian  GetEndian() const;
    /// returns status of endian swap flag
    bool            IsEndianSwap() const { return m_isSwap; }

    void            SetCompressMode( SvStreamCompressFlags nNewMode )
                        { m_nCompressMode = nNewMode; }
    SvStreamCompressFlags GetCompressMode() const { return m_nCompressMode; }

    void SetCryptMaskKey(const OString& rCryptMaskKey);

    void            SetStreamCharSet( rtl_TextEncoding eCharSet )
                        { m_eStreamCharSet = eCharSet; }
    rtl_TextEncoding GetStreamCharSet() const { return m_eStreamCharSet; }

    void            SetLineDelimiter( LineEnd eLineEnd )
                        { m_eLineDelimiter = eLineEnd; }
    LineEnd         GetLineDelimiter() const { return m_eLineDelimiter; }

    SvStream&       ReadUInt16( sal_uInt16& rUInt16 );
    SvStream&       ReadUInt32( sal_uInt32& rUInt32 );
    SvStream&       ReadUInt64( sal_uInt64& rUInt64 );
    SvStream&       ReadInt16( sal_Int16& rInt16 );
    SvStream&       ReadInt32( sal_Int32& rInt32 );
    SvStream&       ReadInt64(sal_Int64 & rInt64);
    SvStream&       ReadSChar( signed char& rChar );
    SvStream&       ReadChar( char& rChar );
    SvStream&       ReadUChar( unsigned char& rChar );
    SvStream&       ReadUtf16( sal_Unicode& rUtf16 );
    SvStream&       ReadCharAsBool( bool& rBool );
    SvStream&       ReadFloat( float& rFloat );
    SvStream&       ReadDouble( double& rDouble );
    SvStream&       ReadStream( SvStream& rStream );

    SvStream&       WriteUInt16( sal_uInt16 nUInt16 );
    SvStream&       WriteUInt32( sal_uInt32 nUInt32 );
    SvStream&       WriteUInt64( sal_uInt64 nuInt64 );
    SvStream&       WriteInt16( sal_Int16 nInt16 );
    SvStream&       WriteInt32( sal_Int32 nInt32 );
    SvStream&       WriteInt64( sal_Int64 nInt64 );
    SvStream&       WriteUInt8( sal_uInt8 nuInt8 );
    SvStream&       WriteUnicode( sal_Unicode );
    SvStream&       WriteOString(std::string_view rStr)
                        { WriteBytes(rStr.data(), rStr.size()); return *this; }
    SvStream&       WriteStream( SvStream& rStream );
    sal_uInt64      WriteStream( SvStream& rStream, sal_uInt64 nSize );

    SvStream&       WriteBool( bool b )
                        { return WriteUChar(static_cast<unsigned char>(b)); }
    SvStream&       WriteSChar( signed char nChar );
    SvStream&       WriteChar( char nChar );
    SvStream&       WriteUChar( unsigned char nChar );
    SvStream&       WriteFloat( float nFloat );
    SvStream&       WriteDouble( const double& rDouble );
    SvStream&       WriteCharPtr( const char* pBuf );

    SvStream&       WriteUInt32AsString( sal_uInt32 nUInt32 );
    SvStream&       WriteInt32AsString( sal_Int32 nInt32 );

    std::size_t     ReadBytes( void* pData, std::size_t nSize );
    std::size_t     WriteBytes( const void* pData, std::size_t nSize );
    sal_uInt64      Seek( sal_uInt64 nPos );
    sal_uInt64      SeekRel( sal_Int64 nPos );
    sal_uInt64      Tell() const { return m_nBufFilePos + m_nBufActualPos;  }
    virtual sal_uInt64 TellEnd();
    // length between current (Tell()) pos and end of stream
    sal_uInt64      remainingSize();
    /// If we have data in our internal buffers, write them out
    void            FlushBuffer();
    /// Call FlushBuffer() and then call flush on the underlying OS stream
    void            Flush();
    // next Tell() <= nSize
    bool            SetStreamSize( sal_uInt64 nSize );

    /** Read a line of bytes.

        @param nMaxBytesToRead
                   Maximum of bytes to read, if line is longer it will be
                   truncated.

        @note NOTE that the default is one character less than STRING_MAXLEN to
              prevent problems after conversion to String that may be lurking
              in various places doing something like
              @code
                for (sal_uInt16 i=0; i < aString.Len(); ++i)
              @endcode
              causing endless loops ...
    */
    bool            ReadLine( OStringBuffer& rStr, sal_Int32 nMaxBytesToRead = 0xFFFE );
    bool            ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead = 0xFFFE );
    bool            WriteLine( std::string_view rStr );

    /** Read a line of bytes.

        @param nMaxBytesToRead
                   Maximum of bytes to read, if line is longer it will be
                   truncated.

        @note NOTE that the default is one character less than STRING_MAXLEN to
              prevent problems after conversion to String that may be lurking
              in various places doing something like
              @code
                for (sal_uInt16 i=0; i < aString.Len(); ++i)
              @endcode
              causing endless loops ...
    */
    bool            ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
                                        sal_Int32 nMaxBytesToRead = 0xFFFE );
    bool            WriteByteStringLine( std::u16string_view rStr, rtl_TextEncoding eDestCharSet );

    /// Switch to no endian swapping and write 0xfeff
    void            StartWritingUnicodeText();

    /** If eReadBomCharSet==RTL_TEXTENCODING_DONTKNOW: read 16bit, if 0xfeff do
        nothing (UTF-16), if 0xfffe switch endian swapping (UTF-16), if 0xefbb
        or 0xbbef read another byte and check for UTF-8. If no UTF-* BOM was
        detected put all read bytes back. This means that if 2 bytes were read
        it was an UTF-16 BOM, if 3 bytes were read it was an UTF-8 BOM. There
        is no UTF-7, UTF-32 or UTF-EBCDIC BOM detection!

        If eReadBomCharSet!=RTL_TEXTENCODING_DONTKNOW: only read a BOM of that
        encoding and switch endian swapping if UTF-16 and 0xfffe. */
    void            StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet );

    /** Read a line of Unicode.

        @param nMaxCodepointsToRead
                   Maximum of codepoints (UCS-2 or UTF-16 pairs, not bytes) to
                   read, if line is longer it will be truncated.
    */
    SAL_DLLPRIVATE bool ReadUniStringLine(OUString& rStr, sal_Int32 nMaxCodepointsToRead);
    /** Read a 32bit length prefixed sequence of utf-16 if
        eSrcCharSet==RTL_TEXTENCODING_UNICODE, otherwise read a 16bit length
        prefixed sequence of bytes and convert from eSrcCharSet */
    OUString        ReadUniOrByteString(rtl_TextEncoding eSrcCharSet);
    /** Write a 32bit length prefixed sequence of utf-16 if
        eSrcCharSet==RTL_TEXTENCODING_UNICODE, otherwise convert to eSrcCharSet
        and write a 16bit length prefixed sequence of bytes */
    SvStream&       WriteUniOrByteString( std::u16string_view rStr, rtl_TextEncoding eDestCharSet );

    /** Read a line of Unicode if eSrcCharSet==RTL_TEXTENCODING_UNICODE,
        otherwise read a line of Bytecode and convert from eSrcCharSet

        @param nMaxCodepointsToRead
                   Maximum of codepoints (2 bytes if Unicode, bytes if not
                   Unicode) to read, if line is longer it will be truncated.

        @note NOTE that the default is one character less than STRING_MAXLEN to
              prevent problems after conversion to String that may be lurking in
              various places doing something like
              @code
                for (sal_uInt16 i=0; i < aString.Len(); ++i)
              @endcode
              causing endless loops ...
    */
    bool            ReadUniOrByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
                                             sal_Int32 nMaxCodepointsToRead = 0xFFFE );
    /** Write a sequence of Unicode characters if
        eDestCharSet==RTL_TEXTENCODING_UNICODE, otherwise write a sequence of
        Bytecodes converted to eDestCharSet */
    bool            WriteUnicodeOrByteText(std::u16string_view rStr, rtl_TextEncoding eDestCharSet );
    bool            WriteUnicodeOrByteText(std::u16string_view rStr )
                    { return WriteUnicodeOrByteText( rStr, GetStreamCharSet() ); }

    /** Write a Unicode character if eDestCharSet==RTL_TEXTENCODING_UNICODE,
        otherwise write as Bytecode converted to eDestCharSet.

        This may result in more than one byte being written if a multi byte
        encoding (e.g. UTF7, UTF8) is chosen. */
    bool            WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet );
    bool            WriteUniOrByteChar( sal_Unicode ch )
                    { return WriteUniOrByteChar( ch, GetStreamCharSet() ); }

    void            SetBufferSize( sal_uInt16 m_nBufSize );
    sal_uInt16      GetBufferSize() const { return m_nBufSize; }

    void            RefreshBuffer();

    bool            IsWritable() const { return m_isWritable; }
    StreamMode      GetStreamMode() const { return m_eStreamMode; }

    sal_Int32       GetVersion() const { return m_nVersion; }
    void            SetVersion( sal_Int32 n ) { m_nVersion = n; }

    friend SvStream& operator<<( SvStream& rStr, SvStrPtr f ); // for Manips

    /// end of input seen during previous i/o operation
    bool eof() const { return m_isEof; }

    /// stream is broken
    bool bad() const { return GetError() != ERRCODE_NONE; }

    /** Get state

        If the state is good() the previous i/o operation succeeded.

        If the state is good(), the next input operation might succeed;
        otherwise, it will fail.

        Applying an input operation to a stream that is not in the good() state
        is a null operation as far as the variable being read into is concerned.

        If we try to read into a variable v and the operation fails, the value
        of v should be unchanged,
    */
    bool good() const { return !(eof() || bad()); }

private:
    template <typename T> SvStream& ReadNumber(T& r);
    template <typename T> SvStream& WriteNumber(T n);

    template<typename T>
    void readNumberWithoutSwap(T& rDataDest)
    { readNumberWithoutSwap_(&rDataDest, sizeof(rDataDest)); }

    SAL_DLLPRIVATE void readNumberWithoutSwap_(void * pDataDest, int nDataSize);

    template<typename T>
    void writeNumberWithoutSwap(T const & rDataSrc)
    { writeNumberWithoutSwap_(&rDataSrc, sizeof(rDataSrc)); }

    SAL_DLLPRIVATE void writeNumberWithoutSwap_(const void * pDataSrc, int nDataSize);
};

inline SvStream& operator<<( SvStream& rStr, SvStrPtr f )
{
    (*f)(rStr);
    return rStr;
}

TOOLS_DLLPUBLIC SvStream& endl( SvStream& rStr );
/// same as endl() but Unicode
TOOLS_DLLPUBLIC SvStream& endlu( SvStream& rStr );
/// call endlu() if m_eStreamCharSet==RTL_TEXTECODING_UNICODE otherwise endl()
TOOLS_DLLPUBLIC SvStream& endlub( SvStream& rStr );

/// Attempt to read nUnits 8bit units to an OString, returned OString's
/// length is number of units successfully read
TOOLS_DLLPUBLIC OString read_uInt8s_ToOString(SvStream& rStrm,
    std::size_t nUnits);

/// Attempt to read nUnits 8bit units to an OUString
inline OUString read_uInt8s_ToOUString(SvStream& rStrm,
    std::size_t nUnits, rtl_TextEncoding eEnc)
{
    return OStringToOUString(read_uInt8s_ToOString(rStrm, nUnits), eEnc);
}

/// Attempt to read nUnits 16bit units to an OUString, returned
/// OUString's length is number of units successfully read
TOOLS_DLLPUBLIC OUString read_uInt16s_ToOUString(SvStream& rStrm,
    std::size_t nUnits);

/// Attempt to read a pascal-style length (of type prefix) prefixed sequence of
/// 16bit units to an OUString, returned OString's length is number of
/// units successfully read.
inline OUString read_uInt16_lenPrefixed_uInt16s_ToOUString(SvStream& rStrm)
{
    sal_uInt16 nUnits = 0;
    rStrm.ReadUInt16( nUnits );
    return read_uInt16s_ToOUString(rStrm, nUnits);
}

inline OUString read_uInt32_lenPrefixed_uInt16s_ToOUString(SvStream& rStrm)
{
    sal_uInt32 nUnits = 0;
    rStrm.ReadUInt32( nUnits );
    return read_uInt16s_ToOUString(rStrm, nUnits);
}

/// Attempt to write a prefixed sequence of nUnits 16bit units from an OUString,
/// returned value is number of bytes written
TOOLS_DLLPUBLIC std::size_t write_uInt16s_FromOUString(SvStream& rStrm,
    std::u16string_view rStr, std::size_t nUnits);

inline std::size_t write_uInt16s_FromOUString(SvStream& rStrm,
    std::u16string_view rStr)
{
    return write_uInt16s_FromOUString(rStrm, rStr, rStr.size());
}

/// Attempt to write a pascal-style length (of type prefix) prefixed sequence
/// of 16bit units from an OUString, returned value is number of bytes written
/// (including byte-count of prefix)
std::size_t write_uInt32_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
                                                std::u16string_view rStr);

/// Attempt to write a pascal-style length (of type prefix) prefixed sequence
/// of 16bit units from an OUString, returned value is number of bytes written
/// (including byte-count of prefix)
UNLESS_MERGELIBS(TOOLS_DLLPUBLIC) std::size_t write_uInt16_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
                                                std::u16string_view rStr);

/// Attempt to read 8bit units to an OString until a zero terminator is
/// encountered, returned OString's length is number of units *definitely*
/// successfully read, check SvStream::good() to see if null terminator was
/// successfully read
TOOLS_DLLPUBLIC OString read_zeroTerminated_uInt8s_ToOString(SvStream& rStrm);

/// Attempt to read 8bit units assuming source encoding eEnc to an OUString
/// until a zero terminator is encountered. Check SvStream::good() to see if
/// null terminator was successfully read
TOOLS_DLLPUBLIC OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStrm, rtl_TextEncoding eEnc);

/// Attempt to read a pascal-style length (of type prefix) prefixed sequence of
/// 8bit units to an OString, returned OString's length is number of units
/// successfully read.
inline OString read_uInt32_lenPrefixed_uInt8s_ToOString(SvStream& rStrm)
{
    sal_uInt32 nUnits = 0;
    rStrm.ReadUInt32(nUnits);
    return read_uInt8s_ToOString(rStrm, nUnits);
}
inline OString read_uInt16_lenPrefixed_uInt8s_ToOString(SvStream& rStrm)
{
    sal_uInt16 nUnits = 0;
    rStrm.ReadUInt16(nUnits);
    return read_uInt8s_ToOString(rStrm, nUnits);
}

inline OString read_uInt8_lenPrefixed_uInt8s_ToOString(SvStream& rStrm)
{
    sal_uInt8 nUnits = 0;
    rStrm.ReadUChar(nUnits);
    return read_uInt8s_ToOString(rStrm, nUnits);
}

inline OUString read_uInt16_lenPrefixed_uInt8s_ToOUString(SvStream& rStrm,
                                                          rtl_TextEncoding eEnc)
{
    return OStringToOUString(read_uInt16_lenPrefixed_uInt8s_ToOString(rStrm), eEnc);
}

inline OUString read_uInt8_lenPrefixed_uInt8s_ToOUString(SvStream& rStrm,
                                                         rtl_TextEncoding eEnc)
{
    return OStringToOUString(read_uInt8_lenPrefixed_uInt8s_ToOString(rStrm), eEnc);
}

/// Attempt to write a prefixed sequence of nUnits 8bit units from an OString,
/// returned value is number of bytes written
inline std::size_t write_uInt8s_FromOString(SvStream& rStrm, std::string_view rStr,
                                                         std::size_t nUnits)
{
    return rStrm.WriteBytes(rStr.data(), nUnits);
}

inline std::size_t write_uInt8s_FromOString(SvStream& rStrm, std::string_view rStr)
{
    return write_uInt8s_FromOString(rStrm, rStr, rStr.size());
}

/// Attempt to write a pascal-style length (of type prefix) prefixed
/// sequence of units from a string-type, returned value is number of bytes
/// written (including byte-count of prefix)
TOOLS_DLLPUBLIC std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm,
                                              std::string_view rStr);

/// Attempt to write a pascal-style length (of type prefix) prefixed sequence
/// of 8bit units from an OUString, returned value is number of bytes written
/// (including byte-count of prefix)
inline std::size_t write_uInt16_lenPrefixed_uInt8s_FromOUString(SvStream& rStrm,
                                               std::u16string_view rStr,
                                               rtl_TextEncoding eEnc)
{
    return write_uInt16_lenPrefixed_uInt8s_FromOString(rStrm, OUStringToOString(rStr, eEnc));
}

[[nodiscard]] TOOLS_DLLPUBLIC bool checkSeek(SvStream &rSt, sal_uInt64 nOffset);

namespace tools
{
/// Is rUrl a file:// URL with no contents?
TOOLS_DLLPUBLIC bool isEmptyFileUrl(const OUString& rUrl);
}

// FileStream

class TOOLS_DLLPUBLIC SvFileStream final : public SvStream
{
private:
    std::unique_ptr<StreamData>
                    pInstanceData;
    OUString        aFilename;
#if defined(_WIN32)
    sal_uInt16      nLockCounter;
#endif
    bool            bIsOpen;

    SvFileStream (const SvFileStream&) = delete;
    SvFileStream & operator= (const SvFileStream&) = delete;

    bool LockFile();
    void UnlockFile();

    virtual std::size_t GetData( void* pData, std::size_t nSize ) override;
    virtual std::size_t PutData( const void* pData, std::size_t nSize ) override;
    virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
    virtual void    SetSize( sal_uInt64 nSize ) override;
    virtual void    FlushData() override;

public:
                    // Switches to Read StreamMode on failed attempt of Write opening
                    SvFileStream( const OUString& rFileName, StreamMode eOpenMode );
                    SvFileStream();
                    virtual ~SvFileStream() override;

    virtual void    ResetError() override;

    void            Open( const OUString& rFileName, StreamMode eOpenMode );
    void            Close();
    bool            IsOpen() const { return bIsOpen; }

    const OUString& GetFileName() const { return aFilename; }
};

// MemoryStream

class TOOLS_DLLPUBLIC SvMemoryStream : public SvStream
{
    SvMemoryStream (const SvMemoryStream&) = delete;
    SvMemoryStream & operator= (const SvMemoryStream&) = delete;

protected:
    std::size_t     nSize;
    std::size_t     nResize;
    std::size_t     nPos;
    std::size_t     nEndOfData;
    sal_uInt8*      pBuf;
    bool            bOwnsData;

    virtual std::size_t GetData( void* pData, std::size_t nSize ) override;
    virtual std::size_t PutData( const void* pData, std::size_t nSize ) override;
    virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
    virtual void    SetSize( sal_uInt64 nSize ) override;
    virtual void    FlushData() override;

    /// AllocateMemory must update pBuf accordingly
    /// - pBuf: Address of new block
    void    AllocateMemory( std::size_t nSize );

    /// ReAllocateMemory must update the following variables:
    /// - pBuf: Address of new block
    /// - nEndOfData: Set to nNewSize-1 , if outside of block
    ///               Set to 0 , if new block size is 0 bytes
    /// - nSize: New block size
    /// - nPos: Set to 0 if position outside of block
    bool    ReAllocateMemory( tools::Long nDiff );

    /// Is called when this stream allocated the buffer or the buffer is
    /// resized. FreeMemory may need to NULLify handles in derived classes.
    void    FreeMemory();

public:
                    SvMemoryStream( void* pBuf, std::size_t nSize, StreamMode eMode);
                    SvMemoryStream( std::size_t nInitSize=512, std::size_t nResize=64 );
                    virtual ~SvMemoryStream() override;

    virtual void    ResetError() override;

    sal_uInt64      GetSize() { return TellEnd(); }
    std::size_t     GetEndOfData() const { return nEndOfData; }
    const void*     GetData() { FlushBuffer(); return pBuf; }

    // return the buffer currently in use, and allocate a new buffer internally
    void*           SwitchBuffer();
    // the buffer is not owned by this class
    void            SetBuffer( void* pBuf, std::size_t nSize, std::size_t nEOF );

    void            ObjectOwnsMemory( bool bOwn ) { bOwnsData = bOwn; }
    void            SetResizeOffset( std::size_t nNewResize ) { nResize = nNewResize; }
    virtual sal_uInt64 TellEnd() override { FlushBuffer(); return nEndOfData; }
};

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */