summaryrefslogtreecommitdiffstats
path: root/tools/source/stream
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tools/source/stream/GenericTypeSerializer.cxx212
-rw-r--r--tools/source/stream/stream.cxx2012
-rw-r--r--tools/source/stream/strmunx.cxx496
-rw-r--r--tools/source/stream/strmwnt.cxx420
-rw-r--r--tools/source/stream/vcompat.cxx68
5 files changed, 3208 insertions, 0 deletions
diff --git a/tools/source/stream/GenericTypeSerializer.cxx b/tools/source/stream/GenericTypeSerializer.cxx
new file mode 100644
index 000000000..8abe23237
--- /dev/null
+++ b/tools/source/stream/GenericTypeSerializer.cxx
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/GenericTypeSerializer.hxx>
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <vector>
+
+namespace tools
+{
+constexpr sal_uInt16 COL_NAME_USER = 0x8000;
+
+constexpr sal_Int32 RECT_EMPTY_VALUE_RIGHT_BOTTOM = -32767;
+
+void GenericTypeSerializer::readColor(Color& rColor)
+{
+ sal_uInt16 nColorNameID(0);
+
+ mrStream.ReadUInt16(nColorNameID);
+
+ if (nColorNameID & COL_NAME_USER)
+ {
+ sal_uInt16 nRed(0);
+ sal_uInt16 nGreen(0);
+ sal_uInt16 nBlue(0);
+
+ mrStream.ReadUInt16(nRed);
+ mrStream.ReadUInt16(nGreen);
+ mrStream.ReadUInt16(nBlue);
+
+ rColor = Color(nRed >> 8, nGreen >> 8, nBlue >> 8);
+ }
+ else
+ {
+ static const std::vector<Color> staticColorArray = {
+ COL_BLACK, // COL_BLACK
+ COL_BLUE, // COL_BLUE
+ COL_GREEN, // COL_GREEN
+ COL_CYAN, // COL_CYAN
+ COL_RED, // COL_RED
+ COL_MAGENTA, // COL_MAGENTA
+ COL_BROWN, // COL_BROWN
+ COL_GRAY, // COL_GRAY
+ COL_LIGHTGRAY, // COL_LIGHTGRAY
+ COL_LIGHTBLUE, // COL_LIGHTBLUE
+ COL_LIGHTGREEN, // COL_LIGHTGREEN
+ COL_LIGHTCYAN, // COL_LIGHTCYAN
+ COL_LIGHTRED, // COL_LIGHTRED
+ COL_LIGHTMAGENTA, // COL_LIGHTMAGENTA
+ COL_YELLOW, // COL_YELLOW
+ COL_WHITE, // COL_WHITE
+ COL_WHITE, // COL_MENUBAR
+ COL_BLACK, // COL_MENUBARTEXT
+ COL_WHITE, // COL_POPUPMENU
+ COL_BLACK, // COL_POPUPMENUTEXT
+ COL_BLACK, // COL_WINDOWTEXT
+ COL_WHITE, // COL_WINDOWWORKSPACE
+ COL_BLACK, // COL_HIGHLIGHT
+ COL_WHITE, // COL_HIGHLIGHTTEXT
+ COL_BLACK, // COL_3DTEXT
+ COL_LIGHTGRAY, // COL_3DFACE
+ COL_WHITE, // COL_3DLIGHT
+ COL_GRAY, // COL_3DSHADOW
+ COL_LIGHTGRAY, // COL_SCROLLBAR
+ COL_WHITE, // COL_FIELD
+ COL_BLACK // COL_FIELDTEXT
+ };
+
+ if (nColorNameID < staticColorArray.size())
+ rColor = staticColorArray[nColorNameID];
+ else
+ rColor = COL_BLACK;
+ }
+}
+
+void GenericTypeSerializer::writeColor(const Color& rColor)
+{
+ mrStream.WriteUInt16(COL_NAME_USER);
+
+ sal_uInt16 nR = rColor.GetRed();
+ sal_uInt16 nG = rColor.GetGreen();
+ sal_uInt16 nB = rColor.GetBlue();
+
+ mrStream.WriteUInt16((nR << 8) + nR);
+ mrStream.WriteUInt16((nG << 8) + nG);
+ mrStream.WriteUInt16((nB << 8) + nB);
+}
+
+void GenericTypeSerializer::readPoint(Point& rPoint)
+{
+ sal_Int32 nX(0);
+ sal_Int32 nY(0);
+
+ mrStream.ReadInt32(nX);
+ mrStream.ReadInt32(nY);
+
+ rPoint.setX(nX);
+ rPoint.setY(nY);
+}
+
+void GenericTypeSerializer::writePoint(const Point& rPoint)
+{
+ mrStream.WriteInt32(rPoint.getX());
+ mrStream.WriteInt32(rPoint.getY());
+}
+
+void GenericTypeSerializer::readSize(Size& rSize)
+{
+ sal_Int32 nWidth(0);
+ sal_Int32 nHeight(0);
+
+ mrStream.ReadInt32(nWidth);
+ mrStream.ReadInt32(nHeight);
+
+ rSize.setWidth(nWidth);
+ rSize.setHeight(nHeight);
+}
+
+void GenericTypeSerializer::writeSize(const Size& rSize)
+{
+ mrStream.WriteInt32(rSize.getWidth());
+ mrStream.WriteInt32(rSize.getHeight());
+}
+
+void GenericTypeSerializer::readRectangle(Rectangle& rRectangle)
+{
+ sal_Int32 nLeft(0);
+ sal_Int32 nTop(0);
+ sal_Int32 nRight(0);
+ sal_Int32 nBottom(0);
+
+ mrStream.ReadInt32(nLeft);
+ mrStream.ReadInt32(nTop);
+ mrStream.ReadInt32(nRight);
+ mrStream.ReadInt32(nBottom);
+
+ if (nRight == RECT_EMPTY_VALUE_RIGHT_BOTTOM || nBottom == RECT_EMPTY_VALUE_RIGHT_BOTTOM)
+ {
+ rRectangle.SetEmpty();
+ }
+ else
+ {
+ rRectangle.SetLeft(nLeft);
+ rRectangle.SetTop(nTop);
+ rRectangle.SetRight(nRight);
+ rRectangle.SetBottom(nBottom);
+ }
+}
+
+void GenericTypeSerializer::writeRectangle(const Rectangle& rRectangle)
+{
+ if (rRectangle.IsEmpty())
+ {
+ mrStream.WriteInt32(0);
+ mrStream.WriteInt32(0);
+ mrStream.WriteInt32(RECT_EMPTY_VALUE_RIGHT_BOTTOM);
+ mrStream.WriteInt32(RECT_EMPTY_VALUE_RIGHT_BOTTOM);
+ }
+ else
+ {
+ mrStream.WriteInt32(rRectangle.Left());
+ mrStream.WriteInt32(rRectangle.Top());
+ mrStream.WriteInt32(rRectangle.Right());
+ mrStream.WriteInt32(rRectangle.Bottom());
+ }
+}
+
+void GenericTypeSerializer::readFraction(Fraction& rFraction)
+{
+ sal_Int32 nNumerator(0);
+ sal_Int32 nDenominator(0);
+
+ mrStream.ReadInt32(nNumerator);
+ mrStream.ReadInt32(nDenominator);
+
+ rFraction = Fraction(nNumerator, nDenominator);
+}
+
+void GenericTypeSerializer::writeFraction(Fraction const& rFraction)
+{
+ if (!rFraction.IsValid())
+ {
+ SAL_WARN("tools.fraction", "'writeFraction()' write an invalid fraction");
+ mrStream.WriteInt32(0);
+ mrStream.WriteInt32(0);
+ }
+ else
+ {
+ mrStream.WriteInt32(rFraction.GetNumerator());
+ mrStream.WriteInt32(rFraction.GetDenominator());
+ }
+}
+
+} // end namespace tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tools/source/stream/stream.cxx b/tools/source/stream/stream.cxx
new file mode 100644
index 000000000..bb84dd468
--- /dev/null
+++ b/tools/source/stream/stream.cxx
@@ -0,0 +1,2012 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// TODO: Read->RefreshBuffer-> React to changes from m_nBufActualLen
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+
+#include <string.h>
+
+#include <o3tl/safeint.hxx>
+#include <osl/endian.h>
+#include <osl/diagnose.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/long.hxx>
+
+#include <comphelper/fileformat.h>
+#include <comphelper/fileurl.hxx>
+
+static void swapNibbles(unsigned char &c)
+{
+ unsigned char nSwapTmp=c;
+ nSwapTmp <<= 4;
+ c >>= 4;
+ c |= nSwapTmp;
+}
+
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <osl/thread.h>
+#include <algorithm>
+
+// !!! Do not inline if already the operators <<,>> are inline
+template <typename T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) == 2, int> = 0>
+static void SwapNumber(T& r)
+ { r = OSL_SWAPWORD(r); }
+template <typename T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) == 4, int> = 0>
+static void SwapNumber(T& r)
+ { r = OSL_SWAPDWORD(r); }
+template <typename T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) == 8, int> = 0>
+static void SwapNumber(T& r)
+ {
+ union
+ {
+ T n;
+ sal_uInt32 c[2];
+ } s;
+
+ s.n = r;
+ std::swap(s.c[0], s.c[1]); // swap the 32 bit words
+ // swap the bytes in the words
+ s.c[0] = OSL_SWAPDWORD(s.c[0]);
+ s.c[1] = OSL_SWAPDWORD(s.c[1]);
+ r = s.n;
+ }
+
+#ifdef UNX
+static void SwapFloat( float& r )
+ {
+ union
+ {
+ float f;
+ sal_uInt32 c;
+ } s;
+
+ s.f = r;
+ s.c = OSL_SWAPDWORD( s.c );
+ r = s.f;
+ }
+
+static void SwapDouble( double& r )
+ {
+ if( sizeof(double) != 8 )
+ {
+ SAL_WARN( "tools.stream", "Can only swap 8-Byte-doubles" );
+ }
+ else
+ {
+ union
+ {
+ double d;
+ sal_uInt32 c[2];
+ } s;
+
+ s.d = r;
+ s.c[0] ^= s.c[1]; // swap 32-bit values in situ
+ s.c[1] ^= s.c[0];
+ s.c[0] ^= s.c[1];
+ s.c[0] = OSL_SWAPDWORD(s.c[0]); // swap dword itself in situ
+ s.c[1] = OSL_SWAPDWORD(s.c[1]);
+ r = s.d;
+ }
+ }
+#endif
+
+//SDO
+
+void SvStream::readNumberWithoutSwap_(void * pDataDest, int nDataSize)
+{
+ if (m_isIoRead && nDataSize <= m_nBufFree)
+ {
+ for (int i = 0; i < nDataSize; i++)
+ static_cast<char*>(pDataDest)[i] = m_pBufPos[i];
+ m_nBufActualPos += nDataSize;
+ m_pBufPos += nDataSize;
+ m_nBufFree -= nDataSize;
+ }
+ else
+ {
+ ReadBytes( pDataDest, nDataSize );
+ }
+}
+
+
+void SvStream::writeNumberWithoutSwap_(const void * pDataSrc, int nDataSize)
+{
+ if (m_isIoWrite && nDataSize <= m_nBufFree)
+ {
+ for (int i = 0; i < nDataSize; i++)
+ m_pBufPos[i] = static_cast<const char*>(pDataSrc)[i];
+ m_nBufFree -= nDataSize;
+ m_nBufActualPos += nDataSize;
+ if (m_nBufActualPos > m_nBufActualLen)
+ m_nBufActualLen = m_nBufActualPos;
+ m_pBufPos += nDataSize;
+ m_isDirty = true;
+ }
+ else
+ {
+ WriteBytes( pDataSrc, nDataSize );
+ }
+}
+
+
+void SvLockBytes::close()
+{
+ if (m_bOwner)
+ delete m_pStream;
+ m_pStream = nullptr;
+}
+
+
+// virtual
+ErrCode SvLockBytes::ReadAt(sal_uInt64 const nPos, void * pBuffer, std::size_t nCount,
+ std::size_t * pRead) const
+{
+ if (!m_pStream)
+ {
+ OSL_FAIL("SvLockBytes::ReadAt(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->Seek(nPos);
+ std::size_t nTheRead = m_pStream->ReadBytes(pBuffer, nCount);
+ if (pRead)
+ *pRead = nTheRead;
+ return m_pStream->GetErrorCode();
+}
+
+// virtual
+ErrCode SvLockBytes::WriteAt(sal_uInt64 const nPos, const void * pBuffer, std::size_t nCount,
+ std::size_t * pWritten)
+{
+ if (!m_pStream)
+ {
+ OSL_FAIL("SvLockBytes::WriteAt(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->Seek(nPos);
+ std::size_t nTheWritten = m_pStream->WriteBytes(pBuffer, nCount);
+ if (pWritten)
+ *pWritten = nTheWritten;
+ return m_pStream->GetErrorCode();
+}
+
+// virtual
+ErrCode SvLockBytes::Flush() const
+{
+ if (!m_pStream)
+ {
+ OSL_FAIL("SvLockBytes::Flush(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->Flush();
+ return m_pStream->GetErrorCode();
+}
+
+// virtual
+ErrCode SvLockBytes::SetSize(sal_uInt64 const nSize)
+{
+ if (!m_pStream)
+ {
+ OSL_FAIL("SvLockBytes::SetSize(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ m_pStream->SetStreamSize(nSize);
+ return m_pStream->GetErrorCode();
+}
+
+ErrCode SvLockBytes::Stat(SvLockBytesStat * pStat) const
+{
+ if (!m_pStream)
+ {
+ OSL_FAIL("SvLockBytes::Stat(): Bad stream");
+ return ERRCODE_NONE;
+ }
+
+ if (pStat)
+ pStat->nSize = m_pStream->TellEnd();
+ return ERRCODE_NONE;
+}
+
+
+std::size_t SvStream::GetData( void* pData, std::size_t nSize )
+{
+ if( !GetError() )
+ {
+ DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
+ std::size_t nRet(0);
+ m_nError = m_xLockBytes->ReadAt(m_nActPos, pData, nSize, &nRet);
+ m_nActPos += nRet;
+ return nRet;
+ }
+ else return 0;
+}
+
+std::size_t SvStream::PutData( const void* pData, std::size_t nSize )
+{
+ if( !GetError() )
+ {
+ DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
+ std::size_t nRet(0);
+ m_nError = m_xLockBytes->WriteAt(m_nActPos, pData, nSize, &nRet);
+ m_nActPos += nRet;
+ return nRet;
+ }
+ else return 0;
+}
+
+sal_uInt64 SvStream::SeekPos(sal_uInt64 const nPos)
+{
+ // check if a truncated STREAM_SEEK_TO_END was passed
+ assert(nPos != SAL_MAX_UINT32);
+ if( !GetError() && nPos == STREAM_SEEK_TO_END )
+ {
+ DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
+ SvLockBytesStat aStat;
+ m_xLockBytes->Stat( &aStat );
+ m_nActPos = aStat.nSize;
+ }
+ else
+ m_nActPos = nPos;
+ return m_nActPos;
+}
+
+void SvStream::FlushData()
+{
+ if( !GetError() )
+ {
+ DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
+ m_nError = m_xLockBytes->Flush();
+ }
+}
+
+void SvStream::SetSize(sal_uInt64 const nSize)
+{
+ DBG_ASSERT( m_xLockBytes.is(), "pure virtual function" );
+ m_nError = m_xLockBytes->SetSize( nSize );
+}
+
+SvStream::SvStream() :
+ m_nActPos(0)
+
+ , m_pBufPos(nullptr)
+ , m_nBufSize(0)
+ , m_nBufActualLen(0)
+ , m_nBufActualPos(0)
+ , m_nBufFree(0)
+ , m_isIoRead(false)
+ , m_isIoWrite(false)
+
+ , m_isDirty(false)
+ , m_isEof(false)
+
+ , m_nCompressMode(SvStreamCompressFlags::NONE)
+#if defined UNX
+ , m_eLineDelimiter(LINEEND_LF) // UNIX-Format
+#else
+ , m_eLineDelimiter(LINEEND_CRLF) // DOS-Format
+#endif
+ , m_eStreamCharSet(osl_getThreadTextEncoding())
+
+ , m_nCryptMask(0)
+
+ , m_nVersion(0)
+
+ , m_nBufFilePos(0)
+ , m_eStreamMode(StreamMode::NONE)
+ , m_isWritable(true)
+
+{
+ SetEndian( SvStreamEndian::LITTLE );
+
+ ClearError();
+}
+
+SvStream::SvStream( SvLockBytes* pLockBytesP ) : SvStream()
+{
+ m_xLockBytes = pLockBytesP;
+ if( pLockBytesP ) {
+ const SvStream* pStrm = pLockBytesP->GetStream();
+ if( pStrm ) {
+ SetError( pStrm->GetErrorCode() );
+ }
+ }
+ SetBufferSize( 256 );
+}
+
+SvStream::~SvStream()
+{
+ if (m_xLockBytes.is())
+ Flush();
+}
+
+void SvStream::ClearError()
+{
+ m_isEof = false;
+ m_nError = ERRCODE_NONE;
+}
+
+void SvStream::SetError( ErrCode nErrorCode )
+{
+ if (m_nError == ERRCODE_NONE)
+ m_nError = nErrorCode;
+}
+
+void SvStream::SetEndian( SvStreamEndian nNewFormat )
+{
+#ifdef OSL_BIGENDIAN
+ m_isSwap = nNewFormat == SvStreamEndian::LITTLE;
+#else
+ m_isSwap = nNewFormat == SvStreamEndian::BIG;
+#endif
+}
+
+SvStreamEndian SvStream::GetEndian() const
+{
+#ifdef OSL_BIGENDIAN
+ return m_isSwap ? SvStreamEndian::LITTLE : SvStreamEndian::BIG;
+#else
+ return m_isSwap ? SvStreamEndian::BIG : SvStreamEndian::LITTLE;
+#endif
+}
+
+void SvStream::SetBufferSize( sal_uInt16 nBufferSize )
+{
+ sal_uInt64 const nActualFilePos = Tell();
+ bool bDontSeek = (m_pRWBuf == nullptr);
+
+ if (m_isDirty && m_isWritable) // due to Windows NT: Access denied
+ FlushBuffer();
+
+ if (m_nBufSize)
+ {
+ m_pRWBuf.reset();
+ m_nBufFilePos += m_nBufActualPos;
+ }
+
+ m_pRWBuf = nullptr;
+ m_nBufActualLen = 0;
+ m_nBufActualPos = 0;
+ m_nBufSize = nBufferSize;
+ if (m_nBufSize)
+ m_pRWBuf.reset(new sal_uInt8[ m_nBufSize ]);
+ m_pBufPos = m_pRWBuf.get();
+ m_isIoRead = m_isIoWrite = false;
+ if( !bDontSeek )
+ SeekPos( nActualFilePos );
+}
+
+void SvStream::ClearBuffer()
+{
+ m_nBufActualLen = 0;
+ m_nBufActualPos = 0;
+ m_nBufFilePos = 0;
+ m_pBufPos = m_pRWBuf.get();
+ m_isDirty = false;
+ m_isIoRead = m_isIoWrite = false;
+
+ m_isEof = false;
+}
+
+void SvStream::ResetError()
+{
+ ClearError();
+}
+
+bool SvStream::ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
+ sal_Int32 nMaxBytesToRead )
+{
+ OString aStr;
+ bool bRet = ReadLine( aStr, nMaxBytesToRead);
+ rStr = OStringToOUString(aStr, eSrcCharSet);
+ return bRet;
+}
+
+bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead )
+{
+ OStringBuffer aBuf(4096);
+ bool rv = ReadLine(aBuf, nMaxBytesToRead);
+ rStr = aBuf.makeStringAndClear();
+ return rv;
+}
+
+bool SvStream::ReadLine( OStringBuffer& aBuf, sal_Int32 nMaxBytesToRead )
+{
+ char buf[256+1];
+ bool bEnd = false;
+ sal_uInt64 nOldFilePos = Tell();
+ char c = 0;
+ std::size_t nTotalLen = 0;
+
+ aBuf.setLength(0);
+ while( !bEnd && !GetError() ) // Don't test for EOF as we
+ // are reading block-wise!
+ {
+ sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes(buf, sizeof(buf)-1));
+ if ( !nLen )
+ {
+ if ( aBuf.isEmpty() )
+ {
+ // Exit on first block-read error
+ m_isEof = true;
+ aBuf.setLength(0);
+ return false;
+ }
+ else
+ break;
+ }
+
+ sal_uInt16 j, n;
+ for( j = n = 0; j < nLen ; ++j )
+ {
+ c = buf[j];
+ if ( c == '\n' || c == '\r' )
+ {
+ bEnd = true;
+ break;
+ }
+ if ( n < j )
+ buf[n] = c;
+ ++n;
+ }
+ nTotalLen += j;
+ if (nTotalLen > o3tl::make_unsigned(nMaxBytesToRead))
+ {
+ n -= nTotalLen - nMaxBytesToRead;
+ nTotalLen = nMaxBytesToRead;
+ bEnd = true;
+ }
+ if ( n )
+ aBuf.append(buf, n);
+ }
+
+ if ( !bEnd && !GetError() && !aBuf.isEmpty() )
+ bEnd = true;
+
+ nOldFilePos += nTotalLen;
+ if( Tell() > nOldFilePos )
+ nOldFilePos++;
+ Seek( nOldFilePos ); // Seek pointer due to BlockRead above
+
+ if ( bEnd && (c=='\r' || c=='\n') ) // Special treatment for DOS files
+ {
+ char cTemp;
+ std::size_t nLen = ReadBytes(&cTemp, sizeof(cTemp));
+ if ( nLen ) {
+ if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
+ Seek( nOldFilePos );
+ }
+ }
+
+ if ( bEnd )
+ m_isEof = false;
+ return bEnd;
+}
+
+bool SvStream::ReadUniStringLine( OUString& rStr, sal_Int32 nMaxCodepointsToRead )
+{
+ sal_Unicode buf[256+1];
+ bool bEnd = false;
+ sal_uInt64 nOldFilePos = Tell();
+ sal_Unicode c = 0;
+ std::size_t nTotalLen = 0;
+
+ DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "ReadUniStringLine: swapping sizeof(sal_Unicode) not implemented" );
+
+ OUStringBuffer aBuf(4096);
+ while( !bEnd && !GetError() ) // Don't test for EOF as we
+ // are reading block-wise!
+ {
+ sal_uInt16 nLen = static_cast<sal_uInt16>(ReadBytes( buf, sizeof(buf)-sizeof(sal_Unicode)));
+ nLen /= sizeof(sal_Unicode);
+ if ( !nLen )
+ {
+ if ( aBuf.isEmpty() )
+ {
+ // exit on first BlockRead error
+ m_isEof = true;
+ rStr.clear();
+ return false;
+ }
+ else
+ break;
+ }
+
+ sal_uInt16 j, n;
+ for( j = n = 0; j < nLen ; ++j )
+ {
+ if (m_isSwap)
+ SwapNumber( buf[n] );
+ c = buf[j];
+ if ( c == '\n' || c == '\r' )
+ {
+ bEnd = true;
+ break;
+ }
+ // erAck 26.02.01: Old behavior was no special treatment of '\0'
+ // character here, but a following rStr+=c did ignore it. Is this
+ // really intended? Or should a '\0' better terminate a line?
+ // The nOldFilePos stuff wasn't correct then anyways.
+ if ( c )
+ {
+ if ( n < j )
+ buf[n] = c;
+ ++n;
+ }
+ }
+ nTotalLen += j;
+ if (nTotalLen > o3tl::make_unsigned(nMaxCodepointsToRead))
+ {
+ n -= nTotalLen - nMaxCodepointsToRead;
+ nTotalLen = nMaxCodepointsToRead;
+ bEnd = true;
+ }
+ if ( n )
+ aBuf.append( buf, n );
+ }
+
+ if ( !bEnd && !GetError() && !aBuf.isEmpty() )
+ bEnd = true;
+
+ nOldFilePos += nTotalLen * sizeof(sal_Unicode);
+ if( Tell() > nOldFilePos )
+ nOldFilePos += sizeof(sal_Unicode);
+ Seek( nOldFilePos ); // seek due to BlockRead above
+
+ if ( bEnd && (c=='\r' || c=='\n') ) // special treatment for DOS files
+ {
+ sal_Unicode cTemp;
+ ReadBytes( &cTemp, sizeof(cTemp) );
+ if (m_isSwap)
+ SwapNumber( cTemp );
+ if( cTemp == c || (cTemp != '\n' && cTemp != '\r') )
+ Seek( nOldFilePos );
+ }
+
+ if ( bEnd )
+ m_isEof = false;
+ rStr = aBuf.makeStringAndClear();
+ return bEnd;
+}
+
+bool SvStream::ReadUniOrByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet,
+ sal_Int32 nMaxCodepointsToRead )
+{
+ if ( eSrcCharSet == RTL_TEXTENCODING_UNICODE )
+ return ReadUniStringLine( rStr, nMaxCodepointsToRead );
+ else
+ return ReadByteStringLine( rStr, eSrcCharSet, nMaxCodepointsToRead );
+}
+
+OString read_zeroTerminated_uInt8s_ToOString(SvStream& rStream)
+{
+ OStringBuffer aOutput(256);
+
+ char buf[ 256 + 1 ];
+ bool bEnd = false;
+ sal_uInt64 nFilePos = rStream.Tell();
+
+ while( !bEnd && !rStream.GetError() )
+ {
+ std::size_t nLen = rStream.ReadBytes(buf, sizeof(buf)-1);
+ if (!nLen)
+ break;
+
+ std::size_t nReallyRead = nLen;
+ const char* pPtr = buf;
+ while (nLen && *pPtr)
+ {
+ ++pPtr;
+ --nLen;
+ }
+
+ bEnd = ( nReallyRead < sizeof(buf)-1 ) // read less than attempted to read
+ || ( ( nLen > 0 ) // OR it is inside the block we read
+ && ( 0 == *pPtr ) // AND found a string terminator
+ );
+
+ aOutput.append(buf, pPtr - buf);
+ }
+
+ nFilePos += aOutput.getLength();
+ if (rStream.Tell() > nFilePos)
+ rStream.Seek(nFilePos+1); // seek due to FileRead above
+ return aOutput.makeStringAndClear();
+}
+
+OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStream, rtl_TextEncoding eEnc)
+{
+ return OStringToOUString(
+ read_zeroTerminated_uInt8s_ToOString(rStream), eEnc);
+}
+
+/** Attempt to write a prefixed sequence of nUnits 16bit units from an OUString,
+ returned value is number of bytes written */
+std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr,
+ std::size_t nUnits)
+{
+ DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "write_uInt16s_FromOUString: swapping sizeof(sal_Unicode) not implemented" );
+ std::size_t nWritten;
+ if (!rStrm.IsEndianSwap())
+ nWritten = rStrm.WriteBytes(rStr.data(), nUnits * sizeof(sal_Unicode));
+ else
+ {
+ std::size_t nLen = nUnits;
+ sal_Unicode aBuf[384];
+ sal_Unicode* const pTmp = ( nLen > 384 ? new sal_Unicode[nLen] : aBuf);
+ memcpy( pTmp, rStr.data(), nLen * sizeof(sal_Unicode) );
+ sal_Unicode* p = pTmp;
+ const sal_Unicode* const pStop = pTmp + nLen;
+ while ( p < pStop )
+ {
+ SwapNumber( *p );
+ p++;
+ }
+ nWritten = rStrm.WriteBytes( pTmp, nLen * sizeof(sal_Unicode) );
+ if ( pTmp != aBuf )
+ delete [] pTmp;
+ }
+ return nWritten;
+}
+
+bool SvStream::WriteUnicodeOrByteText( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
+{
+ if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
+ {
+ write_uInt16s_FromOUString(*this, rStr, rStr.size());
+ return m_nError == ERRCODE_NONE;
+ }
+ else
+ {
+ OString aStr(OUStringToOString(rStr, eDestCharSet));
+ write_uInt8s_FromOString(*this, aStr, aStr.getLength());
+ return m_nError == ERRCODE_NONE;
+ }
+}
+
+bool SvStream::WriteByteStringLine( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
+{
+ return WriteLine(OUStringToOString(rStr, eDestCharSet));
+}
+
+bool SvStream::WriteLine(std::string_view rStr)
+{
+ WriteBytes(rStr.data(), rStr.size());
+ endl(*this);
+ return m_nError == ERRCODE_NONE;
+}
+
+bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet )
+{
+ if ( eDestCharSet == RTL_TEXTENCODING_UNICODE )
+ WriteUnicode(ch);
+ else
+ {
+ OString aStr(&ch, 1, eDestCharSet);
+ WriteBytes(aStr.getStr(), aStr.getLength());
+ }
+ return m_nError == ERRCODE_NONE;
+}
+
+void SvStream::StartWritingUnicodeText()
+{
+ m_isSwap = false; // Switch to no endian swapping
+ // BOM, Byte Order Mark, U+FEFF, see
+ // http://www.unicode.org/faq/utf_bom.html#BOM
+ // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap
+ WriteUInt16(0xfeff);
+}
+
+void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet )
+{
+ if (!( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
+ eReadBomCharSet == RTL_TEXTENCODING_UNICODE ||
+ eReadBomCharSet == RTL_TEXTENCODING_UTF8))
+ return; // nothing to read
+
+ const sal_uInt64 nOldPos = Tell();
+ bool bGetBack = true;
+ unsigned char nFlag(0);
+ ReadUChar( nFlag );
+ switch ( nFlag )
+ {
+ case 0xfe: // UTF-16BE?
+ if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
+ eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
+ {
+ ReadUChar(nFlag);
+ if (nFlag == 0xff)
+ {
+ SetEndian(SvStreamEndian::BIG);
+ bGetBack = false;
+ }
+ }
+ break;
+ case 0xff: // UTF-16LE?
+ if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
+ eReadBomCharSet == RTL_TEXTENCODING_UNICODE)
+ {
+ ReadUChar(nFlag);
+ if (nFlag == 0xfe)
+ {
+ SetEndian(SvStreamEndian::LITTLE);
+ bGetBack = false;
+ }
+ }
+ break;
+ case 0xef: // UTF-8?
+ if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW ||
+ eReadBomCharSet == RTL_TEXTENCODING_UTF8)
+ {
+ ReadUChar(nFlag);
+ if (nFlag == 0xbb)
+ {
+ ReadUChar(nFlag);
+ if (nFlag == 0xbf)
+ bGetBack = false; // it is UTF-8
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ if (bGetBack)
+ Seek(nOldPos); // no BOM, pure data
+}
+
+sal_uInt64 SvStream::SeekRel(sal_Int64 const nPos)
+{
+ sal_uInt64 nActualPos = Tell();
+
+ if ( nPos >= 0 )
+ {
+ if (SAL_MAX_UINT64 - nActualPos > o3tl::make_unsigned(nPos))
+ nActualPos += nPos;
+ }
+ else
+ {
+ sal_uInt64 const nAbsPos = static_cast<sal_uInt64>(-nPos);
+ if ( nActualPos >= nAbsPos )
+ nActualPos -= nAbsPos;
+ }
+
+ assert((m_pBufPos != nullptr) == bool(m_pRWBuf));
+ if (m_pRWBuf)
+ {
+ m_pBufPos = m_pRWBuf.get() + nActualPos;
+ }
+ return Seek( nActualPos );
+}
+
+template <typename T> SvStream& SvStream::ReadNumber(T& r)
+{
+ T n = 0;
+ readNumberWithoutSwap(n);
+ if (good())
+ {
+ if (m_isSwap)
+ SwapNumber(n);
+ r = n;
+ }
+ return *this;
+}
+
+SvStream& SvStream::ReadUInt16(sal_uInt16& r) { return ReadNumber(r); }
+SvStream& SvStream::ReadUInt32(sal_uInt32& r) { return ReadNumber(r); }
+SvStream& SvStream::ReadUInt64(sal_uInt64& r) { return ReadNumber(r); }
+SvStream& SvStream::ReadInt16(sal_Int16& r) { return ReadNumber(r); }
+SvStream& SvStream::ReadInt32(sal_Int32& r) { return ReadNumber(r); }
+SvStream& SvStream::ReadInt64(sal_Int64& r) { return ReadNumber(r); }
+
+SvStream& SvStream::ReadSChar( signed char& r )
+{
+ if (m_isIoRead && sizeof(signed char) <= m_nBufFree)
+ {
+ r = *m_pBufPos;
+ m_nBufActualPos += sizeof(signed char);
+ m_pBufPos += sizeof(signed char);
+ m_nBufFree -= sizeof(signed char);
+ }
+ else
+ ReadBytes( &r, sizeof(signed char) );
+ return *this;
+}
+
+// Special treatment for Chars due to PutBack
+
+SvStream& SvStream::ReadChar( char& r )
+{
+ if (m_isIoRead && sizeof(char) <= m_nBufFree)
+ {
+ r = *m_pBufPos;
+ m_nBufActualPos += sizeof(char);
+ m_pBufPos += sizeof(char);
+ m_nBufFree -= sizeof(char);
+ }
+ else
+ ReadBytes( &r, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::ReadUChar( unsigned char& r )
+{
+ if (m_isIoRead && sizeof(char) <= m_nBufFree)
+ {
+ r = *m_pBufPos;
+ m_nBufActualPos += sizeof(char);
+ m_pBufPos += sizeof(char);
+ m_nBufFree -= sizeof(char);
+ }
+ else
+ ReadBytes( &r, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::ReadUtf16(sal_Unicode& r) { return ReadNumber(r); }
+
+SvStream& SvStream::ReadCharAsBool( bool& r )
+{
+ if (m_isIoRead && sizeof(char) <= m_nBufFree)
+ {
+ SAL_WARN_IF(
+ *m_pBufPos > 1, "tools.stream", unsigned(*m_pBufPos) << " not 0/1");
+ r = *m_pBufPos != 0;
+ m_nBufActualPos += sizeof(char);
+ m_pBufPos += sizeof(char);
+ m_nBufFree -= sizeof(char);
+ }
+ else
+ {
+ unsigned char c;
+ if (ReadBytes(&c, 1) == 1)
+ {
+ SAL_WARN_IF(c > 1, "tools.stream", unsigned(c) << " not 0/1");
+ r = c != 0;
+ }
+ }
+ return *this;
+}
+
+SvStream& SvStream::ReadFloat(float& r)
+{
+ float n = 0;
+ readNumberWithoutSwap(n);
+ if (good())
+ {
+#if defined UNX
+ if (m_isSwap)
+ SwapFloat(n);
+#endif
+ r = n;
+ }
+ return *this;
+}
+
+SvStream& SvStream::ReadDouble(double& r)
+{
+ double n = 0;
+ readNumberWithoutSwap(n);
+ if (good())
+ {
+#if defined UNX
+ if (m_isSwap)
+ SwapDouble(n);
+#endif
+ r = n;
+ }
+ return *this;
+}
+
+SvStream& SvStream::ReadStream( SvStream& rStream )
+{
+ const sal_uInt32 cBufLen = 0x8000;
+ std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
+
+ sal_uInt32 nCount;
+ do {
+ nCount = ReadBytes( pBuf.get(), cBufLen );
+ rStream.WriteBytes( pBuf.get(), nCount );
+ } while( nCount == cBufLen );
+
+ return *this;
+}
+
+template <typename T> SvStream& SvStream::WriteNumber(T n)
+{
+ if (m_isSwap)
+ SwapNumber(n);
+ writeNumberWithoutSwap(n);
+ return *this;
+}
+
+SvStream& SvStream::WriteUInt16(sal_uInt16 v) { return WriteNumber(v); }
+SvStream& SvStream::WriteUInt32(sal_uInt32 v) { return WriteNumber(v); }
+SvStream& SvStream::WriteUInt64(sal_uInt64 v) { return WriteNumber(v); }
+SvStream& SvStream::WriteInt16(sal_Int16 v) { return WriteNumber(v); }
+SvStream& SvStream::WriteInt32(sal_Int32 v) { return WriteNumber(v); }
+SvStream& SvStream::WriteInt64(sal_Int64 v) { return WriteNumber(v); }
+
+SvStream& SvStream::WriteSChar( signed char v )
+{
+ //SDO
+ if (m_isIoWrite && sizeof(signed char) <= m_nBufFree)
+ {
+ *m_pBufPos = v;
+ m_pBufPos++; // sizeof(char);
+ m_nBufActualPos++;
+ if (m_nBufActualPos > m_nBufActualLen) // Append ?
+ m_nBufActualLen = m_nBufActualPos;
+ m_nBufFree--; // = sizeof(char);
+ m_isDirty = true;
+ }
+ else
+ WriteBytes( &v, sizeof(signed char) );
+ return *this;
+}
+
+// Special treatment for Chars due to PutBack
+
+SvStream& SvStream::WriteChar( char v )
+{
+ //SDO
+ if (m_isIoWrite && sizeof(char) <= m_nBufFree)
+ {
+ *m_pBufPos = v;
+ m_pBufPos++; // sizeof(char);
+ m_nBufActualPos++;
+ if (m_nBufActualPos > m_nBufActualLen) // Append ?
+ m_nBufActualLen = m_nBufActualPos;
+ m_nBufFree--; // = sizeof(char);
+ m_isDirty = true;
+ }
+ else
+ WriteBytes( &v, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::WriteUChar( unsigned char v )
+{
+//SDO
+ if (m_isIoWrite && sizeof(char) <= m_nBufFree)
+ {
+ *reinterpret_cast<unsigned char*>(m_pBufPos) = v;
+ m_pBufPos++; // = sizeof(char);
+ m_nBufActualPos++; // = sizeof(char);
+ if (m_nBufActualPos > m_nBufActualLen) // Append ?
+ m_nBufActualLen = m_nBufActualPos;
+ m_nBufFree--;
+ m_isDirty = true;
+ }
+ else
+ WriteBytes( &v, sizeof(char) );
+ return *this;
+}
+
+SvStream& SvStream::WriteUInt8( sal_uInt8 v )
+{
+ return WriteUChar(v);
+}
+
+SvStream& SvStream::WriteUnicode( sal_Unicode v )
+{
+ return WriteUInt16(v);
+}
+
+SvStream& SvStream::WriteFloat( float v )
+{
+#ifdef UNX
+ if (m_isSwap)
+ SwapFloat(v);
+#endif
+ writeNumberWithoutSwap(v);
+ return *this;
+}
+
+SvStream& SvStream::WriteDouble ( const double& r )
+{
+#if defined UNX
+ if (m_isSwap)
+ {
+ double nHelp = r;
+ SwapDouble(nHelp);
+ writeNumberWithoutSwap(nHelp);
+ return *this;
+ }
+ else
+#endif
+ {
+ writeNumberWithoutSwap(r);
+ }
+ return *this;
+}
+
+SvStream& SvStream::WriteCharPtr( const char* pBuf )
+{
+ WriteBytes( pBuf, strlen(pBuf) );
+ return *this;
+}
+
+SvStream& SvStream::WriteStream( SvStream& rStream )
+{
+ const sal_uInt32 cBufLen = 0x8000;
+ std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
+ sal_uInt32 nCount;
+ do {
+ nCount = rStream.ReadBytes( pBuf.get(), cBufLen );
+ WriteBytes( pBuf.get(), nCount );
+ } while( nCount == cBufLen );
+
+ return *this;
+}
+
+sal_uInt64 SvStream::WriteStream( SvStream& rStream, sal_uInt64 nSize )
+{
+ const sal_uInt32 cBufLen = 0x8000;
+ std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
+ sal_uInt32 nCurBufLen = cBufLen;
+ sal_uInt32 nCount;
+ sal_uInt64 nWriteSize = nSize;
+
+ do
+ {
+ nCurBufLen = std::min<sal_uInt64>(nCurBufLen, nWriteSize);
+ nCount = rStream.ReadBytes(pBuf.get(), nCurBufLen);
+ WriteBytes( pBuf.get(), nCount );
+ nWriteSize -= nCount;
+ }
+ while( nWriteSize && nCount == nCurBufLen );
+
+ return nSize - nWriteSize;
+}
+
+OUString SvStream::ReadUniOrByteString( rtl_TextEncoding eSrcCharSet )
+{
+ // read UTF-16 string directly from stream ?
+ if (eSrcCharSet == RTL_TEXTENCODING_UNICODE)
+ return read_uInt32_lenPrefixed_uInt16s_ToOUString(*this);
+ return read_uInt16_lenPrefixed_uInt8s_ToOUString(*this, eSrcCharSet);
+}
+
+SvStream& SvStream::WriteUniOrByteString( std::u16string_view rStr, rtl_TextEncoding eDestCharSet )
+{
+ // write UTF-16 string directly into stream ?
+ if (eDestCharSet == RTL_TEXTENCODING_UNICODE)
+ write_uInt32_lenPrefixed_uInt16s_FromOUString(*this, rStr);
+ else
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(*this, rStr, eDestCharSet);
+ return *this;
+}
+
+void SvStream::FlushBuffer()
+{
+ if (m_isDirty) // Does stream require a flush?
+ {
+ SeekPos(m_nBufFilePos);
+ if (m_nCryptMask)
+ CryptAndWriteBuffer(m_pRWBuf.get(), m_nBufActualLen);
+ else if (PutData(m_pRWBuf.get(), m_nBufActualLen) != m_nBufActualLen)
+ SetError(SVSTREAM_WRITE_ERROR);
+ m_isDirty = false;
+ }
+}
+
+std::size_t SvStream::ReadBytes( void* pData, std::size_t nCount )
+{
+ std::size_t nSaveCount = nCount;
+
+ if (!m_pRWBuf)
+ {
+ nCount = GetData( pData,nCount);
+ if (m_nCryptMask)
+ EncryptBuffer(pData, nCount);
+ m_nBufFilePos += nCount;
+ }
+ else
+ {
+ // check if block is completely within buffer
+ m_isIoRead = true;
+ m_isIoWrite = false;
+ if (nCount <= o3tl::make_unsigned(m_nBufActualLen - m_nBufActualPos))
+ {
+ // => yes
+ if (nCount != 0)
+ memcpy(pData, m_pBufPos, nCount);
+ m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
+ m_pBufPos += nCount;
+ m_nBufFree = m_nBufFree - static_cast<sal_uInt16>(nCount);
+ }
+ else
+ {
+ FlushBuffer();
+
+ // Does data block fit into buffer?
+ if (nCount > m_nBufSize)
+ {
+ // => No! Thus read directly
+ // into target area without using the buffer
+
+ m_isIoRead = false;
+
+ SeekPos(m_nBufFilePos + m_nBufActualPos);
+ m_nBufActualLen = 0;
+ m_pBufPos = m_pRWBuf.get();
+ nCount = GetData( pData, nCount );
+ if (m_nCryptMask)
+ EncryptBuffer(pData, nCount);
+ m_nBufFilePos += nCount;
+ m_nBufFilePos += m_nBufActualPos;
+ m_nBufActualPos = 0;
+ }
+ else
+ {
+ // => Yes. Fill buffer first, then copy to target area
+
+ m_nBufFilePos += m_nBufActualPos;
+ SeekPos(m_nBufFilePos);
+
+ // TODO: Typecast before GetData, sal_uInt16 nCountTmp
+ std::size_t nCountTmp = GetData( m_pRWBuf.get(), m_nBufSize );
+ if (m_nCryptMask)
+ EncryptBuffer(m_pRWBuf.get(), nCountTmp);
+ m_nBufActualLen = static_cast<sal_uInt16>(nCountTmp);
+ if( nCount > nCountTmp )
+ {
+ nCount = nCountTmp; // trim count back, EOF see below
+ }
+ memcpy( pData, m_pRWBuf.get(), nCount );
+ m_nBufActualPos = static_cast<sal_uInt16>(nCount);
+ m_pBufPos = m_pRWBuf.get() + nCount;
+ }
+ }
+ }
+ m_isEof = false;
+ m_nBufFree = m_nBufActualLen - m_nBufActualPos;
+ if (nCount != nSaveCount && m_nError != ERRCODE_IO_PENDING)
+ m_isEof = true;
+ if (nCount == nSaveCount && m_nError == ERRCODE_IO_PENDING)
+ m_nError = ERRCODE_NONE;
+ return nCount;
+}
+
+std::size_t SvStream::WriteBytes( const void* pData, std::size_t nCount )
+{
+ if( !nCount )
+ return 0;
+
+ if (!m_isWritable)
+ {
+ SetError( ERRCODE_IO_CANTWRITE );
+ return 0;
+ }
+
+ if (!m_pRWBuf)
+ {
+ if (m_nCryptMask)
+ nCount = CryptAndWriteBuffer( pData, nCount );
+ else
+ nCount = PutData( pData, nCount );
+ m_nBufFilePos += nCount;
+ return nCount;
+ }
+
+ m_isIoRead = false;
+ m_isIoWrite = true;
+ if (nCount <= o3tl::make_unsigned(m_nBufSize - m_nBufActualPos))
+ {
+ memcpy( m_pBufPos, pData, nCount );
+ m_nBufActualPos = m_nBufActualPos + static_cast<sal_uInt16>(nCount);
+ // Update length if buffer was updated
+ if (m_nBufActualPos > m_nBufActualLen)
+ m_nBufActualLen = m_nBufActualPos;
+
+ m_pBufPos += nCount;
+ m_isDirty = true;
+ }
+ else
+ {
+ FlushBuffer();
+
+ // Does data block fit into buffer?
+ if (nCount > m_nBufSize)
+ {
+ m_isIoWrite = false;
+ m_nBufFilePos += m_nBufActualPos;
+ m_nBufActualLen = 0;
+ m_nBufActualPos = 0;
+ m_pBufPos = m_pRWBuf.get();
+ SeekPos(m_nBufFilePos);
+ if (m_nCryptMask)
+ nCount = CryptAndWriteBuffer( pData, nCount );
+ else
+ nCount = PutData( pData, nCount );
+ m_nBufFilePos += nCount;
+ }
+ else
+ {
+ // Copy block to buffer
+ memcpy( m_pRWBuf.get(), pData, nCount );
+
+ // Mind the order!
+ m_nBufFilePos += m_nBufActualPos;
+ m_nBufActualPos = static_cast<sal_uInt16>(nCount);
+ m_pBufPos = m_pRWBuf.get() + nCount;
+ m_nBufActualLen = static_cast<sal_uInt16>(nCount);
+ m_isDirty = true;
+ }
+ }
+ m_nBufFree = m_nBufSize - m_nBufActualPos;
+ return nCount;
+}
+
+sal_uInt64 SvStream::Seek(sal_uInt64 const nFilePos)
+{
+ m_isIoRead = m_isIoWrite = false;
+ m_isEof = false;
+ if (!m_pRWBuf)
+ {
+ m_nBufFilePos = SeekPos( nFilePos );
+ DBG_ASSERT(Tell() == m_nBufFilePos,"Out Of Sync!");
+ return m_nBufFilePos;
+ }
+
+ // Is seek position within buffer?
+ if (nFilePos >= m_nBufFilePos && nFilePos <= (m_nBufFilePos + m_nBufActualLen))
+ {
+ m_nBufActualPos = static_cast<sal_uInt16>(nFilePos - m_nBufFilePos);
+ m_pBufPos = m_pRWBuf.get() + m_nBufActualPos;
+ // Update m_nBufFree to avoid crash upon PutBack
+ m_nBufFree = m_nBufActualLen - m_nBufActualPos;
+ }
+ else
+ {
+ FlushBuffer();
+ m_nBufActualLen = 0;
+ m_nBufActualPos = 0;
+ m_pBufPos = m_pRWBuf.get();
+ m_nBufFilePos = SeekPos( nFilePos );
+ }
+ return m_nBufFilePos + m_nBufActualPos;
+}
+
+bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
+{
+ const sal_uInt64 nMaxSeek = rSt.TellEnd();
+ return (nOffset <= nMaxSeek && rSt.Seek(nOffset) == nOffset);
+}
+
+namespace tools
+{
+bool isEmptyFileUrl(const OUString& rUrl)
+{
+ if (!comphelper::isFileUrl(rUrl))
+ {
+ return false;
+ }
+
+ SvFileStream aStream(rUrl, StreamMode::READ);
+ if (!aStream.IsOpen())
+ {
+ return false;
+ }
+
+ return aStream.remainingSize() == 0;
+}
+}
+
+//STREAM_SEEK_TO_END in some of the Seek backends is special cased to be
+//efficient, in others e.g. SotStorageStream it's really horribly slow, and in
+//those this should be overridden
+sal_uInt64 SvStream::remainingSize()
+{
+ sal_uInt64 const nCurr = Tell();
+ sal_uInt64 const nEnd = TellEnd();
+ sal_uInt64 nMaxAvailable = nEnd > nCurr ? (nEnd-nCurr) : 0;
+ return nMaxAvailable;
+}
+
+sal_uInt64 SvStream::TellEnd()
+{
+ FlushBuffer();
+ sal_uInt64 const nCurr = Tell();
+ sal_uInt64 const nEnd = Seek(STREAM_SEEK_TO_END);
+ Seek(nCurr);
+ return nEnd;
+}
+
+void SvStream::Flush()
+{
+ FlushBuffer();
+ if (m_isWritable)
+ FlushData();
+}
+
+void SvStream::RefreshBuffer()
+{
+ FlushBuffer();
+ SeekPos(m_nBufFilePos);
+ m_nBufActualLen = static_cast<sal_uInt16>(GetData( m_pRWBuf.get(), m_nBufSize ));
+ if (m_nBufActualLen && m_nError == ERRCODE_IO_PENDING)
+ m_nError = ERRCODE_NONE;
+ if (m_nCryptMask)
+ EncryptBuffer(m_pRWBuf.get(), static_cast<std::size_t>(m_nBufActualLen));
+ m_isIoRead = m_isIoWrite = false;
+}
+
+SvStream& SvStream::WriteInt32AsString(sal_Int32 nInt32)
+{
+ auto const buffer = OString::number(nInt32);
+ WriteBytes(buffer.getStr(), buffer.length);
+ return *this;
+}
+
+SvStream& SvStream::WriteUInt32AsString(sal_uInt32 nUInt32)
+{
+ auto const buffer = OString::number(nUInt32);
+ WriteBytes(buffer.getStr(), buffer.length);
+ return *this;
+}
+
+#define CRYPT_BUFSIZE 1024
+
+/// Encrypt and write
+std::size_t SvStream::CryptAndWriteBuffer( const void* pStart, std::size_t nLen)
+{
+ unsigned char pTemp[CRYPT_BUFSIZE];
+ unsigned char const * pDataPtr = static_cast<unsigned char const *>(pStart);
+ std::size_t nCount = 0;
+ std::size_t nBufCount;
+ unsigned char nMask = m_nCryptMask;
+ do
+ {
+ if( nLen >= CRYPT_BUFSIZE )
+ nBufCount = CRYPT_BUFSIZE;
+ else
+ nBufCount = nLen;
+ nLen -= nBufCount;
+ memcpy( pTemp, pDataPtr, static_cast<sal_uInt16>(nBufCount) );
+ // ******** Encrypt ********
+ for (unsigned char & rn : pTemp)
+ {
+ unsigned char aCh = rn;
+ aCh ^= nMask;
+ swapNibbles(aCh);
+ rn = aCh;
+ }
+ // *************************
+ nCount += PutData( pTemp, nBufCount );
+ pDataPtr += nBufCount;
+ }
+ while ( nLen );
+ return nCount;
+}
+
+void SvStream::EncryptBuffer(void* pStart, std::size_t nLen) const
+{
+ unsigned char* pTemp = static_cast<unsigned char*>(pStart);
+ unsigned char nMask = m_nCryptMask;
+
+ for ( std::size_t n=0; n < nLen; n++, pTemp++ )
+ {
+ unsigned char aCh = *pTemp;
+ swapNibbles(aCh);
+ aCh ^= nMask;
+ *pTemp = aCh;
+ }
+}
+
+static unsigned char implGetCryptMask(const char* pStr, sal_Int32 nLen, tools::Long nVersion)
+{
+ unsigned char nCryptMask = 0;
+
+ if (!nLen)
+ return nCryptMask;
+
+ if( nVersion <= SOFFICE_FILEFORMAT_31 )
+ {
+ while( nLen )
+ {
+ nCryptMask ^= *pStr;
+ pStr++;
+ nLen--;
+ }
+ }
+ else // BugFix #25888#
+ {
+ for( sal_Int32 i = 0; i < nLen; i++ ) {
+ nCryptMask ^= pStr[i];
+ if( nCryptMask & 0x80 ) {
+ nCryptMask <<= 1;
+ nCryptMask++;
+ }
+ else
+ nCryptMask <<= 1;
+ }
+ }
+
+ if( !nCryptMask )
+ nCryptMask = 67;
+
+ return nCryptMask;
+}
+
+void SvStream::SetCryptMaskKey(const OString& rCryptMaskKey)
+{
+ m_aCryptMaskKey = rCryptMaskKey;
+ m_nCryptMask = implGetCryptMask(m_aCryptMaskKey.getStr(),
+ m_aCryptMaskKey.getLength(), GetVersion());
+}
+
+bool SvStream::SetStreamSize(sal_uInt64 const nSize)
+{
+#ifdef DBG_UTIL
+ sal_uInt64 nFPos = Tell();
+#endif
+ sal_uInt16 nBuf = m_nBufSize;
+ SetBufferSize( 0 );
+ SetSize( nSize );
+ if (nSize < m_nBufFilePos)
+ {
+ m_nBufFilePos = nSize;
+ }
+ SetBufferSize( nBuf );
+#ifdef DBG_UTIL
+ DBG_ASSERT(Tell()==nFPos,"SetStreamSize failed");
+#endif
+ return (m_nError == ERRCODE_NONE);
+}
+
+SvStream& endl( SvStream& rStr )
+{
+ LineEnd eDelim = rStr.GetLineDelimiter();
+ if ( eDelim == LINEEND_CR )
+ rStr.WriteChar('\r');
+ else if( eDelim == LINEEND_LF )
+ rStr.WriteChar('\n');
+ else
+ rStr.WriteChar('\r').WriteChar('\n');
+ return rStr;
+}
+
+SvStream& endlu( SvStream& rStrm )
+{
+ switch ( rStrm.GetLineDelimiter() )
+ {
+ case LINEEND_CR :
+ rStrm.WriteUnicode('\r');
+ break;
+ case LINEEND_LF :
+ rStrm.WriteUnicode('\n');
+ break;
+ default:
+ rStrm.WriteUnicode('\r').WriteUnicode('\n');
+ }
+ return rStrm;
+}
+
+SvStream& endlub( SvStream& rStrm )
+{
+ if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
+ return endlu( rStrm );
+ else
+ return endl( rStrm );
+}
+
+SvMemoryStream::SvMemoryStream( void* pBuffer, std::size_t bufSize,
+ StreamMode eMode )
+{
+ if( eMode & StreamMode::WRITE )
+ m_isWritable = true;
+ else
+ m_isWritable = false;
+ nEndOfData = bufSize;
+ bOwnsData = false;
+ pBuf = static_cast<sal_uInt8 *>(pBuffer);
+ nResize = 0;
+ nSize = bufSize;
+ nPos = 0;
+ SetBufferSize( 0 );
+}
+
+SvMemoryStream::SvMemoryStream( std::size_t nInitSize, std::size_t nResizeOffset )
+{
+ m_isWritable = true;
+ bOwnsData = true;
+ nEndOfData = 0;
+ nResize = nResizeOffset;
+ nPos = 0;
+ pBuf = nullptr;
+ if( nResize != 0 && nResize < 16 )
+ nResize = 16;
+ if( nInitSize )
+ AllocateMemory( nInitSize );
+ nSize = nInitSize;
+ SetBufferSize( 64 );
+}
+
+SvMemoryStream::~SvMemoryStream()
+{
+ if( pBuf )
+ {
+ if( bOwnsData )
+ FreeMemory();
+ else
+ FlushBuffer();
+ }
+}
+
+void SvMemoryStream::SetBuffer( void* pNewBuf, std::size_t nCount,
+ std::size_t nEOF )
+{
+ SetBufferSize( 0 ); // Init buffering in the base class
+ Seek( 0 );
+ if( bOwnsData && pNewBuf != pBuf )
+ FreeMemory();
+
+ pBuf = static_cast<sal_uInt8 *>(pNewBuf);
+ nPos = 0;
+ nSize = nCount;
+ nResize = 0;
+ bOwnsData = false;
+
+ if( nEOF > nCount )
+ nEOF = nCount;
+ nEndOfData = nEOF;
+
+ ResetError();
+}
+
+std::size_t SvMemoryStream::GetData( void* pData, std::size_t nCount )
+{
+ std::size_t nMaxCount = nEndOfData-nPos;
+ if( nCount > nMaxCount )
+ nCount = nMaxCount;
+ if (nCount != 0)
+ {
+ memcpy( pData, pBuf+nPos, nCount );
+ }
+ nPos += nCount;
+ return nCount;
+}
+
+std::size_t SvMemoryStream::PutData( const void* pData, std::size_t nCount )
+{
+ if( GetError() )
+ return 0;
+
+ std::size_t nMaxCount = nSize-nPos;
+
+ // check for overflow
+ if( nCount > nMaxCount )
+ {
+ if( nResize == 0 )
+ {
+ // copy as much as possible
+ nCount = nMaxCount;
+ SetError( SVSTREAM_OUTOFMEMORY );
+ }
+ else
+ {
+ tools::Long nNewResize;
+ if( nSize && nSize > nResize )
+ nNewResize = nSize;
+ else
+ nNewResize = nResize;
+
+ if( (nCount-nMaxCount) < nResize )
+ {
+ // lacking memory is smaller than nResize,
+ // resize accordingly
+ if( !ReAllocateMemory( nNewResize) )
+ {
+ nCount = 0;
+ SetError( SVSTREAM_WRITE_ERROR );
+ }
+ }
+ else
+ {
+ // lacking memory is larger than nResize,
+ // resize by (nCount-nMaxCount) + resize offset
+ if( !ReAllocateMemory( nCount-nMaxCount+nNewResize ) )
+ {
+ nCount = 0;
+ SetError( SVSTREAM_WRITE_ERROR );
+ }
+ }
+ }
+ }
+ assert(pBuf && "Possibly Reallocate failed");
+ memcpy( pBuf+nPos, pData, nCount);
+
+ nPos += nCount;
+ if( nPos > nEndOfData )
+ nEndOfData = nPos;
+ return nCount;
+}
+
+sal_uInt64 SvMemoryStream::SeekPos(sal_uInt64 const nNewPos)
+{
+ // nEndOfData: First position in stream not allowed to read from
+ // nSize: Size of allocated buffer
+
+ // check if a truncated STREAM_SEEK_TO_END was passed
+ assert(nNewPos != SAL_MAX_UINT32);
+ if( nNewPos < nEndOfData )
+ nPos = nNewPos;
+ else if( nNewPos == STREAM_SEEK_TO_END )
+ nPos = nEndOfData;
+ else
+ {
+ if( nNewPos >= nSize ) // Does buffer need extension?
+ {
+ if( nResize ) // Is extension possible?
+ {
+ tools::Long nDiff = static_cast<tools::Long>(nNewPos - nSize + 1);
+ nDiff += static_cast<tools::Long>(nResize);
+ ReAllocateMemory( nDiff );
+ nPos = nNewPos;
+ nEndOfData = nNewPos;
+ }
+ else // Extension not possible, set pos to end of data
+ {
+ // SetError( SVSTREAM_OUTOFMEMORY );
+ nPos = nEndOfData;
+ }
+ }
+ else // Expand buffer size
+ {
+ nPos = nNewPos;
+ nEndOfData = nNewPos;
+ }
+ }
+ return nPos;
+}
+
+void SvMemoryStream::FlushData()
+{
+}
+
+void SvMemoryStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+void SvMemoryStream::AllocateMemory( std::size_t nNewSize )
+{
+ pBuf = new sal_uInt8[nNewSize];
+}
+
+// (using Bozo algorithm)
+bool SvMemoryStream::ReAllocateMemory( tools::Long nDiff )
+{
+ if (!m_isWritable || !bOwnsData)
+ return false;
+
+ bool bRetVal = false;
+ tools::Long nTemp = static_cast<tools::Long>(nSize);
+ nTemp += nDiff;
+ std::size_t nNewSize = static_cast<std::size_t>(nTemp);
+
+ if( nNewSize )
+ {
+ sal_uInt8* pNewBuf = new sal_uInt8[nNewSize];
+
+ bRetVal = true; // Success!
+ if( nNewSize < nSize ) // Are we shrinking?
+ {
+ memcpy( pNewBuf, pBuf, nNewSize );
+ if( nPos > nNewSize )
+ nPos = 0;
+ if( nEndOfData >= nNewSize )
+ nEndOfData = nNewSize-1;
+ }
+ else
+ {
+ if (nSize != 0)
+ {
+ memcpy( pNewBuf, pBuf, nSize );
+ }
+ memset(pNewBuf + nSize, 0x00, nNewSize - nSize);
+ }
+
+ FreeMemory();
+
+ pBuf = pNewBuf;
+ nSize = nNewSize;
+ }
+ else
+ {
+ bRetVal = true;
+ FreeMemory();
+ pBuf = nullptr;
+ nSize = 0;
+ nEndOfData = 0;
+ nPos = 0;
+ }
+
+ return bRetVal;
+}
+
+void SvMemoryStream::FreeMemory()
+{
+ assert(bOwnsData);
+ if (bOwnsData)
+ {
+ delete[] pBuf;
+ pBuf = nullptr;
+ }
+}
+
+void* SvMemoryStream::SwitchBuffer()
+{
+ FlushBuffer();
+ if( !bOwnsData )
+ return nullptr;
+ Seek( STREAM_SEEK_TO_BEGIN );
+
+ void* pRetVal = pBuf;
+ pBuf = nullptr;
+ nEndOfData = 0;
+ nResize = 64;
+ nPos = 0;
+
+ ResetError();
+
+ std::size_t nInitSize = 512;
+ AllocateMemory(nInitSize);
+ nSize = nInitSize;
+
+ SetBufferSize( 64 );
+ return pRetVal;
+}
+
+void SvMemoryStream::SetSize(sal_uInt64 const nNewSize)
+{
+ if (!m_isWritable)
+ {
+ SetError(SVSTREAM_INVALID_HANDLE);
+ return;
+ }
+
+ tools::Long nDiff = static_cast<tools::Long>(nNewSize) - static_cast<tools::Long>(nSize);
+ ReAllocateMemory( nDiff );
+}
+
+// Create an OString of nLen bytes from rStream
+// coverity[ +taint_sanitize ]
+OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen)
+{
+ rtl_String *pStr = nullptr;
+ if (nLen)
+ {
+ nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
+ //limit allocation to size of file, but + 1 to set eof state
+ nLen = std::min<sal_uInt64>(nLen, rStrm.remainingSize() + 1);
+ //alloc a (ref-count 1) rtl_String of the desired length.
+ //rtl_String's buffer is uninitialized, except for null termination
+ pStr = rtl_string_alloc(sal::static_int_cast<sal_Int32>(nLen));
+ SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
+ if (pStr)
+ {
+ std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen);
+ if (nWasRead != nLen)
+ {
+ //on (typically unlikely) short read set length to what we could
+ //read, and null terminate. Excess buffer capacity remains of
+ //course, could create a (true) replacement OString if it matters.
+ pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
+ pStr->buffer[pStr->length] = 0;
+ }
+ }
+ }
+
+ //take ownership of buffer and return, otherwise return empty string
+ return pStr ? OString(pStr, SAL_NO_ACQUIRE) : OString();
+}
+
+// Create an OUString of nLen sal_Unicode code units from rStream
+// coverity[ +taint_sanitize ]
+OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen)
+{
+ rtl_uString *pStr = nullptr;
+ if (nLen)
+ {
+ nLen = std::min<std::size_t>(nLen, SAL_MAX_INT32);
+ //limit allocation to size of file, but + 1 to set eof state
+ nLen = o3tl::sanitizing_min<sal_uInt64>(nLen, (rStrm.remainingSize() + 2) / 2);
+ //alloc a (ref-count 1) rtl_uString of the desired length.
+ //rtl_String's buffer is uninitialized, except for null termination
+ pStr = rtl_uString_alloc(sal::static_int_cast<sal_Int32>(nLen));
+ SAL_WARN_IF(!pStr, "tools.stream", "allocation failed");
+ if (pStr)
+ {
+ std::size_t nWasRead = rStrm.ReadBytes(pStr->buffer, nLen*2)/2;
+ if (nWasRead != nLen)
+ {
+ //on (typically unlikely) short read set length to what we could
+ //read, and null terminate. Excess buffer capacity remains of
+ //course, could create a (true) replacement OUString if it matters.
+ pStr->length = sal::static_int_cast<sal_Int32>(nWasRead);
+ pStr->buffer[pStr->length] = 0;
+ }
+ if (rStrm.IsEndianSwap())
+ {
+ for (sal_Int32 i = 0; i < pStr->length; ++i)
+ pStr->buffer[i] = OSL_SWAPWORD(pStr->buffer[i]);
+ }
+ }
+ }
+
+ // take ownership of buffer and return, otherwise return empty string
+ return pStr ? OUString(pStr, SAL_NO_ACQUIRE) : OUString();
+}
+
+namespace
+{
+ template <typename T, typename O> T tmpl_convertLineEnd(const T &rIn, LineEnd eLineEnd)
+ {
+ // Determine linebreaks and compute length
+ bool bConvert = false; // Needs conversion
+ sal_Int32 nStrLen = rIn.getLength();
+ sal_Int32 nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
+ sal_Int32 nLen = 0; // Target length
+ sal_Int32 i = 0; // Source counter
+
+ while (i < nStrLen)
+ {
+ // \r or \n causes linebreak
+ if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
+ {
+ nLen = nLen + nLineEndLen;
+
+ // If set already, skip expensive test
+ if ( !bConvert )
+ {
+ // Do we need to convert?
+ if ( ((eLineEnd != LINEEND_LF) && (rIn[i] == '\n')) ||
+ ((eLineEnd == LINEEND_CRLF) && (i+1) < nStrLen && (rIn[i+1] != '\n')) ||
+ ((eLineEnd == LINEEND_LF) &&
+ ((rIn[i] == '\r') || ((i+1) < nStrLen && rIn[i+1] == '\r'))) ||
+ ((eLineEnd == LINEEND_CR) &&
+ ((rIn[i] == '\n') || ((i+1) < nStrLen && rIn[i+1] == '\n'))) )
+ bConvert = true;
+ }
+
+ // skip char if \r\n or \n\r
+ if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
+ (rIn[i] != rIn[i+1]) )
+ ++i;
+ }
+ else
+ ++nLen;
+ ++i;
+ }
+
+ if (!bConvert)
+ return rIn;
+
+ // convert linebreaks, insert string
+ O aNewData(nLen);
+ i = 0;
+ while (i < nStrLen)
+ {
+ // \r or \n causes linebreak
+ if ( (rIn[i] == '\r') || (rIn[i] == '\n') )
+ {
+ if ( eLineEnd == LINEEND_CRLF )
+ {
+ aNewData.append('\r');
+ aNewData.append('\n');
+ }
+ else
+ {
+ if ( eLineEnd == LINEEND_CR )
+ aNewData.append('\r');
+ else
+ aNewData.append('\n');
+ }
+
+ if ( (i+1) < nStrLen && ((rIn[i+1] == '\r') || (rIn[i+1] == '\n')) &&
+ (rIn[i] != rIn[i+1]) )
+ ++i;
+ }
+ else
+ {
+ aNewData.append(rIn[i]);
+ }
+
+ ++i;
+ }
+
+ return aNewData.makeStringAndClear();
+ }
+}
+
+OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
+{
+ return tmpl_convertLineEnd<OString, OStringBuffer>(rIn, eLineEnd);
+}
+
+OUString convertLineEnd(const OUString &rIn, LineEnd eLineEnd)
+{
+ return tmpl_convertLineEnd<OUString, OUStringBuffer>(rIn, eLineEnd);
+}
+
+std::size_t write_uInt32_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
+ std::u16string_view rStr)
+{
+ std::size_t nWritten = 0;
+ sal_uInt32 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt32>::max());
+ SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
+ "tools.stream",
+ "string too long for prefix count to fit in output type");
+ rStrm.WriteUInt32(nUnits);
+ if (rStrm.good())
+ {
+ nWritten += sizeof(sal_uInt32);
+ nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
+ }
+ return nWritten;
+}
+
+std::size_t write_uInt16_lenPrefixed_uInt16s_FromOUString(SvStream& rStrm,
+ std::u16string_view rStr)
+{
+ std::size_t nWritten = 0;
+ sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
+ SAL_WARN_IF(nUnits != rStr.size(),
+ "tools.stream",
+ "string too long for prefix count to fit in output type");
+ rStrm.WriteUInt16(nUnits);
+ if (rStrm.good())
+ {
+ nWritten += sizeof(nUnits);
+ nWritten += write_uInt16s_FromOUString(rStrm, rStr, nUnits);
+ }
+ return nWritten;
+}
+
+std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm,
+ std::string_view rStr)
+{
+ std::size_t nWritten = 0;
+ sal_uInt16 nUnits = std::min<std::size_t>(rStr.size(), std::numeric_limits<sal_uInt16>::max());
+ SAL_WARN_IF(static_cast<std::size_t>(nUnits) != static_cast<std::size_t>(rStr.size()),
+ "tools.stream",
+ "string too long for sal_uInt16 count to fit in output type");
+ rStrm.WriteUInt16( nUnits );
+ if (rStrm.good())
+ {
+ nWritten += sizeof(sal_uInt16);
+ nWritten += write_uInt8s_FromOString(rStrm, rStr, nUnits);
+ }
+ return nWritten;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tools/source/stream/strmunx.cxx b/tools/source/stream/strmunx.cxx
new file mode 100644
index 000000000..5964529f3
--- /dev/null
+++ b/tools/source/stream/strmunx.cxx
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <tools/stream.hxx>
+#include <map>
+
+#include <mutex>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+
+#include <osl/file.hxx>
+#include <osl/detail/file.h>
+
+using namespace osl;
+
+// InternalLock ----------------------------------------------------------------
+
+namespace {
+
+std::mutex& LockMutex()
+{
+ static std::mutex SINGLETON;
+ return SINGLETON;
+}
+
+std::map<SvFileStream const *, osl::DirectoryItem> gLocks;
+
+bool lockFile( const SvFileStream* pStream )
+{
+ osl::DirectoryItem aItem;
+ if (osl::DirectoryItem::get( pStream->GetFileName(), aItem) != osl::FileBase::E_None )
+ {
+ SAL_INFO("tools.stream", "Failed to lookup stream for locking");
+ return true;
+ }
+
+ osl::FileStatus aStatus( osl_FileStatus_Mask_Type );
+ if ( aItem.getFileStatus( aStatus ) != osl::FileBase::E_None )
+ {
+ SAL_INFO("tools.stream", "Failed to stat stream for locking");
+ return true;
+ }
+ if( aStatus.getFileType() == osl::FileStatus::Directory )
+ return true;
+
+ std::unique_lock aGuard( LockMutex() );
+ for( const auto& [rLockStream, rLockItem] : gLocks )
+ {
+ if( aItem.isIdenticalTo( rLockItem ) )
+ {
+ StreamMode nLockMode = rLockStream->GetStreamMode();
+ StreamMode nNewMode = pStream->GetStreamMode();
+ bool bDenyByOptions = (nLockMode & StreamMode::SHARE_DENYALL) ||
+ ( (nLockMode & StreamMode::SHARE_DENYWRITE) && (nNewMode & StreamMode::WRITE) ) ||
+ ( (nLockMode & StreamMode::SHARE_DENYREAD) && (nNewMode & StreamMode::READ) );
+
+ if( bDenyByOptions )
+ {
+ return false; // file is already locked
+ }
+ }
+ }
+ gLocks[pStream] = aItem;
+ return true;
+}
+
+void unlockFile( SvFileStream const * pStream )
+{
+ std::unique_lock aGuard( LockMutex() );
+ gLocks.erase(pStream);
+}
+
+}
+
+// StreamData ------------------------------------------------------------------
+
+class StreamData
+{
+public:
+ oslFileHandle rHandle;
+
+ StreamData() : rHandle( nullptr ) { }
+};
+
+static ErrCode GetSvError( int nErrno )
+{
+ static struct { int nErr; ErrCode sv; } const errArr[] =
+ {
+ { 0, ERRCODE_NONE },
+ { EACCES, SVSTREAM_ACCESS_DENIED },
+ { EBADF, SVSTREAM_INVALID_HANDLE },
+#if defined(NETBSD) || \
+ defined(FREEBSD) || defined(MACOSX) || defined(OPENBSD) || \
+ defined(__FreeBSD_kernel__) || defined (AIX) || defined(DRAGONFLY) || \
+ defined(IOS) || defined(HAIKU)
+ { EDEADLK, SVSTREAM_LOCKING_VIOLATION },
+#else
+ { EDEADLOCK, SVSTREAM_LOCKING_VIOLATION },
+#endif
+ { EINVAL, SVSTREAM_INVALID_PARAMETER },
+ { EMFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ENFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ENOENT, SVSTREAM_FILE_NOT_FOUND },
+ { EPERM, SVSTREAM_ACCESS_DENIED },
+ { EROFS, SVSTREAM_ACCESS_DENIED },
+ { EAGAIN, SVSTREAM_LOCKING_VIOLATION },
+ { EISDIR, SVSTREAM_PATH_NOT_FOUND },
+ { ELOOP, SVSTREAM_PATH_NOT_FOUND },
+#if !defined(NETBSD) && !defined (FREEBSD) && \
+ !defined(MACOSX) && !defined(OPENBSD) && !defined(__FreeBSD_kernel__) && \
+ !defined(DRAGONFLY)
+ { EMULTIHOP, SVSTREAM_PATH_NOT_FOUND },
+ { ENOLINK, SVSTREAM_PATH_NOT_FOUND },
+#endif
+ { ENOTDIR, SVSTREAM_PATH_NOT_FOUND },
+ { ETXTBSY, SVSTREAM_ACCESS_DENIED },
+ { EEXIST, SVSTREAM_CANNOT_MAKE },
+ { ENOSPC, SVSTREAM_DISK_FULL },
+ { int(0xFFFF), SVSTREAM_GENERALERROR }
+ };
+
+ ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
+ int i=0;
+ do
+ {
+ if ( errArr[i].nErr == nErrno )
+ {
+ nRetVal = errArr[i].sv;
+ break;
+ }
+ ++i;
+ }
+ while( errArr[i].nErr != 0xFFFF );
+ return nRetVal;
+}
+
+static ErrCode GetSvError( oslFileError nErrno )
+{
+ static struct { oslFileError nErr; ErrCode sv; } const errArr[] =
+ {
+ { osl_File_E_None, ERRCODE_NONE },
+ { osl_File_E_ACCES, SVSTREAM_ACCESS_DENIED },
+ { osl_File_E_BADF, SVSTREAM_INVALID_HANDLE },
+ { osl_File_E_DEADLK, SVSTREAM_LOCKING_VIOLATION },
+ { osl_File_E_INVAL, SVSTREAM_INVALID_PARAMETER },
+ { osl_File_E_MFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { osl_File_E_NFILE, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { osl_File_E_NOENT, SVSTREAM_FILE_NOT_FOUND },
+ { osl_File_E_PERM, SVSTREAM_ACCESS_DENIED },
+ { osl_File_E_ROFS, SVSTREAM_ACCESS_DENIED },
+ { osl_File_E_AGAIN, SVSTREAM_LOCKING_VIOLATION },
+ { osl_File_E_ISDIR, SVSTREAM_PATH_NOT_FOUND },
+ { osl_File_E_LOOP, SVSTREAM_PATH_NOT_FOUND },
+ { osl_File_E_MULTIHOP, SVSTREAM_PATH_NOT_FOUND },
+ { osl_File_E_NOLINK, SVSTREAM_PATH_NOT_FOUND },
+ { osl_File_E_NOTDIR, SVSTREAM_PATH_NOT_FOUND },
+ { osl_File_E_EXIST, SVSTREAM_CANNOT_MAKE },
+ { osl_File_E_NOSPC, SVSTREAM_DISK_FULL },
+ { oslFileError(0xFFFF), SVSTREAM_GENERALERROR }
+ };
+
+ ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
+ int i=0;
+ do
+ {
+ if ( errArr[i].nErr == nErrno )
+ {
+ nRetVal = errArr[i].sv;
+ break;
+ }
+ ++i;
+ }
+ while( errArr[i].nErr != oslFileError(0xFFFF) );
+ return nRetVal;
+}
+
+SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nOpenMode )
+{
+ bIsOpen = false;
+ m_isWritable = false;
+ pInstanceData.reset(new StreamData);
+
+ SetBufferSize( 1024 );
+ // convert URL to SystemPath, if necessary
+ OUString aSystemFileName;
+ if( FileBase::getSystemPathFromFileURL( rFileName , aSystemFileName )
+ != FileBase::E_None )
+ {
+ aSystemFileName = rFileName;
+ }
+ Open( aSystemFileName, nOpenMode );
+}
+
+SvFileStream::SvFileStream()
+{
+ bIsOpen = false;
+ m_isWritable = false;
+ pInstanceData.reset(new StreamData);
+ SetBufferSize( 1024 );
+}
+
+SvFileStream::~SvFileStream()
+{
+ Close();
+}
+
+std::size_t SvFileStream::GetData( void* pData, std::size_t nSize )
+{
+ SAL_INFO("tools", OString::number(static_cast<sal_Int64>(nSize)) << " Bytes from " << aFilename);
+
+ sal_uInt64 nRead = 0;
+ if ( IsOpen() )
+ {
+ oslFileError rc = osl_readFile(pInstanceData->rHandle,pData,static_cast<sal_uInt64>(nSize),&nRead);
+ if ( rc != osl_File_E_None )
+ {
+ SetError( ::GetSvError( rc ));
+ return -1;
+ }
+ }
+ return static_cast<std::size_t>(nRead);
+}
+
+std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize )
+{
+ SAL_INFO("tools", OString::number(static_cast<sal_Int64>(nSize)) << " Bytes to " << aFilename);
+
+ sal_uInt64 nWrite = 0;
+ if ( IsOpen() )
+ {
+ oslFileError rc = osl_writeFile(pInstanceData->rHandle,pData,static_cast<sal_uInt64>(nSize),&nWrite);
+ if ( rc != osl_File_E_None )
+ {
+ SetError( ::GetSvError( rc ) );
+ return -1;
+ }
+ else if( !nWrite )
+ SetError( SVSTREAM_DISK_FULL );
+ }
+ return static_cast<std::size_t>(nWrite);
+}
+
+sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
+{
+ // check if a truncated STREAM_SEEK_TO_END was passed
+ assert(nPos != sal_uInt64(sal_uInt32(STREAM_SEEK_TO_END)));
+ if ( IsOpen() )
+ {
+ oslFileError rc;
+ sal_uInt64 nNewPos;
+ if ( nPos != STREAM_SEEK_TO_END )
+ rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_Absolut, nPos );
+ else
+ rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_End, 0 );
+
+ if ( rc != osl_File_E_None )
+ {
+ SetError( SVSTREAM_SEEK_ERROR );
+ return 0;
+ }
+ if ( nPos != STREAM_SEEK_TO_END )
+ return nPos;
+ osl_getFilePos( pInstanceData->rHandle, &nNewPos );
+ return nNewPos;
+ }
+ SetError( SVSTREAM_GENERALERROR );
+ return 0;
+}
+
+void SvFileStream::FlushData()
+{
+ auto rc = osl_syncFile(pInstanceData->rHandle);
+ if (rc != osl_File_E_None)
+ SetError( ::GetSvError( rc ));
+ }
+
+bool SvFileStream::LockFile()
+{
+ int nLockMode = 0;
+
+ if ( ! IsOpen() )
+ return false;
+
+ if (m_eStreamMode & StreamMode::SHARE_DENYALL)
+ {
+ if (m_isWritable)
+ nLockMode = F_WRLCK;
+ else
+ nLockMode = F_RDLCK;
+ }
+
+ if (m_eStreamMode & StreamMode::SHARE_DENYREAD)
+ {
+ if (m_isWritable)
+ nLockMode = F_WRLCK;
+ else
+ {
+ SetError(SVSTREAM_LOCKING_VIOLATION);
+ return false;
+ }
+ }
+
+ if (m_eStreamMode & StreamMode::SHARE_DENYWRITE)
+ {
+ if (m_isWritable)
+ nLockMode = F_WRLCK;
+ else
+ nLockMode = F_RDLCK;
+ }
+
+ if (!nLockMode)
+ return true;
+
+ if( !lockFile( this ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "InternalLock on %s failed\n",
+ OUStringToOString(aFilename, osl_getThreadTextEncoding()).getStr() );
+#endif
+ return false;
+ }
+
+ return true;
+}
+
+void SvFileStream::UnlockFile()
+{
+ if ( ! IsOpen() )
+ return;
+
+ unlockFile( this );
+}
+
+void SvFileStream::Open( const OUString& rFilename, StreamMode nOpenMode )
+{
+ sal_uInt32 uFlags;
+ oslFileHandle nHandleTmp;
+
+ Close();
+ errno = 0;
+ m_eStreamMode = nOpenMode;
+ m_eStreamMode &= ~StreamMode::TRUNC; // don't truncate on reopen
+
+ aFilename = rFilename;
+
+ SAL_INFO("tools", aFilename);
+
+ OUString aFileURL;
+ osl::DirectoryItem aItem;
+ osl::FileStatus aStatus( osl_FileStatus_Mask_Type | osl_FileStatus_Mask_LinkTargetURL );
+
+ // FIXME: we really need to switch to a pure URL model ...
+ if ( osl::File::getFileURLFromSystemPath( aFilename, aFileURL ) != osl::FileBase::E_None )
+ aFileURL = aFilename;
+
+ // don't both stat()ing a temporary file, unnecessary
+ bool bStatValid = true;
+ if (!(nOpenMode & StreamMode::TEMPORARY))
+ {
+ bStatValid = ( osl::DirectoryItem::get( aFileURL, aItem) == osl::FileBase::E_None &&
+ aItem.getFileStatus( aStatus ) == osl::FileBase::E_None );
+
+ // SvFileStream can't open a directory
+ if( bStatValid && aStatus.getFileType() == osl::FileStatus::Directory )
+ {
+ SetError( ::GetSvError( EISDIR ) );
+ return;
+ }
+ }
+
+ if ( !( nOpenMode & StreamMode::WRITE ) )
+ uFlags = osl_File_OpenFlag_Read;
+ else if ( !( nOpenMode & StreamMode::READ ) )
+ uFlags = osl_File_OpenFlag_Write;
+ else
+ uFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write;
+
+ // Fix (MDA, 18.01.95): Don't open with O_CREAT upon RD_ONLY
+ // Important for Read-Only-Filesystems (e.g, CDROM)
+ if ( (!( nOpenMode & StreamMode::NOCREATE )) && ( uFlags != osl_File_OpenFlag_Read ) )
+ uFlags |= osl_File_OpenFlag_Create;
+ if ( nOpenMode & StreamMode::TRUNC )
+ uFlags |= osl_File_OpenFlag_Trunc;
+
+ uFlags |= osl_File_OpenFlag_NoExcl | osl_File_OpenFlag_NoLock;
+
+ if ( nOpenMode & StreamMode::WRITE)
+ {
+ if ( nOpenMode & StreamMode::COPY_ON_SYMLINK )
+ {
+ if ( bStatValid && aStatus.getFileType() == osl::FileStatus::Link &&
+ aStatus.getLinkTargetURL().getLength() > 0 )
+ {
+ // delete the symbolic link, and replace it with the contents of the link
+ if (osl::File::remove( aFileURL ) == osl::FileBase::E_None )
+ {
+ File::copy( aStatus.getLinkTargetURL(), aFileURL );
+#if OSL_DEBUG_LEVEL > 0
+ fprintf( stderr,
+ "Removing link and replacing with file contents (%s) -> (%s).\n",
+ OUStringToOString( aStatus.getLinkTargetURL(),
+ RTL_TEXTENCODING_UTF8).getStr(),
+ OUStringToOString( aFileURL,
+ RTL_TEXTENCODING_UTF8).getStr() );
+#endif
+ }
+ }
+ }
+ }
+
+ oslFileError rc = osl_openFile( aFileURL.pData, &nHandleTmp, uFlags );
+ if ( rc != osl_File_E_None )
+ {
+ if ( uFlags & osl_File_OpenFlag_Write )
+ {
+ // Change to read-only
+ uFlags &= ~osl_File_OpenFlag_Write;
+ rc = osl_openFile( aFileURL.pData, &nHandleTmp, uFlags );
+ }
+ }
+ if ( rc == osl_File_E_None )
+ {
+ pInstanceData->rHandle = nHandleTmp;
+ bIsOpen = true;
+ if ( uFlags & osl_File_OpenFlag_Write )
+ m_isWritable = true;
+
+ if ( !LockFile() ) // whole file
+ {
+ osl_closeFile( nHandleTmp );
+ bIsOpen = false;
+ m_isWritable = false;
+ pInstanceData->rHandle = nullptr;
+ }
+ }
+ else
+ SetError( ::GetSvError( rc ) );
+}
+
+void SvFileStream::Close()
+{
+ UnlockFile();
+
+ if ( IsOpen() )
+ {
+ SAL_INFO("tools", "Closing " << aFilename);
+ FlushBuffer();
+ osl_closeFile( pInstanceData->rHandle );
+ pInstanceData->rHandle = nullptr;
+ }
+
+ bIsOpen = false;
+ m_isWritable = false;
+ SvStream::ClearBuffer();
+ SvStream::ClearError();
+}
+
+/// set filepointer to beginning of file
+void SvFileStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+void SvFileStream::SetSize (sal_uInt64 const nSize)
+{
+ if (IsOpen())
+ {
+ oslFileError rc = osl_setFileSize( pInstanceData->rHandle, nSize );
+ if (rc != osl_File_E_None )
+ {
+ SetError ( ::GetSvError( rc ));
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tools/source/stream/strmwnt.cxx b/tools/source/stream/strmwnt.cxx
new file mode 100644
index 000000000..4ea9c7eb1
--- /dev/null
+++ b/tools/source/stream/strmwnt.cxx
@@ -0,0 +1,420 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// TODO: StreamMode <-> AllocateMemory
+
+#include <string.h>
+#include <limits.h>
+
+#ifdef _WIN32
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+#include <osl/thread.h>
+#include <tools/stream.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+
+#include <osl/file.hxx>
+using namespace osl;
+
+class StreamData
+{
+public:
+ HANDLE hFile;
+
+ StreamData() : hFile(nullptr)
+ {
+ }
+};
+
+static ErrCode GetSvError( DWORD nWntError )
+{
+ static struct { DWORD wnt; ErrCode sv; } errArr[] =
+ {
+ { ERROR_SUCCESS, ERRCODE_NONE },
+ { ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ACCOUNT_DISABLED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ACCOUNT_EXPIRED, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ACCOUNT_RESTRICTION, SVSTREAM_ACCESS_DENIED },
+ { ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_BAD_PATHNAME, SVSTREAM_PATH_NOT_FOUND },
+ // Filename too long
+ { ERROR_BUFFER_OVERFLOW, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_DIRECTORY, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
+ { ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
+ { ERROR_INVALID_DRIVE, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_INVALID_HANDLE, SVSTREAM_INVALID_HANDLE },
+ { ERROR_INVALID_NAME, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_IS_SUBST_PATH, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_IS_SUBST_TARGET, SVSTREAM_INVALID_PARAMETER },
+ { ERROR_LOCK_FAILED, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
+ { ERROR_NEGATIVE_SEEK, SVSTREAM_SEEK_ERROR },
+ { ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
+ { ERROR_READ_FAULT, SVSTREAM_READ_ERROR },
+ { ERROR_SEEK, SVSTREAM_SEEK_ERROR },
+ { ERROR_SEEK_ON_DEVICE, SVSTREAM_SEEK_ERROR },
+ { ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
+ { ERROR_SHARING_PAUSED, SVSTREAM_SHARING_VIOLATION },
+ { ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
+ { ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
+ { ERROR_WRITE_FAULT, SVSTREAM_WRITE_ERROR },
+ { ERROR_WRITE_PROTECT, SVSTREAM_ACCESS_DENIED },
+ { ERROR_DISK_FULL, SVSTREAM_DISK_FULL },
+
+ { DWORD(0xFFFFFFFF), SVSTREAM_GENERALERROR }
+ };
+
+ ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
+ int i=0;
+ do
+ {
+ if( errArr[i].wnt == nWntError )
+ {
+ nRetVal = errArr[i].sv;
+ break;
+ }
+ i++;
+ } while( errArr[i].wnt != DWORD(0xFFFFFFFF) );
+ return nRetVal;
+}
+
+SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nMode )
+{
+ bIsOpen = false;
+ nLockCounter = 0;
+ m_isWritable = false;
+ pInstanceData.reset( new StreamData );
+
+ SetBufferSize( 8192 );
+ // convert URL to SystemPath, if necessary
+ OUString aFileName;
+
+ if ( FileBase::getSystemPathFromFileURL( rFileName, aFileName ) != FileBase::E_None )
+ aFileName = rFileName;
+ Open( aFileName, nMode );
+}
+
+SvFileStream::SvFileStream()
+{
+ bIsOpen = false;
+ nLockCounter = 0;
+ m_isWritable = false;
+ pInstanceData.reset( new StreamData );
+
+ SetBufferSize( 8192 );
+}
+
+SvFileStream::~SvFileStream()
+{
+ Close();
+}
+
+/// Does not check for EOF, makes isEof callable
+std::size_t SvFileStream::GetData( void* pData, std::size_t nSize )
+{
+ DWORD nCount = 0;
+ if( IsOpen() )
+ {
+ bool bResult = ReadFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr);
+ if( !bResult )
+ {
+ std::size_t nTestError = GetLastError();
+ SetError(::GetSvError( nTestError ) );
+ }
+ }
+ return nCount;
+}
+
+std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize )
+{
+ DWORD nCount = 0;
+ if( IsOpen() )
+ {
+ if(!WriteFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr))
+ SetError(::GetSvError( GetLastError() ) );
+ }
+ return nCount;
+}
+
+sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
+{
+ // check if a truncated STREAM_SEEK_TO_END was passed
+ assert(nPos != SAL_MAX_UINT32);
+ DWORD nNewPos = 0;
+ if( IsOpen() )
+ {
+ if( nPos != STREAM_SEEK_TO_END )
+ // 64-Bit files are not supported
+ nNewPos=SetFilePointer(pInstanceData->hFile,nPos,nullptr,FILE_BEGIN);
+ else
+ nNewPos=SetFilePointer(pInstanceData->hFile,0L,nullptr,FILE_END);
+
+ if( nNewPos == 0xFFFFFFFF )
+ {
+ SetError(::GetSvError( GetLastError() ) );
+ nNewPos = 0;
+ }
+ }
+ else
+ SetError( SVSTREAM_GENERALERROR );
+ return static_cast<sal_uInt64>(nNewPos);
+}
+
+void SvFileStream::FlushData()
+{
+ if( IsOpen() )
+ {
+ if( !FlushFileBuffers(pInstanceData->hFile) )
+ SetError(::GetSvError(GetLastError()));
+ }
+}
+
+bool SvFileStream::LockFile()
+{
+ bool bRetVal = false;
+ if( !nLockCounter )
+ {
+ if( IsOpen() )
+ {
+ bRetVal = ::LockFile(pInstanceData->hFile,0L,0L,LONG_MAX,0L );
+ if( bRetVal )
+ {
+ nLockCounter = 1;
+ }
+ else
+ SetError(::GetSvError(GetLastError()));
+ }
+ }
+ else
+ {
+ nLockCounter++;
+ bRetVal = true;
+ }
+ return bRetVal;
+}
+
+void SvFileStream::UnlockFile()
+{
+ if( nLockCounter > 0)
+ {
+ if( nLockCounter == 1)
+ {
+ if( IsOpen() )
+ {
+ if( ::UnlockFile(pInstanceData->hFile,0L,0L,LONG_MAX,0L ) )
+ {
+ nLockCounter = 0;
+ }
+ else
+ SetError(::GetSvError(GetLastError()));
+ }
+ }
+ else
+ {
+ nLockCounter--;
+ }
+ }
+}
+
+/*
+ NOCREATE TRUNC NT-Action
+ ----------------------------------------------
+ 0 (Create) 0 OPEN_ALWAYS
+ 0 (Create) 1 CREATE_ALWAYS
+ 1 0 OPEN_EXISTING
+ 1 1 TRUNCATE_EXISTING
+*/
+void SvFileStream::Open( const OUString& rFilename, StreamMode nMode )
+{
+ OUString aParsedFilename(rFilename);
+
+ SetLastError( ERROR_SUCCESS );
+ Close();
+ SvStream::ClearBuffer();
+
+ m_eStreamMode = nMode;
+ m_eStreamMode &= ~StreamMode::TRUNC; // don't truncate on reopen
+
+ aFilename = aParsedFilename;
+ SetLastError( ERROR_SUCCESS ); // might be changed by Redirector
+
+ DWORD nOpenAction;
+ DWORD nShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD nAccessMode = 0;
+ UINT nOldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
+
+ if( nMode & StreamMode::SHARE_DENYREAD)
+ nShareMode &= ~FILE_SHARE_READ;
+
+ if( nMode & StreamMode::SHARE_DENYWRITE)
+ nShareMode &= ~FILE_SHARE_WRITE;
+
+ if( nMode & StreamMode::SHARE_DENYALL)
+ nShareMode = 0;
+
+ if( nMode & StreamMode::READ )
+ nAccessMode |= GENERIC_READ;
+ if( nMode & StreamMode::WRITE )
+ nAccessMode |= GENERIC_WRITE;
+
+ if( nAccessMode == GENERIC_READ ) // ReadOnly ?
+ nMode |= StreamMode::NOCREATE; // Don't create if readonly
+
+ // Assignment based on true/false table above
+ if( !(nMode & StreamMode::NOCREATE) )
+ {
+ if( nMode & StreamMode::TRUNC )
+ nOpenAction = CREATE_ALWAYS;
+ else
+ nOpenAction = OPEN_ALWAYS;
+ }
+ else
+ {
+ if( nMode & StreamMode::TRUNC )
+ nOpenAction = TRUNCATE_EXISTING;
+ else
+ nOpenAction = OPEN_EXISTING;
+ }
+
+ DWORD nAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
+
+ if ( nMode & StreamMode::TEMPORARY )
+ nAttributes |= FILE_ATTRIBUTE_TEMPORARY;
+
+ pInstanceData->hFile = CreateFileW(
+ o3tl::toW(aFilename.getStr()),
+ nAccessMode,
+ nShareMode,
+ nullptr,
+ nOpenAction,
+ nAttributes,
+ nullptr
+ );
+
+ if( pInstanceData->hFile!=INVALID_HANDLE_VALUE && (
+ // Did Create Always overwrite a file?
+ GetLastError() == ERROR_ALREADY_EXISTS ||
+ // Did Create Always open a new file?
+ GetLastError() == ERROR_FILE_NOT_FOUND ))
+ {
+ // If so, no error
+ if( nOpenAction == OPEN_ALWAYS || nOpenAction == CREATE_ALWAYS )
+ SetLastError( ERROR_SUCCESS );
+ }
+
+ // Otherwise, determine if we're allowed to read
+ if( (pInstanceData->hFile==INVALID_HANDLE_VALUE) &&
+ (nAccessMode & GENERIC_WRITE))
+ {
+ ErrCode nErr = ::GetSvError( GetLastError() );
+ if(nErr==SVSTREAM_ACCESS_DENIED || nErr==SVSTREAM_SHARING_VIOLATION)
+ {
+ nMode &= ~StreamMode::WRITE;
+ nAccessMode = GENERIC_READ;
+ // OV, 28.1.97: Win32 sets file to length 0
+ // if Openaction is CREATE_ALWAYS
+ nOpenAction = OPEN_EXISTING;
+ SetLastError( ERROR_SUCCESS );
+ pInstanceData->hFile = CreateFileW(
+ o3tl::toW(aFilename.getStr()),
+ GENERIC_READ,
+ nShareMode,
+ nullptr,
+ nOpenAction,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+ nullptr
+ );
+ if( GetLastError() == ERROR_ALREADY_EXISTS )
+ SetLastError( ERROR_SUCCESS );
+ }
+ }
+
+ if( GetLastError() != ERROR_SUCCESS )
+ {
+ bIsOpen = false;
+ SetError(::GetSvError( GetLastError() ) );
+ }
+ else
+ {
+ bIsOpen = true;
+ // pInstanceData->bIsEof = false;
+ if( nAccessMode & GENERIC_WRITE )
+ m_isWritable = true;
+ }
+ SetErrorMode( nOldErrorMode );
+}
+
+void SvFileStream::Close()
+{
+ if( IsOpen() )
+ {
+ if( nLockCounter )
+ {
+ nLockCounter = 1;
+ UnlockFile();
+ }
+ FlushBuffer();
+ CloseHandle( pInstanceData->hFile );
+ }
+ bIsOpen = false;
+ nLockCounter= 0;
+ m_isWritable = false;
+ SvStream::ClearBuffer();
+ SvStream::ClearError();
+}
+
+/// Reset filepointer to beginning of file
+void SvFileStream::ResetError()
+{
+ SvStream::ClearError();
+}
+
+void SvFileStream::SetSize(sal_uInt64 const nSize)
+{
+
+ if( IsOpen() )
+ {
+ bool bError = false;
+ HANDLE hFile = pInstanceData->hFile;
+ DWORD const nOld = SetFilePointer( hFile, 0L, nullptr, FILE_CURRENT );
+ if( nOld != 0xffffffff )
+ {
+ if( SetFilePointer(hFile,nSize,nullptr,FILE_BEGIN ) != 0xffffffff)
+ {
+ bool bSucc = SetEndOfFile( hFile );
+ if( !bSucc )
+ bError = true;
+ }
+ if( SetFilePointer( hFile,nOld,nullptr,FILE_BEGIN ) == 0xffffffff)
+ bError = true;
+ }
+ if( bError )
+ SetError(::GetSvError( GetLastError() ) );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tools/source/stream/vcompat.cxx b/tools/source/stream/vcompat.cxx
new file mode 100644
index 000000000..bf85c0c9a
--- /dev/null
+++ b/tools/source/stream/vcompat.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+
+VersionCompatRead::VersionCompatRead(SvStream& rStm)
+ : mrRStm(rStm)
+ , mnCompatPos(0)
+ , mnTotalSize(0)
+ , mnVersion(1)
+{
+ if (mrRStm.GetError())
+ return;
+
+ mrRStm.ReadUInt16(mnVersion);
+ mrRStm.ReadUInt32(mnTotalSize);
+ mnCompatPos = mrRStm.Tell();
+}
+
+VersionCompatWrite::VersionCompatWrite(SvStream& rStm, sal_uInt16 nVersion)
+ : mrWStm(rStm)
+ , mnCompatPos(0)
+ , mnTotalSize(0)
+{
+ if (mrWStm.GetError())
+ return;
+
+ mrWStm.WriteUInt16(nVersion);
+ mnCompatPos = mrWStm.Tell();
+ mnTotalSize = mnCompatPos + 4;
+ mrWStm.SeekRel(4);
+}
+
+VersionCompatRead::~VersionCompatRead()
+{
+ const sal_uInt32 nReadSize = mrRStm.Tell() - mnCompatPos;
+
+ if (mnTotalSize > nReadSize)
+ mrRStm.SeekRel(mnTotalSize - nReadSize);
+}
+
+VersionCompatWrite::~VersionCompatWrite()
+{
+ const sal_uInt32 nEndPos = mrWStm.Tell();
+
+ mrWStm.Seek(mnCompatPos);
+ mrWStm.WriteUInt32(nEndPos - mnTotalSize);
+ mrWStm.Seek(nEndPos);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */