Version 7.3.5.2, tag libreoffice-7.3.5.2
[LibreOffice.git] / tools / source / stream / stream.cxx
blobd42cefdf63cf0e57405307fa20b9030729df589e
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 .
20 // TODO: Read->RefreshBuffer-> React to changes from m_nBufActualLen
22 #include <sal/config.h>
24 #include <cassert>
25 #include <cstddef>
26 #include <memory>
28 #include <string.h>
29 #include <stdio.h>
31 #include <o3tl/safeint.hxx>
32 #include <osl/endian.h>
33 #include <osl/diagnose.h>
34 #include <rtl/strbuf.hxx>
35 #include <rtl/ustrbuf.hxx>
36 #include <sal/log.hxx>
37 #include <tools/long.hxx>
39 #include <comphelper/fileformat.h>
40 #include <comphelper/fileurl.hxx>
42 static void swapNibbles(unsigned char &c)
44 unsigned char nSwapTmp=c;
45 nSwapTmp <<= 4;
46 c >>= 4;
47 c |= nSwapTmp;
50 #include <tools/debug.hxx>
51 #include <tools/stream.hxx>
52 #include <osl/thread.h>
53 #include <algorithm>
55 // !!! Do not inline if already the operators <<,>> are inline
56 template <typename T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) == 2, int> = 0>
57 static void SwapNumber(T& r)
58 { r = OSL_SWAPWORD(r); }
59 template <typename T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) == 4, int> = 0>
60 static void SwapNumber(T& r)
61 { r = OSL_SWAPDWORD(r); }
62 template <typename T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) == 8, int> = 0>
63 static void SwapNumber(T& r)
65 union
67 T n;
68 sal_uInt32 c[2];
69 } s;
71 s.n = r;
72 std::swap(s.c[0], s.c[1]); // swap the 32 bit words
73 // swap the bytes in the words
74 s.c[0] = OSL_SWAPDWORD(s.c[0]);
75 s.c[1] = OSL_SWAPDWORD(s.c[1]);
76 r = s.n;
79 #ifdef UNX
80 static void SwapFloat( float& r )
82 union
84 float f;
85 sal_uInt32 c;
86 } s;
88 s.f = r;
89 s.c = OSL_SWAPDWORD( s.c );
90 r = s.f;
93 static void SwapDouble( double& r )
95 if( sizeof(double) != 8 )
97 SAL_WARN( "tools.stream", "Can only swap 8-Byte-doubles" );
99 else
101 union
103 double d;
104 sal_uInt32 c[2];
105 } s;
107 s.d = r;
108 s.c[0] ^= s.c[1]; // swap 32-bit values in situ
109 s.c[1] ^= s.c[0];
110 s.c[0] ^= s.c[1];
111 s.c[0] = OSL_SWAPDWORD(s.c[0]); // swap dword itself in situ
112 s.c[1] = OSL_SWAPDWORD(s.c[1]);
113 r = s.d;
116 #endif
118 //SDO
120 void SvStream::readNumberWithoutSwap_(void * pDataDest, int nDataSize)
122 if (m_isIoRead && nDataSize <= m_nBufFree)
124 for (int i = 0; i < nDataSize; i++)
125 static_cast<char*>(pDataDest)[i] = m_pBufPos[i];
126 m_nBufActualPos += nDataSize;
127 m_pBufPos += nDataSize;
128 m_nBufFree -= nDataSize;
130 else
132 ReadBytes( pDataDest, nDataSize );
137 void SvStream::writeNumberWithoutSwap_(const void * pDataSrc, int nDataSize)
139 if (m_isIoWrite && nDataSize <= m_nBufFree)
141 for (int i = 0; i < nDataSize; i++)
142 m_pBufPos[i] = static_cast<const char*>(pDataSrc)[i];
143 m_nBufFree -= nDataSize;
144 m_nBufActualPos += nDataSize;
145 if (m_nBufActualPos > m_nBufActualLen)
146 m_nBufActualLen = m_nBufActualPos;
147 m_pBufPos += nDataSize;
148 m_isDirty = true;
150 else
152 WriteBytes( pDataSrc, nDataSize );
157 void SvLockBytes::close()
159 if (m_bOwner)
160 delete m_pStream;
161 m_pStream = nullptr;
165 // virtual
166 ErrCode SvLockBytes::ReadAt(sal_uInt64 const nPos, void * pBuffer, std::size_t nCount,
167 std::size_t * pRead) const
169 if (!m_pStream)
171 OSL_FAIL("SvLockBytes::ReadAt(): Bad stream");
172 return ERRCODE_NONE;
175 m_pStream->Seek(nPos);
176 std::size_t nTheRead = m_pStream->ReadBytes(pBuffer, nCount);
177 if (pRead)
178 *pRead = nTheRead;
179 return m_pStream->GetErrorCode();
182 // virtual
183 ErrCode SvLockBytes::WriteAt(sal_uInt64 const nPos, const void * pBuffer, std::size_t nCount,
184 std::size_t * pWritten)
186 if (!m_pStream)
188 OSL_FAIL("SvLockBytes::WriteAt(): Bad stream");
189 return ERRCODE_NONE;
192 m_pStream->Seek(nPos);
193 std::size_t nTheWritten = m_pStream->WriteBytes(pBuffer, nCount);
194 if (pWritten)
195 *pWritten = nTheWritten;
196 return m_pStream->GetErrorCode();
199 // virtual
200 ErrCode SvLockBytes::Flush() const
202 if (!m_pStream)
204 OSL_FAIL("SvLockBytes::Flush(): Bad stream");
205 return ERRCODE_NONE;
208 m_pStream->Flush();
209 return m_pStream->GetErrorCode();
212 // virtual
213 ErrCode SvLockBytes::SetSize(sal_uInt64 const nSize)
215 if (!m_pStream)
217 OSL_FAIL("SvLockBytes::SetSize(): Bad stream");
218 return ERRCODE_NONE;
221 m_pStream->SetStreamSize(nSize);
222 return m_pStream->GetErrorCode();
225 ErrCode SvLockBytes::Stat(SvLockBytesStat * pStat) const
227 if (!m_pStream)
229 OSL_FAIL("SvLockBytes::Stat(): Bad stream");
230 return ERRCODE_NONE;
233 if (pStat)
234 pStat->nSize = m_pStream->TellEnd();
235 return ERRCODE_NONE;
239 std::size_t SvStream::GetData( void* pData, std::size_t nSize )
241 if( !GetError() )
243 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
244 std::size_t nRet(0);
245 m_nError = m_xLockBytes->ReadAt(m_nActPos, pData, nSize, &nRet);
246 m_nActPos += nRet;
247 return nRet;
249 else return 0;
252 std::size_t SvStream::PutData( const void* pData, std::size_t nSize )
254 if( !GetError() )
256 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
257 std::size_t nRet(0);
258 m_nError = m_xLockBytes->WriteAt(m_nActPos, pData, nSize, &nRet);
259 m_nActPos += nRet;
260 return nRet;
262 else return 0;
265 sal_uInt64 SvStream::SeekPos(sal_uInt64 const nPos)
267 // check if a truncated STREAM_SEEK_TO_END was passed
268 assert(nPos != SAL_MAX_UINT32);
269 if( !GetError() && nPos == STREAM_SEEK_TO_END )
271 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
272 SvLockBytesStat aStat;
273 m_xLockBytes->Stat( &aStat );
274 m_nActPos = aStat.nSize;
276 else
277 m_nActPos = nPos;
278 return m_nActPos;
281 void SvStream::FlushData()
283 if( !GetError() )
285 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
286 m_nError = m_xLockBytes->Flush();
290 void SvStream::SetSize(sal_uInt64 const nSize)
292 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
293 m_nError = m_xLockBytes->SetSize( nSize );
296 SvStream::SvStream() :
297 m_nActPos(0)
299 , m_pBufPos(nullptr)
300 , m_nBufSize(0)
301 , m_nBufActualLen(0)
302 , m_nBufActualPos(0)
303 , m_nBufFree(0)
304 , m_isIoRead(false)
305 , m_isIoWrite(false)
307 , m_isDirty(false)
308 , m_isEof(false)
310 , m_nCompressMode(SvStreamCompressFlags::NONE)
311 #if defined UNX
312 , m_eLineDelimiter(LINEEND_LF) // UNIX-Format
313 #else
314 , m_eLineDelimiter(LINEEND_CRLF) // DOS-Format
315 #endif
316 , m_eStreamCharSet(osl_getThreadTextEncoding())
318 , m_nCryptMask(0)
320 , m_nVersion(0)
322 , m_nBufFilePos(0)
323 , m_eStreamMode(StreamMode::NONE)
324 , m_isWritable(true)
327 SetEndian( SvStreamEndian::LITTLE );
329 ClearError();
332 SvStream::SvStream( SvLockBytes* pLockBytesP ) : SvStream()
334 m_xLockBytes = pLockBytesP;
335 if( pLockBytesP ) {
336 const SvStream* pStrm = pLockBytesP->GetStream();
337 if( pStrm ) {
338 SetError( pStrm->GetErrorCode() );
341 SetBufferSize( 256 );
344 SvStream::~SvStream()
346 if (m_xLockBytes.is())
347 Flush();
350 void SvStream::ClearError()
352 m_isEof = false;
353 m_nError = ERRCODE_NONE;
356 void SvStream::SetError( ErrCode nErrorCode )
358 if (m_nError == ERRCODE_NONE)
359 m_nError = nErrorCode;
362 void SvStream::SetEndian( SvStreamEndian nNewFormat )
364 m_nEndian = nNewFormat;
365 m_isSwap = false;
366 #ifdef OSL_BIGENDIAN
367 if (m_nEndian == SvStreamEndian::LITTLE)
368 m_isSwap = true;
369 #else
370 if (m_nEndian == SvStreamEndian::BIG)
371 m_isSwap = true;
372 #endif
375 void SvStream::SetBufferSize( sal_uInt16 nBufferSize )
377 sal_uInt64 const nActualFilePos = Tell();
378 bool bDontSeek = (m_pRWBuf == nullptr);
380 if (m_isDirty && m_isWritable) // due to Windows NT: Access denied
381 Flush();
383 if (m_nBufSize)
385 m_pRWBuf.reset();
386 m_nBufFilePos += m_nBufActualPos;
389 m_pRWBuf = nullptr;
390 m_nBufActualLen = 0;
391 m_nBufActualPos = 0;
392 m_nBufSize = nBufferSize;
393 if (m_nBufSize)
394 m_pRWBuf.reset(new sal_uInt8[ m_nBufSize ]);
395 m_pBufPos = m_pRWBuf.get();
396 m_isIoRead = m_isIoWrite = false;
397 if( !bDontSeek )
398 SeekPos( nActualFilePos );
401 void SvStream::ClearBuffer()
403 m_nBufActualLen = 0;
404 m_nBufActualPos = 0;
405 m_nBufFilePos = 0;
406 m_pBufPos = m_pRWBuf.get();
407 m_isDirty = false;
408 m_isIoRead = m_isIoWrite = false;
410 m_isEof = false;
413 void SvStream::ResetError()
415 ClearError();
418 bool SvStream::ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
419 sal_Int32 nMaxBytesToRead )
421 OString aStr;
422 bool bRet = ReadLine( aStr, nMaxBytesToRead);
423 rStr = OStringToOUString(aStr, eSrcCharSet);
424 return bRet;
427 bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead )
429 char buf[256+1];
430 bool bEnd = false;
431 sal_uInt64 nOldFilePos = Tell();
432 char c = 0;
433 std::size_t nTotalLen = 0;
435 OStringBuffer aBuf(4096);
436 while( !bEnd && !GetError() ) // Don't test for EOF as we
437 // are reading block-wise!
439 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes(buf, sizeof(buf)-1));
440 if ( !nLen )
442 if ( aBuf.isEmpty() )
444 // Exit on first block-read error
445 m_isEof = true;
446 rStr.clear();
447 return false;
449 else
450 break;
453 sal_uInt16 j, n;
454 for( j = n = 0; j < nLen ; ++j )
456 c = buf[j];
457 if ( c == '\n' || c == '\r' )
459 bEnd = true;
460 break;
462 if ( n < j )
463 buf[n] = c;
464 ++n;
466 nTotalLen += j;
467 if (nTotalLen > o3tl::make_unsigned(nMaxBytesToRead))
469 n -= nTotalLen - nMaxBytesToRead;
470 nTotalLen = nMaxBytesToRead;
471 bEnd = true;
473 if ( n )
474 aBuf.append(buf, n);
477 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
478 bEnd = true;
480 nOldFilePos += nTotalLen;
481 if( Tell() > nOldFilePos )
482 nOldFilePos++;
483 Seek( nOldFilePos ); // Seek pointer due to BlockRead above
485 if ( bEnd && (c=='\r' || c=='\n') ) // Special treatment for DOS files
487 char cTemp;
488 std::size_t nLen = ReadBytes(&cTemp, sizeof(cTemp));
489 if ( nLen ) {
490 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
491 Seek( nOldFilePos );
495 if ( bEnd )
496 m_isEof = false;
497 rStr = aBuf.makeStringAndClear();
498 return bEnd;
501 bool SvStream::ReadUniStringLine( OUString& rStr, sal_Int32 nMaxCodepointsToRead )
503 sal_Unicode buf[256+1];
504 bool bEnd = false;
505 sal_uInt64 nOldFilePos = Tell();
506 sal_Unicode c = 0;
507 std::size_t nTotalLen = 0;
509 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "ReadUniStringLine: swapping sizeof(sal_Unicode) not implemented" );
511 OUStringBuffer aBuf(4096);
512 while( !bEnd && !GetError() ) // Don't test for EOF as we
513 // are reading block-wise!
515 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes( buf, sizeof(buf)-sizeof(sal_Unicode)));
516 nLen /= sizeof(sal_Unicode);
517 if ( !nLen )
519 if ( aBuf.isEmpty() )
521 // exit on first BlockRead error
522 m_isEof = true;
523 rStr.clear();
524 return false;
526 else
527 break;
530 sal_uInt16 j, n;
531 for( j = n = 0; j < nLen ; ++j )
533 if (m_isSwap)
534 SwapNumber( buf[n] );
535 c = buf[j];
536 if ( c == '\n' || c == '\r' )
538 bEnd = true;
539 break;
541 // erAck 26.02.01: Old behavior was no special treatment of '\0'
542 // character here, but a following rStr+=c did ignore it. Is this
543 // really intended? Or should a '\0' better terminate a line?
544 // The nOldFilePos stuff wasn't correct then anyways.
545 if ( c )
547 if ( n < j )
548 buf[n] = c;
549 ++n;
552 nTotalLen += j;
553 if (nTotalLen > o3tl::make_unsigned(nMaxCodepointsToRead))
555 n -= nTotalLen - nMaxCodepointsToRead;
556 nTotalLen = nMaxCodepointsToRead;
557 bEnd = true;
559 if ( n )
560 aBuf.append( buf, n );
563 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
564 bEnd = true;
566 nOldFilePos += nTotalLen * sizeof(sal_Unicode);
567 if( Tell() > nOldFilePos )
568 nOldFilePos += sizeof(sal_Unicode);
569 Seek( nOldFilePos ); // seek due to BlockRead above
571 if ( bEnd && (c=='\r' || c=='\n') ) // special treatment for DOS files
573 sal_Unicode cTemp;
574 ReadBytes( &cTemp, sizeof(cTemp) );
575 if (m_isSwap)
576 SwapNumber( cTemp );
577 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
578 Seek( nOldFilePos );
581 if ( bEnd )
582 m_isEof = false;
583 rStr = aBuf.makeStringAndClear();
584 return bEnd;
587 bool SvStream::ReadUniOrByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
588 sal_Int32 nMaxCodepointsToRead )
590 if ( eSrcCharSet == RTL_TEXTENCODING_UNICODE )
591 return ReadUniStringLine( rStr, nMaxCodepointsToRead );
592 else
593 return ReadByteStringLine( rStr, eSrcCharSet, nMaxCodepointsToRead );
596 OString read_zeroTerminated_uInt8s_ToOString(SvStream& rStream)
598 OStringBuffer aOutput(256);
600 char buf[ 256 + 1 ];
601 bool bEnd = false;
602 sal_uInt64 nFilePos = rStream.Tell();
604 while( !bEnd && !rStream.GetError() )
606 std::size_t nLen = rStream.ReadBytes(buf, sizeof(buf)-1);
607 if (!nLen)
608 break;
610 std::size_t nReallyRead = nLen;
611 const char* pPtr = buf;
612 while (nLen && *pPtr)
614 ++pPtr;
615 --nLen;
618 bEnd = ( nReallyRead < sizeof(buf)-1 ) // read less than attempted to read
619 || ( ( nLen > 0 ) // OR it is inside the block we read
620 && ( 0 == *pPtr ) // AND found a string terminator
623 aOutput.append(buf, pPtr - buf);
626 nFilePos += aOutput.getLength();
627 if (rStream.Tell() > nFilePos)
628 rStream.Seek(nFilePos+1); // seek due to FileRead above
629 return aOutput.makeStringAndClear();
632 OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStream, rtl_TextEncoding eEnc)
634 return OStringToOUString(
635 read_zeroTerminated_uInt8s_ToOString(rStream), eEnc);
638 /** Attempt to write a prefixed sequence of nUnits 16bit units from an OUString,
639 returned value is number of bytes written */
640 std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr,
641 std::size_t nUnits)
643 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "write_uInt16s_FromOUString: swapping sizeof(sal_Unicode) not implemented" );
644 std::size_t nWritten;
645 if (!rStrm.IsEndianSwap())
646 nWritten = rStrm.WriteBytes(rStr.data(), nUnits * sizeof(sal_Unicode));
647 else
649 std::size_t nLen = nUnits;
650 sal_Unicode aBuf[384];
651 sal_Unicode* const pTmp = ( nLen > 384 ? new sal_Unicode[nLen] : aBuf);
652 memcpy( pTmp, rStr.data(), nLen * sizeof(sal_Unicode) );
653 sal_Unicode* p = pTmp;
654 const sal_Unicode* const pStop = pTmp + nLen;
655 while ( p < pStop )
657 SwapNumber( *p );
658 p++;
660 nWritten = rStrm.WriteBytes( pTmp, nLen * sizeof(sal_Unicode) );
661 if ( pTmp != aBuf )
662 delete [] pTmp;
664 return nWritten;
667 bool SvStream::WriteUnicodeOrByteText( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
669 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
671 write_uInt16s_FromOUString(*this, rStr, rStr.size());
672 return m_nError == ERRCODE_NONE;
674 else
676 OString aStr(OUStringToOString(rStr, eDestCharSet));
677 write_uInt8s_FromOString(*this, aStr, aStr.getLength());
678 return m_nError == ERRCODE_NONE;
682 bool SvStream::WriteByteStringLine( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
684 return WriteLine(OUStringToOString(rStr, eDestCharSet));
687 bool SvStream::WriteLine(std::string_view rStr)
689 WriteBytes(rStr.data(), rStr.size());
690 endl(*this);
691 return m_nError == ERRCODE_NONE;
694 bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet )
696 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
697 WriteUnicode(ch);
698 else
700 OString aStr(&ch, 1, eDestCharSet);
701 WriteBytes(aStr.getStr(), aStr.getLength());
703 return m_nError == ERRCODE_NONE;
706 void SvStream::StartWritingUnicodeText()
708 // BOM, Byte Order Mark, U+FEFF, see
709 // http://www.unicode.org/faq/utf_bom.html#BOM
710 // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap
711 writeNumberWithoutSwap(sal_uInt16(0xfeff)); // write native format
714 void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet )
716 if (!( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
717 eReadBomCharSet == RTL_TEXTENCODING_UNICODE ||
718 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
719 return; // nothing to read
721 bool bTryUtf8 = false;
722 sal_uInt16 nFlag(0);
723 sal_sSize nBack = sizeof(nFlag);
724 ReadUInt16( nFlag );
725 switch ( nFlag )
727 case 0xfeff :
728 // native UTF-16
729 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
730 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
731 nBack = 0;
732 break;
733 case 0xfffe :
734 // swapped UTF-16
735 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
736 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
738 SetEndian( m_nEndian == SvStreamEndian::BIG ? SvStreamEndian::LITTLE : SvStreamEndian::BIG );
739 nBack = 0;
741 break;
742 case 0xefbb :
743 if (m_nEndian == SvStreamEndian::BIG &&
744 (eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
745 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
746 bTryUtf8 = true;
747 break;
748 case 0xbbef :
749 if (m_nEndian == SvStreamEndian::LITTLE &&
750 (eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
751 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
752 bTryUtf8 = true;
753 break;
754 default:
755 ; // nothing
757 if (bTryUtf8)
759 unsigned char nChar(0);
760 nBack += sizeof(nChar);
761 ReadUChar( nChar );
762 if (nChar == 0xbf)
763 nBack = 0; // it is UTF-8
765 if (nBack)
766 SeekRel( -nBack ); // no BOM, pure data
769 sal_uInt64 SvStream::SeekRel(sal_Int64 const nPos)
771 sal_uInt64 nActualPos = Tell();
773 if ( nPos >= 0 )
775 if (SAL_MAX_UINT64 - nActualPos > o3tl::make_unsigned(nPos))
776 nActualPos += nPos;
778 else
780 sal_uInt64 const nAbsPos = static_cast<sal_uInt64>(-nPos);
781 if ( nActualPos >= nAbsPos )
782 nActualPos -= nAbsPos;
785 assert((m_pBufPos != nullptr) == bool(m_pRWBuf));
786 if (m_pRWBuf)
788 m_pBufPos = m_pRWBuf.get() + nActualPos;
790 return Seek( nActualPos );
793 template <typename T> SvStream& SvStream::ReadNumber(T& r)
795 T n = 0;
796 readNumberWithoutSwap(n);
797 if (good())
799 if (m_isSwap)
800 SwapNumber(n);
801 r = n;
803 return *this;
806 SvStream& SvStream::ReadUInt16(sal_uInt16& r) { return ReadNumber(r); }
807 SvStream& SvStream::ReadUInt32(sal_uInt32& r) { return ReadNumber(r); }
808 SvStream& SvStream::ReadUInt64(sal_uInt64& r) { return ReadNumber(r); }
809 SvStream& SvStream::ReadInt16(sal_Int16& r) { return ReadNumber(r); }
810 SvStream& SvStream::ReadInt32(sal_Int32& r) { return ReadNumber(r); }
811 SvStream& SvStream::ReadInt64(sal_Int64& r) { return ReadNumber(r); }
813 SvStream& SvStream::ReadSChar( signed char& r )
815 if (m_isIoRead && sizeof(signed char) <= m_nBufFree)
817 r = *m_pBufPos;
818 m_nBufActualPos += sizeof(signed char);
819 m_pBufPos += sizeof(signed char);
820 m_nBufFree -= sizeof(signed char);
822 else
823 ReadBytes( &r, sizeof(signed char) );
824 return *this;
827 // Special treatment for Chars due to PutBack
829 SvStream& SvStream::ReadChar( char& r )
831 if (m_isIoRead && sizeof(char) <= m_nBufFree)
833 r = *m_pBufPos;
834 m_nBufActualPos += sizeof(char);
835 m_pBufPos += sizeof(char);
836 m_nBufFree -= sizeof(char);
838 else
839 ReadBytes( &r, sizeof(char) );
840 return *this;
843 SvStream& SvStream::ReadUChar( unsigned char& r )
845 if (m_isIoRead && sizeof(char) <= m_nBufFree)
847 r = *m_pBufPos;
848 m_nBufActualPos += sizeof(char);
849 m_pBufPos += sizeof(char);
850 m_nBufFree -= sizeof(char);
852 else
853 ReadBytes( &r, sizeof(char) );
854 return *this;
857 SvStream& SvStream::ReadUtf16(sal_Unicode& r) { return ReadNumber(r); }
859 SvStream& SvStream::ReadCharAsBool( bool& r )
861 if (m_isIoRead && sizeof(char) <= m_nBufFree)
863 SAL_WARN_IF(
864 *m_pBufPos > 1, "tools.stream", unsigned(*m_pBufPos) << " not 0/1");
865 r = *m_pBufPos != 0;
866 m_nBufActualPos += sizeof(char);
867 m_pBufPos += sizeof(char);
868 m_nBufFree -= sizeof(char);
870 else
872 unsigned char c;
873 if (ReadBytes(&c, 1) == 1)
875 SAL_WARN_IF(c > 1, "tools.stream", unsigned(c) << " not 0/1");
876 r = c != 0;
879 return *this;
882 SvStream& SvStream::ReadFloat(float& r)
884 float n = 0;
885 readNumberWithoutSwap(n);
886 if (good())
888 #if defined UNX
889 if (m_isSwap)
890 SwapFloat(n);
891 #endif
892 r = n;
894 return *this;
897 SvStream& SvStream::ReadDouble(double& r)
899 double n = 0;
900 readNumberWithoutSwap(n);
901 if (good())
903 #if defined UNX
904 if (m_isSwap)
905 SwapDouble(n);
906 #endif
907 r = n;
909 return *this;
912 SvStream& SvStream::ReadStream( SvStream& rStream )
914 const sal_uInt32 cBufLen = 0x8000;
915 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
917 sal_uInt32 nCount;
918 do {
919 nCount = ReadBytes( pBuf.get(), cBufLen );
920 rStream.WriteBytes( pBuf.get(), nCount );
921 } while( nCount == cBufLen );
923 return *this;
926 template <typename T> SvStream& SvStream::WriteNumber(T n)
928 if (m_isSwap)
929 SwapNumber(n);
930 writeNumberWithoutSwap(n);
931 return *this;
934 SvStream& SvStream::WriteUInt16(sal_uInt16 v) { return WriteNumber(v); }
935 SvStream& SvStream::WriteUInt32(sal_uInt32 v) { return WriteNumber(v); }
936 SvStream& SvStream::WriteUInt64(sal_uInt64 v) { return WriteNumber(v); }
937 SvStream& SvStream::WriteInt16(sal_Int16 v) { return WriteNumber(v); }
938 SvStream& SvStream::WriteInt32(sal_Int32 v) { return WriteNumber(v); }
939 SvStream& SvStream::WriteInt64(sal_Int64 v) { return WriteNumber(v); }
941 SvStream& SvStream::WriteSChar( signed char v )
943 //SDO
944 if (m_isIoWrite && sizeof(signed char) <= m_nBufFree)
946 *m_pBufPos = v;
947 m_pBufPos++; // sizeof(char);
948 m_nBufActualPos++;
949 if (m_nBufActualPos > m_nBufActualLen) // Append ?
950 m_nBufActualLen = m_nBufActualPos;
951 m_nBufFree--; // = sizeof(char);
952 m_isDirty = true;
954 else
955 WriteBytes( &v, sizeof(signed char) );
956 return *this;
959 // Special treatment for Chars due to PutBack
961 SvStream& SvStream::WriteChar( char v )
963 //SDO
964 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
966 *m_pBufPos = v;
967 m_pBufPos++; // sizeof(char);
968 m_nBufActualPos++;
969 if (m_nBufActualPos > m_nBufActualLen) // Append ?
970 m_nBufActualLen = m_nBufActualPos;
971 m_nBufFree--; // = sizeof(char);
972 m_isDirty = true;
974 else
975 WriteBytes( &v, sizeof(char) );
976 return *this;
979 SvStream& SvStream::WriteUChar( unsigned char v )
981 //SDO
982 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
984 *reinterpret_cast<unsigned char*>(m_pBufPos) = v;
985 m_pBufPos++; // = sizeof(char);
986 m_nBufActualPos++; // = sizeof(char);
987 if (m_nBufActualPos > m_nBufActualLen) // Append ?
988 m_nBufActualLen = m_nBufActualPos;
989 m_nBufFree--;
990 m_isDirty = true;
992 else
993 WriteBytes( &v, sizeof(char) );
994 return *this;
997 SvStream& SvStream::WriteUInt8( sal_uInt8 v )
999 return WriteUChar(v);
1002 SvStream& SvStream::WriteUnicode( sal_Unicode v )
1004 return WriteUInt16(v);
1007 SvStream& SvStream::WriteFloat( float v )
1009 #ifdef UNX
1010 if (m_isSwap)
1011 SwapFloat(v);
1012 #endif
1013 writeNumberWithoutSwap(v);
1014 return *this;
1017 SvStream& SvStream::WriteDouble ( const double& r )
1019 #if defined UNX
1020 if (m_isSwap)
1022 double nHelp = r;
1023 SwapDouble(nHelp);
1024 writeNumberWithoutSwap(nHelp);
1025 return *this;
1027 else
1028 #endif
1030 writeNumberWithoutSwap(r);
1032 return *this;
1035 SvStream& SvStream::WriteCharPtr( const char* pBuf )
1037 WriteBytes( pBuf, strlen(pBuf) );
1038 return *this;
1041 SvStream& SvStream::WriteStream( SvStream& rStream )
1043 const sal_uInt32 cBufLen = 0x8000;
1044 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1045 sal_uInt32 nCount;
1046 do {
1047 nCount = rStream.ReadBytes( pBuf.get(), cBufLen );
1048 WriteBytes( pBuf.get(), nCount );
1049 } while( nCount == cBufLen );
1051 return *this;
1054 sal_uInt64 SvStream::WriteStream( SvStream& rStream, sal_uInt64 nSize )
1056 const sal_uInt32 cBufLen = 0x8000;
1057 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1058 sal_uInt32 nCurBufLen = cBufLen;
1059 sal_uInt32 nCount;
1060 sal_uInt64 nWriteSize = nSize;
1064 nCurBufLen = std::min<sal_uInt64>(nCurBufLen, nWriteSize);
1065 nCount = rStream.ReadBytes(pBuf.get(), nCurBufLen);
1066 WriteBytes( pBuf.get(), nCount );
1067 nWriteSize -= nCount;
1069 while( nWriteSize && nCount == nCurBufLen );
1071 return nSize - nWriteSize;
1074 OUString SvStream::ReadUniOrByteString( rtl_TextEncoding eSrcCharSet )
1076 // read UTF-16 string directly from stream ?
1077 if (eSrcCharSet == RTL_TEXTENCODING_UNICODE)
1078 return read_uInt32_lenPrefixed_uInt16s_ToOUString(*this);
1079 return read_uInt16_lenPrefixed_uInt8s_ToOUString(*this, eSrcCharSet);
1082 SvStream& SvStream::WriteUniOrByteString( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
1084 // write UTF-16 string directly into stream ?
1085 if (eDestCharSet == RTL_TEXTENCODING_UNICODE)
1086 write_uInt32_lenPrefixed_uInt16s_FromOUString(*this, rStr);
1087 else
1088 write_uInt16_lenPrefixed_uInt8s_FromOUString(*this, rStr, eDestCharSet);
1089 return *this;
1092 void SvStream::FlushBuffer()
1094 if (m_isDirty) // Does stream require a flush?
1096 SeekPos(m_nBufFilePos);
1097 if (m_nCryptMask)
1098 CryptAndWriteBuffer(m_pRWBuf.get(), m_nBufActualLen);
1099 else if (PutData(m_pRWBuf.get(), m_nBufActualLen) != m_nBufActualLen)
1100 SetError(SVSTREAM_WRITE_ERROR);
1101 m_isDirty = false;
1105 std::size_t SvStream::ReadBytes( void* pData, std::size_t nCount )
1107 std::size_t nSaveCount = nCount;
1109 if (!m_pRWBuf)
1111 nCount = GetData( pData,nCount);
1112 if (m_nCryptMask)
1113 EncryptBuffer(pData, nCount);
1114 m_nBufFilePos += nCount;
1116 else
1118 // check if block is completely within buffer
1119 m_isIoRead = true;
1120 m_isIoWrite = false;
1121 if (nCount <= o3tl::make_unsigned(m_nBufActualLen - m_nBufActualPos))
1123 // => yes
1124 if (nCount != 0)
1125 memcpy(pData, m_pBufPos, nCount);
1126 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1127 m_pBufPos += nCount;
1128 m_nBufFree = m_nBufFree - static_cast<sal_uInt16>(nCount);
1130 else
1132 FlushBuffer();
1134 // Does data block fit into buffer?
1135 if (nCount > m_nBufSize)
1137 // => No! Thus read directly
1138 // into target area without using the buffer
1140 m_isIoRead = false;
1142 SeekPos(m_nBufFilePos + m_nBufActualPos);
1143 m_nBufActualLen = 0;
1144 m_pBufPos = m_pRWBuf.get();
1145 nCount = GetData( pData, nCount );
1146 if (m_nCryptMask)
1147 EncryptBuffer(pData, nCount);
1148 m_nBufFilePos += nCount;
1149 m_nBufFilePos += m_nBufActualPos;
1150 m_nBufActualPos = 0;
1152 else
1154 // => Yes. Fill buffer first, then copy to target area
1156 m_nBufFilePos += m_nBufActualPos;
1157 SeekPos(m_nBufFilePos);
1159 // TODO: Typecast before GetData, sal_uInt16 nCountTmp
1160 std::size_t nCountTmp = GetData( m_pRWBuf.get(), m_nBufSize );
1161 if (m_nCryptMask)
1162 EncryptBuffer(m_pRWBuf.get(), nCountTmp);
1163 m_nBufActualLen = static_cast<sal_uInt16>(nCountTmp);
1164 if( nCount > nCountTmp )
1166 nCount = nCountTmp; // trim count back, EOF see below
1168 memcpy( pData, m_pRWBuf.get(), nCount );
1169 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1170 m_pBufPos = m_pRWBuf.get() + nCount;
1174 m_isEof = false;
1175 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1176 if (nCount != nSaveCount && m_nError != ERRCODE_IO_PENDING)
1177 m_isEof = true;
1178 if (nCount == nSaveCount && m_nError == ERRCODE_IO_PENDING)
1179 m_nError = ERRCODE_NONE;
1180 return nCount;
1183 std::size_t SvStream::WriteBytes( const void* pData, std::size_t nCount )
1185 if( !nCount )
1186 return 0;
1188 if (!m_isWritable)
1190 SetError( ERRCODE_IO_CANTWRITE );
1191 return 0;
1194 if (!m_pRWBuf)
1196 if (m_nCryptMask)
1197 nCount = CryptAndWriteBuffer( pData, nCount );
1198 else
1199 nCount = PutData( pData, nCount );
1200 m_nBufFilePos += nCount;
1201 return nCount;
1204 m_isIoRead = false;
1205 m_isIoWrite = true;
1206 if (nCount <= o3tl::make_unsigned(m_nBufSize - m_nBufActualPos))
1208 memcpy( m_pBufPos, pData, nCount );
1209 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1210 // Update length if buffer was updated
1211 if (m_nBufActualPos > m_nBufActualLen)
1212 m_nBufActualLen = m_nBufActualPos;
1214 m_pBufPos += nCount;
1215 m_isDirty = true;
1217 else
1219 FlushBuffer();
1221 // Does data block fit into buffer?
1222 if (nCount > m_nBufSize)
1224 m_isIoWrite = false;
1225 m_nBufFilePos += m_nBufActualPos;
1226 m_nBufActualLen = 0;
1227 m_nBufActualPos = 0;
1228 m_pBufPos = m_pRWBuf.get();
1229 SeekPos(m_nBufFilePos);
1230 if (m_nCryptMask)
1231 nCount = CryptAndWriteBuffer( pData, nCount );
1232 else
1233 nCount = PutData( pData, nCount );
1234 m_nBufFilePos += nCount;
1236 else
1238 // Copy block to buffer
1239 memcpy( m_pRWBuf.get(), pData, nCount );
1241 // Mind the order!
1242 m_nBufFilePos += m_nBufActualPos;
1243 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1244 m_pBufPos = m_pRWBuf.get() + nCount;
1245 m_nBufActualLen = static_cast<sal_uInt16>(nCount);
1246 m_isDirty = true;
1249 m_nBufFree = m_nBufSize - m_nBufActualPos;
1250 return nCount;
1253 sal_uInt64 SvStream::Seek(sal_uInt64 const nFilePos)
1255 m_isIoRead = m_isIoWrite = false;
1256 m_isEof = false;
1257 if (!m_pRWBuf)
1259 m_nBufFilePos = SeekPos( nFilePos );
1260 DBG_ASSERT(Tell() == m_nBufFilePos,"Out Of Sync!");
1261 return m_nBufFilePos;
1264 // Is seek position within buffer?
1265 if (nFilePos >= m_nBufFilePos && nFilePos <= (m_nBufFilePos + m_nBufActualLen))
1267 m_nBufActualPos = static_cast<sal_uInt16>(nFilePos - m_nBufFilePos);
1268 m_pBufPos = m_pRWBuf.get() + m_nBufActualPos;
1269 // Update m_nBufFree to avoid crash upon PutBack
1270 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1272 else
1274 FlushBuffer();
1275 m_nBufActualLen = 0;
1276 m_nBufActualPos = 0;
1277 m_pBufPos = m_pRWBuf.get();
1278 m_nBufFilePos = SeekPos( nFilePos );
1280 return m_nBufFilePos + m_nBufActualPos;
1283 bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
1285 const sal_uInt64 nMaxSeek = rSt.TellEnd();
1286 return (nOffset <= nMaxSeek && rSt.Seek(nOffset) == nOffset);
1289 namespace tools
1291 bool isEmptyFileUrl(const OUString& rUrl)
1293 if (!comphelper::isFileUrl(rUrl))
1295 return false;
1298 SvFileStream aStream(rUrl, StreamMode::READ);
1299 if (!aStream.IsOpen())
1301 return false;
1304 return aStream.remainingSize() == 0;
1308 //STREAM_SEEK_TO_END in some of the Seek backends is special cased to be
1309 //efficient, in others e.g. SotStorageStream it's really horribly slow, and in
1310 //those this should be overridden
1311 sal_uInt64 SvStream::remainingSize()
1313 sal_uInt64 const nCurr = Tell();
1314 sal_uInt64 const nEnd = TellEnd();
1315 sal_uInt64 nMaxAvailable = nEnd > nCurr ? (nEnd-nCurr) : 0;
1316 return nMaxAvailable;
1319 sal_uInt64 SvStream::TellEnd()
1321 FlushBuffer();
1322 sal_uInt64 const nCurr = Tell();
1323 sal_uInt64 const nEnd = Seek(STREAM_SEEK_TO_END);
1324 Seek(nCurr);
1325 return nEnd;
1328 void SvStream::Flush()
1330 FlushBuffer();
1331 if (m_isWritable)
1332 FlushData();
1335 void SvStream::RefreshBuffer()
1337 FlushBuffer();
1338 SeekPos(m_nBufFilePos);
1339 m_nBufActualLen = static_cast<sal_uInt16>(GetData( m_pRWBuf.get(), m_nBufSize ));
1340 if (m_nBufActualLen && m_nError == ERRCODE_IO_PENDING)
1341 m_nError = ERRCODE_NONE;
1342 if (m_nCryptMask)
1343 EncryptBuffer(m_pRWBuf.get(), static_cast<std::size_t>(m_nBufActualLen));
1344 m_isIoRead = m_isIoWrite = false;
1347 SvStream& SvStream::WriteInt32AsString(sal_Int32 nInt32)
1349 char buffer[12];
1350 std::size_t nLen = sprintf(buffer, "%" SAL_PRIdINT32, nInt32);
1351 WriteBytes(buffer, nLen);
1352 return *this;
1355 SvStream& SvStream::WriteUInt32AsString(sal_uInt32 nUInt32)
1357 char buffer[11];
1358 std::size_t nLen = sprintf(buffer, "%" SAL_PRIuUINT32, nUInt32);
1359 WriteBytes(buffer, nLen);
1360 return *this;
1363 #define CRYPT_BUFSIZE 1024
1365 /// Encrypt and write
1366 std::size_t SvStream::CryptAndWriteBuffer( const void* pStart, std::size_t nLen)
1368 unsigned char pTemp[CRYPT_BUFSIZE];
1369 unsigned char const * pDataPtr = static_cast<unsigned char const *>(pStart);
1370 std::size_t nCount = 0;
1371 std::size_t nBufCount;
1372 unsigned char nMask = m_nCryptMask;
1375 if( nLen >= CRYPT_BUFSIZE )
1376 nBufCount = CRYPT_BUFSIZE;
1377 else
1378 nBufCount = nLen;
1379 nLen -= nBufCount;
1380 memcpy( pTemp, pDataPtr, static_cast<sal_uInt16>(nBufCount) );
1381 // ******** Encrypt ********
1382 for (unsigned char & rn : pTemp)
1384 unsigned char aCh = rn;
1385 aCh ^= nMask;
1386 swapNibbles(aCh);
1387 rn = aCh;
1389 // *************************
1390 nCount += PutData( pTemp, nBufCount );
1391 pDataPtr += nBufCount;
1393 while ( nLen );
1394 return nCount;
1397 void SvStream::EncryptBuffer(void* pStart, std::size_t nLen) const
1399 unsigned char* pTemp = static_cast<unsigned char*>(pStart);
1400 unsigned char nMask = m_nCryptMask;
1402 for ( std::size_t n=0; n < nLen; n++, pTemp++ )
1404 unsigned char aCh = *pTemp;
1405 swapNibbles(aCh);
1406 aCh ^= nMask;
1407 *pTemp = aCh;
1411 static unsigned char implGetCryptMask(const char* pStr, sal_Int32 nLen, tools::Long nVersion)
1413 unsigned char nCryptMask = 0;
1415 if (!nLen)
1416 return nCryptMask;
1418 if( nVersion <= SOFFICE_FILEFORMAT_31 )
1420 while( nLen )
1422 nCryptMask ^= *pStr;
1423 pStr++;
1424 nLen--;
1427 else // BugFix #25888#
1429 for( sal_Int32 i = 0; i < nLen; i++ ) {
1430 nCryptMask ^= pStr[i];
1431 if( nCryptMask & 0x80 ) {
1432 nCryptMask <<= 1;
1433 nCryptMask++;
1435 else
1436 nCryptMask <<= 1;
1440 if( !nCryptMask )
1441 nCryptMask = 67;
1443 return nCryptMask;
1446 void SvStream::SetCryptMaskKey(const OString& rCryptMaskKey)
1448 m_aCryptMaskKey = rCryptMaskKey;
1449 m_nCryptMask = implGetCryptMask(m_aCryptMaskKey.getStr(),
1450 m_aCryptMaskKey.getLength(), GetVersion());
1453 bool SvStream::SetStreamSize(sal_uInt64 const nSize)
1455 #ifdef DBG_UTIL
1456 sal_uInt64 nFPos = Tell();
1457 #endif
1458 sal_uInt16 nBuf = m_nBufSize;
1459 SetBufferSize( 0 );
1460 SetSize( nSize );
1461 if (nSize < m_nBufFilePos)
1463 m_nBufFilePos = nSize;
1465 SetBufferSize( nBuf );
1466 #ifdef DBG_UTIL
1467 DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed");
1468 #endif
1469 return (m_nError == ERRCODE_NONE);
1472 SvStream& endl( SvStream& rStr )
1474 LineEnd eDelim = rStr.GetLineDelimiter();
1475 if ( eDelim == LINEEND_CR )
1476 rStr.WriteChar('\r');
1477 else if( eDelim == LINEEND_LF )
1478 rStr.WriteChar('\n');
1479 else
1480 rStr.WriteChar('\r').WriteChar('\n');
1481 return rStr;
1484 SvStream& endlu( SvStream& rStrm )
1486 switch ( rStrm.GetLineDelimiter() )
1488 case LINEEND_CR :
1489 rStrm.WriteUnicode('\r');
1490 break;
1491 case LINEEND_LF :
1492 rStrm.WriteUnicode('\n');
1493 break;
1494 default:
1495 rStrm.WriteUnicode('\r').WriteUnicode('\n');
1497 return rStrm;
1500 SvStream& endlub( SvStream& rStrm )
1502 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
1503 return endlu( rStrm );
1504 else
1505 return endl( rStrm );
1508 SvMemoryStream::SvMemoryStream( void* pBuffer, std::size_t bufSize,
1509 StreamMode eMode )
1511 if( eMode & StreamMode::WRITE )
1512 m_isWritable = true;
1513 else
1514 m_isWritable = false;
1515 nEndOfData = bufSize;
1516 bOwnsData = false;
1517 pBuf = static_cast<sal_uInt8 *>(pBuffer);
1518 nResize = 0;
1519 nSize = bufSize;
1520 nPos = 0;
1521 SetBufferSize( 0 );
1524 SvMemoryStream::SvMemoryStream( std::size_t nInitSize, std::size_t nResizeOffset )
1526 m_isWritable = true;
1527 bOwnsData = true;
1528 nEndOfData = 0;
1529 nResize = nResizeOffset;
1530 nPos = 0;
1531 pBuf = nullptr;
1532 if( nResize != 0 && nResize < 16 )
1533 nResize = 16;
1534 if( nInitSize )
1535 AllocateMemory( nInitSize );
1536 nSize = nInitSize;
1537 SetBufferSize( 64 );
1540 SvMemoryStream::~SvMemoryStream()
1542 if( pBuf )
1544 if( bOwnsData )
1545 FreeMemory();
1546 else
1547 Flush();
1551 void SvMemoryStream::SetBuffer( void* pNewBuf, std::size_t nCount,
1552 std::size_t nEOF )
1554 SetBufferSize( 0 ); // Init buffering in the base class
1555 Seek( 0 );
1556 if( bOwnsData && pNewBuf != pBuf )
1557 FreeMemory();
1559 pBuf = static_cast<sal_uInt8 *>(pNewBuf);
1560 nPos = 0;
1561 nSize = nCount;
1562 nResize = 0;
1563 bOwnsData = false;
1565 if( nEOF > nCount )
1566 nEOF = nCount;
1567 nEndOfData = nEOF;
1569 ResetError();
1572 std::size_t SvMemoryStream::GetData( void* pData, std::size_t nCount )
1574 std::size_t nMaxCount = nEndOfData-nPos;
1575 if( nCount > nMaxCount )
1576 nCount = nMaxCount;
1577 if (nCount != 0)
1579 memcpy( pData, pBuf+nPos, nCount );
1581 nPos += nCount;
1582 return nCount;
1585 std::size_t SvMemoryStream::PutData( const void* pData, std::size_t nCount )
1587 if( GetError() )
1588 return 0;
1590 std::size_t nMaxCount = nSize-nPos;
1592 // check for overflow
1593 if( nCount > nMaxCount )
1595 if( nResize == 0 )
1597 // copy as much as possible
1598 nCount = nMaxCount;
1599 SetError( SVSTREAM_OUTOFMEMORY );
1601 else
1603 tools::Long nNewResize;
1604 if( nSize && nSize > nResize )
1605 nNewResize = nSize;
1606 else
1607 nNewResize = nResize;
1609 if( (nCount-nMaxCount) < nResize )
1611 // lacking memory is smaller than nResize,
1612 // resize accordingly
1613 if( !ReAllocateMemory( nNewResize) )
1615 nCount = 0;
1616 SetError( SVSTREAM_WRITE_ERROR );
1619 else
1621 // lacking memory is larger than nResize,
1622 // resize by (nCount-nMaxCount) + resize offset
1623 if( !ReAllocateMemory( nCount-nMaxCount+nNewResize ) )
1625 nCount = 0;
1626 SetError( SVSTREAM_WRITE_ERROR );
1631 assert(pBuf && "Possibly Reallocate failed");
1632 memcpy( pBuf+nPos, pData, nCount);
1634 nPos += nCount;
1635 if( nPos > nEndOfData )
1636 nEndOfData = nPos;
1637 return nCount;
1640 sal_uInt64 SvMemoryStream::SeekPos(sal_uInt64 const nNewPos)
1642 // nEndOfData: First position in stream not allowed to read from
1643 // nSize: Size of allocated buffer
1645 // check if a truncated STREAM_SEEK_TO_END was passed
1646 assert(nNewPos != SAL_MAX_UINT32);
1647 if( nNewPos < nEndOfData )
1648 nPos = nNewPos;
1649 else if( nNewPos == STREAM_SEEK_TO_END )
1650 nPos = nEndOfData;
1651 else
1653 if( nNewPos >= nSize ) // Does buffer need extension?
1655 if( nResize ) // Is extension possible?
1657 tools::Long nDiff = static_cast<tools::Long>(nNewPos - nSize + 1);
1658 nDiff += static_cast<tools::Long>(nResize);
1659 ReAllocateMemory( nDiff );
1660 nPos = nNewPos;
1661 nEndOfData = nNewPos;
1663 else // Extension not possible, set pos to end of data
1665 // SetError( SVSTREAM_OUTOFMEMORY );
1666 nPos = nEndOfData;
1669 else // Expand buffer size
1671 nPos = nNewPos;
1672 nEndOfData = nNewPos;
1675 return nPos;
1678 void SvMemoryStream::FlushData()
1682 void SvMemoryStream::ResetError()
1684 SvStream::ClearError();
1687 void SvMemoryStream::AllocateMemory( std::size_t nNewSize )
1689 pBuf = new sal_uInt8[nNewSize];
1692 // (using Bozo algorithm)
1693 bool SvMemoryStream::ReAllocateMemory( tools::Long nDiff )
1695 if (!m_isWritable || !bOwnsData)
1696 return false;
1698 bool bRetVal = false;
1699 tools::Long nTemp = static_cast<tools::Long>(nSize);
1700 nTemp += nDiff;
1701 std::size_t nNewSize = static_cast<std::size_t>(nTemp);
1703 if( nNewSize )
1705 sal_uInt8* pNewBuf = new sal_uInt8[nNewSize];
1707 bRetVal = true; // Success!
1708 if( nNewSize < nSize ) // Are we shrinking?
1710 memcpy( pNewBuf, pBuf, nNewSize );
1711 if( nPos > nNewSize )
1712 nPos = 0;
1713 if( nEndOfData >= nNewSize )
1714 nEndOfData = nNewSize-1;
1716 else
1718 if (nSize != 0)
1720 memcpy( pNewBuf, pBuf, nSize );
1722 memset(pNewBuf + nSize, 0x00, nNewSize - nSize);
1725 FreeMemory();
1727 pBuf = pNewBuf;
1728 nSize = nNewSize;
1730 else
1732 bRetVal = true;
1733 FreeMemory();
1734 pBuf = nullptr;
1735 nSize = 0;
1736 nEndOfData = 0;
1737 nPos = 0;
1740 return bRetVal;
1743 void SvMemoryStream::FreeMemory()
1745 assert(bOwnsData);
1746 if (bOwnsData)
1748 delete[] pBuf;
1749 pBuf = nullptr;
1753 void* SvMemoryStream::SwitchBuffer()
1755 Flush();
1756 if( !bOwnsData )
1757 return nullptr;
1758 Seek( STREAM_SEEK_TO_BEGIN );
1760 void* pRetVal = pBuf;
1761 pBuf = nullptr;
1762 nEndOfData = 0;
1763 nResize = 64;
1764 nPos = 0;
1766 ResetError();
1768 std::size_t nInitSize = 512;
1769 AllocateMemory(nInitSize);
1770 nSize = nInitSize;
1772 SetBufferSize( 64 );
1773 return pRetVal;
1776 void SvMemoryStream::SetSize(sal_uInt64 const nNewSize)
1778 if (!m_isWritable)
1780 SetError(SVSTREAM_INVALID_HANDLE);
1781 return;
1784 tools::Long nDiff = static_cast<tools::Long>(nNewSize) - static_cast<tools::Long>(nSize);
1785 ReAllocateMemory( nDiff );
1788 //Create an OString of nLen bytes from rStream
1789 OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen)
1791 rtl_String *pStr = nullptr;
1792 if (nLen)
1794 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1795 //limit allocation to size of file, but + 1 to set eof state
1796 nLen = std::min<sal_uInt64>(nLen, rStrm.remainingSize() + 1);
1797 //alloc a (ref-count 1) rtl_String of the desired length.
1798 //rtl_String's buffer is uninitialized, except for null termination
1799 pStr = rtl_string_alloc(sal::static_int_cast<sal_Int32>(nLen));
1800 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1801 if (pStr)
1803 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen);
1804 if (nWasRead != nLen)
1806 //on (typically unlikely) short read set length to what we could
1807 //read, and null terminate. Excess buffer capacity remains of
1808 //course, could create a (true) replacement OString if it matters.
1809 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1810 pStr->buffer[pStr->length] = 0;
1815 //take ownership of buffer and return, otherwise return empty string
1816 return pStr ? OString(pStr, SAL_NO_ACQUIRE) : OString();
1819 //Create an OUString of nLen sal_Unicode code units from rStream
1820 OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen)
1822 rtl_uString *pStr = nullptr;
1823 if (nLen)
1825 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1826 //limit allocation to size of file, but + 1 to set eof state
1827 nLen = o3tl::sanitizing_min<sal_uInt64>(nLen, (rStrm.remainingSize() + 2) / 2);
1828 //alloc a (ref-count 1) rtl_uString of the desired length.
1829 //rtl_String's buffer is uninitialized, except for null termination
1830 pStr = rtl_uString_alloc(sal::static_int_cast<sal_Int32>(nLen));
1831 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1832 if (pStr)
1834 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen*2)/2;
1835 if (nWasRead != nLen)
1837 //on (typically unlikely) short read set length to what we could
1838 //read, and null terminate. Excess buffer capacity remains of
1839 //course, could create a (true) replacement OUString if it matters.
1840 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1841 pStr->buffer[pStr->length] = 0;
1843 if (rStrm.IsEndianSwap())
1845 for (sal_Int32 i = 0; i < pStr->length; ++i)
1846 pStr->buffer[i] = OSL_SWAPWORD(pStr->buffer[i]);
1851 //take ownership of buffer and return, otherwise return empty string
1852 return pStr ? OUString(pStr, SAL_NO_ACQUIRE) : OUString();
1855 namespace
1857 template <typename T, typename O> T tmpl_convertLineEnd(const T &rIn, LineEnd eLineEnd)
1859 // Determine linebreaks and compute length
1860 bool bConvert = false; // Needs conversion
1861 sal_Int32 nStrLen = rIn.getLength();
1862 sal_Int32 nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
1863 sal_Int32 nLen = 0; // Target length
1864 sal_Int32 i = 0; // Source counter
1866 while (i < nStrLen)
1868 // \r or \n causes linebreak
1869 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
1871 nLen = nLen + nLineEndLen;
1873 // If set already, skip expensive test
1874 if ( !bConvert )
1876 // Do we need to convert?
1877 if ( ((eLineEnd != LINEEND_LF) && (rIn[i] == '\n')) ||
1878 ((eLineEnd == LINEEND_CRLF) && (i+1) < nStrLen && (rIn[i+1] != '\n')) ||
1879 ((eLineEnd == LINEEND_LF) &&
1880 ((rIn[i] == '\r') || ((i+1) < nStrLen && rIn[i+1] == '\r'))) ||
1881 ((eLineEnd == LINEEND_CR) &&
1882 ((rIn[i] == '\n') || ((i+1) < nStrLen && rIn[i+1] == '\n'))) )
1883 bConvert = true;
1886 // skip char if \r\n or \n\r
1887 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
1888 (rIn[i] != rIn[i+1]) )
1889 ++i;
1891 else
1892 ++nLen;
1893 ++i;
1896 if (!bConvert)
1897 return rIn;
1899 // convert linebreaks, insert string
1900 O aNewData(nLen);
1901 i = 0;
1902 while (i < nStrLen)
1904 // \r or \n causes linebreak
1905 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
1907 if ( eLineEnd == LINEEND_CRLF )
1909 aNewData.append('\r');
1910 aNewData.append('\n');
1912 else
1914 if ( eLineEnd == LINEEND_CR )
1915 aNewData.append('\r');
1916 else
1917 aNewData.append('\n');
1920 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
1921 (rIn[i] != rIn[i+1]) )
1922 ++i;
1924 else
1926 aNewData.append(rIn[i]);
1929 ++i;
1932 return aNewData.makeStringAndClear();
1936 OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
1938 return tmpl_convertLineEnd<OString, OStringBuffer>(rIn, eLineEnd);
1941 OUString convertLineEnd(const OUString &rIn, LineEnd eLineEnd)
1943 return tmpl_convertLineEnd<OUString, OUStringBuffer>(rIn, eLineEnd);
1946 std::size_t write_uInt32_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
1947 std::u16string_view rStr)
1949 std::size_t nWritten = 0;
1950 sal_uInt32 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt32>::max());
1951 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
1952 "tools.stream",
1953 "string too long for prefix count to fit in output type");
1954 rStrm.WriteUInt32(nUnits);
1955 if (rStrm.good())
1957 nWritten += sizeof(sal_uInt32);
1958 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
1960 return nWritten;
1963 std::size_t write_uInt16_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
1964 std::u16string_view rStr)
1966 std::size_t nWritten = 0;
1967 sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
1968 SAL_WARN_IF(nUnits != rStr.size(),
1969 "tools.stream",
1970 "string too long for prefix count to fit in output type");
1971 rStrm.WriteUInt16(nUnits);
1972 if (rStrm.good())
1974 nWritten += sizeof(nUnits);
1975 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
1977 return nWritten;
1980 std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm,
1981 std::string_view rStr)
1983 std::size_t nWritten = 0;
1984 sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
1985 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
1986 "tools.stream",
1987 "string too long for sal_uInt16 count to fit in output type");
1988 rStrm.WriteUInt16( nUnits );
1989 if (rStrm.good())
1991 nWritten += sizeof(sal_uInt16);
1992 nWritten += write_uInt8s_FromOString(rStrm, rStr, nUnits);
1994 return nWritten;
1997 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */