tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / tools / source / stream / stream.cxx
blobd79a452cbadef46901075fcba0169ebd3a7004a3
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>
30 #include <o3tl/safeint.hxx>
31 #include <osl/endian.h>
32 #include <osl/diagnose.h>
33 #include <rtl/strbuf.hxx>
34 #include <rtl/string.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 (void)this;
163 // virtual
164 ErrCode SvLockBytes::ReadAt(sal_uInt64 const , void * , std::size_t ,
165 std::size_t * ) const
167 OSL_FAIL("SvLockBytes::ReadAt(): Bad stream");
168 return ERRCODE_NONE;
171 // virtual
172 ErrCode SvLockBytes::WriteAt(sal_uInt64 const , const void * , std::size_t ,
173 std::size_t * )
175 OSL_FAIL("SvLockBytes::WriteAt(): Bad stream");
176 return ERRCODE_NONE;
179 // virtual
180 ErrCode SvLockBytes::Flush() const
182 OSL_FAIL("SvLockBytes::Flush(): Bad stream");
183 return ERRCODE_NONE;
186 // virtual
187 ErrCode SvLockBytes::SetSize(sal_uInt64)
189 OSL_FAIL("SvLockBytes::SetSize(): Bad stream");
190 return ERRCODE_NONE;
193 ErrCode SvLockBytes::Stat(SvLockBytesStat *) const
195 OSL_FAIL("SvLockBytes::Stat(): Bad stream");
196 return ERRCODE_NONE;
200 std::size_t SvStream::GetData( void* pData, std::size_t nSize )
202 if( !GetError() )
204 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
205 std::size_t nRet(0);
206 m_nError = m_xLockBytes->ReadAt(m_nActPos, pData, nSize, &nRet);
207 m_nActPos += nRet;
208 return nRet;
210 else return 0;
213 std::size_t SvStream::PutData( const void* pData, std::size_t nSize )
215 if( !GetError() )
217 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
218 std::size_t nRet(0);
219 m_nError = m_xLockBytes->WriteAt(m_nActPos, pData, nSize, &nRet);
220 m_nActPos += nRet;
221 return nRet;
223 else return 0;
226 sal_uInt64 SvStream::SeekPos(sal_uInt64 const nPos)
228 // check if a truncated STREAM_SEEK_TO_END was passed
229 assert(nPos != SAL_MAX_UINT32);
230 if( !GetError() && nPos == STREAM_SEEK_TO_END )
232 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
233 SvLockBytesStat aStat;
234 m_xLockBytes->Stat( &aStat );
235 m_nActPos = aStat.nSize;
237 else
238 m_nActPos = nPos;
239 return m_nActPos;
242 void SvStream::FlushData()
244 if( !GetError() )
246 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
247 m_nError = m_xLockBytes->Flush();
251 void SvStream::SetSize(sal_uInt64 const nSize)
253 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
254 m_nError = m_xLockBytes->SetSize( nSize );
257 SvStream::SvStream() :
258 m_nActPos(0)
260 , m_pBufPos(nullptr)
261 , m_nBufSize(0)
262 , m_nBufActualLen(0)
263 , m_nBufActualPos(0)
264 , m_nBufFree(0)
265 , m_isIoRead(false)
266 , m_isIoWrite(false)
268 , m_isDirty(false)
269 , m_isEof(false)
271 , m_nCompressMode(SvStreamCompressFlags::NONE)
272 #if defined UNX
273 , m_eLineDelimiter(LINEEND_LF) // UNIX-Format
274 #else
275 , m_eLineDelimiter(LINEEND_CRLF) // DOS-Format
276 #endif
277 , m_eStreamCharSet(osl_getThreadTextEncoding())
279 , m_nCryptMask(0)
281 , m_nVersion(0)
283 , m_nBufFilePos(0)
284 , m_eStreamMode(StreamMode::NONE)
285 , m_isWritable(true)
288 SetEndian( SvStreamEndian::LITTLE );
290 ClearError();
293 SvStream::SvStream( SvLockBytes* pLockBytesP ) : SvStream()
295 m_xLockBytes = pLockBytesP;
296 SetBufferSize( 256 );
299 SvStream::~SvStream()
301 if (m_xLockBytes.is())
302 Flush();
305 void SvStream::ClearError()
307 m_isEof = false;
308 m_nError = ERRCODE_NONE;
311 void SvStream::SetError( ErrCode nErrorCode )
313 if (m_nError == ERRCODE_NONE || (m_nError.IsWarning() && nErrorCode.IsError()))
314 m_nError = nErrorCode;
317 void SvStream::SetEndian( SvStreamEndian nNewFormat )
319 #ifdef OSL_BIGENDIAN
320 m_isSwap = nNewFormat == SvStreamEndian::LITTLE;
321 #else
322 m_isSwap = nNewFormat == SvStreamEndian::BIG;
323 #endif
326 SvStreamEndian SvStream::GetEndian() const
328 #ifdef OSL_BIGENDIAN
329 return m_isSwap ? SvStreamEndian::LITTLE : SvStreamEndian::BIG;
330 #else
331 return m_isSwap ? SvStreamEndian::BIG : SvStreamEndian::LITTLE;
332 #endif
335 void SvStream::SetBufferSize( sal_uInt16 nBufferSize )
337 sal_uInt64 const nActualFilePos = Tell();
338 bool bDontSeek = (m_pRWBuf == nullptr);
340 if (m_isDirty && m_isWritable) // due to Windows NT: Access denied
341 FlushBuffer();
343 if (m_nBufSize)
345 m_pRWBuf.reset();
346 m_nBufFilePos += m_nBufActualPos;
349 m_pRWBuf = nullptr;
350 m_nBufActualLen = 0;
351 m_nBufActualPos = 0;
352 m_nBufSize = nBufferSize;
353 if (m_nBufSize)
354 m_pRWBuf.reset(new sal_uInt8[ m_nBufSize ]);
355 m_pBufPos = m_pRWBuf.get();
356 m_isIoRead = m_isIoWrite = false;
357 if( !bDontSeek )
358 SeekPos( nActualFilePos );
361 void SvStream::ClearBuffer()
363 m_nBufActualLen = 0;
364 m_nBufActualPos = 0;
365 m_nBufFilePos = 0;
366 m_pBufPos = m_pRWBuf.get();
367 m_isDirty = false;
368 m_isIoRead = m_isIoWrite = false;
370 m_isEof = false;
373 void SvStream::ResetError()
375 ClearError();
378 bool SvStream::ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
379 sal_Int32 nMaxBytesToRead )
381 OString aStr;
382 bool bRet = ReadLine( aStr, nMaxBytesToRead);
383 rStr = OStringToOUString(aStr, eSrcCharSet);
384 return bRet;
387 bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead )
389 OStringBuffer aBuf(4096);
390 bool rv = ReadLine(aBuf, nMaxBytesToRead);
391 rStr = aBuf.makeStringAndClear();
392 return rv;
395 bool SvStream::ReadLine( OStringBuffer& aBuf, sal_Int32 nMaxBytesToRead )
397 char buf[256+1];
398 bool bEnd = false;
399 sal_uInt64 nOldFilePos = Tell();
400 char c = 0;
401 std::size_t nTotalLen = 0;
403 aBuf.setLength(0);
404 while( !bEnd && !GetError() ) // Don't test for EOF as we
405 // are reading block-wise!
407 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes(buf, sizeof(buf)-1));
408 if ( !nLen )
410 if ( aBuf.isEmpty() )
412 // Exit on first block-read error
413 m_isEof = true;
414 aBuf.setLength(0);
415 return false;
417 else
418 break;
421 sal_uInt16 j, n;
422 for( j = n = 0; j < nLen ; ++j )
424 c = buf[j];
425 if ( c == '\n' || c == '\r' )
427 bEnd = true;
428 break;
430 if ( n < j )
431 buf[n] = c;
432 ++n;
434 nTotalLen += j;
435 if (nTotalLen > o3tl::make_unsigned(nMaxBytesToRead))
437 n -= nTotalLen - nMaxBytesToRead;
438 nTotalLen = nMaxBytesToRead;
439 bEnd = true;
441 if ( n )
442 aBuf.append(buf, n);
445 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
446 bEnd = true;
448 nOldFilePos += nTotalLen;
449 if( Tell() > nOldFilePos )
450 nOldFilePos++;
451 Seek( nOldFilePos ); // Seek pointer due to BlockRead above
453 if ( bEnd && (c=='\r' || c=='\n') ) // Special treatment for DOS files
455 char cTemp;
456 std::size_t nLen = ReadBytes(&cTemp, sizeof(cTemp));
457 if ( nLen ) {
458 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
459 Seek( nOldFilePos );
463 if ( bEnd )
464 m_isEof = false;
465 return bEnd;
468 bool SvStream::ReadUniStringLine( OUString& rStr, sal_Int32 nMaxCodepointsToRead )
470 sal_Unicode buf[256+1];
471 bool bEnd = false;
472 sal_uInt64 nOldFilePos = Tell();
473 sal_Unicode c = 0;
474 std::size_t nTotalLen = 0;
476 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "ReadUniStringLine: swapping sizeof(sal_Unicode) not implemented" );
478 OUStringBuffer aBuf(4096);
479 while( !bEnd && !GetError() ) // Don't test for EOF as we
480 // are reading block-wise!
482 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes( buf, sizeof(buf)-sizeof(sal_Unicode)));
483 nLen /= sizeof(sal_Unicode);
484 if ( !nLen )
486 if ( aBuf.isEmpty() )
488 // exit on first BlockRead error
489 m_isEof = true;
490 rStr.clear();
491 return false;
493 else
494 break;
497 sal_uInt16 j, n;
498 for( j = n = 0; j < nLen ; ++j )
500 if (m_isSwap)
501 SwapNumber( buf[n] );
502 c = buf[j];
503 if ( c == '\n' || c == '\r' )
505 bEnd = true;
506 break;
508 // erAck 26.02.01: Old behavior was no special treatment of '\0'
509 // character here, but a following rStr+=c did ignore it. Is this
510 // really intended? Or should a '\0' better terminate a line?
511 // The nOldFilePos stuff wasn't correct then anyways.
512 if ( c )
514 if ( n < j )
515 buf[n] = c;
516 ++n;
519 nTotalLen += j;
520 if (nTotalLen > o3tl::make_unsigned(nMaxCodepointsToRead))
522 n -= nTotalLen - nMaxCodepointsToRead;
523 nTotalLen = nMaxCodepointsToRead;
524 bEnd = true;
526 if ( n )
527 aBuf.append( buf, n );
530 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
531 bEnd = true;
533 nOldFilePos += nTotalLen * sizeof(sal_Unicode);
534 if( Tell() > nOldFilePos )
535 nOldFilePos += sizeof(sal_Unicode);
536 Seek( nOldFilePos ); // seek due to BlockRead above
538 if ( bEnd && (c=='\r' || c=='\n') ) // special treatment for DOS files
540 sal_Unicode cTemp;
541 ReadBytes( &cTemp, sizeof(cTemp) );
542 if (m_isSwap)
543 SwapNumber( cTemp );
544 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
545 Seek( nOldFilePos );
548 if ( bEnd )
549 m_isEof = false;
550 rStr = aBuf.makeStringAndClear();
551 return bEnd;
554 bool SvStream::ReadUniOrByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
555 sal_Int32 nMaxCodepointsToRead )
557 if ( eSrcCharSet == RTL_TEXTENCODING_UNICODE )
558 return ReadUniStringLine( rStr, nMaxCodepointsToRead );
559 else
560 return ReadByteStringLine( rStr, eSrcCharSet, nMaxCodepointsToRead );
563 OString read_zeroTerminated_uInt8s_ToOString(SvStream& rStream)
565 OStringBuffer aOutput(256);
567 char buf[ 256 + 1 ];
568 bool bEnd = false;
569 sal_uInt64 nFilePos = rStream.Tell();
571 while( !bEnd && !rStream.GetError() )
573 std::size_t nLen = rStream.ReadBytes(buf, sizeof(buf)-1);
574 if (!nLen)
575 break;
577 std::size_t nReallyRead = nLen;
578 const char* pPtr = buf;
579 while (nLen && *pPtr)
581 ++pPtr;
582 --nLen;
585 bEnd = ( nReallyRead < sizeof(buf)-1 ) // read less than attempted to read
586 || ( ( nLen > 0 ) // OR it is inside the block we read
587 && ( 0 == *pPtr ) // AND found a string terminator
590 aOutput.append(buf, pPtr - buf);
593 nFilePos += aOutput.getLength();
594 if (rStream.Tell() > nFilePos)
595 rStream.Seek(nFilePos+1); // seek due to FileRead above
596 return aOutput.makeStringAndClear();
599 OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStream, rtl_TextEncoding eEnc)
601 return OStringToOUString(
602 read_zeroTerminated_uInt8s_ToOString(rStream), eEnc);
605 /** Attempt to write a sequence of nUnits 16bit units from an OUString,
606 returned value is number of bytes written */
607 static std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr,
608 std::size_t nUnits)
610 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "write_uInt16s_FromOUString: swapping sizeof(sal_Unicode) not implemented" );
611 std::size_t nWritten;
612 if (!rStrm.IsEndianSwap())
613 nWritten = rStrm.WriteBytes(rStr.data(), nUnits * sizeof(sal_Unicode));
614 else
616 std::size_t nLen = nUnits;
617 sal_Unicode aBuf[384];
618 sal_Unicode* const pTmp = ( nLen > 384 ? new sal_Unicode[nLen] : aBuf);
619 memcpy( pTmp, rStr.data(), nLen * sizeof(sal_Unicode) );
620 sal_Unicode* p = pTmp;
621 const sal_Unicode* const pStop = pTmp + nLen;
622 while ( p < pStop )
624 SwapNumber( *p );
625 p++;
627 nWritten = rStrm.WriteBytes( pTmp, nLen * sizeof(sal_Unicode) );
628 if ( pTmp != aBuf )
629 delete [] pTmp;
631 return nWritten;
634 bool SvStream::WriteUnicodeOrByteText(std::u16string_view rStr, rtl_TextEncoding eDestCharSet, bool bZero)
636 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
638 write_uInt16s_FromOUString(*this, rStr, rStr.size());
639 if (bZero)
640 WriteUnicode(0);
642 else
644 OString aStr(OUStringToOString(rStr, eDestCharSet));
645 WriteBytes(aStr.getStr(), aStr.getLength());
646 if (bZero)
647 WriteChar(0);
649 return m_nError == ERRCODE_NONE;
652 bool SvStream::WriteByteStringLine( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
654 return WriteLine(OUStringToOString(rStr, eDestCharSet));
657 bool SvStream::WriteLine(std::string_view rStr)
659 WriteBytes(rStr.data(), rStr.size());
660 endl(*this);
661 return m_nError == ERRCODE_NONE;
664 bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet )
666 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
667 WriteUnicode(ch);
668 else
670 OString aStr(&ch, 1, eDestCharSet);
671 WriteBytes(aStr.getStr(), aStr.getLength());
673 return m_nError == ERRCODE_NONE;
676 void SvStream::StartWritingUnicodeText()
678 m_isSwap = false; // Switch to no endian swapping
679 // BOM, Byte Order Mark, U+FEFF, see
680 // http://www.unicode.org/faq/utf_bom.html#BOM
681 // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap
682 WriteUInt16(0xfeff);
685 void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet )
687 if (!( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
688 eReadBomCharSet == RTL_TEXTENCODING_UNICODE ||
689 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
690 return; // nothing to read
692 const sal_uInt64 nOldPos = Tell();
693 bool bGetBack = true;
694 unsigned char nFlag(0);
695 ReadUChar( nFlag );
696 switch ( nFlag )
698 case 0xfe: // UTF-16BE?
699 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
700 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
702 ReadUChar(nFlag);
703 if (nFlag == 0xff)
705 SetEndian(SvStreamEndian::BIG);
706 bGetBack = false;
709 break;
710 case 0xff: // UTF-16LE?
711 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
712 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
714 ReadUChar(nFlag);
715 if (nFlag == 0xfe)
717 SetEndian(SvStreamEndian::LITTLE);
718 bGetBack = false;
721 break;
722 case 0xef: // UTF-8?
723 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
724 eReadBomCharSet == RTL_TEXTENCODING_UTF8)
726 ReadUChar(nFlag);
727 if (nFlag == 0xbb)
729 ReadUChar(nFlag);
730 if (nFlag == 0xbf)
731 bGetBack = false; // it is UTF-8
734 break;
735 default:
736 ; // nothing
738 if (bGetBack)
739 Seek(nOldPos); // no BOM, pure data
742 sal_uInt64 SvStream::SeekRel(sal_Int64 const nPos)
744 sal_uInt64 nActualPos = Tell();
746 if ( nPos >= 0 )
748 if (SAL_MAX_UINT64 - nActualPos > o3tl::make_unsigned(nPos))
749 nActualPos += nPos;
751 else
753 sal_uInt64 const nAbsPos = static_cast<sal_uInt64>(-nPos);
754 if ( nActualPos >= nAbsPos )
755 nActualPos -= nAbsPos;
758 assert((m_pBufPos != nullptr) == bool(m_pRWBuf));
759 if (m_pRWBuf)
761 m_pBufPos = m_pRWBuf.get() + nActualPos;
763 return Seek( nActualPos );
766 template <typename T> SvStream& SvStream::ReadNumber(T& r)
768 T n = 0;
769 readNumberWithoutSwap(n);
770 if (good())
772 if (m_isSwap)
773 SwapNumber(n);
774 r = n;
776 return *this;
779 SvStream& SvStream::ReadUInt16(sal_uInt16& r) { return ReadNumber(r); }
780 SvStream& SvStream::ReadUInt32(sal_uInt32& r) { return ReadNumber(r); }
781 SvStream& SvStream::ReadUInt64(sal_uInt64& r) { return ReadNumber(r); }
782 SvStream& SvStream::ReadInt16(sal_Int16& r) { return ReadNumber(r); }
783 SvStream& SvStream::ReadInt32(sal_Int32& r) { return ReadNumber(r); }
784 SvStream& SvStream::ReadInt64(sal_Int64& r) { return ReadNumber(r); }
786 SvStream& SvStream::ReadSChar( signed char& r )
788 if (m_isIoRead && sizeof(signed char) <= m_nBufFree)
790 r = *m_pBufPos;
791 m_nBufActualPos += sizeof(signed char);
792 m_pBufPos += sizeof(signed char);
793 m_nBufFree -= sizeof(signed char);
795 else
796 ReadBytes( &r, sizeof(signed char) );
797 return *this;
800 // Special treatment for Chars due to PutBack
802 SvStream& SvStream::ReadChar( char& r )
804 if (m_isIoRead && sizeof(char) <= m_nBufFree)
806 r = *m_pBufPos;
807 m_nBufActualPos += sizeof(char);
808 m_pBufPos += sizeof(char);
809 m_nBufFree -= sizeof(char);
811 else
812 ReadBytes( &r, sizeof(char) );
813 return *this;
816 SvStream& SvStream::ReadUChar( unsigned char& r )
818 if (m_isIoRead && sizeof(char) <= m_nBufFree)
820 r = *m_pBufPos;
821 m_nBufActualPos += sizeof(char);
822 m_pBufPos += sizeof(char);
823 m_nBufFree -= sizeof(char);
825 else
826 ReadBytes( &r, sizeof(char) );
827 return *this;
830 SvStream& SvStream::ReadUtf16(sal_Unicode& r) { return ReadNumber(r); }
832 SvStream& SvStream::ReadCharAsBool( bool& r )
834 if (m_isIoRead && sizeof(char) <= m_nBufFree)
836 SAL_WARN_IF(
837 *m_pBufPos > 1, "tools.stream", unsigned(*m_pBufPos) << " not 0/1");
838 r = *m_pBufPos != 0;
839 m_nBufActualPos += sizeof(char);
840 m_pBufPos += sizeof(char);
841 m_nBufFree -= sizeof(char);
843 else
845 unsigned char c;
846 if (ReadBytes(&c, 1) == 1)
848 SAL_WARN_IF(c > 1, "tools.stream", unsigned(c) << " not 0/1");
849 r = c != 0;
852 return *this;
855 SvStream& SvStream::ReadFloat(float& r)
857 float n = 0;
858 readNumberWithoutSwap(n);
859 if (good())
861 #if defined UNX
862 if (m_isSwap)
863 SwapFloat(n);
864 #endif
865 r = n;
867 return *this;
870 SvStream& SvStream::ReadDouble(double& r)
872 double n = 0;
873 readNumberWithoutSwap(n);
874 if (good())
876 #if defined UNX
877 if (m_isSwap)
878 SwapDouble(n);
879 #endif
880 r = n;
882 return *this;
885 SvStream& SvStream::ReadStream( SvStream& rStream )
887 const sal_uInt32 cBufLen = 0x8000;
888 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
890 sal_uInt32 nCount;
891 do {
892 nCount = ReadBytes( pBuf.get(), cBufLen );
893 rStream.WriteBytes( pBuf.get(), nCount );
894 } while( nCount == cBufLen );
896 return *this;
899 template <typename T> SvStream& SvStream::WriteNumber(T n)
901 if (m_isSwap)
902 SwapNumber(n);
903 writeNumberWithoutSwap(n);
904 return *this;
907 SvStream& SvStream::WriteUInt16(sal_uInt16 v) { return WriteNumber(v); }
908 SvStream& SvStream::WriteUInt32(sal_uInt32 v) { return WriteNumber(v); }
909 SvStream& SvStream::WriteUInt64(sal_uInt64 v) { return WriteNumber(v); }
910 SvStream& SvStream::WriteInt16(sal_Int16 v) { return WriteNumber(v); }
911 SvStream& SvStream::WriteInt32(sal_Int32 v) { return WriteNumber(v); }
912 SvStream& SvStream::WriteInt64(sal_Int64 v) { return WriteNumber(v); }
914 SvStream& SvStream::WriteSChar( signed char v )
916 //SDO
917 if (m_isIoWrite && sizeof(signed char) <= m_nBufFree)
919 *m_pBufPos = v;
920 m_pBufPos++; // sizeof(char);
921 m_nBufActualPos++;
922 if (m_nBufActualPos > m_nBufActualLen) // Append ?
923 m_nBufActualLen = m_nBufActualPos;
924 m_nBufFree--; // = sizeof(char);
925 m_isDirty = true;
927 else
928 WriteBytes( &v, sizeof(signed char) );
929 return *this;
932 // Special treatment for Chars due to PutBack
934 SvStream& SvStream::WriteChar( char v )
936 //SDO
937 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
939 *m_pBufPos = v;
940 m_pBufPos++; // sizeof(char);
941 m_nBufActualPos++;
942 if (m_nBufActualPos > m_nBufActualLen) // Append ?
943 m_nBufActualLen = m_nBufActualPos;
944 m_nBufFree--; // = sizeof(char);
945 m_isDirty = true;
947 else
948 WriteBytes( &v, sizeof(char) );
949 return *this;
952 SvStream& SvStream::WriteUChar( unsigned char v )
954 //SDO
955 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
957 *reinterpret_cast<unsigned char*>(m_pBufPos) = v;
958 m_pBufPos++; // = sizeof(char);
959 m_nBufActualPos++; // = sizeof(char);
960 if (m_nBufActualPos > m_nBufActualLen) // Append ?
961 m_nBufActualLen = m_nBufActualPos;
962 m_nBufFree--;
963 m_isDirty = true;
965 else
966 WriteBytes( &v, sizeof(char) );
967 return *this;
970 SvStream& SvStream::WriteUInt8( sal_uInt8 v )
972 return WriteUChar(v);
975 SvStream& SvStream::WriteUnicode( sal_Unicode v )
977 return WriteUInt16(v);
980 SvStream& SvStream::WriteFloat( float v )
982 #ifdef UNX
983 if (m_isSwap)
984 SwapFloat(v);
985 #endif
986 writeNumberWithoutSwap(v);
987 return *this;
990 SvStream& SvStream::WriteDouble ( double v )
992 #if defined UNX
993 if (m_isSwap)
994 SwapDouble(v);
995 #endif
996 writeNumberWithoutSwap(v);
997 return *this;
1000 SvStream& SvStream::WriteStream( SvStream& rStream )
1002 const sal_uInt32 cBufLen = 0x8000;
1003 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1004 sal_uInt32 nCount;
1005 do {
1006 nCount = rStream.ReadBytes( pBuf.get(), cBufLen );
1007 WriteBytes( pBuf.get(), nCount );
1008 } while( nCount == cBufLen );
1010 return *this;
1013 sal_uInt64 SvStream::WriteStream( SvStream& rStream, sal_uInt64 nSize )
1015 const sal_uInt32 cBufLen = 0x8000;
1016 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1017 sal_uInt32 nCurBufLen = cBufLen;
1018 sal_uInt32 nCount;
1019 sal_uInt64 nWriteSize = nSize;
1023 nCurBufLen = std::min<sal_uInt64>(nCurBufLen, nWriteSize);
1024 nCount = rStream.ReadBytes(pBuf.get(), nCurBufLen);
1025 WriteBytes( pBuf.get(), nCount );
1026 nWriteSize -= nCount;
1028 while( nWriteSize && nCount == nCurBufLen );
1030 return nSize - nWriteSize;
1033 OUString SvStream::ReadUniOrByteString( rtl_TextEncoding eSrcCharSet )
1035 // read UTF-16 string directly from stream ?
1036 if (eSrcCharSet == RTL_TEXTENCODING_UNICODE)
1037 return read_uInt32_lenPrefixed_uInt16s_ToOUString(*this);
1038 return read_uInt16_lenPrefixed_uInt8s_ToOUString(*this, eSrcCharSet);
1041 SvStream& SvStream::WriteUniOrByteString( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
1043 // write UTF-16 string directly into stream ?
1044 if (eDestCharSet == RTL_TEXTENCODING_UNICODE)
1045 write_uInt32_lenPrefixed_uInt16s_FromOUString(*this, rStr);
1046 else
1047 write_uInt16_lenPrefixed_uInt8s_FromOUString(*this, rStr, eDestCharSet);
1048 return *this;
1051 void SvStream::FlushBuffer()
1053 if (m_isDirty) // Does stream require a flush?
1055 SeekPos(m_nBufFilePos);
1056 if (m_nCryptMask)
1057 CryptAndWriteBuffer(m_pRWBuf.get(), m_nBufActualLen);
1058 else if (PutData(m_pRWBuf.get(), m_nBufActualLen) != m_nBufActualLen)
1059 SetError(SVSTREAM_WRITE_ERROR);
1060 m_isDirty = false;
1064 std::size_t SvStream::ReadBytes( void* pData, std::size_t nCount )
1066 std::size_t nSaveCount = nCount;
1068 if (!m_pRWBuf)
1070 nCount = GetData( pData,nCount);
1071 if (m_nCryptMask)
1072 EncryptBuffer(pData, nCount);
1073 m_nBufFilePos += nCount;
1075 else
1077 // check if block is completely within buffer
1078 m_isIoRead = true;
1079 m_isIoWrite = false;
1080 if (nCount <= o3tl::make_unsigned(m_nBufActualLen - m_nBufActualPos))
1082 // => yes
1083 if (nCount != 0)
1084 memcpy(pData, m_pBufPos, nCount);
1085 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1086 m_pBufPos += nCount;
1087 m_nBufFree = m_nBufFree - static_cast<sal_uInt16>(nCount);
1089 else
1091 FlushBuffer();
1093 // Does data block fit into buffer?
1094 if (nCount > m_nBufSize)
1096 // => No! Thus read directly
1097 // into target area without using the buffer
1099 m_isIoRead = false;
1101 SeekPos(m_nBufFilePos + m_nBufActualPos);
1102 m_nBufActualLen = 0;
1103 m_pBufPos = m_pRWBuf.get();
1104 nCount = GetData( pData, nCount );
1105 if (m_nCryptMask)
1106 EncryptBuffer(pData, nCount);
1107 m_nBufFilePos += nCount;
1108 m_nBufFilePos += m_nBufActualPos;
1109 m_nBufActualPos = 0;
1111 else
1113 // => Yes. Fill buffer first, then copy to target area
1115 m_nBufFilePos += m_nBufActualPos;
1116 SeekPos(m_nBufFilePos);
1118 // TODO: Typecast before GetData, sal_uInt16 nCountTmp
1119 std::size_t nCountTmp = GetData( m_pRWBuf.get(), m_nBufSize );
1120 if (m_nCryptMask)
1121 EncryptBuffer(m_pRWBuf.get(), nCountTmp);
1122 m_nBufActualLen = static_cast<sal_uInt16>(nCountTmp);
1123 if( nCount > nCountTmp )
1125 nCount = nCountTmp; // trim count back, EOF see below
1127 memcpy( pData, m_pRWBuf.get(), nCount );
1128 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1129 m_pBufPos = m_pRWBuf.get() + nCount;
1133 m_isEof = false;
1134 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1135 if (nCount != nSaveCount && m_nError != ERRCODE_IO_PENDING)
1136 m_isEof = true;
1137 if (nCount == nSaveCount && m_nError == ERRCODE_IO_PENDING)
1138 m_nError = ERRCODE_NONE;
1139 return nCount;
1142 std::size_t SvStream::WriteBytes( const void* pData, std::size_t nCount )
1144 if( !nCount )
1145 return 0;
1147 if (!m_isWritable)
1149 SetError( ERRCODE_IO_CANTWRITE );
1150 return 0;
1153 if (!m_pRWBuf)
1155 if (m_nCryptMask)
1156 nCount = CryptAndWriteBuffer( pData, nCount );
1157 else
1158 nCount = PutData( pData, nCount );
1159 m_nBufFilePos += nCount;
1160 return nCount;
1163 m_isIoRead = false;
1164 m_isIoWrite = true;
1165 if (nCount <= o3tl::make_unsigned(m_nBufSize - m_nBufActualPos))
1167 memcpy( m_pBufPos, pData, nCount );
1168 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1169 // Update length if buffer was updated
1170 if (m_nBufActualPos > m_nBufActualLen)
1171 m_nBufActualLen = m_nBufActualPos;
1173 m_pBufPos += nCount;
1174 m_isDirty = true;
1176 else
1178 FlushBuffer();
1180 // Does data block fit into buffer?
1181 if (nCount > m_nBufSize)
1183 m_isIoWrite = false;
1184 m_nBufFilePos += m_nBufActualPos;
1185 m_nBufActualLen = 0;
1186 m_nBufActualPos = 0;
1187 m_pBufPos = m_pRWBuf.get();
1188 SeekPos(m_nBufFilePos);
1189 if (m_nCryptMask)
1190 nCount = CryptAndWriteBuffer( pData, nCount );
1191 else
1192 nCount = PutData( pData, nCount );
1193 m_nBufFilePos += nCount;
1195 else
1197 // Copy block to buffer
1198 memcpy( m_pRWBuf.get(), pData, nCount );
1200 // Mind the order!
1201 m_nBufFilePos += m_nBufActualPos;
1202 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1203 m_pBufPos = m_pRWBuf.get() + nCount;
1204 m_nBufActualLen = static_cast<sal_uInt16>(nCount);
1205 m_isDirty = true;
1208 m_nBufFree = m_nBufSize - m_nBufActualPos;
1209 return nCount;
1212 sal_uInt64 SvStream::Seek(sal_uInt64 const nFilePos)
1214 m_isIoRead = m_isIoWrite = false;
1215 m_isEof = false;
1216 if (!m_pRWBuf)
1218 m_nBufFilePos = SeekPos( nFilePos );
1219 DBG_ASSERT(Tell() == m_nBufFilePos,"Out Of Sync!");
1220 return m_nBufFilePos;
1223 // Is seek position within buffer?
1224 if (nFilePos >= m_nBufFilePos && nFilePos <= (m_nBufFilePos + m_nBufActualLen))
1226 m_nBufActualPos = static_cast<sal_uInt16>(nFilePos - m_nBufFilePos);
1227 m_pBufPos = m_pRWBuf.get() + m_nBufActualPos;
1228 // Update m_nBufFree to avoid crash upon PutBack
1229 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1231 else
1233 FlushBuffer();
1234 m_nBufActualLen = 0;
1235 m_nBufActualPos = 0;
1236 m_pBufPos = m_pRWBuf.get();
1237 m_nBufFilePos = SeekPos( nFilePos );
1239 return m_nBufFilePos + m_nBufActualPos;
1242 bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
1244 const sal_uInt64 nMaxSeek = rSt.TellEnd();
1245 return (nOffset <= nMaxSeek && rSt.Seek(nOffset) == nOffset);
1248 namespace tools
1250 bool isEmptyFileUrl(const OUString& rUrl)
1252 if (!comphelper::isFileUrl(rUrl))
1254 return false;
1257 SvFileStream aStream(rUrl, StreamMode::READ);
1258 if (!aStream.IsOpen())
1260 return false;
1263 return aStream.remainingSize() == 0;
1267 //STREAM_SEEK_TO_END in some of the Seek backends is special cased to be
1268 //efficient, in others e.g. SotStorageStream it's really horribly slow, and in
1269 //those this should be overridden
1270 sal_uInt64 SvStream::remainingSize()
1272 sal_uInt64 const nCurr = Tell();
1273 sal_uInt64 const nEnd = TellEnd();
1274 sal_uInt64 nMaxAvailable = nEnd > nCurr ? (nEnd-nCurr) : 0;
1275 return nMaxAvailable;
1278 sal_uInt64 SvStream::TellEnd()
1280 FlushBuffer();
1281 sal_uInt64 const nCurr = Tell();
1282 sal_uInt64 const nEnd = Seek(STREAM_SEEK_TO_END);
1283 Seek(nCurr);
1284 return nEnd;
1287 void SvStream::Flush()
1289 FlushBuffer();
1290 if (m_isWritable)
1291 FlushData();
1294 void SvStream::RefreshBuffer()
1296 FlushBuffer();
1297 SeekPos(m_nBufFilePos);
1298 m_nBufActualLen = static_cast<sal_uInt16>(GetData( m_pRWBuf.get(), m_nBufSize ));
1299 if (m_nBufActualLen && m_nError == ERRCODE_IO_PENDING)
1300 m_nError = ERRCODE_NONE;
1301 if (m_nCryptMask)
1302 EncryptBuffer(m_pRWBuf.get(), static_cast<std::size_t>(m_nBufActualLen));
1303 m_isIoRead = m_isIoWrite = false;
1306 #define CRYPT_BUFSIZE 1024
1308 /// Encrypt and write
1309 std::size_t SvStream::CryptAndWriteBuffer( const void* pStart, std::size_t nLen)
1311 unsigned char pTemp[CRYPT_BUFSIZE];
1312 unsigned char const * pDataPtr = static_cast<unsigned char const *>(pStart);
1313 std::size_t nCount = 0;
1314 std::size_t nBufCount;
1315 unsigned char nMask = m_nCryptMask;
1318 if( nLen >= CRYPT_BUFSIZE )
1319 nBufCount = CRYPT_BUFSIZE;
1320 else
1321 nBufCount = nLen;
1322 nLen -= nBufCount;
1323 memcpy( pTemp, pDataPtr, static_cast<sal_uInt16>(nBufCount) );
1324 // ******** Encrypt ********
1325 for (unsigned char & rn : pTemp)
1327 unsigned char aCh = rn;
1328 aCh ^= nMask;
1329 swapNibbles(aCh);
1330 rn = aCh;
1332 // *************************
1333 nCount += PutData( pTemp, nBufCount );
1334 pDataPtr += nBufCount;
1336 while ( nLen );
1337 return nCount;
1340 void SvStream::EncryptBuffer(void* pStart, std::size_t nLen) const
1342 unsigned char* pTemp = static_cast<unsigned char*>(pStart);
1343 unsigned char nMask = m_nCryptMask;
1345 for ( std::size_t n=0; n < nLen; n++, pTemp++ )
1347 unsigned char aCh = *pTemp;
1348 swapNibbles(aCh);
1349 aCh ^= nMask;
1350 *pTemp = aCh;
1354 static unsigned char implGetCryptMask(const char* pStr, sal_Int32 nLen, tools::Long nVersion)
1356 unsigned char nCryptMask = 0;
1358 if (!nLen)
1359 return nCryptMask;
1361 if( nVersion <= SOFFICE_FILEFORMAT_31 )
1363 while( nLen )
1365 nCryptMask ^= *pStr;
1366 pStr++;
1367 nLen--;
1370 else // BugFix #25888#
1372 for( sal_Int32 i = 0; i < nLen; i++ ) {
1373 nCryptMask ^= pStr[i];
1374 if( nCryptMask & 0x80 ) {
1375 nCryptMask <<= 1;
1376 nCryptMask++;
1378 else
1379 nCryptMask <<= 1;
1383 if( !nCryptMask )
1384 nCryptMask = 67;
1386 return nCryptMask;
1389 void SvStream::SetCryptMaskKey(const OString& rCryptMaskKey)
1391 m_aCryptMaskKey = rCryptMaskKey;
1392 m_nCryptMask = implGetCryptMask(m_aCryptMaskKey.getStr(),
1393 m_aCryptMaskKey.getLength(), GetVersion());
1396 bool SvStream::SetStreamSize(sal_uInt64 const nSize)
1398 #ifdef DBG_UTIL
1399 sal_uInt64 nFPos = Tell();
1400 #endif
1401 sal_uInt16 nBuf = m_nBufSize;
1402 SetBufferSize( 0 );
1403 SetSize( nSize );
1404 if (nSize < m_nBufFilePos)
1406 m_nBufFilePos = nSize;
1408 SetBufferSize( nBuf );
1409 #ifdef DBG_UTIL
1410 DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed");
1411 #endif
1412 return (m_nError == ERRCODE_NONE);
1415 SvStream& endl( SvStream& rStr )
1417 LineEnd eDelim = rStr.GetLineDelimiter();
1418 if ( eDelim == LINEEND_CR )
1419 rStr.WriteChar('\r');
1420 else if( eDelim == LINEEND_LF )
1421 rStr.WriteChar('\n');
1422 else
1423 rStr.WriteChar('\r').WriteChar('\n');
1424 return rStr;
1427 SvStream& endlu( SvStream& rStrm )
1429 switch ( rStrm.GetLineDelimiter() )
1431 case LINEEND_CR :
1432 rStrm.WriteUnicode('\r');
1433 break;
1434 case LINEEND_LF :
1435 rStrm.WriteUnicode('\n');
1436 break;
1437 default:
1438 rStrm.WriteUnicode('\r').WriteUnicode('\n');
1440 return rStrm;
1443 SvStream& endlub( SvStream& rStrm )
1445 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
1446 return endlu( rStrm );
1447 else
1448 return endl( rStrm );
1451 SvMemoryStream::SvMemoryStream( void* pBuffer, std::size_t bufSize,
1452 StreamMode eMode )
1454 if( eMode & StreamMode::WRITE )
1455 m_isWritable = true;
1456 else
1457 m_isWritable = false;
1458 nEndOfData = bufSize;
1459 bOwnsData = false;
1460 pBuf = static_cast<sal_uInt8 *>(pBuffer);
1461 nResize = 0;
1462 nSize = bufSize;
1463 nPos = 0;
1464 SetBufferSize( 0 );
1467 SvMemoryStream::SvMemoryStream( std::size_t nInitSize, std::size_t nResizeOffset )
1469 m_isWritable = true;
1470 bOwnsData = true;
1471 nEndOfData = 0;
1472 nResize = nResizeOffset;
1473 nPos = 0;
1474 pBuf = nullptr;
1475 if( nResize != 0 && nResize < 16 )
1476 nResize = 16;
1477 if( nInitSize )
1478 AllocateMemory( nInitSize );
1479 nSize = nInitSize;
1480 SetBufferSize( 64 );
1483 SvMemoryStream::~SvMemoryStream()
1485 if( pBuf )
1487 if( bOwnsData )
1488 FreeMemory();
1489 else
1490 FlushBuffer();
1494 void SvMemoryStream::SetBuffer( void* pNewBuf, std::size_t nCount,
1495 std::size_t nEOF )
1497 SetBufferSize( 0 ); // Init buffering in the base class
1498 Seek( 0 );
1499 if( bOwnsData && pNewBuf != pBuf )
1500 FreeMemory();
1502 pBuf = static_cast<sal_uInt8 *>(pNewBuf);
1503 nPos = 0;
1504 nSize = nCount;
1505 nResize = 0;
1506 bOwnsData = false;
1508 if( nEOF > nCount )
1509 nEOF = nCount;
1510 nEndOfData = nEOF;
1512 ResetError();
1515 std::size_t SvMemoryStream::GetData( void* pData, std::size_t nCount )
1517 std::size_t nMaxCount = nEndOfData-nPos;
1518 if( nCount > nMaxCount )
1519 nCount = nMaxCount;
1520 if (nCount != 0)
1522 memcpy( pData, pBuf+nPos, nCount );
1524 nPos += nCount;
1525 return nCount;
1528 std::size_t SvMemoryStream::PutData( const void* pData, std::size_t nCount )
1530 if( GetError() )
1531 return 0;
1533 std::size_t nMaxCount = nSize-nPos;
1535 // check for overflow
1536 if( nCount > nMaxCount )
1538 if( nResize == 0 )
1540 // copy as much as possible
1541 nCount = nMaxCount;
1542 SetError( SVSTREAM_OUTOFMEMORY );
1544 else
1546 tools::Long nNewResize;
1547 if( nSize && nSize > nResize )
1548 nNewResize = nSize;
1549 else
1550 nNewResize = nResize;
1552 if( (nCount-nMaxCount) < nResize )
1554 // lacking memory is smaller than nResize,
1555 // resize accordingly
1556 if( !ReAllocateMemory( nNewResize) )
1558 nCount = 0;
1559 SetError( SVSTREAM_WRITE_ERROR );
1562 else
1564 // lacking memory is larger than nResize,
1565 // resize by (nCount-nMaxCount) + resize offset
1566 if( !ReAllocateMemory( nCount-nMaxCount+nNewResize ) )
1568 nCount = 0;
1569 SetError( SVSTREAM_WRITE_ERROR );
1574 assert(pBuf && "Possibly Reallocate failed");
1575 memcpy( pBuf+nPos, pData, nCount);
1577 nPos += nCount;
1578 if( nPos > nEndOfData )
1579 nEndOfData = nPos;
1580 return nCount;
1583 sal_uInt64 SvMemoryStream::SeekPos(sal_uInt64 const nNewPos)
1585 // nEndOfData: First position in stream not allowed to read from
1586 // nSize: Size of allocated buffer
1588 // check if a truncated STREAM_SEEK_TO_END was passed
1589 assert(nNewPos != SAL_MAX_UINT32);
1590 if( nNewPos < nEndOfData )
1591 nPos = nNewPos;
1592 else if( nNewPos == STREAM_SEEK_TO_END )
1593 nPos = nEndOfData;
1594 else
1596 if( nNewPos >= nSize ) // Does buffer need extension?
1598 if( nResize ) // Is extension possible?
1600 tools::Long nDiff = static_cast<tools::Long>(nNewPos - nSize + 1);
1601 nDiff += static_cast<tools::Long>(nResize);
1602 ReAllocateMemory( nDiff );
1603 nPos = nNewPos;
1604 nEndOfData = nNewPos;
1606 else // Extension not possible, set pos to end of data
1608 // SetError( SVSTREAM_OUTOFMEMORY );
1609 nPos = nEndOfData;
1612 else // Expand buffer size
1614 nPos = nNewPos;
1615 nEndOfData = nNewPos;
1618 return nPos;
1621 void SvMemoryStream::FlushData()
1625 void SvMemoryStream::ResetError()
1627 SvStream::ClearError();
1630 void SvMemoryStream::AllocateMemory( std::size_t nNewSize )
1632 pBuf = new sal_uInt8[nNewSize];
1635 // (using Bozo algorithm)
1636 bool SvMemoryStream::ReAllocateMemory( tools::Long nDiff )
1638 if (!m_isWritable || !bOwnsData)
1639 return false;
1641 bool bRetVal = false;
1642 tools::Long nTemp = static_cast<tools::Long>(nSize);
1643 nTemp += nDiff;
1644 std::size_t nNewSize = static_cast<std::size_t>(nTemp);
1646 if( nNewSize )
1648 sal_uInt8* pNewBuf = new sal_uInt8[nNewSize];
1650 bRetVal = true; // Success!
1651 if( nNewSize < nSize ) // Are we shrinking?
1653 memcpy( pNewBuf, pBuf, nNewSize );
1654 if( nPos > nNewSize )
1655 nPos = 0;
1656 if( nEndOfData >= nNewSize )
1657 nEndOfData = nNewSize-1;
1659 else
1661 if (nSize != 0)
1663 memcpy( pNewBuf, pBuf, nSize );
1665 memset(pNewBuf + nSize, 0x00, nNewSize - nSize);
1668 FreeMemory();
1670 pBuf = pNewBuf;
1671 nSize = nNewSize;
1673 else
1675 bRetVal = true;
1676 FreeMemory();
1677 pBuf = nullptr;
1678 nSize = 0;
1679 nEndOfData = 0;
1680 nPos = 0;
1683 return bRetVal;
1686 void SvMemoryStream::FreeMemory()
1688 assert(bOwnsData);
1689 if (bOwnsData)
1691 delete[] pBuf;
1692 pBuf = nullptr;
1696 void* SvMemoryStream::SwitchBuffer()
1698 FlushBuffer();
1699 if( !bOwnsData )
1700 return nullptr;
1701 Seek( STREAM_SEEK_TO_BEGIN );
1703 void* pRetVal = pBuf;
1704 pBuf = nullptr;
1705 nEndOfData = 0;
1706 nResize = 64;
1707 nPos = 0;
1709 ResetError();
1711 std::size_t nInitSize = 512;
1712 AllocateMemory(nInitSize);
1713 nSize = nInitSize;
1715 SetBufferSize( 64 );
1716 return pRetVal;
1719 void SvMemoryStream::SetSize(sal_uInt64 const nNewSize)
1721 if (!m_isWritable)
1723 SetError(SVSTREAM_INVALID_HANDLE);
1724 return;
1727 tools::Long nDiff = static_cast<tools::Long>(nNewSize) - static_cast<tools::Long>(nSize);
1728 ReAllocateMemory( nDiff );
1731 void SvMemoryStream::MakeReadOnly()
1733 FlushBuffer();
1734 m_isWritable = false;
1735 nResize = 0;
1736 SetBufferSize( 0 );
1739 // Create an OString of nLen bytes from rStream
1740 // coverity[ +taint_sanitize ]
1741 OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen)
1743 rtl_String *pStr = nullptr;
1744 if (nLen)
1746 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1747 //limit allocation to size of file, but + 1 to set eof state
1748 nLen = std::min<sal_uInt64>(nLen, rStrm.remainingSize() + 1);
1749 //alloc a (ref-count 1) rtl_String of the desired length.
1750 //rtl_String's buffer is uninitialized, except for null termination
1751 pStr = rtl_string_alloc(sal::static_int_cast<sal_Int32>(nLen));
1752 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1753 if (pStr)
1755 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen);
1756 if (nWasRead != nLen)
1758 //on (typically unlikely) short read set length to what we could
1759 //read, and null terminate. Excess buffer capacity remains of
1760 //course, could create a (true) replacement OString if it matters.
1761 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1762 pStr->buffer[pStr->length] = 0;
1767 //take ownership of buffer and return, otherwise return empty string
1768 return pStr ? OString(pStr, SAL_NO_ACQUIRE) : OString();
1771 // Create an OUString of nLen sal_Unicode code units from rStream
1772 // coverity[ +taint_sanitize ]
1773 OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen)
1775 rtl_uString *pStr = nullptr;
1776 if (nLen)
1778 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1779 //limit allocation to size of file, but + 1 to set eof state
1780 nLen = o3tl::sanitizing_min<sal_uInt64>(nLen, (rStrm.remainingSize() + 2) / 2);
1781 //alloc a (ref-count 1) rtl_uString of the desired length.
1782 //rtl_String's buffer is uninitialized, except for null termination
1783 pStr = rtl_uString_alloc(sal::static_int_cast<sal_Int32>(nLen));
1784 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1785 if (pStr)
1787 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen*2)/2;
1788 if (nWasRead != nLen)
1790 //on (typically unlikely) short read set length to what we could
1791 //read, and null terminate. Excess buffer capacity remains of
1792 //course, could create a (true) replacement OUString if it matters.
1793 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1794 pStr->buffer[pStr->length] = 0;
1796 if (rStrm.IsEndianSwap())
1798 for (sal_Int32 i = 0; i < pStr->length; ++i)
1799 pStr->buffer[i] = OSL_SWAPWORD(pStr->buffer[i]);
1804 // take ownership of buffer and return, otherwise return empty string
1805 // coverity[tainted_data] - unhelpful untrusted loop bound
1806 return pStr ? OUString(pStr, SAL_NO_ACQUIRE) : OUString();
1809 namespace
1811 template <typename T, typename O> T tmpl_convertLineEnd(const T &rIn, LineEnd eLineEnd)
1813 // Determine linebreaks and compute length
1814 bool bConvert = false; // Needs conversion
1815 sal_Int32 nStrLen = rIn.getLength();
1816 sal_Int32 nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
1817 sal_Int32 nLen = 0; // Target length
1818 sal_Int32 i = 0; // Source counter
1820 while (i < nStrLen)
1822 // \r or \n causes linebreak
1823 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
1825 nLen = nLen + nLineEndLen;
1827 // If set already, skip expensive test
1828 if ( !bConvert )
1830 // Do we need to convert?
1831 if ( ((eLineEnd != LINEEND_LF) && (rIn[i] == '\n')) ||
1832 ((eLineEnd == LINEEND_CRLF) && (i+1) < nStrLen && (rIn[i+1] != '\n')) ||
1833 ((eLineEnd == LINEEND_LF) &&
1834 ((rIn[i] == '\r') || ((i+1) < nStrLen && rIn[i+1] == '\r'))) ||
1835 ((eLineEnd == LINEEND_CR) &&
1836 ((rIn[i] == '\n') || ((i+1) < nStrLen && rIn[i+1] == '\n'))) )
1837 bConvert = true;
1840 // skip char if \r\n or \n\r
1841 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
1842 (rIn[i] != rIn[i+1]) )
1843 ++i;
1845 else
1846 ++nLen;
1847 ++i;
1850 if (!bConvert)
1851 return rIn;
1853 // convert linebreaks, insert string
1854 O aNewData(nLen);
1855 i = 0;
1856 while (i < nStrLen)
1858 // \r or \n causes linebreak
1859 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
1861 if ( eLineEnd == LINEEND_CRLF )
1863 aNewData.append('\r');
1864 aNewData.append('\n');
1866 else
1868 if ( eLineEnd == LINEEND_CR )
1869 aNewData.append('\r');
1870 else
1871 aNewData.append('\n');
1874 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
1875 (rIn[i] != rIn[i+1]) )
1876 ++i;
1878 else
1880 aNewData.append(rIn[i]);
1883 ++i;
1886 return aNewData.makeStringAndClear();
1890 OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
1892 return tmpl_convertLineEnd<OString, OStringBuffer>(rIn, eLineEnd);
1895 OUString convertLineEnd(const OUString &rIn, LineEnd eLineEnd)
1897 return tmpl_convertLineEnd<OUString, OUStringBuffer>(rIn, eLineEnd);
1900 std::size_t write_uInt32_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
1901 std::u16string_view rStr)
1903 std::size_t nWritten = 0;
1904 sal_uInt32 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt32>::max());
1905 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
1906 "tools.stream",
1907 "string too long for prefix count to fit in output type");
1908 rStrm.WriteUInt32(nUnits);
1909 if (rStrm.good())
1911 nWritten += sizeof(sal_uInt32);
1912 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
1914 return nWritten;
1917 std::size_t write_uInt16_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
1918 std::u16string_view rStr)
1920 std::size_t nWritten = 0;
1921 sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
1922 SAL_WARN_IF(nUnits != rStr.size(),
1923 "tools.stream",
1924 "string too long for prefix count to fit in output type");
1925 rStrm.WriteUInt16(nUnits);
1926 if (rStrm.good())
1928 nWritten += sizeof(nUnits);
1929 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
1931 return nWritten;
1934 std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm,
1935 std::string_view rStr)
1937 std::size_t nWritten = 0;
1938 sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
1939 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
1940 "tools.stream",
1941 "string too long for sal_uInt16 count to fit in output type");
1942 rStrm.WriteUInt16( nUnits );
1943 if (rStrm.good())
1945 nWritten += sizeof(sal_uInt16);
1946 nWritten += rStrm.WriteBytes(rStr.data(), nUnits);
1948 return nWritten;
1951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */