Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / tools / source / stream / stream.cxx
blobb482758197393f771b61cc8e8691429943b1110d
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 <cstddef>
23 #include <memory>
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include <osl/endian.h>
30 #include <osl/diagnose.h>
31 #include <sal/log.hxx>
33 #include <comphelper/fileformat.h>
34 #include <comphelper/string.hxx>
36 #define SWAPNIBBLES(c) \
37 unsigned char nSwapTmp=c; \
38 nSwapTmp <<= 4; \
39 c >>= 4; \
40 c |= nSwapTmp;
42 #include <tools/debug.hxx>
43 #include <tools/stream.hxx>
44 #include <osl/thread.h>
45 #include <algorithm>
47 // !!! Do not inline if already the operators <<,>> are inline
48 inline static void SwapUShort( sal_uInt16& r )
49 { r = OSL_SWAPWORD(r); }
50 inline static void SwapShort( short& r )
51 { r = OSL_SWAPWORD(r); }
52 inline static void SwapULong( sal_uInt32& r )
53 { r = OSL_SWAPDWORD(r); }
54 inline static void SwapLongInt( sal_Int32& r )
55 { r = OSL_SWAPDWORD(r); }
57 inline static void SwapUInt64( sal_uInt64& r )
59 union
61 sal_uInt64 n;
62 sal_uInt32 c[2];
63 } s;
65 s.n = r;
66 s.c[0] ^= s.c[1]; // swap the 32 bit words
67 s.c[1] ^= s.c[0];
68 s.c[0] ^= s.c[1];
69 // swap the bytes in the words
70 s.c[0] = OSL_SWAPDWORD(s.c[0]);
71 s.c[1] = OSL_SWAPDWORD(s.c[1]);
72 r = s.n;
74 inline static void SwapInt64( sal_Int64& r )
76 union
78 sal_Int64 n;
79 sal_Int32 c[2];
80 } s;
82 s.n = r;
83 s.c[0] ^= s.c[1]; // swap the 32 bit words
84 s.c[1] ^= s.c[0];
85 s.c[0] ^= s.c[1];
86 // swap the bytes in the words
87 s.c[0] = OSL_SWAPDWORD(s.c[0]);
88 s.c[1] = OSL_SWAPDWORD(s.c[1]);
89 r = s.n;
92 #ifdef UNX
93 inline static void SwapFloat( float& r )
95 union
97 float f;
98 sal_uInt32 c;
99 } s;
101 s.f = r;
102 s.c = OSL_SWAPDWORD( s.c );
103 r = s.f;
106 inline static void SwapDouble( double& r )
108 if( sizeof(double) != 8 )
110 SAL_WARN( "tools.stream", "Can only swap 8-Byte-doubles" );
112 else
114 union
116 double d;
117 sal_uInt32 c[2];
118 } s;
120 s.d = r;
121 s.c[0] ^= s.c[1]; // swap 32-bit values in situ
122 s.c[1] ^= s.c[0];
123 s.c[0] ^= s.c[1];
124 s.c[0] = OSL_SWAPDWORD(s.c[0]); // swap dword itself in situ
125 s.c[1] = OSL_SWAPDWORD(s.c[1]);
126 r = s.d;
129 #endif
131 static void SwapUnicode(sal_Unicode & r) { r = OSL_SWAPWORD(r); }
133 //SDO
135 void SvStream::readNumberWithoutSwap_(void * pDataDest, int nDataSize)
137 if (m_isIoRead && nDataSize <= m_nBufFree)
139 for (int i = 0; i < nDataSize; i++)
140 static_cast<char*>(pDataDest)[i] = m_pBufPos[i];
141 m_nBufActualPos += nDataSize;
142 m_pBufPos += nDataSize;
143 m_nBufFree -= nDataSize;
145 else
147 ReadBytes( pDataDest, nDataSize );
152 void SvStream::writeNumberWithoutSwap_(const void * pDataSrc, int nDataSize)
154 if (m_isIoWrite && nDataSize <= m_nBufFree)
156 for (int i = 0; i < nDataSize; i++)
157 m_pBufPos[i] = static_cast<const char*>(pDataSrc)[i];
158 m_nBufFree -= nDataSize;
159 m_nBufActualPos += nDataSize;
160 if (m_nBufActualPos > m_nBufActualLen)
161 m_nBufActualLen = m_nBufActualPos;
162 m_pBufPos += nDataSize;
163 m_isDirty = true;
165 else
167 WriteBytes( pDataSrc, nDataSize );
171 // class SvLockBytes
173 void SvLockBytes::close()
175 if (m_bOwner)
176 delete m_pStream;
177 m_pStream = nullptr;
181 // virtual
182 ErrCode SvLockBytes::ReadAt(sal_uInt64 const nPos, void * pBuffer, std::size_t nCount,
183 std::size_t * pRead) const
185 if (!m_pStream)
187 OSL_FAIL("SvLockBytes::ReadAt(): Bad stream");
188 return ERRCODE_NONE;
191 m_pStream->Seek(nPos);
192 std::size_t nTheRead = m_pStream->ReadBytes(pBuffer, nCount);
193 if (pRead)
194 *pRead = nTheRead;
195 return m_pStream->GetErrorCode();
198 // virtual
199 ErrCode SvLockBytes::WriteAt(sal_uInt64 const nPos, const void * pBuffer, std::size_t nCount,
200 std::size_t * pWritten)
202 if (!m_pStream)
204 OSL_FAIL("SvLockBytes::WriteAt(): Bad stream");
205 return ERRCODE_NONE;
208 m_pStream->Seek(nPos);
209 std::size_t nTheWritten = m_pStream->WriteBytes(pBuffer, nCount);
210 if (pWritten)
211 *pWritten = nTheWritten;
212 return m_pStream->GetErrorCode();
215 // virtual
216 ErrCode SvLockBytes::Flush() const
218 if (!m_pStream)
220 OSL_FAIL("SvLockBytes::Flush(): Bad stream");
221 return ERRCODE_NONE;
224 m_pStream->Flush();
225 return m_pStream->GetErrorCode();
228 // virtual
229 ErrCode SvLockBytes::SetSize(sal_uInt64 const nSize)
231 if (!m_pStream)
233 OSL_FAIL("SvLockBytes::SetSize(): Bad stream");
234 return ERRCODE_NONE;
237 m_pStream->SetStreamSize(nSize);
238 return m_pStream->GetErrorCode();
241 ErrCode SvLockBytes::Stat(SvLockBytesStat * pStat, SvLockBytesStatFlag) const
243 if (!m_pStream)
245 OSL_FAIL("SvLockBytes::Stat(): Bad stream");
246 return ERRCODE_NONE;
249 if (pStat)
251 sal_uInt64 const nPos = m_pStream->Tell();
252 pStat->nSize = m_pStream->Seek(STREAM_SEEK_TO_END);
253 m_pStream->Seek(nPos);
255 return ERRCODE_NONE;
258 // class SvStream
260 std::size_t SvStream::GetData( void* pData, std::size_t nSize )
262 if( !GetError() )
264 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
265 std::size_t nRet(0);
266 m_nError = m_xLockBytes->ReadAt(m_nActPos, pData, nSize, &nRet);
267 m_nActPos += nRet;
268 return nRet;
270 else return 0;
273 std::size_t SvStream::PutData( const void* pData, std::size_t nSize )
275 if( !GetError() )
277 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
278 std::size_t nRet(0);
279 m_nError = m_xLockBytes->WriteAt(m_nActPos, pData, nSize, &nRet);
280 m_nActPos += nRet;
281 return nRet;
283 else return 0;
286 sal_uInt64 SvStream::SeekPos(sal_uInt64 const nPos)
288 // check if a truncated STREAM_SEEK_TO_END was passed
289 assert(nPos != SAL_MAX_UINT32);
290 if( !GetError() && nPos == STREAM_SEEK_TO_END )
292 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
293 SvLockBytesStat aStat;
294 m_xLockBytes->Stat( &aStat, SVSTATFLAG_DEFAULT );
295 m_nActPos = aStat.nSize;
297 else
298 m_nActPos = nPos;
299 return m_nActPos;
302 void SvStream::FlushData()
304 if( !GetError() )
306 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
307 m_nError = m_xLockBytes->Flush();
311 void SvStream::SetSize(sal_uInt64 const nSize)
313 DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
314 m_nError = m_xLockBytes->SetSize( nSize );
317 SvStream::SvStream() :
318 m_nActPos(0)
320 , m_pRWBuf(nullptr)
321 , m_pBufPos(nullptr)
322 , m_nBufSize(0)
323 , m_nBufActualLen(0)
324 , m_nBufActualPos(0)
325 , m_nBufFree(0)
326 , m_isIoRead(false)
327 , m_isIoWrite(false)
329 , m_isDirty(false)
330 , m_isConsistent(true)
331 , m_isEof(false)
333 , m_nCompressMode(SvStreamCompressFlags::NONE)
334 #if defined UNX
335 , m_eLineDelimiter(LINEEND_LF) // UNIX-Format
336 #else
337 , m_eLineDelimiter(LINEEND_CRLF) // DOS-Format
338 #endif
339 , m_eStreamCharSet(osl_getThreadTextEncoding())
341 , m_nCryptMask(0)
343 , m_nVersion(0)
345 , m_nBufFilePos(0)
346 , m_eStreamMode(StreamMode::NONE)
347 , m_isWritable(true)
350 SetEndian( SvStreamEndian::LITTLE );
352 ClearError();
355 SvStream::SvStream( SvLockBytes* pLockBytesP ) : SvStream()
357 m_xLockBytes = pLockBytesP;
358 if( pLockBytesP ) {
359 const SvStream* pStrm = pLockBytesP->GetStream();
360 if( pStrm ) {
361 SetError( pStrm->GetErrorCode() );
364 SetBufferSize( 256 );
367 SvStream::~SvStream()
369 if (m_xLockBytes.is())
370 Flush();
373 void SvStream::ClearError()
375 m_isEof = false;
376 m_nError = ERRCODE_NONE;
379 void SvStream::SetError( ErrCode nErrorCode )
381 if (m_nError == ERRCODE_NONE)
382 m_nError = nErrorCode;
385 void SvStream::SetEndian( SvStreamEndian nNewFormat )
387 m_nEndian = nNewFormat;
388 m_isSwap = false;
389 #ifdef OSL_BIGENDIAN
390 if (m_nEndian == SvStreamEndian::LITTLE)
391 m_isSwap = true;
392 #else
393 if (m_nEndian == SvStreamEndian::BIG)
394 m_isSwap = true;
395 #endif
398 void SvStream::SetBufferSize( sal_uInt16 nBufferSize )
400 sal_uInt64 const nActualFilePos = Tell();
401 bool bDontSeek = (m_pRWBuf == nullptr);
403 if (m_isDirty && m_isConsistent && m_isWritable) // due to Windows NT: Access denied
404 Flush();
406 if (m_nBufSize)
408 m_pRWBuf.reset();
409 m_nBufFilePos += m_nBufActualPos;
412 m_pRWBuf = nullptr;
413 m_nBufActualLen = 0;
414 m_nBufActualPos = 0;
415 m_nBufSize = nBufferSize;
416 if (m_nBufSize)
417 m_pRWBuf.reset(new sal_uInt8[ m_nBufSize ]);
418 m_isConsistent = true;
419 m_pBufPos = m_pRWBuf.get();
420 m_isIoRead = m_isIoWrite = false;
421 if( !bDontSeek )
422 SeekPos( nActualFilePos );
425 void SvStream::ClearBuffer()
427 m_nBufActualLen = 0;
428 m_nBufActualPos = 0;
429 m_nBufFilePos = 0;
430 m_pBufPos = m_pRWBuf.get();
431 m_isDirty = false;
432 m_isConsistent = true;
433 m_isIoRead = m_isIoWrite = false;
435 m_isEof = false;
438 void SvStream::ResetError()
440 ClearError();
443 bool SvStream::ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
444 sal_Int32 nMaxBytesToRead )
446 OString aStr;
447 bool bRet = ReadLine( aStr, nMaxBytesToRead);
448 rStr = OStringToOUString(aStr, eSrcCharSet);
449 return bRet;
452 bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead )
454 sal_Char buf[256+1];
455 bool bEnd = false;
456 sal_uInt64 nOldFilePos = Tell();
457 sal_Char c = 0;
458 std::size_t nTotalLen = 0;
460 OStringBuffer aBuf(4096);
461 while( !bEnd && !GetError() ) // Don't test for EOF as we
462 // are reading block-wise!
464 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes(buf, sizeof(buf)-1));
465 if ( !nLen )
467 if ( aBuf.isEmpty() )
469 // Exit on first block-read error
470 m_isEof = true;
471 rStr.clear();
472 return false;
474 else
475 break;
478 sal_uInt16 j, n;
479 for( j = n = 0; j < nLen ; ++j )
481 c = buf[j];
482 if ( c == '\n' || c == '\r' )
484 bEnd = true;
485 break;
487 if ( n < j )
488 buf[n] = c;
489 ++n;
491 nTotalLen += j;
492 if (nTotalLen > static_cast<std::size_t>(nMaxBytesToRead))
494 n -= nTotalLen - nMaxBytesToRead;
495 nTotalLen = nMaxBytesToRead;
496 bEnd = true;
498 if ( n )
499 aBuf.append(buf, n);
502 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
503 bEnd = true;
505 nOldFilePos += nTotalLen;
506 if( Tell() > nOldFilePos )
507 nOldFilePos++;
508 Seek( nOldFilePos ); // Seek pointer due to BlockRead above
510 if ( bEnd && (c=='\r' || c=='\n') ) // Special treatment for DOS files
512 char cTemp;
513 std::size_t nLen = ReadBytes(&cTemp, sizeof(cTemp));
514 if ( nLen ) {
515 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
516 Seek( nOldFilePos );
520 if ( bEnd )
521 m_isEof = false;
522 rStr = aBuf.makeStringAndClear();
523 return bEnd;
526 bool SvStream::ReadUniStringLine( OUString& rStr, sal_Int32 nMaxCodepointsToRead )
528 sal_Unicode buf[256+1];
529 bool bEnd = false;
530 sal_uInt64 nOldFilePos = Tell();
531 sal_Unicode c = 0;
532 std::size_t nTotalLen = 0;
534 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "ReadUniStringLine: swapping sizeof(sal_Unicode) not implemented" );
536 OUStringBuffer aBuf(4096);
537 while( !bEnd && !GetError() ) // Don't test for EOF as we
538 // are reading block-wise!
540 sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes( buf, sizeof(buf)-sizeof(sal_Unicode)));
541 nLen /= sizeof(sal_Unicode);
542 if ( !nLen )
544 if ( aBuf.isEmpty() )
546 // exit on first BlockRead error
547 m_isEof = true;
548 rStr.clear();
549 return false;
551 else
552 break;
555 sal_uInt16 j, n;
556 for( j = n = 0; j < nLen ; ++j )
558 if (m_isSwap)
559 SwapUnicode( buf[n] );
560 c = buf[j];
561 if ( c == '\n' || c == '\r' )
563 bEnd = true;
564 break;
566 // erAck 26.02.01: Old behavior was no special treatment of '\0'
567 // character here, but a following rStr+=c did ignore it. Is this
568 // really intended? Or should a '\0' better terminate a line?
569 // The nOldFilePos stuff wasn't correct then anyways.
570 if ( c )
572 if ( n < j )
573 buf[n] = c;
574 ++n;
577 nTotalLen += j;
578 if (nTotalLen > static_cast<std::size_t>(nMaxCodepointsToRead))
580 n -= nTotalLen - nMaxCodepointsToRead;
581 nTotalLen = nMaxCodepointsToRead;
582 bEnd = true;
584 if ( n )
585 aBuf.append( buf, n );
588 if ( !bEnd && !GetError() && !aBuf.isEmpty() )
589 bEnd = true;
591 nOldFilePos += nTotalLen * sizeof(sal_Unicode);
592 if( Tell() > nOldFilePos )
593 nOldFilePos += sizeof(sal_Unicode);
594 Seek( nOldFilePos ); // seek due to BlockRead above
596 if ( bEnd && (c=='\r' || c=='\n') ) // special treatment for DOS files
598 sal_Unicode cTemp;
599 ReadBytes( &cTemp, sizeof(cTemp) );
600 if (m_isSwap)
601 SwapUnicode( cTemp );
602 if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
603 Seek( nOldFilePos );
606 if ( bEnd )
607 m_isEof = false;
608 rStr = aBuf.makeStringAndClear();
609 return bEnd;
612 bool SvStream::ReadUniOrByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
613 sal_Int32 nMaxCodepointsToRead )
615 if ( eSrcCharSet == RTL_TEXTENCODING_UNICODE )
616 return ReadUniStringLine( rStr, nMaxCodepointsToRead );
617 else
618 return ReadByteStringLine( rStr, eSrcCharSet, nMaxCodepointsToRead );
621 OString read_zeroTerminated_uInt8s_ToOString(SvStream& rStream)
623 OStringBuffer aOutput(256);
625 sal_Char buf[ 256 + 1 ];
626 bool bEnd = false;
627 sal_uInt64 nFilePos = rStream.Tell();
629 while( !bEnd && !rStream.GetError() )
631 std::size_t nLen = rStream.ReadBytes(buf, sizeof(buf)-1);
632 if (!nLen)
633 break;
635 std::size_t nReallyRead = nLen;
636 const sal_Char* pPtr = buf;
637 while (nLen && *pPtr)
639 ++pPtr;
640 --nLen;
643 bEnd = ( nReallyRead < sizeof(buf)-1 ) // read less than attempted to read
644 || ( ( nLen > 0 ) // OR it is inside the block we read
645 && ( 0 == *pPtr ) // AND found a string terminator
648 aOutput.append(buf, pPtr - buf);
651 nFilePos += aOutput.getLength();
652 if (rStream.Tell() > nFilePos)
653 rStream.Seek(nFilePos+1); // seek due to FileRead above
654 return aOutput.makeStringAndClear();
657 OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStream, rtl_TextEncoding eEnc)
659 return OStringToOUString(
660 read_zeroTerminated_uInt8s_ToOString(rStream), eEnc);
663 /** Attempt to write a prefixed sequence of nUnits 16bit units from an OUString,
664 returned value is number of bytes written */
665 std::size_t write_uInt16s_FromOUString(SvStream& rStrm, const OUString& rStr,
666 std::size_t nUnits)
668 DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "write_uInt16s_FromOUString: swapping sizeof(sal_Unicode) not implemented" );
669 std::size_t nWritten;
670 if (!rStrm.IsEndianSwap())
671 nWritten = rStrm.WriteBytes(rStr.getStr(), nUnits * sizeof(sal_Unicode));
672 else
674 std::size_t nLen = nUnits;
675 sal_Unicode aBuf[384];
676 sal_Unicode* const pTmp = ( nLen > 384 ? new sal_Unicode[nLen] : aBuf);
677 memcpy( pTmp, rStr.getStr(), nLen * sizeof(sal_Unicode) );
678 sal_Unicode* p = pTmp;
679 const sal_Unicode* const pStop = pTmp + nLen;
680 while ( p < pStop )
682 SwapUnicode( *p );
683 p++;
685 nWritten = rStrm.WriteBytes( pTmp, nLen * sizeof(sal_Unicode) );
686 if ( pTmp != aBuf )
687 delete [] pTmp;
689 return nWritten;
692 bool SvStream::WriteUnicodeOrByteText( const OUString& rStr, rtl_TextEncoding eDestCharSet )
694 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
696 write_uInt16s_FromOUString(*this, rStr, rStr.getLength());
697 return m_nError == ERRCODE_NONE;
699 else
701 OString aStr(OUStringToOString(rStr, eDestCharSet));
702 write_uInt8s_FromOString(*this, aStr, aStr.getLength());
703 return m_nError == ERRCODE_NONE;
707 bool SvStream::WriteByteStringLine( const OUString& rStr, rtl_TextEncoding eDestCharSet )
709 return WriteLine(OUStringToOString(rStr, eDestCharSet));
712 bool SvStream::WriteLine(const OString& rStr)
714 WriteBytes(rStr.getStr(), rStr.getLength());
715 endl(*this);
716 return m_nError == ERRCODE_NONE;
719 bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet )
721 if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
722 WriteUnicode(ch);
723 else
725 OString aStr(&ch, 1, eDestCharSet);
726 WriteBytes(aStr.getStr(), aStr.getLength());
728 return m_nError == ERRCODE_NONE;
731 void SvStream::StartWritingUnicodeText()
733 // BOM, Byte Order Mark, U+FEFF, see
734 // http://www.unicode.org/faq/utf_bom.html#BOM
735 // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap
736 writeNumberWithoutSwap(sal_uInt16(0xfeff)); // write native format
739 void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet )
741 if (!( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
742 eReadBomCharSet == RTL_TEXTENCODING_UNICODE ||
743 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
744 return; // nothing to read
746 bool bTryUtf8 = false;
747 sal_uInt16 nFlag(0);
748 sal_sSize nBack = sizeof(nFlag);
749 ReadUInt16( nFlag );
750 switch ( nFlag )
752 case 0xfeff :
753 // native UTF-16
754 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
755 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
756 nBack = 0;
757 break;
758 case 0xfffe :
759 // swapped UTF-16
760 if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
761 eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
763 SetEndian( m_nEndian == SvStreamEndian::BIG ? SvStreamEndian::LITTLE : SvStreamEndian::BIG );
764 nBack = 0;
766 break;
767 case 0xefbb :
768 if (m_nEndian == SvStreamEndian::BIG &&
769 (eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
770 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
771 bTryUtf8 = true;
772 break;
773 case 0xbbef :
774 if (m_nEndian == SvStreamEndian::LITTLE &&
775 (eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
776 eReadBomCharSet == RTL_TEXTENCODING_UTF8))
777 bTryUtf8 = true;
778 break;
779 default:
780 ; // nothing
782 if (bTryUtf8)
784 unsigned char nChar(0);
785 nBack += sizeof(nChar);
786 ReadUChar( nChar );
787 if (nChar == 0xbf)
788 nBack = 0; // it is UTF-8
790 if (nBack)
791 SeekRel( -nBack ); // no BOM, pure data
794 sal_uInt64 SvStream::SeekRel(sal_Int64 const nPos)
796 sal_uInt64 nActualPos = Tell();
798 if ( nPos >= 0 )
800 if (SAL_MAX_UINT64 - nActualPos > static_cast<sal_uInt64>(nPos))
801 nActualPos += nPos;
803 else
805 sal_uInt64 const nAbsPos = static_cast<sal_uInt64>(-nPos);
806 if ( nActualPos >= nAbsPos )
807 nActualPos -= nAbsPos;
810 m_pBufPos = m_pRWBuf.get() + nActualPos;
811 return Seek( nActualPos );
814 SvStream& SvStream::ReadUInt16(sal_uInt16& r)
816 sal_uInt16 n = 0;
817 readNumberWithoutSwap(n);
818 if (good())
820 if (m_isSwap)
821 SwapUShort(n);
822 r = n;
824 return *this;
827 SvStream& SvStream::ReadUInt32(sal_uInt32& r)
829 sal_uInt32 n = 0;
830 readNumberWithoutSwap(n);
831 if (good())
833 if (m_isSwap)
834 SwapULong(n);
835 r = n;
837 return *this;
840 SvStream& SvStream::ReadUInt64(sal_uInt64& r)
842 sal_uInt64 n = 0;
843 readNumberWithoutSwap(n);
844 if (good())
846 if (m_isSwap)
847 SwapUInt64(n);
848 r = n;
850 return *this;
853 SvStream& SvStream::ReadInt16(sal_Int16& r)
855 sal_Int16 n = 0;
856 readNumberWithoutSwap(n);
857 if (good())
859 if (m_isSwap)
860 SwapShort(n);
861 r = n;
863 return *this;
866 SvStream& SvStream::ReadInt32(sal_Int32& r)
868 sal_Int32 n = 0;
869 readNumberWithoutSwap(n);
870 if (good())
872 if (m_isSwap)
873 SwapLongInt(n);
874 r = n;
876 return *this;
879 SvStream& SvStream::ReadInt64(sal_Int64& r)
881 sal_Int64 n = 0;
882 readNumberWithoutSwap(n);
883 if (good())
885 if (m_isSwap)
886 SwapInt64(n);
887 r = n;
889 return *this;
892 SvStream& SvStream::ReadSChar( signed char& r )
894 if ((m_isIoRead || !m_isConsistent) &&
895 sizeof(signed char) <= m_nBufFree)
897 r = *m_pBufPos;
898 m_nBufActualPos += sizeof(signed char);
899 m_pBufPos += sizeof(signed char);
900 m_nBufFree -= sizeof(signed char);
902 else
903 ReadBytes( &r, sizeof(signed char) );
904 return *this;
907 // Special treatment for Chars due to PutBack
909 SvStream& SvStream::ReadChar( char& r )
911 if ((m_isIoRead || !m_isConsistent) &&
912 sizeof(char) <= m_nBufFree)
914 r = *m_pBufPos;
915 m_nBufActualPos += sizeof(char);
916 m_pBufPos += sizeof(char);
917 m_nBufFree -= sizeof(char);
919 else
920 ReadBytes( &r, sizeof(char) );
921 return *this;
924 SvStream& SvStream::ReadUChar( unsigned char& r )
926 if ((m_isIoRead || !m_isConsistent) &&
927 sizeof(char) <= m_nBufFree)
929 r = *m_pBufPos;
930 m_nBufActualPos += sizeof(char);
931 m_pBufPos += sizeof(char);
932 m_nBufFree -= sizeof(char);
934 else
935 ReadBytes( &r, sizeof(char) );
936 return *this;
939 SvStream& SvStream::ReadUtf16(sal_Unicode& r)
941 sal_uInt16 n = 0;
942 readNumberWithoutSwap(n);
943 if (good())
945 if (m_isSwap)
946 SwapUShort(n);
947 r = sal_Unicode(n);
949 return *this;
952 SvStream& SvStream::ReadCharAsBool( bool& r )
954 if ((m_isIoRead || !m_isConsistent) &&
955 sizeof(char) <= m_nBufFree)
957 SAL_WARN_IF(
958 *m_pBufPos > 1, "tools.stream", unsigned(*m_pBufPos) << " not 0/1");
959 r = *m_pBufPos != 0;
960 m_nBufActualPos += sizeof(char);
961 m_pBufPos += sizeof(char);
962 m_nBufFree -= sizeof(char);
964 else
966 unsigned char c;
967 if (ReadBytes(&c, 1) == 1)
969 SAL_WARN_IF(c > 1, "tools.stream", unsigned(c) << " not 0/1");
970 r = c != 0;
973 return *this;
976 SvStream& SvStream::ReadFloat(float& r)
978 float n = 0;
979 readNumberWithoutSwap(n);
980 if (good())
982 #if defined UNX
983 if (m_isSwap)
984 SwapFloat(n);
985 #endif
986 r = n;
988 return *this;
991 SvStream& SvStream::ReadDouble(double& r)
993 double n = 0;
994 readNumberWithoutSwap(n);
995 if (good())
997 #if defined UNX
998 if (m_isSwap)
999 SwapDouble(n);
1000 #endif
1001 r = n;
1003 return *this;
1006 SvStream& SvStream::ReadStream( SvStream& rStream )
1008 const sal_uInt32 cBufLen = 0x8000;
1009 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1011 sal_uInt32 nCount;
1012 do {
1013 nCount = ReadBytes( pBuf.get(), cBufLen );
1014 rStream.WriteBytes( pBuf.get(), nCount );
1015 } while( nCount == cBufLen );
1017 return *this;
1020 SvStream& SvStream::WriteUInt16( sal_uInt16 v )
1022 if (m_isSwap)
1023 SwapUShort(v);
1024 writeNumberWithoutSwap(v);
1025 return *this;
1028 SvStream& SvStream::WriteUInt32( sal_uInt32 v )
1030 if (m_isSwap)
1031 SwapULong(v);
1032 writeNumberWithoutSwap(v);
1033 return *this;
1036 SvStream& SvStream::WriteUInt64( sal_uInt64 v )
1038 if (m_isSwap)
1039 SwapUInt64(v);
1040 writeNumberWithoutSwap(v);
1041 return *this;
1044 SvStream& SvStream::WriteInt16( sal_Int16 v )
1046 if (m_isSwap)
1047 SwapShort(v);
1048 writeNumberWithoutSwap(v);
1049 return *this;
1052 SvStream& SvStream::WriteInt32( sal_Int32 v )
1054 if (m_isSwap)
1055 SwapLongInt(v);
1056 writeNumberWithoutSwap(v);
1057 return *this;
1060 SvStream& SvStream::WriteInt64 (sal_Int64 v)
1062 if (m_isSwap)
1063 SwapInt64(v);
1064 writeNumberWithoutSwap(v);
1065 return *this;
1068 SvStream& SvStream::WriteSChar( signed char v )
1070 //SDO
1071 if (m_isIoWrite && sizeof(signed char) <= m_nBufFree)
1073 *m_pBufPos = v;
1074 m_pBufPos++; // sizeof(char);
1075 m_nBufActualPos++;
1076 if (m_nBufActualPos > m_nBufActualLen) // Append ?
1077 m_nBufActualLen = m_nBufActualPos;
1078 m_nBufFree--; // = sizeof(char);
1079 m_isDirty = true;
1081 else
1082 WriteBytes( &v, sizeof(signed char) );
1083 return *this;
1086 // Special treatment for Chars due to PutBack
1088 SvStream& SvStream::WriteChar( char v )
1090 //SDO
1091 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
1093 *m_pBufPos = v;
1094 m_pBufPos++; // sizeof(char);
1095 m_nBufActualPos++;
1096 if (m_nBufActualPos > m_nBufActualLen) // Append ?
1097 m_nBufActualLen = m_nBufActualPos;
1098 m_nBufFree--; // = sizeof(char);
1099 m_isDirty = true;
1101 else
1102 WriteBytes( &v, sizeof(char) );
1103 return *this;
1106 SvStream& SvStream::WriteUChar( unsigned char v )
1108 //SDO
1109 if (m_isIoWrite && sizeof(char) <= m_nBufFree)
1111 *reinterpret_cast<unsigned char*>(m_pBufPos) = v;
1112 m_pBufPos++; // = sizeof(char);
1113 m_nBufActualPos++; // = sizeof(char);
1114 if (m_nBufActualPos > m_nBufActualLen) // Append ?
1115 m_nBufActualLen = m_nBufActualPos;
1116 m_nBufFree--;
1117 m_isDirty = true;
1119 else
1120 WriteBytes( &v, sizeof(char) );
1121 return *this;
1124 SvStream& SvStream::WriteUInt8( sal_uInt8 v )
1126 return WriteUChar(v);
1129 SvStream& SvStream::WriteUnicode( sal_Unicode v )
1131 return WriteUInt16(v);
1134 SvStream& SvStream::WriteFloat( float v )
1136 #ifdef UNX
1137 if (m_isSwap)
1138 SwapFloat(v);
1139 #endif
1140 writeNumberWithoutSwap(v);
1141 return *this;
1144 SvStream& SvStream::WriteDouble ( const double& r )
1146 #if defined UNX
1147 if (m_isSwap)
1149 double nHelp = r;
1150 SwapDouble(nHelp);
1151 writeNumberWithoutSwap(nHelp);
1152 return *this;
1154 else
1155 #endif
1157 writeNumberWithoutSwap(r);
1159 return *this;
1162 SvStream& SvStream::WriteCharPtr( const char* pBuf )
1164 WriteBytes( pBuf, strlen(pBuf) );
1165 return *this;
1168 SvStream& SvStream::WriteStream( SvStream& rStream )
1170 const sal_uInt32 cBufLen = 0x8000;
1171 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1172 sal_uInt32 nCount;
1173 do {
1174 nCount = rStream.ReadBytes( pBuf.get(), cBufLen );
1175 WriteBytes( pBuf.get(), nCount );
1176 } while( nCount == cBufLen );
1178 return *this;
1181 sal_uInt64 SvStream::WriteStream( SvStream& rStream, sal_uInt64 nSize )
1183 const sal_uInt32 cBufLen = 0x8000;
1184 std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
1185 sal_uInt32 nCurBufLen = cBufLen;
1186 sal_uInt32 nCount;
1187 sal_uInt64 nWriteSize = nSize;
1191 nCurBufLen = std::min<sal_uInt64>(nCurBufLen, nWriteSize);
1192 nCount = rStream.ReadBytes(pBuf.get(), nCurBufLen);
1193 WriteBytes( pBuf.get(), nCount );
1194 nWriteSize -= nCount;
1196 while( nWriteSize && nCount == nCurBufLen );
1198 return nSize - nWriteSize;
1201 OUString SvStream::ReadUniOrByteString( rtl_TextEncoding eSrcCharSet )
1203 // read UTF-16 string directly from stream ?
1204 if (eSrcCharSet == RTL_TEXTENCODING_UNICODE)
1205 return read_uInt32_lenPrefixed_uInt16s_ToOUString(*this);
1206 return read_uInt16_lenPrefixed_uInt8s_ToOUString(*this, eSrcCharSet);
1209 SvStream& SvStream::WriteUniOrByteString( const OUString& rStr, rtl_TextEncoding eDestCharSet )
1211 // write UTF-16 string directly into stream ?
1212 if (eDestCharSet == RTL_TEXTENCODING_UNICODE)
1213 write_uInt32_lenPrefixed_uInt16s_FromOUString(*this, rStr);
1214 else
1215 write_uInt16_lenPrefixed_uInt8s_FromOUString(*this, rStr, eDestCharSet);
1216 return *this;
1219 void SvStream::FlushBuffer(bool isConsistent)
1221 if (m_isDirty && isConsistent) // Does stream require a flush?
1223 SeekPos(m_nBufFilePos);
1224 if (m_nCryptMask)
1225 CryptAndWriteBuffer(m_pRWBuf.get(), m_nBufActualLen);
1226 else if (PutData(m_pRWBuf.get(), m_nBufActualLen) != m_nBufActualLen)
1227 SetError(SVSTREAM_WRITE_ERROR);
1228 m_isDirty = false;
1232 std::size_t SvStream::ReadBytes( void* pData, std::size_t nCount )
1234 std::size_t nSaveCount = nCount;
1235 if (!m_isConsistent)
1236 RefreshBuffer();
1238 if (!m_pRWBuf)
1240 nCount = GetData( pData,nCount);
1241 if (m_nCryptMask)
1242 EncryptBuffer(pData, nCount);
1243 m_nBufFilePos += nCount;
1245 else
1247 // check if block is completely within buffer
1248 m_isIoRead = true;
1249 m_isIoWrite = false;
1250 if (nCount <= static_cast<std::size_t>(m_nBufActualLen - m_nBufActualPos))
1252 // => yes
1253 if (nCount != 0)
1254 memcpy(pData, m_pBufPos, static_cast<size_t>(nCount));
1255 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1256 m_pBufPos += nCount;
1257 m_nBufFree = m_nBufFree - static_cast<sal_uInt16>(nCount);
1259 else
1261 FlushBuffer(true);
1263 // Does data block fit into buffer?
1264 if (nCount > m_nBufSize)
1266 // => No! Thus read directly
1267 // into target area without using the buffer
1269 m_isIoRead = false;
1271 SeekPos(m_nBufFilePos + m_nBufActualPos);
1272 m_nBufActualLen = 0;
1273 m_pBufPos = m_pRWBuf.get();
1274 nCount = GetData( pData, nCount );
1275 if (m_nCryptMask)
1276 EncryptBuffer(pData, nCount);
1277 m_nBufFilePos += nCount;
1278 m_nBufFilePos += m_nBufActualPos;
1279 m_nBufActualPos = 0;
1281 else
1283 // => Yes. Fill buffer first, then copy to target area
1285 m_nBufFilePos += m_nBufActualPos;
1286 SeekPos(m_nBufFilePos);
1288 // TODO: Typecast before GetData, sal_uInt16 nCountTmp
1289 std::size_t nCountTmp = GetData( m_pRWBuf.get(), m_nBufSize );
1290 if (m_nCryptMask)
1291 EncryptBuffer(m_pRWBuf.get(), nCountTmp);
1292 m_nBufActualLen = static_cast<sal_uInt16>(nCountTmp);
1293 if( nCount > nCountTmp )
1295 nCount = nCountTmp; // trim count back, EOF see below
1297 memcpy( pData, m_pRWBuf.get(), static_cast<size_t>(nCount) );
1298 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1299 m_pBufPos = m_pRWBuf.get() + nCount;
1303 m_isEof = false;
1304 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1305 if (nCount != nSaveCount && m_nError != ERRCODE_IO_PENDING)
1306 m_isEof = true;
1307 if (nCount == nSaveCount && m_nError == ERRCODE_IO_PENDING)
1308 m_nError = ERRCODE_NONE;
1309 return nCount;
1312 std::size_t SvStream::WriteBytes( const void* pData, std::size_t nCount )
1314 if( !nCount )
1315 return 0;
1317 if (!m_isWritable)
1319 SetError( ERRCODE_IO_CANTWRITE );
1320 return 0;
1322 if (!m_isConsistent)
1323 RefreshBuffer(); // Remove changes in buffer through PutBack
1325 if (!m_pRWBuf)
1327 if (m_nCryptMask)
1328 nCount = CryptAndWriteBuffer( pData, nCount );
1329 else
1330 nCount = PutData( pData, nCount );
1331 m_nBufFilePos += nCount;
1332 return nCount;
1335 m_isIoRead = false;
1336 m_isIoWrite = true;
1337 if (nCount <= static_cast<std::size_t>(m_nBufSize - m_nBufActualPos))
1339 memcpy( m_pBufPos, pData, static_cast<size_t>(nCount) );
1340 m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
1341 // Update length if buffer was updated
1342 if (m_nBufActualPos > m_nBufActualLen)
1343 m_nBufActualLen = m_nBufActualPos;
1345 m_pBufPos += nCount;
1346 m_isDirty = true;
1348 else
1350 FlushBuffer(true);
1352 // Does data block fit into buffer?
1353 if (nCount > m_nBufSize)
1355 m_isIoWrite = false;
1356 m_nBufFilePos += m_nBufActualPos;
1357 m_nBufActualLen = 0;
1358 m_nBufActualPos = 0;
1359 m_pBufPos = m_pRWBuf.get();
1360 SeekPos(m_nBufFilePos);
1361 if (m_nCryptMask)
1362 nCount = CryptAndWriteBuffer( pData, nCount );
1363 else
1364 nCount = PutData( pData, nCount );
1365 m_nBufFilePos += nCount;
1367 else
1369 // Copy block to buffer
1370 memcpy( m_pRWBuf.get(), pData, static_cast<size_t>(nCount) );
1372 // Mind the order!
1373 m_nBufFilePos += m_nBufActualPos;
1374 m_nBufActualPos = static_cast<sal_uInt16>(nCount);
1375 m_pBufPos = m_pRWBuf.get() + nCount;
1376 m_nBufActualLen = static_cast<sal_uInt16>(nCount);
1377 m_isDirty = true;
1380 m_nBufFree = m_nBufSize - m_nBufActualPos;
1381 return nCount;
1384 sal_uInt64 SvStream::Seek(sal_uInt64 const nFilePos)
1386 m_isIoRead = m_isIoWrite = false;
1387 m_isEof = false;
1388 if (!m_pRWBuf)
1390 m_nBufFilePos = SeekPos( nFilePos );
1391 DBG_ASSERT(Tell() == m_nBufFilePos,"Out Of Sync!");
1392 return m_nBufFilePos;
1395 // Is seek position within buffer?
1396 if (nFilePos >= m_nBufFilePos && nFilePos <= (m_nBufFilePos + m_nBufActualLen))
1398 m_nBufActualPos = static_cast<sal_uInt16>(nFilePos - m_nBufFilePos);
1399 m_pBufPos = m_pRWBuf.get() + m_nBufActualPos;
1400 // Update m_nBufFree to avoid crash upon PutBack
1401 m_nBufFree = m_nBufActualLen - m_nBufActualPos;
1403 else
1405 FlushBuffer(m_isConsistent);
1406 m_nBufActualLen = 0;
1407 m_nBufActualPos = 0;
1408 m_pBufPos = m_pRWBuf.get();
1409 m_nBufFilePos = SeekPos( nFilePos );
1411 return m_nBufFilePos + m_nBufActualPos;
1414 bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
1416 const sal_uInt64 nMaxSeek(rSt.Tell() + rSt.remainingSize());
1417 return (nOffset <= nMaxSeek && rSt.Seek(nOffset) == nOffset);
1420 //STREAM_SEEK_TO_END in the some of the Seek backends is special cased to be
1421 //efficient, in others e.g. SotStorageStream it's really horribly slow, and in
1422 //those this should be overridden
1423 sal_uInt64 SvStream::remainingSize()
1425 sal_uInt64 const nCurr = Tell();
1426 sal_uInt64 const nEnd = Seek(STREAM_SEEK_TO_END);
1427 sal_uInt64 nMaxAvailable = nEnd > nCurr ? (nEnd-nCurr) : 0;
1428 Seek(nCurr);
1429 return nMaxAvailable;
1432 void SvStream::Flush()
1434 FlushBuffer(m_isConsistent);
1435 if (m_isWritable)
1436 FlushData();
1439 void SvStream::RefreshBuffer()
1441 FlushBuffer(m_isConsistent);
1442 SeekPos(m_nBufFilePos);
1443 m_nBufActualLen = static_cast<sal_uInt16>(GetData( m_pRWBuf.get(), m_nBufSize ));
1444 if (m_nBufActualLen && m_nError == ERRCODE_IO_PENDING)
1445 m_nError = ERRCODE_NONE;
1446 if (m_nCryptMask)
1447 EncryptBuffer(m_pRWBuf.get(), static_cast<std::size_t>(m_nBufActualLen));
1448 m_isConsistent = true;
1449 m_isIoRead = m_isIoWrite = false;
1452 SvStream& SvStream::WriteInt32AsString(sal_Int32 nInt32)
1454 char buffer[12];
1455 std::size_t nLen = sprintf(buffer, "%" SAL_PRIdINT32, nInt32);
1456 WriteBytes(buffer, nLen);
1457 return *this;
1460 SvStream& SvStream::WriteUInt32AsString(sal_uInt32 nUInt32)
1462 char buffer[11];
1463 std::size_t nLen = sprintf(buffer, "%" SAL_PRIuUINT32, nUInt32);
1464 WriteBytes(buffer, nLen);
1465 return *this;
1468 #define CRYPT_BUFSIZE 1024
1470 /// Encrypt and write
1471 std::size_t SvStream::CryptAndWriteBuffer( const void* pStart, std::size_t nLen)
1473 unsigned char pTemp[CRYPT_BUFSIZE];
1474 unsigned char const * pDataPtr = static_cast<unsigned char const *>(pStart);
1475 std::size_t nCount = 0;
1476 std::size_t nBufCount;
1477 unsigned char nMask = m_nCryptMask;
1480 if( nLen >= CRYPT_BUFSIZE )
1481 nBufCount = CRYPT_BUFSIZE;
1482 else
1483 nBufCount = nLen;
1484 nLen -= nBufCount;
1485 memcpy( pTemp, pDataPtr, static_cast<sal_uInt16>(nBufCount) );
1486 // ******** Encrypt ********
1487 for (unsigned char & rn : pTemp)
1489 unsigned char aCh = rn;
1490 aCh ^= nMask;
1491 SWAPNIBBLES(aCh)
1492 rn = aCh;
1494 // *************************
1495 nCount += PutData( pTemp, nBufCount );
1496 pDataPtr += nBufCount;
1498 while ( nLen );
1499 return nCount;
1502 bool SvStream::EncryptBuffer(void* pStart, std::size_t nLen) const
1504 unsigned char* pTemp = static_cast<unsigned char*>(pStart);
1505 unsigned char nMask = m_nCryptMask;
1507 for ( std::size_t n=0; n < nLen; n++, pTemp++ )
1509 unsigned char aCh = *pTemp;
1510 SWAPNIBBLES(aCh)
1511 aCh ^= nMask;
1512 *pTemp = aCh;
1514 return true;
1517 static unsigned char implGetCryptMask(const sal_Char* pStr, sal_Int32 nLen, long nVersion)
1519 unsigned char nCryptMask = 0;
1521 if (!nLen)
1522 return nCryptMask;
1524 if( nVersion <= SOFFICE_FILEFORMAT_31 )
1526 while( nLen )
1528 nCryptMask ^= *pStr;
1529 pStr++;
1530 nLen--;
1533 else // BugFix #25888#
1535 for( sal_Int32 i = 0; i < nLen; i++ ) {
1536 nCryptMask ^= pStr[i];
1537 if( nCryptMask & 0x80 ) {
1538 nCryptMask <<= 1;
1539 nCryptMask++;
1541 else
1542 nCryptMask <<= 1;
1546 if( !nCryptMask )
1547 nCryptMask = 67;
1549 return nCryptMask;
1552 void SvStream::SetCryptMaskKey(const OString& rCryptMaskKey)
1554 m_aCryptMaskKey = rCryptMaskKey;
1555 m_nCryptMask = implGetCryptMask(m_aCryptMaskKey.getStr(),
1556 m_aCryptMaskKey.getLength(), GetVersion());
1559 bool SvStream::SetStreamSize(sal_uInt64 const nSize)
1561 #ifdef DBG_UTIL
1562 sal_uInt64 nFPos = Tell();
1563 #endif
1564 sal_uInt16 nBuf = m_nBufSize;
1565 SetBufferSize( 0 );
1566 SetSize( nSize );
1567 SetBufferSize( nBuf );
1568 #ifdef DBG_UTIL
1569 DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed");
1570 #endif
1571 return (m_nError == ERRCODE_NONE);
1574 SvStream& endl( SvStream& rStr )
1576 LineEnd eDelim = rStr.GetLineDelimiter();
1577 if ( eDelim == LINEEND_CR )
1578 rStr.WriteChar('\r');
1579 else if( eDelim == LINEEND_LF )
1580 rStr.WriteChar('\n');
1581 else
1582 rStr.WriteChar('\r').WriteChar('\n');
1583 return rStr;
1586 SvStream& endlu( SvStream& rStrm )
1588 switch ( rStrm.GetLineDelimiter() )
1590 case LINEEND_CR :
1591 rStrm.WriteUnicode('\r');
1592 break;
1593 case LINEEND_LF :
1594 rStrm.WriteUnicode('\n');
1595 break;
1596 default:
1597 rStrm.WriteUnicode('\r').WriteUnicode('\n');
1599 return rStrm;
1602 SvStream& endlub( SvStream& rStrm )
1604 if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
1605 return endlu( rStrm );
1606 else
1607 return endl( rStrm );
1610 SvMemoryStream::SvMemoryStream( void* pBuffer, std::size_t bufSize,
1611 StreamMode eMode )
1613 if( eMode & StreamMode::WRITE )
1614 m_isWritable = true;
1615 else
1616 m_isWritable = false;
1617 nEndOfData = bufSize;
1618 bOwnsData = false;
1619 pBuf = static_cast<sal_uInt8 *>(pBuffer);
1620 nResize = 0;
1621 nSize = bufSize;
1622 nPos = 0;
1623 SetBufferSize( 0 );
1626 SvMemoryStream::SvMemoryStream( std::size_t nInitSize, std::size_t nResizeOffset )
1628 m_isWritable = true;
1629 bOwnsData = true;
1630 nEndOfData = 0;
1631 nResize = nResizeOffset;
1632 nPos = 0;
1633 pBuf = nullptr;
1634 if( nResize != 0 && nResize < 16 )
1635 nResize = 16;
1636 if( nInitSize && !AllocateMemory( nInitSize ) )
1638 SetError( SVSTREAM_OUTOFMEMORY );
1639 nSize = 0;
1641 else
1642 nSize = nInitSize;
1643 SetBufferSize( 64 );
1646 SvMemoryStream::~SvMemoryStream()
1648 if( pBuf )
1650 if( bOwnsData )
1651 FreeMemory();
1652 else
1653 Flush();
1657 const void* SvMemoryStream::GetBuffer()
1659 return GetData();
1662 sal_uInt64 SvMemoryStream::GetSize()
1664 Flush();
1665 sal_uInt64 const nTemp = Tell();
1666 sal_uInt64 const nLength = Seek( STREAM_SEEK_TO_END );
1667 Seek( nTemp );
1668 return nLength;
1671 void SvMemoryStream::SetBuffer( void* pNewBuf, std::size_t nCount,
1672 std::size_t nEOF )
1674 SetBufferSize( 0 ); // Init buffering in the base class
1675 Seek( 0 );
1676 if( bOwnsData )
1678 if( pNewBuf != pBuf )
1679 FreeMemory();
1682 pBuf = static_cast<sal_uInt8 *>(pNewBuf);
1683 nPos = 0;
1684 nSize = nCount;
1685 nResize = 0;
1686 bOwnsData = false;
1688 if( nEOF > nCount )
1689 nEOF = nCount;
1690 nEndOfData = nEOF;
1692 ResetError();
1695 std::size_t SvMemoryStream::GetData( void* pData, std::size_t nCount )
1697 std::size_t nMaxCount = nEndOfData-nPos;
1698 if( nCount > nMaxCount )
1699 nCount = nMaxCount;
1700 if (nCount != 0)
1702 memcpy( pData, pBuf+nPos, static_cast<size_t>(nCount) );
1704 nPos += nCount;
1705 return nCount;
1708 std::size_t SvMemoryStream::PutData( const void* pData, std::size_t nCount )
1710 if( GetError() )
1711 return 0L;
1713 std::size_t nMaxCount = nSize-nPos;
1715 // check for overflow
1716 if( nCount > nMaxCount )
1718 if( nResize == 0 )
1720 // copy as much as possible
1721 nCount = nMaxCount;
1722 SetError( SVSTREAM_OUTOFMEMORY );
1724 else
1726 long nNewResize;
1727 if( nSize && nSize > nResize )
1728 nNewResize = nSize;
1729 else
1730 nNewResize = nResize;
1732 if( (nCount-nMaxCount) < nResize )
1734 // lacking memory is smaller than nResize,
1735 // resize accordingly
1736 if( !ReAllocateMemory( nNewResize) )
1738 nCount = 0;
1739 SetError( SVSTREAM_WRITE_ERROR );
1742 else
1744 // lacking memory is larger than nResize,
1745 // resize by (nCount-nMaxCount) + resize offset
1746 if( !ReAllocateMemory( nCount-nMaxCount+nNewResize ) )
1748 nCount = 0;
1749 SetError( SVSTREAM_WRITE_ERROR );
1754 assert(pBuf && "Possibly Reallocate failed");
1755 memcpy( pBuf+nPos, pData, static_cast<size_t>(nCount));
1757 nPos += nCount;
1758 if( nPos > nEndOfData )
1759 nEndOfData = nPos;
1760 return nCount;
1763 sal_uInt64 SvMemoryStream::SeekPos(sal_uInt64 const nNewPos)
1765 // nEndOfData: First position in stream not allowed to read from
1766 // nSize: Size of allocated buffer
1768 // check if a truncated STREAM_SEEK_TO_END was passed
1769 assert(nNewPos != SAL_MAX_UINT32);
1770 if( nNewPos < nEndOfData )
1771 nPos = nNewPos;
1772 else if( nNewPos == STREAM_SEEK_TO_END )
1773 nPos = nEndOfData;
1774 else
1776 if( nNewPos >= nSize ) // Does buffer need extension?
1778 if( nResize ) // Is extension possible?
1780 long nDiff = static_cast<long>(nNewPos - nSize + 1);
1781 nDiff += static_cast<long>(nResize);
1782 ReAllocateMemory( nDiff );
1783 nPos = nNewPos;
1784 nEndOfData = nNewPos;
1786 else // Extension not possible, set pos to end of data
1788 // SetError( SVSTREAM_OUTOFMEMORY );
1789 nPos = nEndOfData;
1792 else // Expand buffer size
1794 nPos = nNewPos;
1795 nEndOfData = nNewPos;
1798 return nPos;
1801 void SvMemoryStream::FlushData()
1805 void SvMemoryStream::ResetError()
1807 SvStream::ClearError();
1810 bool SvMemoryStream::AllocateMemory( std::size_t nNewSize )
1812 pBuf = new sal_uInt8[nNewSize];
1813 return( pBuf != nullptr );
1816 // (using Bozo algorithm)
1817 bool SvMemoryStream::ReAllocateMemory( long nDiff )
1819 if (!m_isWritable || !bOwnsData)
1820 return false;
1822 bool bRetVal = false;
1823 long nTemp = static_cast<long>(nSize);
1824 nTemp += nDiff;
1825 std::size_t nNewSize = static_cast<std::size_t>(nTemp);
1827 if( nNewSize )
1829 sal_uInt8* pNewBuf = new sal_uInt8[nNewSize];
1831 bRetVal = true; // Success!
1832 if( nNewSize < nSize ) // Are we shrinking?
1834 memcpy( pNewBuf, pBuf, static_cast<size_t>(nNewSize) );
1835 if( nPos > nNewSize )
1836 nPos = 0;
1837 if( nEndOfData >= nNewSize )
1838 nEndOfData = nNewSize-1;
1840 else
1842 if (nSize != 0)
1844 memcpy( pNewBuf, pBuf, static_cast<size_t>(nSize) );
1846 memset(pNewBuf + nSize, 0x00, nNewSize - nSize);
1849 FreeMemory();
1851 pBuf = pNewBuf;
1852 nSize = nNewSize;
1854 else
1856 bRetVal = true;
1857 FreeMemory();
1858 pBuf = nullptr;
1859 nSize = 0;
1860 nEndOfData = 0;
1861 nPos = 0;
1864 return bRetVal;
1867 void SvMemoryStream::FreeMemory()
1869 assert(bOwnsData);
1870 if (bOwnsData)
1872 delete[] pBuf;
1873 pBuf = nullptr;
1877 void* SvMemoryStream::SwitchBuffer()
1879 Flush();
1880 if( !bOwnsData )
1881 return nullptr;
1882 Seek( STREAM_SEEK_TO_BEGIN );
1884 void* pRetVal = pBuf;
1885 pBuf = nullptr;
1886 nEndOfData = 0;
1887 nResize = 64;
1888 nPos = 0;
1890 if( nResize != 0 && nResize < 16 )
1891 nResize = 16;
1893 ResetError();
1895 std::size_t nInitSize = 512;
1896 if( !AllocateMemory(nInitSize) )
1898 SetError( SVSTREAM_OUTOFMEMORY );
1899 nSize = 0;
1901 else
1902 nSize = nInitSize;
1904 SetBufferSize( 64 );
1905 return pRetVal;
1908 void SvMemoryStream::SetSize(sal_uInt64 const nNewSize)
1910 if (!m_isWritable)
1912 SetError(SVSTREAM_INVALID_HANDLE);
1913 return;
1916 long nDiff = static_cast<long>(nNewSize) - static_cast<long>(nSize);
1917 ReAllocateMemory( nDiff );
1920 //Create a OString of nLen bytes from rStream
1921 OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen)
1923 rtl_String *pStr = nullptr;
1924 if (nLen)
1926 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1927 //limit allocation to size of file, but + 1 to set eof state
1928 nLen = std::min<sal_uInt64>(nLen, rStrm.remainingSize() + 1);
1929 //alloc a (ref-count 1) rtl_String of the desired length.
1930 //rtl_String's buffer is uninitialized, except for null termination
1931 pStr = rtl_string_alloc(sal::static_int_cast<sal_Int32>(nLen));
1932 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1933 if (pStr)
1935 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen);
1936 if (nWasRead != nLen)
1938 //on (typically unlikely) short read set length to what we could
1939 //read, and null terminate. Excess buffer capacity remains of
1940 //course, could create a (true) replacement OString if it matters.
1941 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1942 pStr->buffer[pStr->length] = 0;
1947 //take ownership of buffer and return, otherwise return empty string
1948 return pStr ? OString(pStr, SAL_NO_ACQUIRE) : OString();
1951 //Create a OUString of nLen sal_Unicode code units from rStream
1952 OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen)
1954 rtl_uString *pStr = nullptr;
1955 if (nLen)
1957 nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
1958 //limit allocation to size of file, but + 1 to set eof state
1959 nLen = std::min<sal_uInt64>(nLen, (rStrm.remainingSize() + 2) / 2);
1960 //alloc a (ref-count 1) rtl_uString of the desired length.
1961 //rtl_String's buffer is uninitialized, except for null termination
1962 pStr = rtl_uString_alloc(sal::static_int_cast<sal_Int32>(nLen));
1963 SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
1964 if (pStr)
1966 std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen*2)/2;
1967 if (nWasRead != nLen)
1969 //on (typically unlikely) short read set length to what we could
1970 //read, and null terminate. Excess buffer capacity remains of
1971 //course, could create a (true) replacement OUString if it matters.
1972 pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
1973 pStr->buffer[pStr->length] = 0;
1975 if (rStrm.IsEndianSwap())
1977 for (sal_Int32 i = 0; i < pStr->length; ++i)
1978 pStr->buffer[i] = OSL_SWAPWORD(pStr->buffer[i]);
1983 //take ownership of buffer and return, otherwise return empty string
1984 return pStr ? OUString(pStr, SAL_NO_ACQUIRE) : OUString();
1987 namespace
1989 template <typename T, typename O> T tmpl_convertLineEnd(const T &rIn, LineEnd eLineEnd)
1991 // Determine linebreaks and compute length
1992 bool bConvert = false; // Needs conversion
1993 sal_Int32 nStrLen = rIn.getLength();
1994 sal_Int32 nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
1995 sal_Int32 nLen = 0; // Target length
1996 sal_Int32 i = 0; // Source counter
1998 while (i < nStrLen)
2000 // \r or \n causes linebreak
2001 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
2003 nLen = nLen + nLineEndLen;
2005 // If set already, skip expensive test
2006 if ( !bConvert )
2008 // Do we need to convert?
2009 if ( ((eLineEnd != LINEEND_LF) && (rIn[i] == '\n')) ||
2010 ((eLineEnd == LINEEND_CRLF) && (i+1) < nStrLen && (rIn[i+1] != '\n')) ||
2011 ((eLineEnd == LINEEND_LF) &&
2012 ((rIn[i] == '\r') || ((i+1) < nStrLen && rIn[i+1] == '\r'))) ||
2013 ((eLineEnd == LINEEND_CR) &&
2014 ((rIn[i] == '\n') || ((i+1) < nStrLen && rIn[i+1] == '\n'))) )
2015 bConvert = true;
2018 // skip char if \r\n or \n\r
2019 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
2020 (rIn[i] != rIn[i+1]) )
2021 ++i;
2023 else
2024 ++nLen;
2025 ++i;
2028 if (!bConvert)
2029 return rIn;
2031 // convert linebreaks, insert string
2032 O aNewData(nLen);
2033 i = 0;
2034 while (i < nStrLen)
2036 // \r or \n causes linebreak
2037 if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
2039 if ( eLineEnd == LINEEND_CRLF )
2041 aNewData.append('\r');
2042 aNewData.append('\n');
2044 else
2046 if ( eLineEnd == LINEEND_CR )
2047 aNewData.append('\r');
2048 else
2049 aNewData.append('\n');
2052 if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
2053 (rIn[i] != rIn[i+1]) )
2054 ++i;
2056 else
2058 aNewData.append(rIn[i]);
2061 ++i;
2064 return aNewData.makeStringAndClear();
2068 OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
2070 return tmpl_convertLineEnd<OString, OStringBuffer>(rIn, eLineEnd);
2073 OUString convertLineEnd(const OUString &rIn, LineEnd eLineEnd)
2075 return tmpl_convertLineEnd<OUString, OUStringBuffer>(rIn, eLineEnd);
2078 std::size_t write_uInt32_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
2079 const OUString &rStr)
2081 std::size_t nWritten = 0;
2082 sal_uInt32 nUnits = std::min<std::size_t>(rStr.getLength(), std::numeric_limits<sal_uInt32>::max());
2083 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.getLength()),
2084 "tools.stream",
2085 "string too long for prefix count to fit in output type");
2086 rStrm.WriteUInt32(nUnits);
2087 if (rStrm.good())
2089 nWritten += sizeof(sal_uInt32);
2090 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
2092 return nWritten;
2095 std::size_t write_uInt16_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
2096 const OUString &rStr)
2098 std::size_t nWritten = 0;
2099 sal_uInt16 nUnits = std::min<std::size_t>(rStr.getLength(), std::numeric_limits<sal_uInt16>::max());
2100 SAL_WARN_IF(nUnits != rStr.getLength(),
2101 "tools.stream",
2102 "string too long for prefix count to fit in output type");
2103 rStrm.WriteUInt16(nUnits);
2104 if (rStrm.good())
2106 nWritten += sizeof(nUnits);
2107 nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
2109 return nWritten;
2112 std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm,
2113 const OString &rStr)
2115 std::size_t nWritten = 0;
2116 sal_uInt16 nUnits = std::min<std::size_t>(rStr.getLength(), std::numeric_limits<sal_uInt16>::max());
2117 SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.getLength()),
2118 "tools.stream",
2119 "string too long for sal_uInt16 count to fit in output type");
2120 rStrm.WriteUInt16( nUnits );
2121 if (rStrm.good())
2123 nWritten += sizeof(sal_uInt16);
2124 nWritten += write_uInt8s_FromOString(rStrm, rStr, nUnits);
2126 return nWritten;
2129 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */