/* -*- 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 <string.h>
#include <unordered_map>
#include <vector>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/factory.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <osl/endian.h>
#include <com/sun/star/io/NotConnectedException.hpp>
#include <com/sun/star/io/XObjectInputStream.hpp>
#include <com/sun/star/io/XObjectOutputStream.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/io/XMarkableStream.hpp>
#include <com/sun/star/io/XConnectable.hpp>
#include <com/sun/star/io/UnexpectedEOFException.hpp>
#include <com/sun/star/io/WrongFormatException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
using namespace ::cppu;
using namespace ::osl;
using namespace ::std;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
#include <services.hxx>
namespace io_stm {
class ODataInputStream :
public WeakImplHelper <
XDataInputStream,
XActiveDataSink,
XConnectable,
XServiceInfo
>
{
public:
ODataInputStream( )
: m_bValidStream( false )
{
}
public: // XInputStream
virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
virtual sal_Int32 SAL_CALL available() override;
virtual void SAL_CALL closeInput() override;
public: // XDataInputStream
virtual sal_Int8 SAL_CALL readBoolean() override;
virtual sal_Int8 SAL_CALL readByte() override;
virtual sal_Unicode SAL_CALL readChar() override;
virtual sal_Int16 SAL_CALL readShort() override;
virtual sal_Int32 SAL_CALL readLong() override;
virtual sal_Int64 SAL_CALL readHyper() override;
virtual float SAL_CALL readFloat() override;
virtual double SAL_CALL readDouble() override;
virtual OUString SAL_CALL readUTF() override;
public: // XActiveDataSink
virtual void SAL_CALL setInputStream(const Reference< XInputStream > & aStream) override;
virtual Reference< XInputStream > SAL_CALL getInputStream() override;
public: // XConnectable
virtual void SAL_CALL setPredecessor(const Reference < XConnectable >& aPredecessor) override;
virtual Reference < XConnectable > SAL_CALL getPredecessor() override;
virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor) override;
virtual Reference < XConnectable > SAL_CALL getSuccessor() override ;
public: // XServiceInfo
OUString SAL_CALL getImplementationName() override;
Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
protected:
Reference < XConnectable > m_pred;
Reference < XConnectable > m_succ;
Reference < XInputStream > m_input;
bool m_bValidStream;
};
// XInputStream
sal_Int32 ODataInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
{
if( !m_bValidStream )
{
throw NotConnectedException( );
}
sal_Int32 nRead = m_input->readBytes( aData , nBytesToRead );
return nRead;
}
sal_Int32 ODataInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
{
if( !m_bValidStream )
throw NotConnectedException( );
sal_Int32 nRead = m_input->readSomeBytes( aData , nMaxBytesToRead );
return nRead;
}
void ODataInputStream::skipBytes(sal_Int32 nBytesToSkip)
{
if( !m_bValidStream )
throw NotConnectedException( );
m_input->skipBytes( nBytesToSkip );
}
sal_Int32 ODataInputStream::available()
{
if( !m_bValidStream )
throw NotConnectedException( );
sal_Int32 nAvail = m_input->available( );
return nAvail;
}
void ODataInputStream::closeInput()
{
if( !m_bValidStream )
throw NotConnectedException( );
m_input->closeInput( );
setInputStream( Reference< XInputStream > () );
setPredecessor( Reference < XConnectable >() );
setSuccessor( Reference < XConnectable >() );
m_bValidStream = false;
}
//== XDataInputStream ===========================================
// XDataInputStream
sal_Int8 ODataInputStream::readBoolean()
{
return readByte();
}
sal_Int8 ODataInputStream::readByte()
{
Sequence<sal_Int8> aTmp(1);
if( 1 != readBytes( aTmp, 1 ) )
{
throw UnexpectedEOFException();
}
return aTmp.getArray()[0];
}
sal_Unicode ODataInputStream::readChar()
{
Sequence<sal_Int8> aTmp(2);
if( 2 != readBytes( aTmp, 2 ) )
{
throw UnexpectedEOFException();
}
const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray());
return (static_cast<sal_Unicode>(pBytes[0]) << 8) + pBytes[1];
}
sal_Int16 ODataInputStream::readShort()
{
Sequence<sal_Int8> aTmp(2);
if( 2 != readBytes( aTmp, 2 ) )
{
throw UnexpectedEOFException();
}
const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray());
return (static_cast<sal_Int16>(pBytes[0]) << 8) + pBytes[1];
}
sal_Int32 ODataInputStream::readLong()
{
Sequence<sal_Int8> aTmp(4);
if( 4 != readBytes( aTmp, 4 ) )
{
throw UnexpectedEOFException( );
}
const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray());
return (static_cast<sal_Int32>(pBytes[0]) << 24) + (static_cast<sal_Int32>(pBytes[1]) << 16) + (static_cast<sal_Int32>(pBytes[2]) << 8) + pBytes[3];
}
sal_Int64 ODataInputStream::readHyper()
{
Sequence<sal_Int8> aTmp(8);
if( 8 != readBytes( aTmp, 8 ) )
{
throw UnexpectedEOFException( );
}
const sal_uInt8 * pBytes = reinterpret_cast<const sal_uInt8 *>(aTmp.getConstArray());
return
(static_cast<sal_Int64>(pBytes[0]) << 56) +
(static_cast<sal_Int64>(pBytes[1]) << 48) +
(static_cast<sal_Int64>(pBytes[2]) << 40) +
(static_cast<sal_Int64>(pBytes[3]) << 32) +
(static_cast<sal_Int64>(pBytes[4]) << 24) +
(static_cast<sal_Int64>(pBytes[5]) << 16) +
(static_cast<sal_Int64>(pBytes[6]) << 8) +
pBytes[7];
}
float ODataInputStream::readFloat()
{
union { float f; sal_uInt32 n; } a;
a.n = readLong();
return a.f;
}
double ODataInputStream::readDouble()
{
union { double d; struct { sal_uInt32 n1; sal_uInt32 n2; } ad; } a;
#if defined OSL_LITENDIAN
a.ad.n2 = readLong();
a.ad.n1 = readLong();
#else
a.ad.n1 = readLong();
a.ad.n2 = readLong();
#endif
return a.d;
}
OUString ODataInputStream::readUTF()
{
sal_uInt16 nShortLen = static_cast<sal_uInt16>(readShort());
sal_Int32 nUTFLen;
if( (sal_uInt16(0xffff)) == nShortLen )
{
// is interpreted as a sign, that string is longer than 64k
// incompatible to older XDataInputStream-routines, when strings are exactly 64k
nUTFLen = readLong();
}
else
{
nUTFLen = static_cast<sal_Int32>(nShortLen);
}
Sequence<sal_Unicode> aBuffer( nUTFLen );
sal_Unicode * pStr = aBuffer.getArray();
sal_Int32 nCount = 0;
sal_Int32 nStrLen = 0;
while( nCount < nUTFLen )
{
sal_uInt8 c = static_cast<sal_uInt8>(readByte());
sal_uInt8 char2, char3;
switch( c >> 4 )
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
nCount++;
pStr[nStrLen++] = c;
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
nCount += 2;
if( nCount > nUTFLen )
{
throw WrongFormatException( );
}
char2 = static_cast<sal_uInt8>(readByte());
if( (char2 & 0xC0) != 0x80 )
{
throw WrongFormatException( );
}
pStr[nStrLen++] = (sal_Unicode(c & 0x1F) << 6) | (char2 & 0x3F);
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
nCount += 3;
if( nCount > nUTFLen )
{
throw WrongFormatException( );
}
char2 = static_cast<sal_uInt8>(readByte());
char3 = static_cast<sal_uInt8>(readByte());
if( ((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80) ) {
throw WrongFormatException( );
}
pStr[nStrLen++] = (sal_Unicode(c & 0x0F) << 12) |
(sal_Unicode(char2 & 0x3F) << 6) |
(char3 & 0x3F);
break;
default:
// 10xx xxxx, 1111 xxxx
throw WrongFormatException();
//throw new UTFDataFormatException();
}
}
return OUString( pStr, nStrLen );
}
// XActiveDataSource
void ODataInputStream::setInputStream(const Reference< XInputStream > & aStream)
{
if( m_input != aStream ) {
m_input = aStream;
Reference < XConnectable > pred( m_input , UNO_QUERY );
setPredecessor( pred );
}
m_bValidStream = m_input.is();
}
Reference< XInputStream > ODataInputStream::getInputStream()
{
return m_input;
}
// XDataSink
void ODataInputStream::setSuccessor( const Reference < XConnectable > &r )
{
/// if the references match, nothing needs to be done
if( m_succ != r ) {
/// store the reference for later use
m_succ = r;
if( m_succ.is() ) {
/// set this instance as the sink !
m_succ->setPredecessor( Reference< XConnectable > (
static_cast< XConnectable * >(this) ) );
}
}
}
Reference < XConnectable > ODataInputStream::getSuccessor()
{
return m_succ;
}
// XDataSource
void ODataInputStream::setPredecessor( const Reference < XConnectable > &r )
{
if( r != m_pred ) {
m_pred = r;
if( m_pred.is() ) {
m_pred->setSuccessor( Reference< XConnectable > (
static_cast< XConnectable * >(this) ) );
}
}
}
Reference < XConnectable > ODataInputStream::getPredecessor()
{
return m_pred;
}
// XServiceInfo
OUString ODataInputStream::getImplementationName()
{
return ODataInputStream_getImplementationName();
}
// XServiceInfo
sal_Bool ODataInputStream::supportsService(const OUString& ServiceName)
{
return cppu::supportsService(this, ServiceName);
}
// XServiceInfo
Sequence< OUString > ODataInputStream::getSupportedServiceNames()
{
return ODataInputStream_getSupportedServiceNames();
}
/***
*
* registration information
*
*
****/
Reference< XInterface > ODataInputStream_CreateInstance(
SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
{
ODataInputStream *p = new ODataInputStream;
return Reference< XInterface > ( static_cast<OWeakObject *>(p) );
}
OUString ODataInputStream_getImplementationName()
{
return OUString("com.sun.star.comp.io.stm.DataInputStream");
}
Sequence<OUString> ODataInputStream_getSupportedServiceNames()
{
Sequence<OUString> aRet { "com.sun.star.io.DataInputStream" };
return aRet;
}
class ODataOutputStream :
public WeakImplHelper <
XDataOutputStream,
XActiveDataSource,
XConnectable,
XServiceInfo >
{
public:
ODataOutputStream()
: m_bValidStream( false )
{
}
public: // XOutputStream
virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override;
virtual void SAL_CALL flush() override;
virtual void SAL_CALL closeOutput() override;
public: // XDataOutputStream
virtual void SAL_CALL writeBoolean(sal_Bool Value) override;
virtual void SAL_CALL writeByte(sal_Int8 Value) override;
virtual void SAL_CALL writeChar(sal_Unicode Value) override;
virtual void SAL_CALL writeShort(sal_Int16 Value) override;
virtual void SAL_CALL writeLong(sal_Int32 Value) override;
virtual void SAL_CALL writeHyper(sal_Int64 Value) override;
virtual void SAL_CALL writeFloat(float Value) override;
virtual void SAL_CALL writeDouble(double Value) override;
virtual void SAL_CALL writeUTF(const OUString& Value) override;
public: // XActiveDataSource
virtual void SAL_CALL setOutputStream(const Reference< XOutputStream > & aStream) override;
virtual Reference < XOutputStream > SAL_CALL getOutputStream() override;
public: // XConnectable
virtual void SAL_CALL setPredecessor(const Reference < XConnectable >& aPredecessor) override;
virtual Reference < XConnectable > SAL_CALL getPredecessor() override;
virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor) override;
virtual Reference < XConnectable > SAL_CALL getSuccessor() override;
public: // XServiceInfo
OUString SAL_CALL getImplementationName() override;
Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
protected:
Reference < XConnectable > m_succ;
Reference < XConnectable > m_pred;
Reference< XOutputStream > m_output;
bool m_bValidStream;
};
// XOutputStream
void ODataOutputStream::writeBytes(const Sequence< sal_Int8 >& aData)
{
if( !m_bValidStream )
throw NotConnectedException( );
m_output->writeBytes( aData );
}
void ODataOutputStream::flush()
{
if( !m_bValidStream )
throw NotConnectedException();
m_output->flush();
}
void ODataOutputStream::closeOutput()
{
if( !m_bValidStream )
throw NotConnectedException();
m_output->closeOutput();
setOutputStream( Reference< XOutputStream > () );
setPredecessor( Reference < XConnectable >() );
setSuccessor( Reference < XConnectable >() );
}
// XDataOutputStream
void ODataOutputStream::writeBoolean(sal_Bool Value)
{
if( Value )
{
writeByte( 1 );
}
else
{
writeByte( 0 );
}
}
void ODataOutputStream::writeByte(sal_Int8 Value)
{
Sequence<sal_Int8> aTmp( 1 );
aTmp.getArray()[0] = Value;
writeBytes( aTmp );
}
void ODataOutputStream::writeChar(sal_Unicode Value)
{
Sequence<sal_Int8> aTmp( 2 );
sal_Int8 * pBytes = aTmp.getArray();
pBytes[0] = sal_Int8(Value >> 8);
pBytes[1] = sal_Int8(Value);
writeBytes( aTmp );
}
void ODataOutputStream::writeShort(sal_Int16 Value)
{
Sequence<sal_Int8> aTmp( 2 );
sal_Int8 * pBytes = aTmp.getArray();
pBytes[0] = sal_Int8(Value >> 8);
pBytes[1] = sal_Int8(Value);
writeBytes( aTmp );
}
void ODataOutputStream::writeLong(sal_Int32 Value)
{
Sequence<sal_Int8> aTmp( 4 );
sal_Int8 * pBytes = aTmp.getArray();
pBytes[0] = sal_Int8(Value >> 24);
pBytes[1] = sal_Int8(Value >> 16);
pBytes[2] = sal_Int8(Value >> 8);
pBytes[3] = sal_Int8(Value);
writeBytes( aTmp );
}
void ODataOutputStream::writeHyper(sal_Int64 Value)
{
Sequence<sal_Int8> aTmp( 8 );
sal_Int8 * pBytes = aTmp.getArray();
pBytes[0] = sal_Int8(Value >> 56);
pBytes[1] = sal_Int8(Value >> 48);
pBytes[2] = sal_Int8(Value >> 40);
pBytes[3] = sal_Int8(Value >> 32);
pBytes[4] = sal_Int8(Value >> 24);
pBytes[5] = sal_Int8(Value >> 16);
pBytes[6] = sal_Int8(Value >> 8);
pBytes[7] = sal_Int8(Value);
writeBytes( aTmp );
}
void ODataOutputStream::writeFloat(float Value)
{
union { float f; sal_uInt32 n; } a;
a.f = Value;
writeLong( a.n );
}
void ODataOutputStream::writeDouble(double Value)
{
union { double d; struct { sal_uInt32 n1; sal_uInt32 n2; } ad; } a;
a.d = Value;
#if defined OSL_LITENDIAN
writeLong( a.ad.n2 );
writeLong( a.ad.n1 );
#else
writeLong( a.ad.n1 );
writeLong( a.ad.n2 );
#endif
}
void ODataOutputStream::writeUTF(const OUString& Value)
{
sal_Int32 nStrLen = Value.getLength();
const sal_Unicode * pStr = Value.getStr();
sal_Int32 nUTFLen = 0;
sal_Int32 i;
for( i = 0 ; i < nStrLen ; i++ )
{
sal_uInt16 c = pStr[i];
if( (c >= 0x0001) && (c <= 0x007F) )
{
nUTFLen++;
}
else if( c > 0x07FF )
{
nUTFLen += 3;
}
else
{
nUTFLen += 2;
}
}
// compatibility mode for older implementations, where it was not possible
// to write blocks bigger than 64 k. Note that there is a tradeoff. Blocks,
// that are exactly 64k long can not be read by older routines when written
// with these routines and the other way round !!!!!
if( nUTFLen >= 0xFFFF ) {
writeShort( sal_Int16(-1) );
writeLong( nUTFLen );
}
else {
writeShort( static_cast<sal_uInt16>(nUTFLen) );
}
for( i = 0 ; i < nStrLen ; i++ )
{
sal_uInt16 c = pStr[i];
if( (c >= 0x0001) && (c <= 0x007F) )
{
writeByte(sal_Int8(c));
}
else if( c > 0x07FF )
{
writeByte(sal_Int8(0xE0 | ((c >> 12) & 0x0F)));
writeByte(sal_Int8(0x80 | ((c >> 6) & 0x3F)));
writeByte(sal_Int8(0x80 | ((c >> 0) & 0x3F)));
}
else
{
writeByte(sal_Int8(0xC0 | ((c >> 6) & 0x1F)));
writeByte(sal_Int8(0x80 | ((c >> 0) & 0x3F)));
}
}
}
// XActiveDataSource
void ODataOutputStream::setOutputStream(const Reference< XOutputStream > & aStream)
{
if( m_output != aStream ) {
m_output = aStream;
m_bValidStream = m_output.is();
Reference < XConnectable > succ( m_output , UNO_QUERY );
setSuccessor( succ );
}
}
Reference< XOutputStream > ODataOutputStream::getOutputStream()
{
return m_output;
}
// XDataSink
void ODataOutputStream::setSuccessor( const Reference < XConnectable > &r )
{
/// if the references match, nothing needs to be done
if( m_succ != r )
{
/// store the reference for later use
m_succ = r;
if( m_succ.is() )
{
/// set this instance as the sink !
m_succ->setPredecessor( Reference < XConnectable > (
static_cast< XConnectable * >(this) ));
}
}
}
Reference < XConnectable > ODataOutputStream::getSuccessor()
{
return m_succ;
}
// XDataSource
void ODataOutputStream::setPredecessor( const Reference < XConnectable > &r )
{
if( r != m_pred ) {
m_pred = r;
if( m_pred.is() ) {
m_pred->setSuccessor( Reference< XConnectable > (
static_cast< XConnectable * >(this) ));
}
}
}
Reference < XConnectable > ODataOutputStream::getPredecessor()
{
return m_pred;
}
// XServiceInfo
OUString ODataOutputStream::getImplementationName()
{
return ODataOutputStream_getImplementationName();
}
// XServiceInfo
sal_Bool ODataOutputStream::supportsService(const OUString& ServiceName)
{
return cppu::supportsService(this, ServiceName);
}
// XServiceInfo
Sequence< OUString > ODataOutputStream::getSupportedServiceNames()
{
return ODataOutputStream_getSupportedServiceNames();
}
Reference< XInterface > ODataOutputStream_CreateInstance(
SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
{
ODataOutputStream *p = new ODataOutputStream;
Reference< XInterface > xService = *p;
return xService;
}
OUString ODataOutputStream_getImplementationName()
{
return OUString("com.sun.star.comp.io.stm.DataOutputStream");
}
Sequence<OUString> ODataOutputStream_getSupportedServiceNames()
{
Sequence<OUString> aRet { "com.sun.star.io.DataOutputStream" };
return aRet;
}
struct equalObjectContainer_Impl
{
bool operator()(const Reference< XInterface > & s1,
const Reference< XInterface > & s2) const
{
return s1 == s2;
}
};
struct hashObjectContainer_Impl
{
size_t operator()(const Reference< XInterface > & xRef) const
{
return reinterpret_cast<size_t>(xRef.get());
}
};
typedef std::unordered_map
<
Reference< XInterface >,
sal_Int32,
hashObjectContainer_Impl,
equalObjectContainer_Impl
> ObjectContainer_Impl;
class OObjectOutputStream:
public ImplInheritanceHelper<
ODataOutputStream, /* parent */
XObjectOutputStream, XMarkableStream >
{
public:
OObjectOutputStream()
: m_nMaxId(0) ,
m_bValidMarkable(false)
{
}
public:
// XOutputStream
virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override
{ ODataOutputStream::writeBytes( aData ); }
virtual void SAL_CALL flush() override
{ ODataOutputStream::flush(); }
virtual void SAL_CALL closeOutput() override
{ ODataOutputStream::closeOutput(); }
public:
// XDataOutputStream
virtual void SAL_CALL writeBoolean(sal_Bool Value) override
{ ODataOutputStream::writeBoolean( Value ); }
virtual void SAL_CALL writeByte(sal_Int8 Value) override
{ ODataOutputStream::writeByte( Value ); }
virtual void SAL_CALL writeChar(sal_Unicode Value) override
{ ODataOutputStream::writeChar( Value ); }
virtual void SAL_CALL writeShort(sal_Int16 Value) override
{ ODataOutputStream::writeShort( Value ); }
virtual void SAL_CALL writeLong(sal_Int32 Value) override
{ ODataOutputStream::writeLong( Value ); }
virtual void SAL_CALL writeHyper(sal_Int64 Value) override
{ ODataOutputStream::writeHyper( Value ); }
virtual void SAL_CALL writeFloat(float Value) override
{ ODataOutputStream::writeFloat( Value ); }
virtual void SAL_CALL writeDouble(double Value) override
{ ODataOutputStream::writeDouble( Value ); }
virtual void SAL_CALL writeUTF(const OUString& Value) override
{ ODataOutputStream::writeUTF( Value );}
// XObjectOutputStream
virtual void SAL_CALL writeObject( const Reference< XPersistObject > & r ) override;
public: // XMarkableStream
virtual sal_Int32 SAL_CALL createMark() override;
virtual void SAL_CALL deleteMark(sal_Int32 Mark) override;
virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override;
virtual void SAL_CALL jumpToFurthest() override;
virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override;
public: // XServiceInfo
OUString SAL_CALL getImplementationName() override;
Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
private:
void connectToMarkable();
private:
ObjectContainer_Impl m_mapObject;
sal_Int32 m_nMaxId;
Reference< XMarkableStream > m_rMarkable;
bool m_bValidMarkable;
};
void OObjectOutputStream::writeObject( const Reference< XPersistObject > & xPObj )
{
connectToMarkable();
bool bWriteObj = false;
// create Mark to write length of info
sal_uInt32 nInfoLenMark = m_rMarkable->createMark();
// length of the info data (is later rewritten)
OObjectOutputStream::writeShort( 0 );
// write the object identifier
if( xPObj.is() )
{
Reference< XInterface > rX( xPObj , UNO_QUERY );
ObjectContainer_Impl::const_iterator aIt
= m_mapObject.find( rX );
if( aIt == m_mapObject.end() )
{
// insert new object in hash table
m_mapObject[ rX ] = ++m_nMaxId;
ODataOutputStream::writeLong( m_nMaxId );
ODataOutputStream::writeUTF( xPObj->getServiceName() );
bWriteObj = true;
}
else
{
ODataOutputStream::writeLong( (*aIt).second );
ODataOutputStream::writeUTF( OUString() );
}
}
else
{
ODataOutputStream::writeLong( 0 );
ODataOutputStream::writeUTF( OUString() );
}
sal_uInt32 nObjLenMark = m_rMarkable->createMark();
ODataOutputStream::writeLong( 0 );
sal_Int32 nInfoLen = m_rMarkable->offsetToMark( nInfoLenMark );
m_rMarkable->jumpToMark( nInfoLenMark );
// write length of the info data
ODataOutputStream::writeShort( static_cast<sal_Int16>(nInfoLen) );
// jump to the end of the stream
m_rMarkable->jumpToFurthest();
if( bWriteObj )
xPObj->write( Reference< XObjectOutputStream > (
static_cast< XObjectOutputStream * >(this) ) );
sal_Int32 nObjLen = m_rMarkable->offsetToMark( nObjLenMark ) -4;
m_rMarkable->jumpToMark( nObjLenMark );
// write length of the info data
ODataOutputStream::writeLong( nObjLen );
// jump to the end of the stream
m_rMarkable->jumpToFurthest();
m_rMarkable->deleteMark( nObjLenMark );
m_rMarkable->deleteMark( nInfoLenMark );
}
void OObjectOutputStream::connectToMarkable()
{
if( ! m_bValidMarkable ) {
if( ! m_bValidStream )
{
throw NotConnectedException();
}
// find the markable stream !
Reference< XInterface > rTry(m_output);
while( true ) {
if( ! rTry.is() )
{
throw NotConnectedException();
}
Reference < XMarkableStream > markable( rTry , UNO_QUERY );
if( markable.is() )
{
m_rMarkable = markable;
break;
}
Reference < XActiveDataSource > source( rTry , UNO_QUERY );
rTry = source;
}
m_bValidMarkable = true;
}
}
sal_Int32 OObjectOutputStream::createMark()
{
connectToMarkable(); // throws an exception, if a markable is not connected !
return m_rMarkable->createMark();
}
void OObjectOutputStream::deleteMark(sal_Int32 Mark)
{
if( ! m_bValidMarkable )
{
throw NotConnectedException();
}
m_rMarkable->deleteMark( Mark );
}
void OObjectOutputStream::jumpToMark(sal_Int32 nMark)
{
if( ! m_bValidMarkable )
{
throw NotConnectedException();
}
m_rMarkable->jumpToMark( nMark );
}
void OObjectOutputStream::jumpToFurthest()
{
connectToMarkable();
m_rMarkable->jumpToFurthest();
}
sal_Int32 OObjectOutputStream::offsetToMark(sal_Int32 nMark)
{
if( ! m_bValidMarkable )
{
throw NotConnectedException();
}
return m_rMarkable->offsetToMark( nMark );
}
Reference< XInterface > OObjectOutputStream_CreateInstance(
SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
{
OObjectOutputStream *p = new OObjectOutputStream;
return Reference< XInterface > ( static_cast< OWeakObject * >(p) );
}
OUString OObjectOutputStream_getImplementationName()
{
return OUString("com.sun.star.comp.io.stm.ObjectOutputStream");
}
Sequence<OUString> OObjectOutputStream_getSupportedServiceNames()
{
Sequence<OUString> aRet { "com.sun.star.io.ObjectOutputStream" };
return aRet;
}
// XServiceInfo
OUString OObjectOutputStream::getImplementationName()
{
return OObjectOutputStream_getImplementationName();
}
// XServiceInfo
sal_Bool OObjectOutputStream::supportsService(const OUString& ServiceName)
{
return cppu::supportsService(this, ServiceName);
}
// XServiceInfo
Sequence< OUString > OObjectOutputStream::getSupportedServiceNames()
{
return OObjectOutputStream_getSupportedServiceNames();
}
class OObjectInputStream:
public ImplInheritanceHelper<
ODataInputStream, /* parent */
XObjectInputStream, XMarkableStream >
{
public:
explicit OObjectInputStream( const Reference < XComponentContext > &r)
: m_rSMgr( r->getServiceManager() )
, m_rCxt( r )
, m_bValidMarkable(false)
{
}
public: // XInputStream
virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override
{ return ODataInputStream::readBytes( aData , nBytesToRead ); }
virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override
{ return ODataInputStream::readSomeBytes( aData, nMaxBytesToRead ); }
virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override
{ ODataInputStream::skipBytes( nBytesToSkip ); }
virtual sal_Int32 SAL_CALL available() override
{ return ODataInputStream::available(); }
virtual void SAL_CALL closeInput() override
{ ODataInputStream::closeInput(); }
public: // XDataInputStream
virtual sal_Int8 SAL_CALL readBoolean() override
{ return ODataInputStream::readBoolean(); }
virtual sal_Int8 SAL_CALL readByte() override
{ return ODataInputStream::readByte(); }
virtual sal_Unicode SAL_CALL readChar() override
{ return ODataInputStream::readChar(); }
virtual sal_Int16 SAL_CALL readShort() override
{ return ODataInputStream::readShort(); }
virtual sal_Int32 SAL_CALL readLong() override
{ return ODataInputStream::readLong(); }
virtual sal_Int64 SAL_CALL readHyper() override
{ return ODataInputStream::readHyper(); }
virtual float SAL_CALL readFloat() override
{ return ODataInputStream::readFloat(); }
virtual double SAL_CALL readDouble() override
{ return ODataInputStream::readDouble(); }
virtual OUString SAL_CALL readUTF() override
{ return ODataInputStream::readUTF(); }
public: // XObjectInputStream
virtual Reference< XPersistObject > SAL_CALL readObject( ) override;
public: // XMarkableStream
virtual sal_Int32 SAL_CALL createMark() override;
virtual void SAL_CALL deleteMark(sal_Int32 Mark) override;
virtual void SAL_CALL jumpToMark(sal_Int32 nMark) override;
virtual void SAL_CALL jumpToFurthest() override;
virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark) override;
public: // XServiceInfo
OUString SAL_CALL getImplementationName() override;
Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
private:
void connectToMarkable();
private:
Reference < XMultiComponentFactory > m_rSMgr;
Reference < XComponentContext > m_rCxt;
bool m_bValidMarkable;
Reference < XMarkableStream > m_rMarkable;
vector < Reference< XPersistObject > > m_aPersistVector;
};
Reference< XPersistObject > OObjectInputStream::readObject()
{
// check if chain contains a XMarkableStream
connectToMarkable();
Reference< XPersistObject > xLoadedObj;
// create Mark to skip newer versions
sal_uInt32 nMark = m_rMarkable->createMark();
// length of the data
sal_Int32 nLen = static_cast<sal_uInt16>(ODataInputStream::readShort());
if( nLen < 0xc )
{
throw WrongFormatException();
}
// read the object identifier
sal_uInt32 nId = readLong();
// the name of the persist model
// MM ???
OUString aName = readUTF();
// Read the length of the object
sal_Int32 nObjLen = readLong();
if( 0 == nId && 0 != nObjLen )
{
throw WrongFormatException();
}
// skip data of new version
skipBytes( nLen - m_rMarkable->offsetToMark( nMark ) );
bool bLoadSuccessful = true;
if( nId )
{
if( !aName.isEmpty() )
{
// load the object
Reference< XInterface > x = m_rSMgr->createInstanceWithContext( aName, m_rCxt );
xLoadedObj.set( x, UNO_QUERY );
if( xLoadedObj.is() )
{
sal_uInt32 nSize = m_aPersistVector.size();
if( nSize <= nId )
{
// grow to the right size
Reference< XPersistObject > xEmpty;
m_aPersistVector.insert( m_aPersistVector.end(), static_cast<long>(nId - nSize + 1), xEmpty );
}
m_aPersistVector[nId] = xLoadedObj;
xLoadedObj->read( Reference< XObjectInputStream >(
static_cast< XObjectInputStream * >(this) ) );
}
else
{
// no service with this name could be instantiated
bLoadSuccessful = false;
}
}
else {
if( m_aPersistVector.size() < nId )
{
// id unknown, load failure !
bLoadSuccessful = false;
}
else
{
// Object has already been read,
xLoadedObj = m_aPersistVector[nId];
}
}
}
// skip to the position behind the object
skipBytes( nObjLen + nLen - m_rMarkable->offsetToMark( nMark ) );
m_rMarkable->deleteMark( nMark );
if( ! bLoadSuccessful )
{
throw WrongFormatException();
}
return xLoadedObj;
}
void OObjectInputStream::connectToMarkable()
{
if( ! m_bValidMarkable ) {
if( ! m_bValidStream )
{
throw NotConnectedException( );
}
// find the markable stream !
Reference< XInterface > rTry(m_input);
while( true ) {
if( ! rTry.is() )
{
throw NotConnectedException( );
}
Reference< XMarkableStream > markable( rTry , UNO_QUERY );
if( markable.is() )
{
m_rMarkable = markable;
break;
}
Reference < XActiveDataSink > sink( rTry , UNO_QUERY );
rTry = sink;
}
m_bValidMarkable = true;
}
}
sal_Int32 OObjectInputStream::createMark()
{
connectToMarkable(); // throws an exception, if a markable is not connected !
return m_rMarkable->createMark();
}
void OObjectInputStream::deleteMark(sal_Int32 Mark)
{
if( ! m_bValidMarkable )
{
throw NotConnectedException();
}
m_rMarkable->deleteMark( Mark );
}
void OObjectInputStream::jumpToMark(sal_Int32 nMark)
{
if( ! m_bValidMarkable )
{
throw NotConnectedException();
}
m_rMarkable->jumpToMark( nMark );
}
void OObjectInputStream::jumpToFurthest()
{
connectToMarkable();
m_rMarkable->jumpToFurthest();
}
sal_Int32 OObjectInputStream::offsetToMark(sal_Int32 nMark)
{
if( ! m_bValidMarkable )
{
throw NotConnectedException();
}
return m_rMarkable->offsetToMark( nMark );
}
// XServiceInfo
OUString OObjectInputStream::getImplementationName()
{
return OObjectInputStream_getImplementationName();
}
// XServiceInfo
sal_Bool OObjectInputStream::supportsService(const OUString& ServiceName)
{
return cppu::supportsService(this, ServiceName);
}
// XServiceInfo
Sequence< OUString > OObjectInputStream::getSupportedServiceNames()
{
return OObjectInputStream_getSupportedServiceNames();
}
Reference< XInterface > OObjectInputStream_CreateInstance( const Reference < XComponentContext > & rCtx )
{
OObjectInputStream *p = new OObjectInputStream( rCtx );
return Reference< XInterface> ( static_cast< OWeakObject * >(p) );
}
OUString OObjectInputStream_getImplementationName()
{
return OUString("com.sun.star.comp.io.stm.ObjectInputStream");
}
Sequence<OUString> OObjectInputStream_getSupportedServiceNames()
{
Sequence<OUString> aRet { "com.sun.star.io.ObjectInputStream" };
return aRet;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V557 Array overrun is possible. The 'nId' index is pointing beyond array bound.
↑ V773 The function was exited without releasing the 'p' pointer. A memory leak is possible.