Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / tools / source / stream / stream.cxx
blob6318348de5ec367452c963e6662ac0b6a39de4ce
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 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 #ifdef OSL_BIGENDIAN
365 m_isSwap = nNewFormat == SvStreamEndian::LITTLE;
366 #else
367 m_isSwap = nNewFormat == SvStreamEndian::BIG;
368 #endif
371 SvStreamEndian SvStream::GetEndian() const
373 #ifdef OSL_BIGENDIAN
374 return m_isSwap ? SvStreamEndian::LITTLE : SvStreamEndian::BIG;
375 #else
376 return m_isSwap ? SvStreamEndian::BIG : SvStreamEndian::LITTLE;
377 #endif
380 void SvStream::SetBufferSize( sal_uInt16 nBufferSize )
382 sal_uInt64 const nActualFilePos = Tell();
383 bool bDontSeek = (m_pRWBuf == nullptr);
385 if (m_isDirty && m_isWritable) // due to Windows NT: Access denied
386 FlushBuffer();
388 if (m_nBufSize)
390 m_pRWBuf.reset();
391 m_nBufFilePos += m_nBufActualPos;
394 m_pRWBuf = nullptr;
395 m_nBufActualLen = 0;
396 m_nBufActualPos = 0;
397 m_nBufSize = nBufferSize;
398 if (m_nBufSize)
399 m_pRWBuf.reset(new sal_uInt8[ m_nBufSize ]);
400 m_pBufPos = m_pRWBuf.get();
401 m_isIoRead = m_isIoWrite = false;
402 if( !bDontSeek )
403 SeekPos( nActualFilePos );
406 void SvStream::ClearBuffer()
408 m_nBufActualLen = 0;
409 m_nBufActualPos = 0;
410 m_nBufFilePos = 0;
411 m_pBufPos = m_pRWBuf.get();
412 m_isDirty = false;
413 m_isIoRead = m_isIoWrite = false;
415 m_isEof = false;
418 void SvStream::ResetError()
420 ClearError();
423 bool SvStream::ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
424 sal_Int32 nMaxBytesToRead )
426 OString aStr;
427 bool bRet = ReadLine( aStr, nMaxBytesToRead);
428 rStr = OStringToOUString(aStr, eSrcCharSet);
429 return bRet;
432 bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead )
434 OStringBuffer aBuf(4096);
435 bool rv = ReadLine(aBuf, nMaxBytesToRead);
436 rStr = aBuf.makeStringAndClear();
437 return rv;
440 bool SvStream::ReadLine( OStringBuffer& aBuf, sal_Int32 nMaxBytesToRead )
442 char buf[256+1];
443 bool bEnd = false;
444 sal_uInt64 nOldFilePos = Tell();
445 char c = 0;
446 std::size_t nTotalLen = 0;
448 aBuf.setLength(0);
449 while( !bEnd && !GetError() ) // Don't test for EOF as we
450 // are reading block-wise!
452 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes(buf, sizeof(buf)-1));
453 if ( !nLen )
455 if ( aBuf.isEmpty() )
457 // Exit on first block-read error
458 m_isEof = true;
459 aBuf.setLength(0);
460 return false;
462 else
463 break;
466 sal_uInt16 j, n;
467 for( j = n = 0; j < nLen ; ++j )
469 c = buf[j];
470 if ( c == '\n' || c == '\r' )
472 bEnd = true;
473 break;
475 if ( n < j )
476 buf[n] = c;
477 ++n;
479 nTotalLen += j;
480 if (nTotalLen > o3tl::make_unsigned(nMaxBytesToRead))
482 n -= nTotalLen - nMaxBytesToRead;
483 nTotalLen = nMaxBytesToRead;
484 bEnd = true;
486 if ( n )
487 aBuf.append(buf, n);
490 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
491 bEnd = true;
493 nOldFilePos += nTotalLen;
494 if( Tell() > nOldFilePos )
495 nOldFilePos++;
496 Seek( nOldFilePos ); // Seek pointer due to BlockRead above
498 if ( bEnd && (c=='\r' || c=='\n') ) // Special treatment for DOS files
500 char cTemp;
501 std::size_t nLen = ReadBytes(&cTemp, sizeof(cTemp));
502 if ( nLen ) {
503 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
504 Seek( nOldFilePos );
508 if ( bEnd )
509 m_isEof = false;
510 return bEnd;
513 bool SvStream::ReadUniStringLine( OUString& rStr, sal_Int32 nMaxCodepointsToRead )
515 sal_Unicode buf[256+1];
516 bool bEnd = false;
517 sal_uInt64 nOldFilePos = Tell();
518 sal_Unicode c = 0;
519 std::size_t nTotalLen = 0;
521 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "ReadUniStringLine: swapping sizeof(sal_Unicode) not implemented" );
523 OUStringBuffer aBuf(4096);
524 while( !bEnd && !GetError() ) // Don't test for EOF as we
525 // are reading block-wise!
527 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes( buf, sizeof(buf)-sizeof(sal_Unicode)));
528 nLen /= sizeof(sal_Unicode);
529 if ( !nLen )
531 if ( aBuf.isEmpty() )
533 // exit on first BlockRead error
534 m_isEof = true;
535 rStr.clear();
536 return false;
538 else
539 break;
542 sal_uInt16 j, n;
543 for( j = n = 0; j < nLen ; ++j )
545 if (m_isSwap)
546 SwapNumber( buf[n] );
547 c = buf[j];
548 if ( c == '\n' || c == '\r' )
550 bEnd = true;
551 break;
553 // erAck 26.02.01: Old behavior was no special treatment of '\0'
554 // character here, but a following rStr+=c did ignore it. Is this
555 // really intended? Or should a '\0' better terminate a line?
556 // The nOldFilePos stuff wasn't correct then anyways.
557 if ( c )
559 if ( n < j )
560 buf[n] = c;
561 ++n;
564 nTotalLen += j;
565 if (nTotalLen > o3tl::make_unsigned(nMaxCodepointsToRead))
567 n -= nTotalLen - nMaxCodepointsToRead;
568 nTotalLen = nMaxCodepointsToRead;
569 bEnd = true;
571 if ( n )
572 aBuf.append( buf, n );
575 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
576 bEnd = true;
578 nOldFilePos += nTotalLen * sizeof(sal_Unicode);
579 if( Tell() > nOldFilePos )
580 nOldFilePos += sizeof(sal_Unicode);
581 Seek( nOldFilePos ); // seek due to BlockRead above
583 if ( bEnd && (c=='\r' || c=='\n') ) // special treatment for DOS files
585 sal_Unicode cTemp;
586 ReadBytes( &cTemp, sizeof(cTemp) );
587 if (m_isSwap)
588 SwapNumber( cTemp );
589 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
590 Seek( nOldFilePos );
593 if ( bEnd )
594 m_isEof = false;
595 rStr = aBuf.makeStringAndClear();
596 return bEnd;
599 bool SvStream::ReadUniOrByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
600 sal_Int32 nMaxCodepointsToRead )
602 if ( eSrcCharSet == RTL_TEXTENCODING_UNICODE )
603 return ReadUniStringLine( rStr, nMaxCodepointsToRead );
604 else
605 return ReadByteStringLine( rStr, eSrcCharSet, nMaxCodepointsToRead );
608 OString read_zeroTerminated_uInt8s_ToOString(SvStream& rStream)
610 OStringBuffer aOutput(256);
612 char buf[ 256 + 1 ];
613 bool bEnd = false;
614 sal_uInt64 nFilePos = rStream.Tell();
616 while( !bEnd && !rStream.GetError() )
618 std::size_t nLen = rStream.ReadBytes(buf, sizeof(buf)-1);
619 if (!nLen)
620 break;
622 std::size_t nReallyRead = nLen;
623 const char* pPtr = buf;
624 while (nLen && *pPtr)
626 ++pPtr;
627 --nLen;
630 bEnd = ( nReallyRead < sizeof(buf)-1 ) // read less than attempted to read
631 || ( ( nLen > 0 ) // OR it is inside the block we read
632 && ( 0 == *pPtr ) // AND found a string terminator
635 aOutput.append(buf, pPtr - buf);
638 nFilePos += aOutput.getLength();
639 if (rStream.Tell() > nFilePos)
640 rStream.Seek(nFilePos+1); // seek due to FileRead above
641 return aOutput.makeStringAndClear();
644 OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStream, rtl_TextEncoding eEnc)
646 return OStringToOUString(
647 read_zeroTerminated_uInt8s_ToOString(rStream), eEnc);
650 /** Attempt to write a prefixed sequence of nUnits 16bit units from an OUString,
651 returned value is number of bytes written */
652 std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr,
653 std::size_t nUnits)
655 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "write_uInt16s_FromOUString: swapping sizeof(sal_Unicode) not implemented" );
656 std::size_t nWritten;
657 if (!rStrm.IsEndianSwap())
658 nWritten = rStrm.WriteBytes(rStr.data(), nUnits * sizeof(sal_Unicode));
659 else
661 std::size_t nLen = nUnits;
662 sal_Unicode aBuf[384];
663 sal_Unicode* const pTmp = ( nLen > 384 ? new sal_Unicode[nLen] : aBuf);
664 memcpy( pTmp, rStr.data(), nLen * sizeof(sal_Unicode) );
665 sal_Unicode* p = pTmp;
666 const sal_Unicode* const pStop = pTmp + nLen;
667 while ( p < pStop )
669 SwapNumber( *p );
670 p++;
672 nWritten = rStrm.WriteBytes( pTmp, nLen * sizeof(sal_Unicode) );
673 if ( pTmp != aBuf )
674 delete [] pTmp;
676 return nWritten;
679 bool SvStream::WriteUnicodeOrByteText( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
681 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
683 write_uInt16s_FromOUString(*this, rStr, rStr.size());
684 return m_nError == ERRCODE_NONE;
686 else
688 OString aStr(OUStringToOString(rStr, eDestCharSet));
689 write_uInt8s_FromOString(*this, aStr, aStr.getLength());
690 return m_nError == ERRCODE_NONE;
694 bool SvStream::WriteByteStringLine( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
696 return WriteLine(OUStringToOString(rStr, eDestCharSet));
699 bool SvStream::WriteLine(std::string_view rStr)
701 WriteBytes(rStr.data(), rStr.size());
702 endl(*this);
703 return m_nError == ERRCODE_NONE;
706 bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet )
708 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
709 WriteUnicode(ch);
710 else
712 OString aStr(&ch, 1, eDestCharSet);
713 WriteBytes(aStr.getStr(), aStr.getLength());
715 return m_nError == ERRCODE_NONE;
718 void SvStream::StartWritingUnicodeText()
720 m_isSwap = false; // Switch to no endian swapping
721 // BOM, Byte Order Mark, U+FEFF, see
722 // http://www.unicode.org/faq/utf_bom.html#BOM
723 // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap
724 WriteUInt16(0xfeff);
727 void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet )
729 if (!( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
730 eReadBomCharSet == RTL_TEXTENCODING_UNICODE ||
731 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
732 return; // nothing to read
734 const sal_uInt64 nOldPos = Tell();
735 bool bGetBack = true;
736 unsigned char nFlag(0);
737 ReadUChar( nFlag );
738 switch ( nFlag )
740 case 0xfe: // UTF-16BE?
741 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
742 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
744 ReadUChar(nFlag);
745 if (nFlag == 0xff)
747 SetEndian(SvStreamEndian::BIG);
748 bGetBack = false;
751 break;
752 case 0xff: // UTF-16LE?
753 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
754 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
756 ReadUChar(nFlag);
757 if (nFlag == 0xfe)
759 SetEndian(SvStreamEndian::LITTLE);
760 bGetBack = false;
763 break;
764 case 0xef: // UTF-8?
765 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
766 eReadBomCharSet == RTL_TEXTENCODING_UTF8)
768 ReadUChar(nFlag);
769 if (nFlag == 0xbb)
771 ReadUChar(nFlag);
772 if (nFlag == 0xbf)
773 bGetBack = false; // it is UTF-8
776 break;
777 default:
778 ; // nothing
780 if (bGetBack)
781 Seek(nOldPos); // no BOM, pure data
784 sal_uInt64 SvStream::SeekRel(sal_Int64 const nPos)
786 sal_uInt64 nActualPos = Tell();
788 if ( nPos >= 0 )
790 if (SAL_MAX_UINT64 - nActualPos > o3tl::make_unsigned(nPos))
791 nActualPos += nPos;
793 else
795 sal_uInt64 const nAbsPos = static_cast<sal_uInt64>(-nPos);
796 if ( nActualPos >= nAbsPos )
797 nActualPos -= nAbsPos;
800 assert((m_pBufPos != nullptr) == bool(m_pRWBuf));
801 if (m_pRWBuf)
803 m_pBufPos = m_pRWBuf.get() + nActualPos;
805 return Seek( nActualPos );
808 template <typename T> SvStream& SvStream::ReadNumber(T& r)
810 T n = 0;
811 readNumberWithoutSwap(n);
812 if (good())
814 if (m_isSwap)
815 SwapNumber(n);
816 r = n;
818 return *this;
821 SvStream& SvStream::ReadUInt16(sal_uInt16& r) { return ReadNumber(r); }
822 SvStream& SvStream::ReadUInt32(sal_uInt32& r) { return ReadNumber(r); }
823 SvStream& SvStream::ReadUInt64(sal_uInt64& r) { return ReadNumber(r); }
824 SvStream& SvStream::ReadInt16(sal_Int16& r) { return ReadNumber(r); }
825 SvStream& SvStream::ReadInt32(sal_Int32& r) { return ReadNumber(r); }
826 SvStream& SvStream::ReadInt64(sal_Int64& r) { return ReadNumber(r); }
828 SvStream& SvStream::ReadSChar( signed char& r )
830 if (m_isIoRead && sizeof(signed char) <= m_nBufFree)
832 r = *m_pBufPos;
833 m_nBufActualPos += sizeof(signed char);
834 m_pBufPos += sizeof(signed char);
835 m_nBufFree -= sizeof(signed char);
837 else
838 ReadBytes( &r, sizeof(signed char) );
839 return *this;
842 // Special treatment for Chars due to PutBack
844 SvStream& SvStream::ReadChar( char& r )
846 if (m_isIoRead && sizeof(char) <= m_nBufFree)
848 r = *m_pBufPos;
849 m_nBufActualPos += sizeof(char);
850 m_pBufPos += sizeof(char);
851 m_nBufFree -= sizeof(char);
853 else
854 ReadBytes( &r, sizeof(char) );
855 return *this;
858 SvStream& SvStream::ReadUChar( unsigned char& r )
860 if (m_isIoRead && sizeof(char) <= m_nBufFree)
862 r = *m_pBufPos;
863 m_nBufActualPos += sizeof(char);
864 m_pBufPos += sizeof(char);
865 m_nBufFree -= sizeof(char);
867 else
868 ReadBytes( &r, sizeof(char) );
869 return *this;
872 SvStream& SvStream::ReadUtf16(sal_Unicode& r) { return ReadNumber(r); }
874 SvStream& SvStream::ReadCharAsBool( bool& r )
876 if (m_isIoRead && sizeof(char) <= m_nBufFree)
878 SAL_WARN_IF(
879 *m_pBufPos > 1, "tools.stream", unsigned(*m_pBufPos) << " not 0/1");
880 r = *m_pBufPos != 0;
881 m_nBufActualPos += sizeof(char);
882 m_pBufPos += sizeof(char);
883 m_nBufFree -= sizeof(char);
885 else
887 unsigned char c;
888 if (ReadBytes(&c, 1) == 1)
890 SAL_WARN_IF(c > 1, "tools.stream", unsigned(c) << " not 0/1");
891 r = c != 0;
894 return *this;
897 SvStream& SvStream::ReadFloat(float& r)
899 float n = 0;
900 readNumberWithoutSwap(n);
901 if (good())
903 #if defined UNX
904 if (m_isSwap)
905 SwapFloat(n);
906 #endif
907 r = n;
909 return *this;
912 SvStream& SvStream::ReadDouble(double& r)
914 double n = 0;
915 readNumberWithoutSwap(n);
916 if (good())
918 #if defined UNX
919 if (m_isSwap)
920 SwapDouble(n);
921 #endif
922 r = n;
924 return *this;
927 SvStream& SvStream::ReadStream( SvStream& rStream )
929 const sal_uInt32 cBufLen = 0x8000;
930 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
932 sal_uInt32 nCount;
933 do {
934 nCount = ReadBytes( pBuf.get(), cBufLen );
935 rStream.WriteBytes( pBuf.get(), nCount );
936 } while( nCount == cBufLen );
938 return *this;
941 template <typename T> SvStream& SvStream::WriteNumber(T n)
943 if (m_isSwap)
944 SwapNumber(n);
945 writeNumberWithoutSwap(n);
946 return *this;
949 SvStream& SvStream::WriteUInt16(sal_uInt16 v) { return WriteNumber(v); }
950 SvStream& SvStream::WriteUInt32(sal_uInt32 v) { return WriteNumber(v); }
951 SvStream& SvStream::WriteUInt64(sal_uInt64 v) { return WriteNumber(v); }
952 SvStream& SvStream::WriteInt16(sal_Int16 v) { return WriteNumber(v); }
953 SvStream& SvStream::WriteInt32(sal_Int32 v) { return WriteNumber(v); }
954 SvStream& SvStream::WriteInt64(sal_Int64 v) { return WriteNumber(v); }
956 SvStream& SvStream::WriteSChar( signed char v )
958 //SDO
959 if (m_isIoWrite && sizeof(signed char) <= m_nBufFree)
961 *m_pBufPos = v;
962 m_pBufPos++; // sizeof(char);
963 m_nBufActualPos++;
964 if (m_nBufActualPos > m_nBufActualLen) // Append ?
965 m_nBufActualLen = m_nBufActualPos;
966 m_nBufFree--; // = sizeof(char);
967 m_isDirty = true;
969 else
970 WriteBytes( &v, sizeof(signed char) );
971 return *this;
974 // Special treatment for Chars due to PutBack
976 SvStream& SvStream::WriteChar( char v )
978 //SDO
979 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
981 *m_pBufPos = v;
982 m_pBufPos++; // sizeof(char);
983 m_nBufActualPos++;
984 if (m_nBufActualPos > m_nBufActualLen) // Append ?
985 m_nBufActualLen = m_nBufActualPos;
986 m_nBufFree--; // = sizeof(char);
987 m_isDirty = true;
989 else
990 WriteBytes( &v, sizeof(char) );
991 return *this;
994 SvStream& SvStream::WriteUChar( unsigned char v )
996 //SDO
997 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
999 *reinterpret_cast<unsigned char*>(m_pBufPos) = v;
1000 m_pBufPos++; // = sizeof(char);
1001 m_nBufActualPos++; // = sizeof(char);
1002 if (m_nBufActualPos > m_nBufActualLen) // Append ?
1003 m_nBufActualLen = m_nBufActualPos;
1004 m_nBufFree--;
1005 m_isDirty = true;
1007 else
1008 WriteBytes( &v, sizeof(char) );
1009 return *this;
1012 SvStream& SvStream::WriteUInt8( sal_uInt8 v )
1014 return WriteUChar(v);
1017 SvStream& SvStream::WriteUnicode( sal_Unicode v )
1019 return WriteUInt16(v);
1022 SvStream& SvStream::WriteFloat( float v )
1024 #ifdef UNX
1025 if (m_isSwap)
1026 SwapFloat(v);
1027 #endif
1028 writeNumberWithoutSwap(v);
1029 return *this;
1032 SvStream& SvStream::WriteDouble ( const double& r )
1034 #if defined UNX
1035 if (m_isSwap)
1037 double nHelp = r;
1038 SwapDouble(nHelp);
1039 writeNumberWithoutSwap(nHelp);
1040 return *this;
1042 else
1043 #endif
1045 writeNumberWithoutSwap(r);
1047 return *this;
1050 SvStream& SvStream::WriteStream( SvStream& rStream )
1052 const sal_uInt32 cBufLen = 0x8000;
1053 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1054 sal_uInt32 nCount;
1055 do {
1056 nCount = rStream.ReadBytes( pBuf.get(), cBufLen );
1057 WriteBytes( pBuf.get(), nCount );
1058 } while( nCount == cBufLen );
1060 return *this;
1063 sal_uInt64 SvStream::WriteStream( SvStream& rStream, sal_uInt64 nSize )
1065 const sal_uInt32 cBufLen = 0x8000;
1066 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1067 sal_uInt32 nCurBufLen = cBufLen;
1068 sal_uInt32 nCount;
1069 sal_uInt64 nWriteSize = nSize;
1073 nCurBufLen = std::min<sal_uInt64>(nCurBufLen, nWriteSize);
1074 nCount = rStream.ReadBytes(pBuf.get(), nCurBufLen);
1075 WriteBytes( pBuf.get(), nCount );
1076 nWriteSize -= nCount;
1078 while( nWriteSize && nCount == nCurBufLen );
1080 return nSize - nWriteSize;
1083 OUString SvStream::ReadUniOrByteString( rtl_TextEncoding eSrcCharSet )
1085 // read UTF-16 string directly from stream ?
1086 if (eSrcCharSet == RTL_TEXTENCODING_UNICODE)
1087 return read_uInt32_lenPrefixed_uInt16s_ToOUString(*this);
1088 return read_uInt16_lenPrefixed_uInt8s_ToOUString(*this, eSrcCharSet);
1091 SvStream& SvStream::WriteUniOrByteString( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
1093 // write UTF-16 string directly into stream ?
1094 if (eDestCharSet == RTL_TEXTENCODING_UNICODE)
1095 write_uInt32_lenPrefixed_uInt16s_FromOUString(*this, rStr);
1096 else
1097 write_uInt16_lenPrefixed_uInt8s_FromOUString(*this, rStr, eDestCharSet);
1098 return *this;
1101 void SvStream::FlushBuffer()
1103 if (m_isDirty) // Does stream require a flush?
1105 SeekPos(m_nBufFilePos);
1106 if (m_nCryptMask)
1107 CryptAndWriteBuffer(m_pRWBuf.get(), m_nBufActualLen);
1108 else if (PutData(m_pRWBuf.get(), m_nBufActualLen) != m_nBufActualLen)
1109 SetError(SVSTREAM_WRITE_ERROR);
1110 m_isDirty = false;
1114 std::size_t SvStream::ReadBytes( void* pData, std::size_t nCount )
1116 std::size_t nSaveCount = nCount;
1118 if (!m_pRWBuf)
1120 nCount = GetData( pData,nCount);
1121 if (m_nCryptMask)
1122 EncryptBuffer(pData, nCount);
1123 m_nBufFilePos += nCount;
1125 else
1127 // check if block is completely within buffer
1128 m_isIoRead = true;
1129 m_isIoWrite = false;
1130 if (nCount <= o3tl::make_unsigned(m_nBufActualLen - m_nBufActualPos))
1132 // => yes
1133 if (nCount != 0)
1134 memcpy(pData, m_pBufPos, nCount);
1135 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1136 m_pBufPos += nCount;
1137 m_nBufFree = m_nBufFree - static_cast<sal_uInt16>(nCount);
1139 else
1141 FlushBuffer();
1143 // Does data block fit into buffer?
1144 if (nCount > m_nBufSize)
1146 // => No! Thus read directly
1147 // into target area without using the buffer
1149 m_isIoRead = false;
1151 SeekPos(m_nBufFilePos + m_nBufActualPos);
1152 m_nBufActualLen = 0;
1153 m_pBufPos = m_pRWBuf.get();
1154 nCount = GetData( pData, nCount );
1155 if (m_nCryptMask)
1156 EncryptBuffer(pData, nCount);
1157 m_nBufFilePos += nCount;
1158 m_nBufFilePos += m_nBufActualPos;
1159 m_nBufActualPos = 0;
1161 else
1163 // => Yes. Fill buffer first, then copy to target area
1165 m_nBufFilePos += m_nBufActualPos;
1166 SeekPos(m_nBufFilePos);
1168 // TODO: Typecast before GetData, sal_uInt16 nCountTmp
1169 std::size_t nCountTmp = GetData( m_pRWBuf.get(), m_nBufSize );
1170 if (m_nCryptMask)
1171 EncryptBuffer(m_pRWBuf.get(), nCountTmp);
1172 m_nBufActualLen = static_cast<sal_uInt16>(nCountTmp);
1173 if( nCount > nCountTmp )
1175 nCount = nCountTmp; // trim count back, EOF see below
1177 memcpy( pData, m_pRWBuf.get(), nCount );
1178 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1179 m_pBufPos = m_pRWBuf.get() + nCount;
1183 m_isEof = false;
1184 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1185 if (nCount != nSaveCount && m_nError != ERRCODE_IO_PENDING)
1186 m_isEof = true;
1187 if (nCount == nSaveCount && m_nError == ERRCODE_IO_PENDING)
1188 m_nError = ERRCODE_NONE;
1189 return nCount;
1192 std::size_t SvStream::WriteBytes( const void* pData, std::size_t nCount )
1194 if( !nCount )
1195 return 0;
1197 if (!m_isWritable)
1199 SetError( ERRCODE_IO_CANTWRITE );
1200 return 0;
1203 if (!m_pRWBuf)
1205 if (m_nCryptMask)
1206 nCount = CryptAndWriteBuffer( pData, nCount );
1207 else
1208 nCount = PutData( pData, nCount );
1209 m_nBufFilePos += nCount;
1210 return nCount;
1213 m_isIoRead = false;
1214 m_isIoWrite = true;
1215 if (nCount <= o3tl::make_unsigned(m_nBufSize - m_nBufActualPos))
1217 memcpy( m_pBufPos, pData, nCount );
1218 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1219 // Update length if buffer was updated
1220 if (m_nBufActualPos > m_nBufActualLen)
1221 m_nBufActualLen = m_nBufActualPos;
1223 m_pBufPos += nCount;
1224 m_isDirty = true;
1226 else
1228 FlushBuffer();
1230 // Does data block fit into buffer?
1231 if (nCount > m_nBufSize)
1233 m_isIoWrite = false;
1234 m_nBufFilePos += m_nBufActualPos;
1235 m_nBufActualLen = 0;
1236 m_nBufActualPos = 0;
1237 m_pBufPos = m_pRWBuf.get();
1238 SeekPos(m_nBufFilePos);
1239 if (m_nCryptMask)
1240 nCount = CryptAndWriteBuffer( pData, nCount );
1241 else
1242 nCount = PutData( pData, nCount );
1243 m_nBufFilePos += nCount;
1245 else
1247 // Copy block to buffer
1248 memcpy( m_pRWBuf.get(), pData, nCount );
1250 // Mind the order!
1251 m_nBufFilePos += m_nBufActualPos;
1252 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1253 m_pBufPos = m_pRWBuf.get() + nCount;
1254 m_nBufActualLen = static_cast<sal_uInt16>(nCount);
1255 m_isDirty = true;
1258 m_nBufFree = m_nBufSize - m_nBufActualPos;
1259 return nCount;
1262 sal_uInt64 SvStream::Seek(sal_uInt64 const nFilePos)
1264 m_isIoRead = m_isIoWrite = false;
1265 m_isEof = false;
1266 if (!m_pRWBuf)
1268 m_nBufFilePos = SeekPos( nFilePos );
1269 DBG_ASSERT(Tell() == m_nBufFilePos,"Out Of Sync!");
1270 return m_nBufFilePos;
1273 // Is seek position within buffer?
1274 if (nFilePos >= m_nBufFilePos && nFilePos <= (m_nBufFilePos + m_nBufActualLen))
1276 m_nBufActualPos = static_cast<sal_uInt16>(nFilePos - m_nBufFilePos);
1277 m_pBufPos = m_pRWBuf.get() + m_nBufActualPos;
1278 // Update m_nBufFree to avoid crash upon PutBack
1279 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1281 else
1283 FlushBuffer();
1284 m_nBufActualLen = 0;
1285 m_nBufActualPos = 0;
1286 m_pBufPos = m_pRWBuf.get();
1287 m_nBufFilePos = SeekPos( nFilePos );
1289 return m_nBufFilePos + m_nBufActualPos;
1292 bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
1294 const sal_uInt64 nMaxSeek = rSt.TellEnd();
1295 return (nOffset <= nMaxSeek && rSt.Seek(nOffset) == nOffset);
1298 namespace tools
1300 bool isEmptyFileUrl(const OUString& rUrl)
1302 if (!comphelper::isFileUrl(rUrl))
1304 return false;
1307 SvFileStream aStream(rUrl, StreamMode::READ);
1308 if (!aStream.IsOpen())
1310 return false;
1313 return aStream.remainingSize() == 0;
1317 //STREAM_SEEK_TO_END in some of the Seek backends is special cased to be
1318 //efficient, in others e.g. SotStorageStream it's really horribly slow, and in
1319 //those this should be overridden
1320 sal_uInt64 SvStream::remainingSize()
1322 sal_uInt64 const nCurr = Tell();
1323 sal_uInt64 const nEnd = TellEnd();
1324 sal_uInt64 nMaxAvailable = nEnd > nCurr ? (nEnd-nCurr) : 0;
1325 return nMaxAvailable;
1328 sal_uInt64 SvStream::TellEnd()
1330 FlushBuffer();
1331 sal_uInt64 const nCurr = Tell();
1332 sal_uInt64 const nEnd = Seek(STREAM_SEEK_TO_END);
1333 Seek(nCurr);
1334 return nEnd;
1337 void SvStream::Flush()
1339 FlushBuffer();
1340 if (m_isWritable)
1341 FlushData();
1344 void SvStream::RefreshBuffer()
1346 FlushBuffer();
1347 SeekPos(m_nBufFilePos);
1348 m_nBufActualLen = static_cast<sal_uInt16>(GetData( m_pRWBuf.get(), m_nBufSize ));
1349 if (m_nBufActualLen && m_nError == ERRCODE_IO_PENDING)
1350 m_nError = ERRCODE_NONE;
1351 if (m_nCryptMask)
1352 EncryptBuffer(m_pRWBuf.get(), static_cast<std::size_t>(m_nBufActualLen));
1353 m_isIoRead = m_isIoWrite = false;
1356 #define CRYPT_BUFSIZE 1024
1358 /// Encrypt and write
1359 std::size_t SvStream::CryptAndWriteBuffer( const void* pStart, std::size_t nLen)
1361 unsigned char pTemp[CRYPT_BUFSIZE];
1362 unsigned char const * pDataPtr = static_cast<unsigned char const *>(pStart);
1363 std::size_t nCount = 0;
1364 std::size_t nBufCount;
1365 unsigned char nMask = m_nCryptMask;
1368 if( nLen >= CRYPT_BUFSIZE )
1369 nBufCount = CRYPT_BUFSIZE;
1370 else
1371 nBufCount = nLen;
1372 nLen -= nBufCount;
1373 memcpy( pTemp, pDataPtr, static_cast<sal_uInt16>(nBufCount) );
1374 // ******** Encrypt ********
1375 for (unsigned char & rn : pTemp)
1377 unsigned char aCh = rn;
1378 aCh ^= nMask;
1379 swapNibbles(aCh);
1380 rn = aCh;
1382 // *************************
1383 nCount += PutData( pTemp, nBufCount );
1384 pDataPtr += nBufCount;
1386 while ( nLen );
1387 return nCount;
1390 void SvStream::EncryptBuffer(void* pStart, std::size_t nLen) const
1392 unsigned char* pTemp = static_cast<unsigned char*>(pStart);
1393 unsigned char nMask = m_nCryptMask;
1395 for ( std::size_t n=0; n < nLen; n++, pTemp++ )
1397 unsigned char aCh = *pTemp;
1398 swapNibbles(aCh);
1399 aCh ^= nMask;
1400 *pTemp = aCh;
1404 static unsigned char implGetCryptMask(const char* pStr, sal_Int32 nLen, tools::Long nVersion)
1406 unsigned char nCryptMask = 0;
1408 if (!nLen)
1409 return nCryptMask;
1411 if( nVersion <= SOFFICE_FILEFORMAT_31 )
1413 while( nLen )
1415 nCryptMask ^= *pStr;
1416 pStr++;
1417 nLen--;
1420 else // BugFix #25888#
1422 for( sal_Int32 i = 0; i < nLen; i++ ) {
1423 nCryptMask ^= pStr[i];
1424 if( nCryptMask & 0x80 ) {
1425 nCryptMask <<= 1;
1426 nCryptMask++;
1428 else
1429 nCryptMask <<= 1;
1433 if( !nCryptMask )
1434 nCryptMask = 67;
1436 return nCryptMask;
1439 void SvStream::SetCryptMaskKey(const OString& rCryptMaskKey)
1441 m_aCryptMaskKey = rCryptMaskKey;
1442 m_nCryptMask = implGetCryptMask(m_aCryptMaskKey.getStr(),
1443 m_aCryptMaskKey.getLength(), GetVersion());
1446 bool SvStream::SetStreamSize(sal_uInt64 const nSize)
1448 #ifdef DBG_UTIL
1449 sal_uInt64 nFPos = Tell();
1450 #endif
1451 sal_uInt16 nBuf = m_nBufSize;
1452 SetBufferSize( 0 );
1453 SetSize( nSize );
1454 if (nSize < m_nBufFilePos)
1456 m_nBufFilePos = nSize;
1458 SetBufferSize( nBuf );
1459 #ifdef DBG_UTIL
1460 DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed");
1461 #endif
1462 return (m_nError == ERRCODE_NONE);
1465 SvStream& endl( SvStream& rStr )
1467 LineEnd eDelim = rStr.GetLineDelimiter();
1468 if ( eDelim == LINEEND_CR )
1469 rStr.WriteChar('\r');
1470 else if( eDelim == LINEEND_LF )
1471 rStr.WriteChar('\n');
1472 else
1473 rStr.WriteChar('\r').WriteChar('\n');
1474 return rStr;
1477 SvStream& endlu( SvStream& rStrm )
1479 switch ( rStrm.GetLineDelimiter() )
1481 case LINEEND_CR :
1482 rStrm.WriteUnicode('\r');
1483 break;
1484 case LINEEND_LF :
1485 rStrm.WriteUnicode('\n');
1486 break;
1487 default:
1488 rStrm.WriteUnicode('\r').WriteUnicode('\n');
1490 return rStrm;
1493 SvStream& endlub( SvStream& rStrm )
1495 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
1496 return endlu( rStrm );
1497 else
1498 return endl( rStrm );
1501 SvMemoryStream::SvMemoryStream( void* pBuffer, std::size_t bufSize,
1502 StreamMode eMode )
1504 if( eMode & StreamMode::WRITE )
1505 m_isWritable = true;
1506 else
1507 m_isWritable = false;
1508 nEndOfData = bufSize;
1509 bOwnsData = false;
1510 pBuf = static_cast<sal_uInt8 *>(pBuffer);
1511 nResize = 0;
1512 nSize = bufSize;
1513 nPos = 0;
1514 SetBufferSize( 0 );
1517 SvMemoryStream::SvMemoryStream( std::size_t nInitSize, std::size_t nResizeOffset )
1519 m_isWritable = true;
1520 bOwnsData = true;
1521 nEndOfData = 0;
1522 nResize = nResizeOffset;
1523 nPos = 0;
1524 pBuf = nullptr;
1525 if( nResize != 0 && nResize < 16 )
1526 nResize = 16;
1527 if( nInitSize )
1528 AllocateMemory( nInitSize );
1529 nSize = nInitSize;
1530 SetBufferSize( 64 );
1533 SvMemoryStream::~SvMemoryStream()
1535 if( pBuf )
1537 if( bOwnsData )
1538 FreeMemory();
1539 else
1540 FlushBuffer();
1544 void SvMemoryStream::SetBuffer( void* pNewBuf, std::size_t nCount,
1545 std::size_t nEOF )
1547 SetBufferSize( 0 ); // Init buffering in the base class
1548 Seek( 0 );
1549 if( bOwnsData && pNewBuf != pBuf )
1550 FreeMemory();
1552 pBuf = static_cast<sal_uInt8 *>(pNewBuf);
1553 nPos = 0;
1554 nSize = nCount;
1555 nResize = 0;
1556 bOwnsData = false;
1558 if( nEOF > nCount )
1559 nEOF = nCount;
1560 nEndOfData = nEOF;
1562 ResetError();
1565 std::size_t SvMemoryStream::GetData( void* pData, std::size_t nCount )
1567 std::size_t nMaxCount = nEndOfData-nPos;
1568 if( nCount > nMaxCount )
1569 nCount = nMaxCount;
1570 if (nCount != 0)
1572 memcpy( pData, pBuf+nPos, nCount );
1574 nPos += nCount;
1575 return nCount;
1578 std::size_t SvMemoryStream::PutData( const void* pData, std::size_t nCount )
1580 if( GetError() )
1581 return 0;
1583 std::size_t nMaxCount = nSize-nPos;
1585 // check for overflow
1586 if( nCount > nMaxCount )
1588 if( nResize == 0 )
1590 // copy as much as possible
1591 nCount = nMaxCount;
1592 SetError( SVSTREAM_OUTOFMEMORY );
1594 else
1596 tools::Long nNewResize;
1597 if( nSize && nSize > nResize )
1598 nNewResize = nSize;
1599 else
1600 nNewResize = nResize;
1602 if( (nCount-nMaxCount) < nResize )
1604 // lacking memory is smaller than nResize,
1605 // resize accordingly
1606 if( !ReAllocateMemory( nNewResize) )
1608 nCount = 0;
1609 SetError( SVSTREAM_WRITE_ERROR );
1612 else
1614 // lacking memory is larger than nResize,
1615 // resize by (nCount-nMaxCount) + resize offset
1616 if( !ReAllocateMemory( nCount-nMaxCount+nNewResize ) )
1618 nCount = 0;
1619 SetError( SVSTREAM_WRITE_ERROR );
1624 assert(pBuf && "Possibly Reallocate failed");
1625 memcpy( pBuf+nPos, pData, nCount);
1627 nPos += nCount;
1628 if( nPos > nEndOfData )
1629 nEndOfData = nPos;
1630 return nCount;
1633 sal_uInt64 SvMemoryStream::SeekPos(sal_uInt64 const nNewPos)
1635 // nEndOfData: First position in stream not allowed to read from
1636 // nSize: Size of allocated buffer
1638 // check if a truncated STREAM_SEEK_TO_END was passed
1639 assert(nNewPos != SAL_MAX_UINT32);
1640 if( nNewPos < nEndOfData )
1641 nPos = nNewPos;
1642 else if( nNewPos == STREAM_SEEK_TO_END )
1643 nPos = nEndOfData;
1644 else
1646 if( nNewPos >= nSize ) // Does buffer need extension?
1648 if( nResize ) // Is extension possible?
1650 tools::Long nDiff = static_cast<tools::Long>(nNewPos - nSize + 1);
1651 nDiff += static_cast<tools::Long>(nResize);
1652 ReAllocateMemory( nDiff );
1653 nPos = nNewPos;
1654 nEndOfData = nNewPos;
1656 else // Extension not possible, set pos to end of data
1658 // SetError( SVSTREAM_OUTOFMEMORY );
1659 nPos = nEndOfData;
1662 else // Expand buffer size
1664 nPos = nNewPos;
1665 nEndOfData = nNewPos;
1668 return nPos;
1671 void SvMemoryStream::FlushData()
1675 void SvMemoryStream::ResetError()
1677 SvStream::ClearError();
1680 void SvMemoryStream::AllocateMemory( std::size_t nNewSize )
1682 pBuf = new sal_uInt8[nNewSize];
1685 // (using Bozo algorithm)
1686 bool SvMemoryStream::ReAllocateMemory( tools::Long nDiff )
1688 if (!m_isWritable || !bOwnsData)
1689 return false;
1691 bool bRetVal = false;
1692 tools::Long nTemp = static_cast<tools::Long>(nSize);
1693 nTemp += nDiff;
1694 std::size_t nNewSize = static_cast<std::size_t>(nTemp);
1696 if( nNewSize )
1698 sal_uInt8* pNewBuf = new sal_uInt8[nNewSize];
1700 bRetVal = true; // Success!
1701 if( nNewSize < nSize ) // Are we shrinking?
1703 memcpy( pNewBuf, pBuf, nNewSize );
1704 if( nPos > nNewSize )
1705 nPos = 0;
1706 if( nEndOfData >= nNewSize )
1707 nEndOfData = nNewSize-1;
1709 else
1711 if (nSize != 0)
1713 memcpy( pNewBuf, pBuf, nSize );
1715 memset(pNewBuf + nSize, 0x00, nNewSize - nSize);
1718 FreeMemory();
1720 pBuf = pNewBuf;
1721 nSize = nNewSize;
1723 else
1725 bRetVal = true;
1726 FreeMemory();
1727 pBuf = nullptr;
1728 nSize = 0;
1729 nEndOfData = 0;
1730 nPos = 0;
1733 return bRetVal;
1736 void SvMemoryStream::FreeMemory()
1738 assert(bOwnsData);
1739 if (bOwnsData)
1741 delete[] pBuf;
1742 pBuf = nullptr;
1746 void* SvMemoryStream::SwitchBuffer()
1748 FlushBuffer();
1749 if( !bOwnsData )
1750 return nullptr;
1751 Seek( STREAM_SEEK_TO_BEGIN );
1753 void* pRetVal = pBuf;
1754 pBuf = nullptr;
1755 nEndOfData = 0;
1756 nResize = 64;
1757 nPos = 0;
1759 ResetError();
1761 std::size_t nInitSize = 512;
1762 AllocateMemory(nInitSize);
1763 nSize = nInitSize;
1765 SetBufferSize( 64 );
1766 return pRetVal;
1769 void SvMemoryStream::SetSize(sal_uInt64 const nNewSize)
1771 if (!m_isWritable)
1773 SetError(SVSTREAM_INVALID_HANDLE);
1774 return;
1777 tools::Long nDiff = static_cast<tools::Long>(nNewSize) - static_cast<tools::Long>(nSize);
1778 ReAllocateMemory( nDiff );
1781 void SvMemoryStream::MakeReadOnly()
1783 FlushBuffer();
1784 m_isWritable = false;
1785 nResize = 0;
1786 SetBufferSize( 0 );
1789 // Create an OString of nLen bytes from rStream
1790 // coverity[ +taint_sanitize ]
1791 OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen)
1793 rtl_String *pStr = nullptr;
1794 if (nLen)
1796 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1797 //limit allocation to size of file, but + 1 to set eof state
1798 nLen = std::min<sal_uInt64>(nLen, rStrm.remainingSize() + 1);
1799 //alloc a (ref-count 1) rtl_String of the desired length.
1800 //rtl_String's buffer is uninitialized, except for null termination
1801 pStr = rtl_string_alloc(sal::static_int_cast<sal_Int32>(nLen));
1802 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1803 if (pStr)
1805 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen);
1806 if (nWasRead != nLen)
1808 //on (typically unlikely) short read set length to what we could
1809 //read, and null terminate. Excess buffer capacity remains of
1810 //course, could create a (true) replacement OString if it matters.
1811 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1812 pStr->buffer[pStr->length] = 0;
1817 //take ownership of buffer and return, otherwise return empty string
1818 return pStr ? OString(pStr, SAL_NO_ACQUIRE) : OString();
1821 // Create an OUString of nLen sal_Unicode code units from rStream
1822 // coverity[ +taint_sanitize ]
1823 OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen)
1825 rtl_uString *pStr = nullptr;
1826 if (nLen)
1828 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1829 //limit allocation to size of file, but + 1 to set eof state
1830 nLen = o3tl::sanitizing_min<sal_uInt64>(nLen, (rStrm.remainingSize() + 2) / 2);
1831 //alloc a (ref-count 1) rtl_uString of the desired length.
1832 //rtl_String's buffer is uninitialized, except for null termination
1833 pStr = rtl_uString_alloc(sal::static_int_cast<sal_Int32>(nLen));
1834 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1835 if (pStr)
1837 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen*2)/2;
1838 if (nWasRead != nLen)
1840 //on (typically unlikely) short read set length to what we could
1841 //read, and null terminate. Excess buffer capacity remains of
1842 //course, could create a (true) replacement OUString if it matters.
1843 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1844 pStr->buffer[pStr->length] = 0;
1846 if (rStrm.IsEndianSwap())
1848 for (sal_Int32 i = 0; i < pStr->length; ++i)
1849 pStr->buffer[i] = OSL_SWAPWORD(pStr->buffer[i]);
1854 // take ownership of buffer and return, otherwise return empty string
1855 // coverity[tainted_data] - unhelpful untrusted loop bound
1856 return pStr ? OUString(pStr, SAL_NO_ACQUIRE) : OUString();
1859 namespace
1861 template <typename T, typename O> T tmpl_convertLineEnd(const T &rIn, LineEnd eLineEnd)
1863 // Determine linebreaks and compute length
1864 bool bConvert = false; // Needs conversion
1865 sal_Int32 nStrLen = rIn.getLength();
1866 sal_Int32 nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
1867 sal_Int32 nLen = 0; // Target length
1868 sal_Int32 i = 0; // Source counter
1870 while (i < nStrLen)
1872 // \r or \n causes linebreak
1873 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
1875 nLen = nLen + nLineEndLen;
1877 // If set already, skip expensive test
1878 if ( !bConvert )
1880 // Do we need to convert?
1881 if ( ((eLineEnd != LINEEND_LF) && (rIn[i] == '\n')) ||
1882 ((eLineEnd == LINEEND_CRLF) && (i+1) < nStrLen && (rIn[i+1] != '\n')) ||
1883 ((eLineEnd == LINEEND_LF) &&
1884 ((rIn[i] == '\r') || ((i+1) < nStrLen && rIn[i+1] == '\r'))) ||
1885 ((eLineEnd == LINEEND_CR) &&
1886 ((rIn[i] == '\n') || ((i+1) < nStrLen && rIn[i+1] == '\n'))) )
1887 bConvert = true;
1890 // skip char if \r\n or \n\r
1891 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
1892 (rIn[i] != rIn[i+1]) )
1893 ++i;
1895 else
1896 ++nLen;
1897 ++i;
1900 if (!bConvert)
1901 return rIn;
1903 // convert linebreaks, insert string
1904 O aNewData(nLen);
1905 i = 0;
1906 while (i < nStrLen)
1908 // \r or \n causes linebreak
1909 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
1911 if ( eLineEnd == LINEEND_CRLF )
1913 aNewData.append('\r');
1914 aNewData.append('\n');
1916 else
1918 if ( eLineEnd == LINEEND_CR )
1919 aNewData.append('\r');
1920 else
1921 aNewData.append('\n');
1924 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
1925 (rIn[i] != rIn[i+1]) )
1926 ++i;
1928 else
1930 aNewData.append(rIn[i]);
1933 ++i;
1936 return aNewData.makeStringAndClear();
1940 OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
1942 return tmpl_convertLineEnd<OString, OStringBuffer>(rIn, eLineEnd);
1945 OUString convertLineEnd(const OUString &rIn, LineEnd eLineEnd)
1947 return tmpl_convertLineEnd<OUString, OUStringBuffer>(rIn, eLineEnd);
1950 std::size_t write_uInt32_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
1951 std::u16string_view rStr)
1953 std::size_t nWritten = 0;
1954 sal_uInt32 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt32>::max());
1955 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
1956 "tools.stream",
1957 "string too long for prefix count to fit in output type");
1958 rStrm.WriteUInt32(nUnits);
1959 if (rStrm.good())
1961 nWritten += sizeof(sal_uInt32);
1962 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
1964 return nWritten;
1967 std::size_t write_uInt16_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
1968 std::u16string_view rStr)
1970 std::size_t nWritten = 0;
1971 sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
1972 SAL_WARN_IF(nUnits != rStr.size(),
1973 "tools.stream",
1974 "string too long for prefix count to fit in output type");
1975 rStrm.WriteUInt16(nUnits);
1976 if (rStrm.good())
1978 nWritten += sizeof(nUnits);
1979 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
1981 return nWritten;
1984 std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm,
1985 std::string_view rStr)
1987 std::size_t nWritten = 0;
1988 sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
1989 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
1990 "tools.stream",
1991 "string too long for sal_uInt16 count to fit in output type");
1992 rStrm.WriteUInt16( nUnits );
1993 if (rStrm.good())
1995 nWritten += sizeof(sal_uInt16);
1996 nWritten += write_uInt8s_FromOString(rStrm, rStr, nUnits);
1998 return nWritten;
2001 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */