diff options
Diffstat (limited to 'package')
145 files changed, 39577 insertions, 0 deletions
diff --git a/package/dtd/Manifest.dtd b/package/dtd/Manifest.dtd new file mode 100644 index 000000000000..0030645143b6 --- /dev/null +++ b/package/dtd/Manifest.dtd @@ -0,0 +1,62 @@ +<!-- + + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + + Copyright 2008 by Sun Microsystems, Inc. + + OpenOffice.org - a multi-platform office productivity suite + + $RCSfile: Manifest.dtd,v $ + + $Revision: 1.10 $ + + This file is part of OpenOffice.org. + + OpenOffice.org is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + OpenOffice.org is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details + (a copy is included in the LICENSE file that accompanied this code). + + You should have received a copy of the GNU Lesser General Public License + version 3 along with OpenOffice.org. If not, see + <http://www.openoffice.org/license.html> + for a copy of the LGPLv3 License. + +--> +<!ELEMENT manifest:manifest (manifest:file-entry+)> +<!ATTLIST manifest:manifest xmlns:manifest CDATA #FIXED "http://openoffice.org/2001/manifest"> + +<!ELEMENT manifest:file-entry (manifest:encryption-data?)> +<!-- manifest:size is usually only specified for encrypted entries --> +<!ATTLIST manifest:file-entry + manifest:full-path CDATA #REQUIRED + manifest:size CDATA #IMPLIED + manifest:media-type CDATA #REQUIRED +> + +<!ELEMENT manifest:encryption-data (manifest:algorithm,manifest:key-derivation)> +<!ATTLIST manifest:encryption-data + manifest:checksum-type CDATA #REQUIRED + manifest:checksum CDATA #REQUIRED > +<!-- algorithm-name specifies the name of the algorithm used to encrypt + the stream, for example Blowfish + manifest:initialisation-vector is stored encoded in Base64 --> +<!ELEMENT manifest:algorithm EMPTY> +<!ATTLIST manifest:algorithm + manifest:algorithm-name CDATA #REQUIRED + manifest:initialisation-vector CDATA #REQUIRED> + +<!ELEMENT manifest:key-derivation EMPTY> +<!-- manifest:key-derivation-name specifies the name of the algorithm used to derive + the key, for example PBKDF2 (see rfc 2898 ) + manifest:salt is stored encoded in Base64 --> +<!ATTLIST manifest:key-derivation + manifest:key-derivation-name CDATA #REQUIRED + manifest:salt CDATA #REQUIRED + manifest:iteration-count CDATA #REQUIRED> + diff --git a/package/inc/ByteChucker.hxx b/package/inc/ByteChucker.hxx new file mode 100644 index 000000000000..de18fb578fae --- /dev/null +++ b/package/inc/ByteChucker.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ByteChucker.hxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _BYTE_CHUCKER_HXX_ +#define _BYTE_CHUCKER_HXX_ + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +namespace com { namespace sun { namespace star { + namespace io { class XSeekable; class XOutputStream; } +} } } +class ByteChucker +{ +protected: + com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > xStream; + com::sun::star::uno::Reference < com::sun::star::io::XSeekable > xSeek; + com::sun::star::uno::Sequence < sal_Int8 > a1Sequence, a2Sequence, a4Sequence; + sal_Int8 * const p1Sequence, * const p2Sequence, * const p4Sequence; + +public: + ByteChucker (com::sun::star::uno::Reference<com::sun::star::io::XOutputStream> xOstream); + ~ByteChucker(); + + void WriteBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + sal_Int64 GetPosition() + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + ByteChucker& operator << (sal_Int8 nInt8); + ByteChucker& operator << (sal_Int16 nInt16); + ByteChucker& operator << (sal_Int32 nInt32); + ByteChucker& operator << (sal_uInt8 nuInt8); + ByteChucker& operator << (sal_uInt16 nuInt16); + ByteChucker& operator << (sal_uInt32 nuInt32); +}; + +#endif diff --git a/package/inc/ByteGrabber.hxx b/package/inc/ByteGrabber.hxx new file mode 100644 index 000000000000..d4869845f066 --- /dev/null +++ b/package/inc/ByteGrabber.hxx @@ -0,0 +1,80 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ByteGrabber.hxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _BYTE_GRABBER_HXX_ +#define _BYTE_GRABBER_HXX_ + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <osl/mutex.hxx> + +namespace com { namespace sun { namespace star { + namespace io { class XSeekable; class XInputStream; } +} } } +class ByteGrabber +{ +protected: + ::osl::Mutex m_aMutex; + + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream; + com::sun::star::uno::Reference < com::sun::star::io::XSeekable > xSeek; + com::sun::star::uno::Sequence < sal_Int8 > aSequence; + const sal_Int8 *pSequence; + +public: + ByteGrabber (com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xIstream); + ~ByteGrabber(); + + void setInputStream (com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewStream); + // XInputStream + sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + sal_Int64 SAL_CALL seek( sal_Int64 location ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + sal_Int64 SAL_CALL getPosition( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + sal_Int64 SAL_CALL getLength( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + ByteGrabber& operator >> (sal_Int8& rInt8); + ByteGrabber& operator >> (sal_Int16& rInt16); + ByteGrabber& operator >> (sal_Int32& rInt32); + ByteGrabber& operator >> (sal_uInt8& ruInt8); + ByteGrabber& operator >> (sal_uInt16& ruInt16); + ByteGrabber& operator >> (sal_uInt32& ruInt32); +}; + +#endif diff --git a/package/inc/CRC32.hxx b/package/inc/CRC32.hxx new file mode 100644 index 000000000000..ae55a1e8fcf1 --- /dev/null +++ b/package/inc/CRC32.hxx @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: CRC32.hxx,v $ + * $Revision: 1.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CRC32_HXX +#define _CRC32_HXX + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/RuntimeException.hpp> + +namespace com { namespace sun { namespace star { + namespace io { class XInputStream; } +} } } +class CRC32 +{ +protected: + sal_uInt32 nCRC; +public: + CRC32(); + ~CRC32(); + + sal_Int32 SAL_CALL updateStream (::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > & xStream) + throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL updateSegment(const ::com::sun::star::uno::Sequence< sal_Int8 > &b, sal_Int32 off, sal_Int32 len) + throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL update(const ::com::sun::star::uno::Sequence< sal_Int8 > &b) + throw(::com::sun::star::uno::RuntimeException); + sal_Int32 SAL_CALL getValue() + throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL reset() + throw(::com::sun::star::uno::RuntimeException); +}; + +#endif diff --git a/package/inc/Deflater.hxx b/package/inc/Deflater.hxx new file mode 100644 index 000000000000..187f0a4d826c --- /dev/null +++ b/package/inc/Deflater.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Deflater.hxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _DEFLATER_HXX_ +#define _DEFLATER_HXX_ + +#include <com/sun/star/uno/Sequence.hxx> + +extern "C" +{ + typedef struct z_stream_s z_stream; +} + +class Deflater +{ +protected: + com::sun::star::uno::Sequence< sal_Int8 > sInBuffer; + sal_Bool bFinish; + sal_Bool bFinished; + sal_Bool bSetParams; + sal_Int32 nLevel, nStrategy; + sal_Int32 nOffset, nLength; + z_stream* pStream; + + void init (sal_Int32 nLevel, sal_Int32 nStrategy, sal_Bool bNowrap); + sal_Int32 doDeflateBytes (com::sun::star::uno::Sequence < sal_Int8 > &rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength); + +public: + ~Deflater(); + Deflater(sal_Int32 nSetLevel, sal_Bool bNowrap); + void SAL_CALL setInputSegment( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ); + void SAL_CALL setLevel( sal_Int32 nNewLevel ); + sal_Bool SAL_CALL needsInput( ); + void SAL_CALL finish( ); + sal_Bool SAL_CALL finished( ); + sal_Int32 SAL_CALL doDeflateSegment( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ); + sal_Int32 SAL_CALL getTotalIn( ); + sal_Int32 SAL_CALL getTotalOut( ); + void SAL_CALL reset( ); + void SAL_CALL end( ); +}; + +#endif diff --git a/package/inc/EncryptedDataHeader.hxx b/package/inc/EncryptedDataHeader.hxx new file mode 100644 index 000000000000..a3bdea0f4c86 --- /dev/null +++ b/package/inc/EncryptedDataHeader.hxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: EncryptedDataHeader.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ENCRYPTED_DATA_HEADER_HXX_ +#define _ENCRYPTED_DATA_HEADER_HXX_ + +#include <sal/types.h> + +/* The structure of this header is as follows: + + Header signature 4 bytes + Version number 2 bytes + Iteraction count 4 bytes + Size 4 bytes + Salt length 2 bytes + IV length 2 bytes + Digest length 2 bytes + MediaType length 2 bytes + Salt content X bytes + IV content X bytes + digest content X bytes + MediaType X bytes + +*/ +const sal_uInt32 n_ConstHeader = 0x0502474dL; // "MG\002\005" +const sal_Int32 n_ConstHeaderSize = 22; // + salt length + iv length + digest length + mediatype length +const sal_Int16 n_ConstCurrentVersion = 1; +#endif diff --git a/package/inc/EncryptionData.hxx b/package/inc/EncryptionData.hxx new file mode 100644 index 000000000000..6dd50624c928 --- /dev/null +++ b/package/inc/EncryptionData.hxx @@ -0,0 +1,46 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: EncryptionData.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ENCRYPTION_DATA_HXX_ +#define _ENCRYPTION_DATA_HXX_ + +#include <com/sun/star/uno/Sequence.hxx> +#include <cppuhelper/weak.hxx> + +class EncryptionData : public cppu::OWeakObject +{ +public: + // On export aKey holds the derived key + // On import aKey holds the hash of the user enterred key + com::sun::star::uno::Sequence < sal_Int8 > aKey; + com::sun::star::uno::Sequence < sal_uInt8 > aSalt, aInitVector, aDigest; + sal_Int32 nIterationCount; + EncryptionData(): nIterationCount ( 0 ){} +}; +#endif diff --git a/package/inc/HashMaps.hxx b/package/inc/HashMaps.hxx new file mode 100644 index 000000000000..b1b1950ad8d6 --- /dev/null +++ b/package/inc/HashMaps.hxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: HashMaps.hxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _HASHMAPS_HXX +#define _HASHMAPS_HXX + +#include <ZipEntry.hxx> +#include <vos/ref.hxx> +#include <hash_map> + +struct eqFunc +{ + sal_Bool operator()( const rtl::OUString &r1, + const rtl::OUString &r2) const + { + return r1 == r2; + } +}; + +class ZipPackageFolder; +namespace com { namespace sun { namespace star { namespace packages { +class ContentInfo; +} } } } + +typedef std::hash_map < rtl::OUString, + ZipPackageFolder *, + ::rtl::OUStringHash, + eqFunc > FolderHash; + +typedef std::hash_map < rtl::OUString, + vos::ORef < com::sun::star::packages::ContentInfo >, + ::rtl::OUStringHash, + eqFunc > ContentHash; + +typedef std::hash_map < rtl::OUString, + ZipEntry, + rtl::OUStringHash, + eqFunc > EntryHash; + +#endif diff --git a/package/inc/Inflater.hxx b/package/inc/Inflater.hxx new file mode 100644 index 000000000000..7805a9cc84bb --- /dev/null +++ b/package/inc/Inflater.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Inflater.hxx,v $ + * $Revision: 1.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _INFLATER_HXX_ +#define _INFLATER_HXX_ + +#include <com/sun/star/uno/Sequence.hxx> + +extern "C" +{ + typedef struct z_stream_s z_stream; +} +class Inflater +{ +protected: + sal_Bool bFinish, bFinished, bSetParams, bNeedDict; + sal_Int32 nOffset, nLength, nLastInflateError; + z_stream* pStream; + com::sun::star::uno::Sequence < sal_Int8 > sInBuffer; + sal_Int32 doInflateBytes (com::sun::star::uno::Sequence < sal_Int8 > &rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength); + +public: + Inflater(sal_Bool bNoWrap = sal_False); + ~Inflater(); + void SAL_CALL setInput( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer ); + sal_Bool SAL_CALL needsDictionary( ); + sal_Bool SAL_CALL finished( ); + sal_Int32 SAL_CALL doInflateSegment( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ); + void SAL_CALL end( ); + + sal_Int32 getLastInflateError() { return nLastInflateError; } +}; + +#endif diff --git a/package/inc/PackageConstants.hxx b/package/inc/PackageConstants.hxx new file mode 100644 index 000000000000..3f8e4b583395 --- /dev/null +++ b/package/inc/PackageConstants.hxx @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PackageConstants.hxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _PACKAGE_CONSTANTS_HXX_ +#define _PACKAGE_CONSTANTS_HXX_ + +#include <sal/types.h> + +const sal_Int32 n_ConstBufferSize = 32768; +const sal_Int32 n_ConstMaxMemoryStreamSize = 20480; +const sal_Int32 n_ConstDigestLength = 1024; + +#define PACKAGE_FORMAT 1 +#define ZIP_FORMAT 2 +#define OFOPXML_FORMAT 3 + +// the constants related to the manifest.xml entries +#define PKG_MNFST_MEDIATYPE 0 +#define PKG_MNFST_VERSION 1 +#define PKG_MNFST_FULLPATH 2 + +#define PKG_MNFST_INIVECTOR 3 +#define PKG_MNFST_SALT 4 +#define PKG_MNFST_ITERATION 5 +#define PKG_MNFST_UCOMPSIZE 6 +#define PKG_MNFST_DIGEST 7 + +#define PKG_SIZE_NOENCR_MNFST 3 +#define PKG_SIZE_ENCR_MNFST 8 + + +#endif + diff --git a/package/inc/ZipEntry.hxx b/package/inc/ZipEntry.hxx new file mode 100644 index 000000000000..eed7a7a7cff5 --- /dev/null +++ b/package/inc/ZipEntry.hxx @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipEntry.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_ENTRY_HXX_ +#define _ZIP_ENTRY_HXX_ + +#include <rtl/ustring.hxx> + +struct ZipEntry +{ + sal_Int16 nVersion; + sal_Int16 nFlag; + sal_Int16 nMethod; + sal_Int32 nTime; + sal_Int32 nCrc; + sal_Int32 nCompressedSize; + sal_Int32 nSize; + sal_Int32 nOffset; + sal_Int16 nPathLen; + sal_Int16 nExtraLen; + ::rtl::OUString sPath; +}; +#endif diff --git a/package/inc/ZipEnumeration.hxx b/package/inc/ZipEnumeration.hxx new file mode 100644 index 000000000000..f7cae67c4532 --- /dev/null +++ b/package/inc/ZipEnumeration.hxx @@ -0,0 +1,46 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipEnumeration.hxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_ENUMERATION_HXX +#define _ZIP_ENUMERATION_HXX + +#include <HashMaps.hxx> + +class ZipEnumeration +{ +protected: + EntryHash &rEntryHash; + EntryHash::const_iterator aIterator; +public: + sal_Bool SAL_CALL hasMoreElements(); + const ZipEntry * SAL_CALL nextElement(); + ZipEnumeration( EntryHash &rNewEntryHash ); + ~ZipEnumeration(); +}; +#endif diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx new file mode 100644 index 000000000000..a4129f4fbbfe --- /dev/null +++ b/package/inc/ZipFile.hxx @@ -0,0 +1,201 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipFile.hxx,v $ + * $Revision: 1.24 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_FILE_HXX +#define _ZIP_FILE_HXX + +#include <com/sun/star/packages/zip/ZipException.hpp> +#include <com/sun/star/packages/zip/ZipIOException.hpp> +#include <com/sun/star/packages/NoEncryptionException.hpp> +#include <com/sun/star/packages/WrongPasswordException.hpp> +#include <ByteGrabber.hxx> +#include <HashMaps.hxx> +#ifndef _INFLATER_HXX +#include <Inflater.hxx> +#endif + +#include <mutexholder.hxx> + +namespace com { namespace sun { namespace star { + namespace lang { class XMultiServiceFactory; } + namespace ucb { class XProgressHandler; } +} } } +namespace vos +{ + template < class T > class ORef; +} +/* + * We impose arbitrary but reasonable limit on ZIP files. + */ + +#define ZIP_MAXNAMELEN 512 +#define ZIP_MAXEXTRA 256 +#define ZIP_MAXENTRIES (0x10000 - 2) + +typedef void* rtlCipher; +class ZipEnumeration; +class EncryptionData; + +class ZipFile +{ +protected: + ::osl::Mutex m_aMutex; + + ::rtl::OUString sComment; /* zip file comment */ + EntryHash aEntries; + ByteGrabber aGrabber; + Inflater aInflater; + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream; + com::sun::star::uno::Reference < com::sun::star::io::XSeekable > xSeek; + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > xFactory; + ::com::sun::star::uno::Reference < ::com::sun::star::ucb::XProgressHandler > xProgressHandler; + + sal_Bool bRecoveryMode; + + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > createMemoryStream( + ZipEntry & rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bRawStream, + sal_Bool bDecrypt ); + + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > createFileStream( + ZipEntry & rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bRawStream, + sal_Bool bDecrypt ); + + // aMediaType parameter is used only for raw stream header creation + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > createUnbufferedStream( + SotMutexHolderRef aMutexHolder, + ZipEntry & rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Int8 nStreamMode, + sal_Bool bDecrypt, + ::rtl::OUString aMediaType = ::rtl::OUString() ); + + sal_Bool hasValidPassword ( ZipEntry & rEntry, const vos::ORef < EncryptionData > &rData ); + + sal_Bool checkSizeAndCRC( const ZipEntry& aEntry ); + + sal_Int32 getCRC( sal_Int32 nOffset, sal_Int32 nSize ); + + void getSizeAndCRC( sal_Int32 nOffset, sal_Int32 nCompressedSize, sal_Int32 *nSize, sal_Int32 *nCRC ); + +public: + + ZipFile( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > &xInput, + const com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > &xNewFactory, + sal_Bool bInitialise + ) + throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException); + + ZipFile( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > &xInput, + const com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > &xNewFactory, + sal_Bool bInitialise, + sal_Bool bForceRecover, + ::com::sun::star::uno::Reference < ::com::sun::star::ucb::XProgressHandler > xProgress + ) + throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException); + + ~ZipFile(); + + EntryHash& GetEntryHash() { return aEntries; } + + void setInputStream ( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewStream ); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawData( + ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bDecrypt, + SotMutexHolderRef aMutexHolder ) + throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException); + + static sal_Bool StaticGetCipher ( const vos::ORef < EncryptionData > & xEncryptionData, rtlCipher &rCipher, sal_Bool bDecode ); + + static void StaticFillHeader ( const vos::ORef < EncryptionData > & rData, + sal_Int32 nSize, + const ::rtl::OUString& aMediaType, + sal_Int8 * & pHeader ); + + static sal_Bool StaticFillData ( vos::ORef < EncryptionData > & rData, + sal_Int32 &rSize, + ::rtl::OUString& aMediaType, + ::com::sun::star::uno::Reference < com::sun::star::io::XInputStream > &rStream ); + + static ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > StaticGetDataFromRawStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xStream, + const vos::ORef < EncryptionData > &rData ) + throw ( ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::packages::zip::ZipIOException, + ::com::sun::star::uno::RuntimeException ); + + static sal_Bool StaticHasValidPassword ( const ::com::sun::star::uno::Sequence< sal_Int8 > &aReadBuffer, + const vos::ORef < EncryptionData > &rData ); + + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( + ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bDecrypt, + SotMutexHolderRef aMutexHolder ) + throw(::com::sun::star::io::IOException, ::com::sun::star::packages::zip::ZipException, ::com::sun::star::uno::RuntimeException); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getDataStream( + ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bDecrypt, + SotMutexHolderRef aMutexHolder ) + throw ( ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::packages::zip::ZipException, + ::com::sun::star::uno::RuntimeException ); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getWrappedRawStream( + ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + const ::rtl::OUString& aMediaType, + SotMutexHolderRef aMutexHolder ) + throw ( ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::io::IOException, + ::com::sun::star::packages::zip::ZipException, + ::com::sun::star::uno::RuntimeException ); + + ZipEnumeration * SAL_CALL entries( ); +protected: + sal_Bool readLOC ( ZipEntry &rEntry) + throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException); + sal_Int32 readCEN() + throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException); + sal_Int32 findEND() + throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException); + sal_Int32 recover() + throw(::com::sun::star::io::IOException, com::sun::star::packages::zip::ZipException, com::sun::star::uno::RuntimeException); + +}; + +#endif diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx new file mode 100644 index 000000000000..37af31e88445 --- /dev/null +++ b/package/inc/ZipOutputStream.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipOutputStream.hxx,v $ + * $Revision: 1.25 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_OUTPUT_STREAM_HXX +#define _ZIP_OUTPUT_STREAM_HXX + +#include <ByteChucker.hxx> +#ifndef _DEFLATER_HXX +#include <Deflater.hxx> +#endif +#include <CRC32.hxx> +#include <rtl/cipher.h> +#ifndef RTL_DIGEST_H_ +#include <rtl/digest.h> +#endif + +#include <vector> + +struct ZipEntry; +class EncryptionData; +namespace vos +{ + template < class T > class ORef; +} +class ZipOutputStream +{ +protected: + com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > xStream; + ::std::vector < ZipEntry * > aZipList; + com::sun::star::uno::Sequence < sal_Int8 > aBuffer, aEncryptionBuffer; + ::rtl::OUString sComment; + Deflater aDeflater; + rtlCipher aCipher; + rtlDigest aDigest; + CRC32 aCRC; + ByteChucker aChucker; + ZipEntry *pCurrentEntry; + sal_Int16 nMethod, nLevel, mnDigested; + sal_Bool bFinished, bEncryptCurrentEntry; + EncryptionData *pCurrentEncryptData; + +public: + ZipOutputStream( com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > &xOStream ); + ~ZipOutputStream(); + + // rawWrite to support a direct write to the output stream + void SAL_CALL rawWrite( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void SAL_CALL rawCloseEntry( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + // XZipOutputStream interfaces + void SAL_CALL setMethod( sal_Int32 nNewMethod ) + throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL setLevel( sal_Int32 nNewLevel ) + throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL putNextEntry( ZipEntry& rEntry, + vos::ORef < EncryptionData > &rData, + sal_Bool bEncrypt = sal_False ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void SAL_CALL closeEntry( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void SAL_CALL write( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void SAL_CALL finish( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + static sal_uInt32 getCurrentDosTime ( ); +protected: + void doDeflate(); + void writeEND(sal_uInt32 nOffset, sal_uInt32 nLength) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void writeCEN( const ZipEntry &rEntry ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void writeEXT( const ZipEntry &rEntry ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + sal_Int32 writeLOC( const ZipEntry &rEntry ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); +}; + +#endif diff --git a/package/inc/ZipPackage.hxx b/package/inc/ZipPackage.hxx new file mode 100644 index 000000000000..72cba808de15 --- /dev/null +++ b/package/inc/ZipPackage.hxx @@ -0,0 +1,192 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackage.hxx,v $ + * $Revision: 1.41.20.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_HXX +#define _ZIP_PACKAGE_HXX + +#include <cppuhelper/implbase7.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif +#include <HashMaps.hxx> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <osl/file.h> +#include <mutexholder.hxx> + +class ZipOutputStream; +class ZipPackageFolder; +class ZipFile; +class ByteGrabber; +namespace com { namespace sun { namespace star { + namespace container { class XNameContainer; } + namespace io { class XStream; class XOutputStream; class XInputStream; class XSeekable; class XActiveDataStreamer; } + namespace lang { class XMultiServiceFactory; } + namespace task { class XInteractionHandler; } +} } } +enum SegmentEnum +{ + e_Aborted = -1000, + e_Retry, + e_Finished, + e_Success = 0 +}; + +enum InitialisationMode +{ + e_IMode_None, + e_IMode_URL, + e_IMode_XInputStream, + e_IMode_XStream +}; + +class ZipPackage : public cppu::WeakImplHelper7 + < + com::sun::star::lang::XInitialization, + com::sun::star::lang::XSingleServiceFactory, + com::sun::star::lang::XUnoTunnel, + com::sun::star::lang::XServiceInfo, + com::sun::star::container::XHierarchicalNameAccess, + com::sun::star::util::XChangesBatch, + com::sun::star::beans::XPropertySet + > +{ +protected: + SotMutexHolderRef m_aMutexHolder; + + ::com::sun::star::uno::Sequence < sal_Int8 > m_aEncryptionKey; + FolderHash m_aRecent; + ::rtl::OUString m_aURL; + sal_Bool m_bHasEncryptedEntries; + sal_Bool m_bHasNonEncryptedEntries; + sal_Bool m_bInconsistent; + sal_Bool m_bUseManifest; + sal_Bool m_bForceRecovery; + + sal_Bool m_bMediaTypeFallbackUsed; + sal_Int16 m_nFormat; + sal_Bool m_bAllowRemoveOnInsert; + + InitialisationMode m_eMode; + + ::com::sun::star::uno::Reference < com::sun::star::container::XNameContainer > m_xRootFolder; + ::com::sun::star::uno::Reference < com::sun::star::io::XStream > m_xStream; + ::com::sun::star::uno::Reference < com::sun::star::io::XInputStream > m_xContentStream; + ::com::sun::star::uno::Reference < com::sun::star::io::XSeekable > m_xContentSeek; + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > m_xFactory; + + ZipPackageFolder *m_pRootFolder; + ZipFile *m_pZipFile; + + void parseManifest(); + void parseContentType(); + void getZipFileContents(); + + void WriteMimetypeMagicFile( ZipOutputStream& aZipOut ); + void WriteManifest( ZipOutputStream& aZipOut, const ::std::vector< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > >& aManList ); + void WriteContentTypes( ZipOutputStream& aZipOut, const ::std::vector< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > >& aManList ); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > writeTempFile(); + ::com::sun::star::uno::Reference < ::com::sun::star::io::XActiveDataStreamer > openOriginalForOutput(); + void DisconnectFromTargetAndThrowException_Impl( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xTempStream ); + +public: + ZipPackage (const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > &xNewFactory); + virtual ~ZipPackage( void ); + ZipFile& getZipFile() { return *m_pZipFile;} + const com::sun::star::uno::Sequence < sal_Int8 > & getEncryptionKey ( ) {return m_aEncryptionKey;} + sal_Int16 getFormat() const { return m_nFormat; } + + SotMutexHolderRef GetSharedMutexRef() { return m_aMutexHolder; } + + void ConnectTo( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream ); + + // XInitialization + virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) + throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + // XHierarchicalNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByHierarchicalName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByHierarchicalName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + // XSingleServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( ) + throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) + throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + // XChangesBatch + virtual void SAL_CALL commitChanges( ) + throw(::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasPendingChanges( ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::util::ElementChange > SAL_CALL getPendingChanges( ) + throw(::com::sun::star::uno::RuntimeException); + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw(::com::sun::star::uno::RuntimeException); + com::sun::star::uno::Sequence < sal_Int8 > getUnoTunnelImplementationId( void ) + throw(::com::sun::star::uno::RuntimeException); + // XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); + + // Uno componentiseralation + static ::rtl::OUString static_getImplementationName(); + static ::com::sun::star::uno::Sequence < ::rtl::OUString > static_getSupportedServiceNames(); + static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleServiceFactory > createServiceFactory( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory ); + sal_Bool SAL_CALL static_supportsService(rtl::OUString const & rServiceName); +}; +#endif diff --git a/package/inc/ZipPackageBuffer.hxx b/package/inc/ZipPackageBuffer.hxx new file mode 100644 index 000000000000..81f461bb2e77 --- /dev/null +++ b/package/inc/ZipPackageBuffer.hxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageBuffer.hxx,v $ + * $Revision: 1.18 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_BUFFER_HXX +#define _ZIP_PACKAGE_BUFFER_HXX + +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#ifndef _CPPUHELPER_IMPLBASE3_HXX +#include <cppuhelper/implbase3.hxx> +#endif + +class ZipPackage; + +class ZipPackageBuffer : public ::cppu::WeakImplHelper3 +< + com::sun::star::io::XInputStream, + com::sun::star::io::XOutputStream, + com::sun::star::io::XSeekable +> +{ +protected: + com::sun::star::uno::Sequence < sal_Int8 > m_aBuffer; + sal_Int64 m_nBufferSize, m_nEnd, m_nCurrent; + sal_Bool m_bMustInitBuffer; +public: + ZipPackageBuffer(sal_Int64 nNewBufferSize); + virtual ~ZipPackageBuffer(void); + + inline void realloc ( sal_Int32 nSize ) { m_aBuffer.realloc ( nSize ); } + inline const sal_Int8 * getConstArray () const { return m_aBuffer.getConstArray(); } + inline const com::sun::star::uno::Sequence < sal_Int8> getSequence () const { return m_aBuffer; } + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XOutputStream + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL flush( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeOutput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/inc/ZipPackageFolder.hxx b/package/inc/ZipPackageFolder.hxx new file mode 100644 index 000000000000..1edbae7f5d3d --- /dev/null +++ b/package/inc/ZipPackageFolder.hxx @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageFolder.hxx,v $ + * $Revision: 1.39 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_FOLDER_HXX +#define _ZIP_PACKAGE_FOLDER_HXX + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/beans/StringPair.hpp> +#include <HashMaps.hxx> +#include <ZipPackageEntry.hxx> +#include <cppuhelper/implbase2.hxx> + +namespace com { namespace sun { namespace star { +namespace beans +{ + struct PropertyValue; +} +} } } +class ZipFile; +class ZipPackage; +class ZipOutputStream; +struct ZipEntry; +typedef void* rtlRandomPool; + +class ZipPackageFolder : public cppu::ImplInheritanceHelper2 +< + ZipPackageEntry, + ::com::sun::star::container::XNameContainer, + ::com::sun::star::container::XEnumerationAccess +> +{ + static com::sun::star::uno::Sequence < sal_Int8 > aImplementationId; + +protected: + ContentHash maContents; + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > m_xFactory; + sal_Int16 m_nFormat; + ::rtl::OUString m_sVersion; + +public: + + ZipPackageFolder( const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory >& xFactory, + sal_Int16 nFormat, + sal_Bool bAllowRemoveOnInsert ); + virtual ~ZipPackageFolder(); + + ::rtl::OUString& GetVersion() { return m_sVersion; } + void SetVersion( const ::rtl::OUString& aVersion ) { m_sVersion = aVersion; } + + sal_Bool LookForUnexpectedODF12Streams( const ::rtl::OUString& aPath ); + + void setChildStreamsTypeByExtension( const ::com::sun::star::beans::StringPair& aPair ); + + void doInsertByName ( ZipPackageEntry *pEntry, sal_Bool bSetParent ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + com::sun::star::packages::ContentInfo & doGetByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + static void copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource); + static ::com::sun::star::uno::Sequence < sal_Int8 > static_getImplementationId() + { + return aImplementationId; + } + + void setPackageFormat_Impl( sal_Int16 nFormat ) { m_nFormat = nFormat; } + void setRemoveOnInsertMode_Impl( sal_Bool bRemove ) { this->mbAllowRemoveOnInsert = bRemove; } + + // Recursive functions + void saveContents(rtl::OUString &rPath, std::vector < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList, ZipOutputStream & rZipOut, com::sun::star::uno::Sequence < sal_Int8 > &rEncryptionKey, rtlRandomPool & rRandomPool) + throw(::com::sun::star::uno::RuntimeException); + void releaseUpwardRef(); + + // XNameContainer + virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeByName( const ::rtl::OUString& Name ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XEnumerationAccess + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration( ) + throw(::com::sun::star::uno::RuntimeException); + + // XElementAccess + virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasElements( ) + throw(::com::sun::star::uno::RuntimeException); + + // XNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + + // XNameReplace + virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XPropertySet + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw(::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/inc/makefile.mk b/package/inc/makefile.mk new file mode 100644 index 000000000000..22c1356c8d42 --- /dev/null +++ b/package/inc/makefile.mk @@ -0,0 +1,51 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=.. + +PRJNAME=package +TARGET=inc + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + +.IF "$(ENABLE_PCH)"!="" +ALLTAR : \ + $(SLO)$/precompiled.pch \ + $(SLO)$/precompiled_ex.pch + +.ENDIF # "$(ENABLE_PCH)"!="" + diff --git a/package/inc/mutexholder.hxx b/package/inc/mutexholder.hxx new file mode 100644 index 000000000000..69edfdb03917 --- /dev/null +++ b/package/inc/mutexholder.hxx @@ -0,0 +1,134 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: mutexholder.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __MUTEXHOLDER_HXX_ +#define __MUTEXHOLDER_HXX_ + +#include <osl/mutex.hxx> + +class SotMutexHolder +{ + ::osl::Mutex m_aMutex; + sal_Int32 m_nRefCount; + + public: + SotMutexHolder() : m_nRefCount( 0 ) {} + + void AddRef() + { + m_nRefCount++; + } + + void ReleaseRef() + { + if ( !--m_nRefCount ) + delete this; + } + + ::osl::Mutex& GetMutex() { return m_aMutex; } +}; + +class SotMutexHolderRef +{ + SotMutexHolder* m_pHolder; + +public: + SotMutexHolderRef() + : m_pHolder( NULL ) + {} + + SotMutexHolderRef( SotMutexHolder* pHolder ) + : m_pHolder( pHolder ) + { + if ( m_pHolder ) + m_pHolder->AddRef(); + } + + SotMutexHolderRef( const SotMutexHolderRef& rRef ) + : m_pHolder( rRef.m_pHolder ) + { + if ( m_pHolder ) + m_pHolder->AddRef(); + } + + ~SotMutexHolderRef() + { + if ( m_pHolder ) + m_pHolder->ReleaseRef(); + } + + SotMutexHolderRef& operator =( const SotMutexHolderRef& rRef ) + { + if ( m_pHolder ) + m_pHolder->ReleaseRef(); + + m_pHolder = rRef.m_pHolder; + + if ( m_pHolder ) + m_pHolder->AddRef(); + + return *this; + } + + SotMutexHolderRef& operator =( SotMutexHolder* pHolder ) + { + if ( m_pHolder ) + m_pHolder->ReleaseRef(); + + m_pHolder = pHolder; + + if ( m_pHolder ) + m_pHolder->AddRef(); + return *this; + } + + SotMutexHolder* operator ->() const + { + return m_pHolder; + } + + SotMutexHolder& operator *() const + { + return *m_pHolder; + } + + operator SotMutexHolder*() const + { + return m_pHolder; + } + + sal_Bool Is() const + { + return m_pHolder != NULL; + } +}; + +#endif + diff --git a/package/inc/pch/precompiled_package.cxx b/package/inc/pch/precompiled_package.cxx new file mode 100644 index 000000000000..9d3671822727 --- /dev/null +++ b/package/inc/pch/precompiled_package.cxx @@ -0,0 +1,32 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: precompiled_package.cxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_package.hxx" + diff --git a/package/inc/pch/precompiled_package.hxx b/package/inc/pch/precompiled_package.hxx new file mode 100644 index 000000000000..5a72c051e9e6 --- /dev/null +++ b/package/inc/pch/precompiled_package.hxx @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: precompiled_package.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): Generated on 2006-09-01 17:49:53.889391 + +#ifdef PRECOMPILED_HEADERS +#endif + diff --git a/package/inc/zipfileaccess.hxx b/package/inc/zipfileaccess.hxx new file mode 100644 index 000000000000..fbee9799930e --- /dev/null +++ b/package/inc/zipfileaccess.hxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: zipfileaccess.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _ZIPFILEACCESS_HXX_ +#define _ZIPFILEACCESS_HXX_ + +#include <com/sun/star/packages/zip/XZipFileAccess.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/implbase5.hxx> + +#include <mutexholder.hxx> + +#include <ZipFile.hxx> +#include <HashMaps.hxx> + +class OZipFileAccess : public ::cppu::WeakImplHelper5< + ::com::sun::star::packages::zip::XZipFileAccess, + ::com::sun::star::container::XNameAccess, + ::com::sun::star::lang::XInitialization, + ::com::sun::star::lang::XComponent, + ::com::sun::star::lang::XServiceInfo > +{ + SotMutexHolderRef m_aMutexHolder; + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory; + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xContentStream; + ZipFile* m_pZipFile; + + ::cppu::OInterfaceContainerHelper* m_pListenersContainer; + + sal_Bool m_bDisposed; + +public: + OZipFileAccess( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory ); + + virtual ~OZipFileAccess(); + + ::com::sun::star::uno::Sequence< ::rtl::OUString > GetPatternsFromString_Impl( const ::rtl::OUString& aString ); + + sal_Bool StringGoodForPattern_Impl( const ::rtl::OUString& aString, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPattern ); + + + static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL impl_staticGetSupportedServiceNames(); + + static ::rtl::OUString SAL_CALL impl_staticGetImplementationName(); + + static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL impl_staticCreateSelfInstance( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ); + + + // XInitialization + virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // XNameAccess + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasElements( ) throw (::com::sun::star::uno::RuntimeException); + + // XZipFileAccess + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getStreamByPattern( const ::rtl::OUString& aPattern ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + // XComponent + virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/package/prj/build.lst b/package/prj/build.lst new file mode 100644 index 000000000000..0b508271765c --- /dev/null +++ b/package/prj/build.lst @@ -0,0 +1,9 @@ +pk package : cppu cppuhelper comphelper ucbhelper sal ZLIB:zlib NULL +pk package usr1 - all pk_mkout NULL +pk package\inc nmake - all pk_inc NULL +pk package\source\zipapi nmake - all pk_zipapi pk_inc NULL +pk package\source\zippackage nmake - all pk_zippackage pk_inc NULL +pk package\source\manifest nmake - all pk_manifest pk_inc NULL +pk package\source\xstor nmake - all pk_xstor pk_manifest pk_inc NULL +pk package\util nmake - all pk_util pk_zipapi pk_zippackage pk_manifest pk_xstor NULL + diff --git a/package/prj/d.lst b/package/prj/d.lst new file mode 100644 index 000000000000..23966d0cfeae --- /dev/null +++ b/package/prj/d.lst @@ -0,0 +1,5 @@ +..\%__SRC%\misc\*.map %_DEST%\bin%_EXT%\*.map +..\%__SRC%\bin\*.dll %_DEST%\bin%_EXT%\*.dll +..\%__SRC%\lib\lib*.so %_DEST%\lib%_EXT%\lib*.so +..\%__SRC%\lib\*.dylib %_DEST%\lib%_EXT%\*.dylib +..\dtd\*.dtd %_DEST%\bin%_EXT%\*.* diff --git a/package/qa/ofopxmlstorages/StorageTest.java b/package/qa/ofopxmlstorages/StorageTest.java new file mode 100644 index 000000000000..5f3b2ff2a799 --- /dev/null +++ b/package/qa/ofopxmlstorages/StorageTest.java @@ -0,0 +1,7 @@ +package complex.ofopxmlstorages; + +public interface StorageTest +{ + boolean test(); +} + diff --git a/package/qa/ofopxmlstorages/StorageUnitTest.java b/package/qa/ofopxmlstorages/StorageUnitTest.java new file mode 100644 index 000000000000..71b9fa395a2d --- /dev/null +++ b/package/qa/ofopxmlstorages/StorageUnitTest.java @@ -0,0 +1,161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: StorageUnitTest.java,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +package complex.ofopxmlstorages; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XMultiComponentFactory; +import com.sun.star.connection.XConnector; +import com.sun.star.connection.XConnection; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.XNamingService; +import com.sun.star.uno.XComponentContext; + +import com.sun.star.container.*; +import com.sun.star.beans.*; +import com.sun.star.lang.*; + +import complexlib.ComplexTestCase; + +import complex.ofopxmlstorages.*; + +import util.utils; +import java.util.*; +import java.io.*; + +/* This unit test for storage objects is designed to + * test most important statements from storage service + * specification. + * + * Regression tests are added to extend the tested + * functionalities. + */ +public class StorageUnitTest extends ComplexTestCase +{ + private XMultiServiceFactory m_xMSF = null; + private XSingleServiceFactory m_xStorageFactory = null; + + public String[] getTestMethodNames() + { + return new String[] { + "ExecuteTest01", + "ExecuteTest02", + "ExecuteTest03", + "ExecuteTest04", + "ExecuteTest05", + "ExecuteTest06", + "ExecuteTest07", + "ExecuteTest08" + }; + } + + public String getTestObjectName() + { + return "StorageUnitTest"; + } + + public void before() + { + m_xMSF = (XMultiServiceFactory)param.getMSF(); + if ( m_xMSF == null ) + { + failed( "Can't create service factory!" ); + return; + } + + try { + Object oStorageFactory = m_xMSF.createInstance( "com.sun.star.embed.StorageFactory" ); + m_xStorageFactory = (XSingleServiceFactory)UnoRuntime.queryInterface( XSingleServiceFactory.class, + oStorageFactory ); + } + catch( Exception e ) + { + failed( "Can't create storage factory!" ); + return; + } + + if ( m_xStorageFactory == null ) + { + failed( "Can't create service factory!" ); + return; + } + } + + public void ExecuteTest01() + { + StorageTest aTest = new Test01( m_xMSF, m_xStorageFactory, log ); + assure( "Test01 failed!", aTest.test() ); + } + + public void ExecuteTest02() + { + StorageTest aTest = new Test02( m_xMSF, m_xStorageFactory, log ); + assure( "Test02 failed!", aTest.test() ); + } + + public void ExecuteTest03() + { + StorageTest aTest = new Test03( m_xMSF, m_xStorageFactory, log ); + assure( "Test03 failed!", aTest.test() ); + } + + public void ExecuteTest04() + { + StorageTest aTest = new Test04( m_xMSF, m_xStorageFactory, log ); + assure( "Test04 failed!", aTest.test() ); + } + + public void ExecuteTest05() + { + StorageTest aTest = new Test05( m_xMSF, m_xStorageFactory, log ); + assure( "Test05 failed!", aTest.test() ); + } + + public void ExecuteTest06() + { + StorageTest aTest = new Test06( m_xMSF, m_xStorageFactory, log ); + assure( "Test06 failed!", aTest.test() ); + } + + public void ExecuteTest07() + { + StorageTest aTest = new Test07( m_xMSF, m_xStorageFactory, log ); + assure( "Test07 failed!", aTest.test() ); + } + + public void ExecuteTest08() + { + StorageTest aTest = new Test08( m_xMSF, m_xStorageFactory, log ); + assure( "Test08 failed!", aTest.test() ); + } +} + diff --git a/package/qa/ofopxmlstorages/Test01.java b/package/qa/ofopxmlstorages/Test01.java new file mode 100644 index 000000000000..abb73c3fc48b --- /dev/null +++ b/package/qa/ofopxmlstorages/Test01.java @@ -0,0 +1,200 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test01 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test01( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test01: " ); + } + + public boolean test() + { + StringPair[][] aRelations1 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue1" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value1" ) } + }; + + StringPair[][] aRelations2 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue2" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) } + }; + + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + XStorage xTempStorage = m_aTestHelper.createTempStorage( m_xMSF, m_xStorageFactory ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, + "SubStream2", + "MediaType2", + false, + pBytes2, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + true, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + false, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + // create temporary storage based on a previously created temporary file + XStorage xTempFileStorage = m_aTestHelper.createStorageFromURL( m_xStorageFactory, + sTempFileURL, + ElementModes.WRITE ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + XStorage xResultStorage = m_aTestHelper.createStorageFromURL( m_xStorageFactory, + sTempFileURL, + ElementModes.WRITE ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, + true, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, + false, + ElementModes.READ, + aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, + "SubStream1", + "MediaType1", + pBytes1, + aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, + "SubStream2", + "MediaType2", + pBytes2, + aRelations2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/ofopxmlstorages/Test02.java b/package/qa/ofopxmlstorages/Test02.java new file mode 100644 index 000000000000..4ba7892b8295 --- /dev/null +++ b/package/qa/ofopxmlstorages/Test02.java @@ -0,0 +1,164 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test02 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test02( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test02: " ); + } + + public boolean test() + { + try + { + StringPair[][] aRelations = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) } + }; + + + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + XStorage xTempStorage = m_aTestHelper.createStorageFromStream( m_xStorageFactory, + xTempFileStream, + ElementModes.WRITE ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + true, + ElementModes.WRITE, + aRelations ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + false, + ElementModes.WRITE, + aRelations ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + + // ================================================ + // now check all the written information + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + + // open input stream + XStorage xResultStorage = m_aTestHelper.createStorageFromInputStream( m_xStorageFactory, xTempInStream ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, true, ElementModes.READ, aRelations ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, + false, + ElementModes.READ, + aRelations ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream1", "MediaType1", pBytes1, aRelations ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/ofopxmlstorages/Test03.java b/package/qa/ofopxmlstorages/Test03.java new file mode 100644 index 000000000000..e3424c9106f2 --- /dev/null +++ b/package/qa/ofopxmlstorages/Test03.java @@ -0,0 +1,233 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; +import com.sun.star.container.XNameAccess; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test03 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test03( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test03: " ); + } + + public boolean test() + { + try + { + StringPair[][] aRelations = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) } + }; + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + XStorage xTempStorage = m_aTestHelper.createTempStorage( m_xMSF, m_xStorageFactory ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, + "SubStream2", + "MediaType2", + false, + pBytes2, + aRelations ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + false, + ElementModes.WRITE, + aRelations ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // ================================================ + // check storage hyerarchy tree + // ================================================ + + // check that isStorageElement() and isStreamElement reacts to nonexisting object correctly + try { + xTempStorage.isStorageElement( "does not exist" ); + m_aTestHelper.Error( "Nonexisting element doesn't detected by isStorageElement() call!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by isStorageElement() call: " + e ); + return false; + } + + try { + xTempStorage.isStreamElement( "does not exist" ); + m_aTestHelper.Error( "Nonexisting element doesn't detected by isStreamElement() call!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by isStreamElement() call: " + e ); + return false; + } + + XNameAccess xRootNameAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xTempStorage ); + if ( xRootNameAccess == null ) + { + m_aTestHelper.Error( "Root storage doesn't support XNameAccess!" ); + return false; + } + + try { + if ( !xTempStorage.isStorageElement( "SubStorage1" ) || xTempStorage.isStreamElement( "SubStorage1" ) ) + { + m_aTestHelper.Error( "Child 'SubStorage1' can not be detected as storage!" ); + return false; + } + + if ( xTempStorage.isStorageElement( "SubStream1" ) || !xTempStorage.isStreamElement( "SubStream1" ) ) + { + m_aTestHelper.Error( "Child 'SubStream1' can not be detected as stream!" ); + return false; + } + } + catch( Exception e ) + { + m_aTestHelper.Error( "Child's type can not be detected, exception: " + e ); + return false; + } + + + // check that root storage contents are represented correctly + String sRootCont[] = xRootNameAccess.getElementNames(); + + if ( sRootCont.length != 2 ) + { + m_aTestHelper.Error( "Root storage contains wrong amount of children!" ); + return false; + } + + if ( !( sRootCont[0].equals( "SubStorage1" ) && sRootCont[1].equals( "SubStream1" ) + || sRootCont[0].equals( "SubStream1" ) && sRootCont[1].equals( "SubStorage1" ) ) + || !( xRootNameAccess.hasByName( "SubStream1" ) && xRootNameAccess.hasByName( "SubStorage1" ) ) ) + { + m_aTestHelper.Error( "Root storage contains wrong list of children!" ); + return false; + } + + // get storage through XNameAccess + XStorage xResultSubStorage = getStorageFromNameAccess( xRootNameAccess, "SubStorage1" ); + if ( xResultSubStorage == null ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, + false, + ElementModes.READ, + aRelations ) ) + return false; + + XNameAccess xChildAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xResultSubStorage ); + if ( xChildAccess == null ) + { + m_aTestHelper.Error( "Child storage doesn't support XNameAccess!" ); + return false; + } + + if ( !xChildAccess.hasByName( "SubStream2" ) + || !xResultSubStorage.isStreamElement( "SubStream2" ) + || xResultSubStorage.isStorageElement( "SubStream2" ) ) + { + m_aTestHelper.Error( "'SubStream2' can not be detected as child stream element of 'SubStorage1'!" ); + return false; + } + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + + public XStorage getStorageFromNameAccess( XNameAccess xAccess, String sName ) + { + try + { + Object oStorage = xAccess.getByName( sName ); + XStorage xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oStorage ); + + if ( xResult != null ) + return xResult; + else + m_aTestHelper.Error( "Can't retrieve substorage '" + sName + "' through XNameAccess!" ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't retrieve substorage '" + sName + "' through XNameAccess, exception: " + e ); + } + + return null; + } + +} + diff --git a/package/qa/ofopxmlstorages/Test04.java b/package/qa/ofopxmlstorages/Test04.java new file mode 100644 index 000000000000..8b99c15bd77c --- /dev/null +++ b/package/qa/ofopxmlstorages/Test04.java @@ -0,0 +1,308 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; +import com.sun.star.lang.DisposedException; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.container.XNameAccess; + +import com.sun.star.embed.*; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test04 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test04( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test04: " ); + } + + public boolean test() + { + StringPair[][] aRelations1 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue1" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value1" ) } + }; + + StringPair[][] aRelations2 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue2" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) } + }; + + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + XStorage xTempStorage = m_aTestHelper.createTempStorage( m_xMSF, m_xStorageFactory ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open substorages and create streams there + + // first substorage of the root storage + XStorage xTempSubStorage1 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage1, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations1 ) ) + return false; + + // second substorage of the root storage + XStorage xTempSubStorage2 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage2", + ElementModes.WRITE ); + if ( xTempSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage2, + "SubStream2", + "MediaType2", + false, + pBytes2, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + true, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage1, + false, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage2, + false, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + // create temporary storage based on a previously created temporary file + XStorage xTempFileStorage = m_aTestHelper.createStorageFromURL( m_xStorageFactory, + sTempFileURL, + ElementModes.WRITE ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "SubStorage1", xTempFileStorage ) ) + return false; + + // if storage is not commited before disposing all the changes will be lost + if ( !m_aTestHelper.commitStorage( xTempSubStorage2 ) ) + return false; + + // a storage must be disposed before moving/removing otherwise the access will be denied + if ( !m_aTestHelper.disposeStorage( xTempSubStorage2 ) ) + return false; + + if ( !m_aTestHelper.moveElementTo( xTempStorage, "SubStorage2", xTempFileStorage ) ) + return false; + + // SubStorage2 must be removed and disposed now + try + { + xTempSubStorage2.isStreamElement( "SubStream2" ); + m_aTestHelper.Error( "SubStorage2 must be disposed already!" ); + return false; + } + catch( com.sun.star.lang.DisposedException de ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception in case of disposed storage, exception: " + e ); + return false; + } + + if ( !m_aTestHelper.copyElementTo( xTempSubStorage1, "SubStream1", xTempFileStorage ) ) + return false; + + if ( !m_aTestHelper.renameElement( xTempFileStorage, "SubStream1", "SubStream1_copy" ) ) + return false; + + if ( !m_aTestHelper.moveElementTo( xTempSubStorage1, "SubStream1", xTempFileStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + XStorage xResStorage = m_aTestHelper.createStorageFromURL( m_xStorageFactory, + sTempFileURL, + ElementModes.WRITE ); + + if ( xResStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + // open and check SubStorage1 + XStorage xResSubStorage1 = m_aTestHelper.openSubStorage( xResStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubStorage1, + false, + ElementModes.READ, + aRelations2 ) ) + return false; + + + // open and check SubStorage2 + XStorage xResSubStorage2 = m_aTestHelper.openSubStorage( xResStorage, + "SubStorage2", + ElementModes.READ ); + if ( xResSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubStorage2, + false, + ElementModes.READ, + aRelations2 ) ) + return false; + + + // check all the result streams + + if ( !m_aTestHelper.checkStream( xResStorage, "SubStream1", "MediaType1", pBytes1, aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResStorage, "SubStream1_copy", "MediaType1", pBytes1, aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubStorage1, "SubStream1", "MediaType1", pBytes1, aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubStorage2, "SubStream2", "MediaType2", pBytes2, aRelations2 ) ) + return false; + + // the storage must be disposed before removing + if ( !m_aTestHelper.disposeStorage( xResSubStorage2 ) ) + return false; + + // remove element and check that it was removed completelly + if ( !m_aTestHelper.removeElement( xResStorage, "SubStorage2" ) ) + return false; + + try + { + XNameAccess xResAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xResStorage ); + if ( xResAccess.hasByName( "SubStorage2" ) ) + m_aTestHelper.Error( "SubStorage2 must be removed already!" ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't get access to root storage, exception: " + e ); + return false; + } + + try + { + xResSubStorage2.isStreamElement( "SubStream2" ); + + m_aTestHelper.Error( "SubStorage2 must be disposed already!" ); + return false; + } + catch( com.sun.star.lang.DisposedException de ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception in case of disposed storage, exception: " + e ); + return false; + } + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/ofopxmlstorages/Test05.java b/package/qa/ofopxmlstorages/Test05.java new file mode 100644 index 000000000000..36439ca6ebcd --- /dev/null +++ b/package/qa/ofopxmlstorages/Test05.java @@ -0,0 +1,314 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; + +import com.sun.star.embed.*; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test05 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test05( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test05: " ); + } + + public boolean test() + { + StringPair[][] aRelations1 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue1" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value1" ) } + }; + + StringPair[][] aRelations2 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue2" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) } + }; + + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + XStorage xTempFileStorage = m_aTestHelper.createStorageFromURL( m_xStorageFactory, + sTempFileURL, + ElementModes.WRITE ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempFileStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substorage + XStorage xSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xSubSubStorage, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xSubSubStorage, + "SubStream2", + "MediaType2", + false, + pBytes2, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempFileStorage, + true, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + false, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xSubSubStorage, + false, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + + // commit all the storages + if ( !m_aTestHelper.commitStorage( xSubSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // try to open an opened substorage, open call must fail + if ( !m_aTestHelper.cantOpenStorage( xTempFileStorage, "SubStorage1" ) ) + return false; + + + // reopen created streams + XStream xSubStream1 = m_aTestHelper.OpenStream( xSubSubStorage, + "SubStream1", + ElementModes.WRITE | ElementModes.NOCREATE ); + XStream xSubStream2 = m_aTestHelper.OpenStream( xSubSubStorage, + "SubStream2", + ElementModes.READ | ElementModes.NOCREATE ); + if ( xSubStream1 == null || xSubStream2 == null ) + return false; + + // it should be possible to have more then one copy of stream for reading + XStream xSubStream2clone = m_aTestHelper.OpenStream( xSubSubStorage, + "SubStream2", + ElementModes.READ | ElementModes.NOCREATE ); + if ( xSubStream2 == null ) + return false; + + + // so now the first stream can not be open neither for reading nor for writing + if ( !m_aTestHelper.cantOpenStream( xSubSubStorage, "SubStream1", ElementModes.WRITE ) + || !m_aTestHelper.cantOpenStream( xSubSubStorage, "SubStream1", ElementModes.READ ) ) + return false; + + // the second stream can not be open for writing + if ( !m_aTestHelper.cantOpenStream( xSubSubStorage, "SubStream2", ElementModes.WRITE ) ) + return false; + + + // dispose xTestSubStorage, all the subtree must be disposed + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // check that subtree was disposed correctly + try + { + xSubSubStorage.isStreamElement( "SubStream1" ); + m_aTestHelper.Error( "Substorage was not disposed!" ); + return false; + } + catch ( com.sun.star.lang.DisposedException de ) + {} + catch ( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by disposed storage: " + e ); + return false; + } + + try + { + xSubStream1.getInputStream(); + m_aTestHelper.Error( "Writeable substream was not disposed!" ); + return false; + } + catch ( com.sun.star.lang.DisposedException de ) + {} + catch ( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by disposed stream: " + e ); + return false; + } + + try + { + xSubStream2.getInputStream(); + m_aTestHelper.Error( "Readonly substream was not disposed!" ); + return false; + } + catch ( com.sun.star.lang.DisposedException de ) + {} + catch ( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by disposed stream: " + e ); + return false; + } + + + // dispose root storage + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + + // ================================================ + // now check all the written and copied information + // ================================================ + + XStorage xResultStorage = m_aTestHelper.createStorageFromURL( m_xStorageFactory, + sTempFileURL, + ElementModes.READ ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, + true, + ElementModes.READ, + aRelations2 ) ) + return false; + + // open existing substorage + XStorage xResSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage 'SubSubStorage'!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubStorage, + false, + ElementModes.READ, + aRelations2 ) ) + return false; + + // open existing substorage + XStorage xResSubSubStorage = m_aTestHelper.openSubStorage( xResSubStorage, + "SubSubStorage1", + ElementModes.READ ); + if ( xResSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage 'SubSubStorage'!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubSubStorage, + false, + ElementModes.READ, + aRelations2 ) ) + return false; + + // check substreams + if ( !m_aTestHelper.checkStream( xResSubSubStorage, + "SubStream1", + "MediaType1", + pBytes1, + aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubSubStorage, + "SubStream2", + "MediaType2", + pBytes2, + aRelations2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/ofopxmlstorages/Test06.java b/package/qa/ofopxmlstorages/Test06.java new file mode 100644 index 000000000000..61969db88e12 --- /dev/null +++ b/package/qa/ofopxmlstorages/Test06.java @@ -0,0 +1,277 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.ElementExistException; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test06 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test06( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test06: " ); + } + + public boolean test() + { + try + { + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + XStorage xTempStorage = m_aTestHelper.createTempStorage( m_xMSF, m_xStorageFactory ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + try + { + xTempStorage.copyToStorage( null ); + m_aTestHelper.Error( "The method must throw an exception because of illegal parameter!" ); + return false; + } + catch( com.sun.star.lang.IllegalArgumentException iae ) + {} + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion because of illegal parameter : " + e ); + return false; + } + + // open new substorages + XStorage xTempSubStorage1 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + XStorage xTempSubStorage2 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage2", + ElementModes.WRITE ); + if ( xTempSubStorage1 == null || xTempSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // in case stream is open for reading it must exist + try + { + xTempSubStorage1.openStreamElement( "NonExistingStream", ElementModes.READ ); + m_aTestHelper.Error( "The method must throw an exception in case of try to open nonexistent stream for reading!" ); + return false; + } + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to open nonexistent stream for reading : " + e ); + return false; + } + + // in case a storage is open for reading it must exist + try + { + xTempSubStorage1.openStreamElement( "NonExistingStorage", ElementModes.READ ); + m_aTestHelper.Error( "The method must throw an exception in case of try to open nonexistent storage for reading!" ); + return false; + } + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to open nonexistent storage for reading : " + e ); + return false; + } + + // in case of removing nonexistent element an exception must be thrown + try + { + xTempSubStorage1.removeElement( "NonExistingElement" ); + m_aTestHelper.Error( "An exception must be thrown in case of removing nonexistent element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to remove nonexistent element : " + e ); + return false; + } + + // in case of renaming of nonexistent element an exception must be thrown + try + { + xTempSubStorage1.renameElement( "NonExistingElement", "NewName" ); + m_aTestHelper.Error( "An exception must be thrown in case of renaming nonexistent element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to rename nonexistent element : " + e ); + return false; + } + + // in case of renaming to a name of existent element an exception must be thrown + try + { + xTempStorage.renameElement( "SubStorage1", "SubStorage2" ); + m_aTestHelper.Error( "An exception must be thrown in case of renaming to the name of existent element!" ); + return false; + } + catch( com.sun.star.container.ElementExistException ee ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to rename to the name of existent element : " + e ); + return false; + } + + // in case of copying target storage must be provided + try + { + xTempStorage.copyElementTo( "SubStorage1", null, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case empty reference is provided as target for copying!" ); + return false; + } + catch( com.sun.star.lang.IllegalArgumentException iae ) + {} + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case empty reference is provieded as target for copying : " + e ); + return false; + } + + // in case of moving target storage must be provided + try + { + xTempStorage.moveElementTo( "SubStorage1", null, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case empty reference is provided as target for moving!" ); + return false; + } + catch( com.sun.star.lang.IllegalArgumentException iae ) + {} + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case empty reference is provieded as target for moving : " + e ); + return false; + } + + + // prepare target for further testings + + // create new temporary storage based on arbitrary medium + XStorage xTargetStorage = m_aTestHelper.createTempStorage( m_xMSF, m_xStorageFactory ); + if ( xTargetStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTargetSubStorage = m_aTestHelper.openSubStorage( xTargetStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTargetSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // in case of copying of nonexistent element an exception must be thrown + try + { + xTempStorage.copyElementTo( "Nonexistent element", xTargetStorage, "Target" ); + m_aTestHelper.Error( "An exception must be thrown in case of copying of nonexisting element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of copying of nonexistent element: " + e ); + return false; + } + + // in case of moving of nonexistent element an exception must be thrown + try + { + xTempStorage.moveElementTo( "Nonexistent element", xTargetStorage, "Target" ); + m_aTestHelper.Error( "An exception must be thrown in case of moving of nonexisting element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of moving of nonexistent element: " + e ); + return false; + } + + // in case target for copying already exists an exception must be thrown + try + { + xTempStorage.copyElementTo( "SubStorage1", xTargetStorage, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case target for copying already exists!" ); + return false; + } + catch( com.sun.star.container.ElementExistException ee ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case target for copying already exists: " + e ); + return false; + } + + // in case target for moving already exists an exception must be thrown + try + { + xTempStorage.moveElementTo( "SubStorage1", xTargetStorage, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case target for moving already exists!" ); + return false; + } + catch( com.sun.star.container.ElementExistException ee ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case target for moving already exists: " + e ); + return false; + } + + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/ofopxmlstorages/Test07.java b/package/qa/ofopxmlstorages/Test07.java new file mode 100644 index 000000000000..bcd85d5d01c0 --- /dev/null +++ b/package/qa/ofopxmlstorages/Test07.java @@ -0,0 +1,258 @@ +package complex.ofopxmlstorages; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.container.XNameAccess; +import com.sun.star.io.XStream; + +import com.sun.star.embed.*; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test07 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test07( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test07: " ); + } + + public boolean test() + { + StringPair[][] aRelations1 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue1" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value1" ) } + }; + + StringPair[][] aRelations2 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue2" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown2" ), new StringPair( "Target", "URL value 2" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal2" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown" ), new StringPair( "Target", "URL value" ) } + }; + + try + { + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + XStorage xTempStorage = m_aTestHelper.createTempStorage( m_xMSF, m_xStorageFactory ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations1 ) ) + return false; + + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, + "SubStream2", + "MediaType2", + true, + pBytes2, + aRelations2 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + true, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + false, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + // ============================== + // check cloning at current state + // ============================== + + // the new storage still was not commited so the clone must be empty + XStorage xClonedSubStorage = m_aTestHelper.cloneSubStorage( m_xMSF, m_xStorageFactory, xTempStorage, "SubStorage1" ); + + if ( xClonedSubStorage == null ) + { + m_aTestHelper.Error( "The result of clone is empty!" ); + return false; + } + + XNameAccess xClonedNameAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xClonedSubStorage ); + if ( xClonedNameAccess == null ) + { + m_aTestHelper.Error( "XNameAccess is not implemented by the clone!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xClonedSubStorage, + true, + ElementModes.WRITE, + new StringPair[0][0] ) ) + return false; + + if ( xClonedNameAccess.hasElements() ) + { + m_aTestHelper.Error( "The new substorage still was not commited so it must be empty!" ); + return false; + } + + if ( !m_aTestHelper.disposeStorage( xClonedSubStorage ) ) + return false; + + xClonedSubStorage = null; + xClonedNameAccess = null; + + // the new stream was opened, written and closed, that means flashed + // so the clone must contain all the information + XStream xClonedSubStream = m_aTestHelper.cloneSubStream( xTempStorage, "SubStream1" ); + if ( !m_aTestHelper.InternalCheckStream( xClonedSubStream, + "SubStream1", + "MediaType1", + pBytes1, + aRelations1 ) ) + return false; + + if ( !m_aTestHelper.disposeStream( xClonedSubStream, "SubStream1" ) ) + return false; + + // ============================== + // commit substorage and check cloning + // ============================== + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + xClonedSubStorage = m_aTestHelper.cloneSubStorage( m_xMSF, m_xStorageFactory, xTempStorage, "SubStorage1" ); + if ( xClonedSubStorage == null ) + { + m_aTestHelper.Error( "The result of clone is empty!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xClonedSubStorage, + true, + ElementModes.WRITE, + aRelations2 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xClonedSubStorage, + "SubStream2", + "MediaType2", + pBytes2, + aRelations2 ) ) + return false; + + XStorage xCloneOfRoot = m_aTestHelper.cloneStorage( m_xMSF, m_xStorageFactory, xTempStorage ); + if ( xCloneOfRoot == null ) + { + m_aTestHelper.Error( "The result of root clone is empty!" ); + return false; + } + + XNameAccess xCloneOfRootNA = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xCloneOfRoot ); + if ( xCloneOfRootNA == null ) + { + m_aTestHelper.Error( "XNameAccess is not implemented by the root clone!" ); + return false; + } + + if ( xCloneOfRootNA.hasElements() ) + { + m_aTestHelper.Error( "The root storage still was not commited so it's clone must be empty!" ); + return false; + } + + if ( !m_aTestHelper.disposeStorage( xCloneOfRoot ) ) + return false; + + xCloneOfRoot = null; + + // ============================== + // commit root storage and check cloning + // ============================== + + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + xCloneOfRoot = m_aTestHelper.cloneStorage( m_xMSF, m_xStorageFactory, xTempStorage ); + if ( xCloneOfRoot == null ) + { + m_aTestHelper.Error( "The result of root clone is empty!" ); + return false; + } + + XStorage xSubStorageOfClone = xCloneOfRoot.openStorageElement( "SubStorage1", ElementModes.READ ); + if ( xSubStorageOfClone == null ) + { + m_aTestHelper.Error( "The result of root clone is wrong!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xSubStorageOfClone, + false, + ElementModes.READ, + aRelations2 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xSubStorageOfClone, + "SubStream2", + "MediaType2", + pBytes2, + aRelations2 ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/ofopxmlstorages/Test08.java b/package/qa/ofopxmlstorages/Test08.java new file mode 100644 index 000000000000..eaed60d4d8e3 --- /dev/null +++ b/package/qa/ofopxmlstorages/Test08.java @@ -0,0 +1,261 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; +import com.sun.star.beans.StringPair; + +import share.LogWriter; +import complex.ofopxmlstorages.TestHelper; +import complex.ofopxmlstorages.StorageTest; + +public class Test08 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test08( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test08: " ); + } + + public boolean test() + { + StringPair[][] aRelations1 = + { { new StringPair( "Id", "Num1" ) }, + { new StringPair( "Target", "TargetURLValue1" ), new StringPair( "Id", "Num6" ) }, + { new StringPair( "Target", "" ), new StringPair( "Id", "Num7" ) }, + { new StringPair( "Id", "Num2" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num3" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num4" ), new StringPair( "TargetMode", "Internal1" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value 1" ) }, + { new StringPair( "Id", "Num5" ), new StringPair( "TargetMode", "" ), new StringPair( "Type", "unknown1" ), new StringPair( "Target", "URL value1" ) } + }; + + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + XStorage xTempStorage = m_aTestHelper.createStorageFromStream( m_xStorageFactory, + xTempFileStream, + ElementModes.WRITE ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, + "SubStream1", + "MediaType1", + true, + pBytes1, + aRelations1 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + true, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + // set Relations for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + false, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // ================================================ + // check substorage + // ================================================ + + if ( !checkSubStorages( xTempStorage, pBytes1, aRelations1 ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // now check all the written information with readwrite access + // ================================================ + + XStorage xResWriteStorage = m_aTestHelper.createStorageFromStream( m_xStorageFactory, + xTempFileStream, + ElementModes.WRITE ); + if ( xResWriteStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResWriteStorage, + true, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + if( !checkSubStorages( xResWriteStorage, pBytes1, aRelations1 ) ) + return false; + + // try to open for writing after opening for reading + XStorage xResWSubStorage = m_aTestHelper.openSubStorage( xResWriteStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xResWSubStorage == null ) + { + m_aTestHelper.Error( "Can't open substorage for writing after it was opened for reading!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResWSubStorage, + false, + ElementModes.WRITE, + aRelations1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResWSubStorage, + "SubStream1", + "MediaType1", + pBytes1, + aRelations1 ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xResWriteStorage ) ) + return false; + + + // ================================================ + // now check all the written information with readonly access + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + // open input stream + // since no mode is provided the result storage must be opened readonly + XStorage xResultStorage = m_aTestHelper.createStorageFromInputStream( m_xStorageFactory, + xTempInStream ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, + true, + ElementModes.READ, + aRelations1 ) ) + return false; + + if( !checkSubStorages( xResultStorage, pBytes1, aRelations1 ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + + private boolean checkSubStorages( XStorage xStorage, byte[] pBytes1, StringPair[][] aRelations ) + { + XStorage xReadSubStorage1 = m_aTestHelper.openSubStorage( xStorage, + "SubStorage1", + ElementModes.READ ); + + XStorage xReadSubStorage2 = m_aTestHelper.openSubStorage( xStorage, + "SubStorage1", + ElementModes.READ ); + + if ( xReadSubStorage1 == null || xReadSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't open substorage for reading!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xReadSubStorage1, + false, + ElementModes.READ, + aRelations ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xReadSubStorage2, + false, + ElementModes.READ, + aRelations ) ) + return false; + + if ( !m_aTestHelper.checkStream( xReadSubStorage1, + "SubStream1", + "MediaType1", + pBytes1, + aRelations ) ) + return false; + + if ( !m_aTestHelper.checkStream( xReadSubStorage2, + "SubStream1", + "MediaType1", + pBytes1, + aRelations ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xReadSubStorage1 ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xReadSubStorage2 ) ) + return false; + + return true; + } +} + diff --git a/package/qa/ofopxmlstorages/TestHelper.java b/package/qa/ofopxmlstorages/TestHelper.java new file mode 100644 index 000000000000..6b153fd2b960 --- /dev/null +++ b/package/qa/ofopxmlstorages/TestHelper.java @@ -0,0 +1,1098 @@ +package complex.ofopxmlstorages; + +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.AnyConverter; + +import com.sun.star.lang.*; +import com.sun.star.embed.*; +import com.sun.star.packages.*; +import com.sun.star.io.*; +import com.sun.star.beans.*; + +import share.LogWriter; + +public class TestHelper { + + LogWriter m_aLogWriter; + String m_sTestPrefix; + + public TestHelper( LogWriter aLogWriter, String sTestPrefix ) + { + m_aLogWriter = aLogWriter; + m_sTestPrefix = sTestPrefix; + } + + public boolean WriteBytesToStream( XStream xStream, + String sStreamName, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + StringPair[][] aRelations ) + { + // get output stream of substream + XOutputStream xOutput = xStream.getOutputStream(); + if ( xOutput == null ) + { + Error( "Can't get XOutputStream implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // get XTrucate implementation from output stream + XTruncate xTruncate = (XTruncate) UnoRuntime.queryInterface( XTruncate.class, xOutput ); + if ( xTruncate == null ) + { + Error( "Can't get XTruncate implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // write requested byte sequence + try + { + xTruncate.truncate(); + xOutput.writeBytes( pBytes ); + } + catch( Exception e ) + { + Error( "Can't write to stream '" + sStreamName + "', exception: " + e ); + return false; + } + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStream ); + if ( xPropSet == null ) + { + Error( "Can't get XPropertySet implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // set properties to the stream + try + { + xPropSet.setPropertyValue( "MediaType", sMediaType ); + xPropSet.setPropertyValue( "Compressed", new Boolean( bCompressed ) ); + } + catch( Exception e ) + { + Error( "Can't set properties to substream '" + sStreamName + "', exception: " + e ); + return false; + } + + // check size property of the stream + try + { + int nSize = AnyConverter.toInt( xPropSet.getPropertyValue( "Size" ) ); + if ( nSize != pBytes.length ) + { + Error( "The 'Size' property of substream '" + sStreamName + "' contains wrong value!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't get 'Size' property from substream '" + sStreamName + "', exception: " + e ); + return false; + } + + // get access to the relationship information + XRelationshipAccess xRelAccess = (XRelationshipAccess) UnoRuntime.queryInterface( XRelationshipAccess.class, xStream ); + if ( xRelAccess == null ) + { + Error( "Can't get XRelationshipAccess implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // set the relationship information + try + { + xRelAccess.insertRelationships( aRelations, false ); + } + catch( Exception e ) + { + Error( "Can't set relationships to substream '" + sStreamName + "', exception: " + e ); + return false; + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xStream, sStreamName ) ) + return false; + + return true; + } + + public boolean WriteBytesToSubstream( XStorage xStorage, + String sStreamName, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + StringPair[][] aRelations ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openStreamElement( sStreamName, ElementModes.WRITE ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + return false; + } + + return WriteBytesToStream( xSubStream, sStreamName, sMediaType, bCompressed, pBytes, aRelations ); + } + + public boolean setStorageTypeAndCheckProps( XStorage xStorage, + boolean bIsRoot, + int nMode, + StringPair[][] aRelations ) + { + boolean bOk = false; + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStorage ); + if ( xPropSet != null ) + { + try + { + // get "IsRoot" and "OpenMode" properties and control there values + boolean bPropIsRoot = AnyConverter.toBoolean( xPropSet.getPropertyValue( "IsRoot" ) ); + int nPropMode = AnyConverter.toInt( xPropSet.getPropertyValue( "OpenMode" ) ); + + bOk = true; + if ( bPropIsRoot != bIsRoot ) + { + Error( "'IsRoot' property contains wrong value!" ); + bOk = false; + } + + if ( ( bIsRoot + && ( nPropMode | ElementModes.READ ) != ( nMode | ElementModes.READ ) ) + || ( !bIsRoot && ( nPropMode & nMode ) != nMode ) ) + { + Error( "'OpenMode' property contains wrong value, expected " + nMode + ", in reality " + nPropMode + "!" ); + bOk = false; + } + } + catch( Exception e ) + { + Error( "Can't control properties of substorage, exception: " + e ); + } + } + else + { + Error( "Can't get XPropertySet implementation from storage!" ); + } + + // get access to the relationship information + XRelationshipAccess xRelAccess = (XRelationshipAccess) UnoRuntime.queryInterface( XRelationshipAccess.class, xStorage ); + + if ( xRelAccess == null ) + { + Error( "Can't get XRelationshipAccess implementation from the storage!" ); + return false; + } + + // set the relationship information + try + { + xRelAccess.insertRelationships( aRelations, false ); + } + catch( Exception e ) + { + Error( "Can't set relationships to the storage, exception: " + e ); + return false; + } + + + return bOk; + } + + public boolean checkRelations( StringPair[][] aStorRels, StringPair[][] aTestRels ) + { + // Message( "StorageRels:" ); + // PrintRelations( aStorRels ); + // Message( "TestRels:" ); + // PrintRelations( aTestRels ); + + if ( aStorRels.length != aTestRels.length ) + { + Error( "The provided relations sequence has different size than the storage's one!" ); + return false; + } + + for ( int nStorInd = 0; nStorInd < aStorRels.length; nStorInd++ ) + { + int nStorIDInd = -1; + for ( int nStorTagInd = 0; nStorTagInd < aStorRels[nStorInd].length; nStorTagInd++ ) + { + if ( aStorRels[nStorInd][nStorTagInd].First.equals( "Id" ) ) + { + nStorIDInd = nStorTagInd; + break; + } + } + + if ( nStorIDInd == -1 ) + { + Error( "One of the storage relations entries has no ID!" ); + return false; + } + + for ( int nInd = 0; nInd < aTestRels.length; nInd++ ) + { + int nIDInd = -1; + for ( int nTagInd = 0; nTagInd < aTestRels[nInd].length; nTagInd++ ) + { + if ( aTestRels[nInd][nTagInd].First.equals( "Id" ) ) + { + nIDInd = nTagInd; + break; + } + } + + if ( nIDInd == -1 ) + { + Error( "One of the test hardcoded entries has no ID, num = " + nInd + ", length = " + aTestRels[nInd].length + ", global length = " + aTestRels.length + "!" ); + return false; + } + + if ( aStorRels[nStorInd][nStorIDInd].Second.equals( aTestRels[nInd][nIDInd].Second ) ) + { + boolean[] pRelCheckMark = new boolean[ aTestRels[nInd].length ]; + for ( int nCheckInd = 0; nCheckInd < pRelCheckMark.length; nCheckInd++ ) + { + pRelCheckMark[nCheckInd] = false; + } + + for ( int nStorTagInd = 0; nStorTagInd < aStorRels[nStorInd].length; nStorTagInd++ ) + { + boolean bFound = false; + for ( int nTagInd = 0; nTagInd < aTestRels[nInd].length; nTagInd++ ) + { + if ( aTestRels[nInd][nTagInd].First.equals( aStorRels[nStorInd][nStorTagInd].First ) ) + { + if ( !aTestRels[nInd][nTagInd].Second.equals( aStorRels[nStorInd][nStorTagInd].Second ) ) + { + Error( "Test rel. num. " + nInd + " has different tag \"" + aTestRels[nInd][nTagInd].First + "\" value!" ); + return false; + } + + bFound = true; + pRelCheckMark[nTagInd] = true; + break; + } + } + + if ( !bFound ) + { + Error( "Stor rel. num. " + nStorInd + " has unexpected tag \"" + aStorRels[nStorInd][nStorTagInd].First + "\", ID = \"" + aStorRels[nStorInd][nStorIDInd].Second + "\"!" ); + return false; + } + } + + for ( int nCheckInd = 0; nCheckInd < pRelCheckMark.length; nCheckInd++ ) + { + if ( !pRelCheckMark[nCheckInd] && !aTestRels[nInd][nCheckInd].Second.equals( "" ) ) + { + Error( "Test rel. num. " + nInd + " has unexpected tag \"" + aTestRels[nInd][nCheckInd].First + "\" with nonempty value!" ); + return false; + } + } + + break; + } + } + } + + return true; + } + + public boolean checkStorageProperties( XStorage xStorage, + boolean bIsRoot, + int nMode, + StringPair[][] aRelations ) + { + boolean bOk = false; + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStorage ); + if ( xPropSet != null ) + { + try + { + // get "IsRoot" and "OpenMode" properties and control there values + boolean bPropIsRoot = AnyConverter.toBoolean( xPropSet.getPropertyValue( "IsRoot" ) ); + int nPropMode = AnyConverter.toInt( xPropSet.getPropertyValue( "OpenMode" ) ); + + bOk = true; + if ( bPropIsRoot != bIsRoot ) + { + Error( "'IsRoot' property contains wrong value!" ); + bOk = false; + } + + if ( ( bIsRoot + && ( nPropMode | ElementModes.READ ) != ( nMode | ElementModes.READ ) ) + || ( !bIsRoot && ( nPropMode & nMode ) != nMode ) ) + { + Error( "'OpenMode' property contains wrong value, expected " + nMode + ", in reality " + nPropMode + "!" ); + bOk = false; + } + } + catch( Exception e ) + { + Error( "Can't get properties of substorage, exception: " + e ); + } + } + else + { + Error( "Can't get XPropertySet implementation from storage!" ); + } + + // get access to the relationship information + XRelationshipAccess xRelAccess = (XRelationshipAccess) UnoRuntime.queryInterface( XRelationshipAccess.class, xStorage ); + + if ( xRelAccess == null ) + { + Error( "Can't get XRelationshipAccess implementation from the checked storage!" ); + return false; + } + + // get the relationship information + StringPair[][] aStorRels; + try + { + aStorRels = xRelAccess.getAllRelationships(); + } + catch( Exception e ) + { + Error( "Can't get relationships of the checked storage, exception: " + e ); + return false; + } + + if ( !checkRelations( aStorRels, aRelations ) ) + { + Error( "StorageRelationsChecking has failed!" ); + return false; + } + + return bOk; + } + + public boolean InternalCheckStream( XStream xStream, + String sName, + String sMediaType, + byte[] pBytes, + StringPair[][] aRelations ) + { + // get input stream of substream + XInputStream xInput = xStream.getInputStream(); + if ( xInput == null ) + { + Error( "Can't get XInputStream implementation from substream '" + sName + "'!" ); + return false; + } + + byte pContents[][] = new byte[1][]; // ??? + + // read contents + try + { + xInput.readBytes( pContents, pBytes.length + 1 ); + } + catch( Exception e ) + { + Error( "Can't read from stream '" + sName + "', exception: " + e ); + return false; + } + + // check size of stream data + if ( pContents.length == 0 ) + { + Error( "SubStream '" + sName + "' reading produced disaster!" ); + return false; + } + + if ( pBytes.length != pContents[0].length ) + { + Error( "SubStream '" + sName + "' contains wrong amount of data! (" + pContents[0].length + "/" + pBytes.length + ")" ); + return false; + } + + // check stream data + for ( int ind = 0; ind < pBytes.length; ind++ ) + { + if ( pBytes[ind] != pContents[0][ind] ) + { + Error( "SubStream '" + sName + "' contains wrong data! ( byte num. " + + ind + " should be" + pBytes[ind] + " but it is " + pContents[0][ind] + ")" ); + return false; + } + } + + // check properties + boolean bOk = false; + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStream ); + if ( xPropSet != null ) + { + try + { + // get "MediaType" and "Size" properties and control there values + String sPropMediaType = AnyConverter.toString( xPropSet.getPropertyValue( "MediaType" ) ); + int nPropSize = AnyConverter.toInt( xPropSet.getPropertyValue( "Size" ) ); + + bOk = true; + if ( !sPropMediaType.equals( sMediaType ) ) + { + Error( "'MediaType' property contains wrong value for stream '" + sName + "',\nexpected: '" + + sMediaType + "', set: '" + sPropMediaType + "'!" ); + bOk = false; + } + + if ( nPropSize != pBytes.length ) + { + Error( "'Size' property contains wrong value for stream'" + sName + "'!" ); + bOk = false; + } + } + catch( Exception e ) + { + Error( "Can't get properties of substream '" + sName + "', exception: " + e ); + } + } + else + { + Error( "Can't get XPropertySet implementation from stream '" + sName + "'!" ); + } + + + // get access to the relationship information + XRelationshipAccess xRelAccess = (XRelationshipAccess) UnoRuntime.queryInterface( XRelationshipAccess.class, xStream ); + + if ( xRelAccess == null ) + { + Error( "Can't get XRelationshipAccess implementation from the stream\"" + sName + "\"!" ); + return false; + } + + // get the relationship information + StringPair[][] aStorRels; + try + { + aStorRels = xRelAccess.getAllRelationships(); + } + catch( Exception e ) + { + Error( "Can't get relationships of the substream '" + sName + "', exception: " + e ); + return false; + } + + if ( !checkRelations( aStorRels, aRelations ) ) + { + Error( "Stream '" + sName + "' RelationsChecking has failed!" ); + return false; + } + + return bOk; + } + + public boolean checkStream( XStorage xParentStorage, + String sName, + String sMediaType, + byte[] pBytes, + StringPair[][] aRelations ) + { + // open substream element first + XStream xSubStream = null; + try + { + Object oSubStream = xParentStorage.openStreamElement( sName, ElementModes.READ ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open substream '" + sName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't open substream '" + sName + "', exception : " + e + "!" ); + return false; + } + + boolean bResult = InternalCheckStream( xSubStream, sName, sMediaType, pBytes, aRelations ); + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sName ) ) + return false; + + return bResult; + } + + public boolean copyStorage( XStorage xSourceStorage, XStorage xDestStorage ) + { + // copy xSourceStorage to xDestStorage + try + { + xSourceStorage.copyToStorage( xDestStorage ); + } + catch( Exception e ) + { + Error( "Storage copying failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean commitStorage( XStorage xStorage ) + { + // XTransactedObject must be supported by storages + XTransactedObject xTransact = (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xStorage ); + if ( xTransact == null ) + { + Error( "Storage doesn't implement transacted access!" ); + return false; + } + + try + { + xTransact.commit(); + } + catch( Exception e ) + { + Error( "Storage commit failed, exception:" + e ); + return false; + } + + return true; + } + + public boolean disposeStream( XStream xStream, String sStreamName ) + { + XComponent xComponent = (XComponent) UnoRuntime.queryInterface( XComponent.class, xStream ); + if ( xComponent == null ) + { + Error( "Can't get XComponent implementation from substream '" + sStreamName + "'!" ); + return false; + } + + try + { + xComponent.dispose(); + } + catch( Exception e ) + { + Error( "Substream '" + sStreamName + "' disposing throws exception: " + e ); + return false; + } + + return true; + } + + public boolean disposeStorage( XStorage xStorage ) + { + // dispose the storage + XComponent xComponent = (XComponent) UnoRuntime.queryInterface( XComponent.class, xStorage ); + if ( xComponent == null ) + { + Error( "Can't retrieve XComponent implementation from storage!" ); + return false; + } + + try + { + xComponent.dispose(); + } + catch( Exception e ) + { + Error( "Storage disposing failed!" ); + return false; + } + + return true; + } + + public XInputStream getInputStream( XStream xStream ) + { + XInputStream xInTemp = null; + try + { + xInTemp = xStream.getInputStream(); + if ( xInTemp == null ) + Error( "Can't get the input part of a stream!" ); + } + catch ( Exception e ) + { + Error( "Can't get the input part of a stream, exception :" + e ); + } + + return xInTemp; + } + + public boolean closeOutput( XStream xStream ) + { + XOutputStream xOutTemp = null; + try + { + xOutTemp = xStream.getOutputStream(); + if ( xOutTemp == null ) + { + Error( "Can't get the output part of a stream!" ); + return false; + } + } + catch ( Exception e ) + { + Error( "Can't get the output part of a stream, exception :" + e ); + return false; + } + + try + { + xOutTemp.closeOutput(); + } + catch ( Exception e ) + { + Error( "Can't close output part of a stream, exception :" + e ); + return false; + } + + return true; + } + + public XStorage openSubStorage( XStorage xStorage, String sName, int nMode ) + { + // open existing substorage + try + { + Object oSubStorage = xStorage.openStorageElement( sName, nMode ); + XStorage xSubStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oSubStorage ); + return xSubStorage; + } + catch( Exception e ) + { + Error( "Can't open substorage '" + sName + "', exception: " + e ); + } + + return null; + } + + public XStream CreateTempFileStream( XMultiServiceFactory xMSF ) + { + // try to get temporary file representation + XStream xTempFileStream = null; + try + { + Object oTempFile = xMSF.createInstance( "com.sun.star.io.TempFile" ); + xTempFileStream = (XStream)UnoRuntime.queryInterface( XStream.class, oTempFile ); + } + catch( Exception e ) + {} + + if ( xTempFileStream == null ) + Error( "Can't create temporary file!" ); + + return xTempFileStream; + } + + public String CreateTempFile( XMultiServiceFactory xMSF ) + { + String sResult = null; + + // try to get temporary file representation + XPropertySet xTempFileProps = null; + try + { + Object oTempFile = xMSF.createInstance( "com.sun.star.io.TempFile" ); + xTempFileProps = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, oTempFile ); + } + catch( Exception e ) + {} + + if ( xTempFileProps != null ) + { + try + { + xTempFileProps.setPropertyValue( "RemoveFile", new Boolean( false ) ); + sResult = AnyConverter.toString( xTempFileProps.getPropertyValue( "Uri" ) ); + } + catch( Exception e ) + { + Error( "Can't control TempFile properties, exception: " + e ); + } + } + else + { + Error( "Can't create temporary file representation!" ); + } + + // close temporary file explicitly + try + { + XStream xStream = (XStream)UnoRuntime.queryInterface( XStream.class, xTempFileProps ); + if ( xStream != null ) + { + XOutputStream xOut = xStream.getOutputStream(); + if ( xOut != null ) + xOut.closeOutput(); + + XInputStream xIn = xStream.getInputStream(); + if ( xIn != null ) + xIn.closeInput(); + } + else + Error( "Can't close TempFile!" ); + } + catch( Exception e ) + { + Error( "Can't close TempFile, exception: " + e ); + } + + return sResult; + } + + public boolean copyElementTo( XStorage xSource, String sName, XStorage xDest ) + { + // copy element with name sName from xSource to xDest + try + { + xSource.copyElementTo( sName, xDest, sName ); + } + catch( Exception e ) + { + Error( "Element copying failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean copyElementTo( XStorage xSource, String sName, XStorage xDest, String sTargetName ) + { + // copy element with name sName from xSource to xDest + try + { + xSource.copyElementTo( sName, xDest, sTargetName ); + } + catch( Exception e ) + { + Error( "Element copying failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean moveElementTo( XStorage xSource, String sName, XStorage xDest ) + { + // move element with name sName from xSource to xDest + try + { + xSource.moveElementTo( sName, xDest, sName ); + } + catch( Exception e ) + { + Error( "Element moving failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean renameElement( XStorage xStorage, String sOldName, String sNewName ) + { + // rename element with name sOldName to sNewName + try + { + xStorage.renameElement( sOldName, sNewName ); + } + catch( Exception e ) + { + Error( "Element renaming failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean removeElement( XStorage xStorage, String sName ) + { + // remove element with name sName + try + { + xStorage.removeElement( sName ); + } + catch( Exception e ) + { + Error( "Element removing failed, exception: " + e ); + return false; + } + + return true; + } + + public XStream OpenStream( XStorage xStorage, + String sStreamName, + int nMode ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openStreamElement( sStreamName, nMode ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + Error( "Can't create substream '" + sStreamName + "'!" ); + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + } + + return xSubStream; + } + + public boolean cantOpenStorage( XStorage xStorage, String sName ) + { + // try to open an opened substorage, open call must fail + try + { + Object oDummyStorage = xStorage.openStorageElement( sName, ElementModes.READ ); + Error( "The trying to reopen opened substorage '" + sName + "' must fail!" ); + } + catch( Exception e ) + { + return true; + } + + return false; + } + + public boolean cantOpenStream( XStorage xStorage, String sName, int nMode ) + { + // try to open the substream with specified mode must fail + try + { + Object oDummyStream = xStorage.openStreamElement( sName, nMode ); + Error( "The trying to open substoream '" + sName + "' must fail!" ); + } + catch( Exception e ) + { + return true; + } + + return false; + } + + public XStorage createStorageFromURL( + XSingleServiceFactory xFactory, + String aURL, + int nMode ) + { + XStorage xResult = null; + + try + { + PropertyValue[] aAddArgs = new PropertyValue[1]; + aAddArgs[0] = new PropertyValue(); + aAddArgs[0].Name = "StorageFormat"; + aAddArgs[0].Value = "OFOPXMLFormat"; + + Object pArgs[] = new Object[3]; + pArgs[0] = (Object) aURL; + pArgs[1] = new Integer( nMode ); + pArgs[2] = (Object) aAddArgs; + + Object oTempStorage = xFactory.createInstanceWithArguments( pArgs ); + xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + } + catch( Exception e ) + { + Error( "Can't create storage from URL, exception: " + e ); + return null; + } + + if ( xResult == null ) + Error( "Can't create storage from URL!" ); + + return xResult; + } + + public XStorage createStorageFromStream( + XSingleServiceFactory xFactory, + XStream xStream, + int nMode ) + { + XStorage xResult = null; + + try + { + PropertyValue[] aAddArgs = new PropertyValue[1]; + aAddArgs[0] = new PropertyValue(); + aAddArgs[0].Name = "StorageFormat"; + aAddArgs[0].Value = "OFOPXMLFormat"; + + Object pArgs[] = new Object[3]; + pArgs[0] = (Object) xStream; + pArgs[1] = new Integer( nMode ); + pArgs[2] = (Object) aAddArgs; + + Object oTempStorage = xFactory.createInstanceWithArguments( pArgs ); + xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + } + catch( Exception e ) + { + Error( "Can't create storage from stream, exception: " + e ); + return null; + } + + if ( xResult == null ) + Error( "Can't create storage from stream!" ); + + return xResult; + } + + public XStorage createStorageFromInputStream( + XSingleServiceFactory xFactory, + XInputStream xInStream ) + { + XStorage xResult = null; + + try + { + PropertyValue[] aAddArgs = new PropertyValue[1]; + aAddArgs[0] = new PropertyValue(); + aAddArgs[0].Name = "StorageFormat"; + aAddArgs[0].Value = "OFOPXMLFormat"; + + Object pArgs[] = new Object[3]; + pArgs[0] = (Object) xInStream; + pArgs[1] = new Integer( ElementModes.READ ); + pArgs[2] = (Object) aAddArgs; + + Object oTempStorage = xFactory.createInstanceWithArguments( pArgs ); + xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + } + catch( Exception e ) + { + Error( "Can't create storage from input stream, exception: " + e ); + return null; + } + + if ( xResult == null ) + Error( "Can't create storage from input stream!" ); + + return xResult; + } + + public XStorage createTempStorage( XMultiServiceFactory xMSF, XSingleServiceFactory xFactory ) + { + // create a temporary storage + XStorage xResult = null; + XStream xStream = CreateTempFileStream( xMSF ); + if ( xStream == null ) + { + Error( "Can't create temp file stream!" ); + return null; + } + + try + { + xResult = createStorageFromStream( xFactory, xStream, ElementModes.WRITE ); + } + catch( Exception e ) + { + Error( "Can't create temp storage, exception: " + e ); + } + + return xResult; + } + + public XStorage cloneStorage( XMultiServiceFactory xMSF, XSingleServiceFactory xFactory, XStorage xStorage ) + { + // create a copy of a last commited version of specified storage + XStorage xResult = null; + try + { + xResult = createTempStorage( xMSF, xFactory ); + if ( xResult != null ) + xStorage.copyLastCommitTo( xResult ); + } + catch( Exception e ) + { + Error( "Can't clone storage, exception: " + e ); + return null; + } + + return xResult; + } + + public XStorage cloneSubStorage( XMultiServiceFactory xMSF, XSingleServiceFactory xFactory, XStorage xStorage, String sName ) + { + // create a copy of a last commited version of specified substorage + XStorage xResult = null; + try + { + xResult = createTempStorage( xMSF, xFactory ); + if ( xResult != null ) + xStorage.copyStorageElementLastCommitTo( sName, xResult ); + } + catch( Exception e ) + { + Error( "Can't clone substorage '" + sName + "', exception: " + e ); + return null; + } + + return xResult; + } + + public XStream cloneSubStream( XStorage xStorage, String sName ) + { + // clone existing substream + try + { + XStream xStream = xStorage.cloneStreamElement( sName ); + return xStream; + } + catch( Exception e ) + { + Error( "Can't clone substream '" + sName + "', exception: " + e ); + } + + return null; + } + + public void Error( String sError ) + { + m_aLogWriter.println( m_sTestPrefix + "Error: " + sError ); + } + + public void Message( String sMessage ) + { + m_aLogWriter.println( m_sTestPrefix + sMessage ); + } + + public void PrintRelations( StringPair[][] aRels ) + { + m_aLogWriter.println( "========" ); + for ( int nInd1 = 0; nInd1 < aRels.length; nInd1++ ) + { + for ( int nInd2 = 0; nInd2 < aRels[nInd1].length; nInd2++ ) + { + m_aLogWriter.println( "\"" + aRels[nInd1][nInd2].First + "\" = \"" + aRels[nInd1][nInd2].Second + "\", " ); + } + m_aLogWriter.println( "========" ); + } + } +} + diff --git a/package/qa/ofopxmlstorages/makefile.mk b/package/qa/ofopxmlstorages/makefile.mk new file mode 100644 index 000000000000..f4a99196181d --- /dev/null +++ b/package/qa/ofopxmlstorages/makefile.mk @@ -0,0 +1,95 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.5.18.1 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/.. +TARGET = StorageUnitTest +PRJNAME = package +PACKAGE = complex$/ofopxmlstorages + +# --- Settings ----------------------------------------------------- +.INCLUDE: settings.mk + + +#----- compile .java files ----------------------------------------- + +JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar OOoRunner.jar + +JAVAFILES =\ + StorageUnitTest.java\ + StorageTest.java\ + TestHelper.java\ + Test01.java\ + Test02.java\ + Test03.java\ + Test04.java\ + Test05.java\ + Test06.java\ + Test07.java\ + Test08.java + +JAVACLASSFILES = $(foreach,i,$(JAVAFILES) $(CLASSDIR)$/$(PACKAGE)$/$(i:b).class) + +#----- make a jar from compiled files ------------------------------ + +MAXLINELENGTH = 100000 + +JARCLASSDIRS = $(PACKAGE) +JARTARGET = $(TARGET).jar +JARCOMPRESS = TRUE + +# --- Parameters for the test -------------------------------------- + +# start an office if the parameter is set for the makefile +.IF "$(OFFICE)" == "" +CT_APPEXECCOMMAND = +.ELSE +CT_APPEXECCOMMAND = -AppExecutionCommand "$(OFFICE)$/soffice -accept=socket,host=localhost,port=8100;urp;" +.ENDIF + +# test base is java complex +CT_TESTBASE = -TestBase java_complex + +# test looks something like the.full.package.TestName +CT_TEST = -o $(PACKAGE:s\$/\.\).$(JAVAFILES:b) + +# start the runner application +CT_APP = org.openoffice.Runner + +# --- Targets ------------------------------------------------------ + +.INCLUDE: target.mk + +RUN: run + +run: + java -cp $(CLASSPATH) $(CT_APP) $(CT_TESTBASE) $(CT_APPEXECCOMMAND) $(CT_TEST) + + diff --git a/package/qa/storages/BorderedStream.java b/package/qa/storages/BorderedStream.java new file mode 100644 index 000000000000..7972b7a3ef0a --- /dev/null +++ b/package/qa/storages/BorderedStream.java @@ -0,0 +1,195 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; +import com.sun.star.io.XOutputStream; +import com.sun.star.io.XTruncate; +import com.sun.star.io.XSeekable; + + +public class BorderedStream + implements XStream, XInputStream, XOutputStream, XTruncate, XSeekable +{ + int m_nMaxSize; + int m_nCurSize; + int m_nCurPos; + byte m_pBytes[]; + + public BorderedStream( int nMaxSize ) + { + m_nMaxSize = nMaxSize; + m_nCurSize = 0; + m_nCurPos = 0; + m_pBytes = new byte[m_nMaxSize]; + } + + //============== + // XStream + //============== + + // ---------------------------------------------------------- + public synchronized XInputStream getInputStream() + throws com.sun.star.uno.RuntimeException + { + return (XInputStream)UnoRuntime.queryInterface( XInputStream.class, this ); + } + + // ---------------------------------------------------------- + public synchronized XOutputStream getOutputStream() + throws com.sun.star.uno.RuntimeException + { + return (XOutputStream)UnoRuntime.queryInterface( XOutputStream.class, this ); + } + + //============== + // XInputStream + //============== + + // ---------------------------------------------------------- + public synchronized int readBytes( byte[][] aData, int nBytesToRead ) + throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + int nRead = 0; + if ( m_pBytes != null && nBytesToRead > 0 ) + { + int nAvailable = m_nCurSize - m_nCurPos; + if ( nBytesToRead > nAvailable ) + nBytesToRead = nAvailable; + + aData[0] = new byte[nBytesToRead]; + for ( int nInd = 0; nInd < nBytesToRead; nInd++ ) + aData[0][nInd] = m_pBytes[m_nCurPos+nInd]; + + nRead = nBytesToRead; + m_nCurPos += nRead; + } + else + { + aData[0] = new byte[0]; + } + + return nRead; + } + + // ---------------------------------------------------------- + public synchronized int readSomeBytes( byte[][] aData, int nMaxBytesToRead ) + throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + return readBytes( aData, nMaxBytesToRead ); + } + + // ---------------------------------------------------------- + public synchronized void skipBytes( int nBytesToSkip ) + throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + if ( nBytesToSkip < 0 ) + throw new com.sun.star.io.IOException(); // illegal argument + + if ( m_nCurSize - m_nCurPos > nBytesToSkip ) + m_nCurPos += nBytesToSkip; + else + m_nCurPos = m_nCurSize; + } + + // ---------------------------------------------------------- + public synchronized int available() + throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + return 0; + } + + // ---------------------------------------------------------- + public synchronized void closeInput() + throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + // no need to do anything + } + + + //============== + // XOutputStream + //============== + + // ---------------------------------------------------------- + public synchronized void writeBytes( byte[] aData ) + throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + if ( m_pBytes != null && aData.length > 0 ) + { + if ( aData.length > m_nMaxSize - m_nCurPos ) + throw new com.sun.star.io.IOException(); + + for ( int nInd = 0; nInd < aData.length; nInd++ ) + m_pBytes[m_nCurPos+nInd] = aData[nInd]; + + m_nCurPos += aData.length; + if ( m_nCurPos > m_nCurSize ) + m_nCurSize = m_nCurPos; + } + } + + // ---------------------------------------------------------- + public synchronized void flush() + throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + // nothing to do + } + + // ---------------------------------------------------------- + public synchronized void closeOutput() + throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + // nothing to do + } + + + //============== + // XTruncate + //============== + + // ---------------------------------------------------------- + public synchronized void truncate() + throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + m_nCurSize = 0; + m_nCurPos = 0; + } + + + //============== + // XSeekable + //============== + + // ---------------------------------------------------------- + public synchronized void seek( long location ) + throws com.sun.star.lang.IllegalArgumentException, com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + if ( location > (long)m_nCurSize ) + throw new com.sun.star.lang.IllegalArgumentException(); + + m_nCurPos = (int)location; + } + + // ---------------------------------------------------------- + public synchronized long getPosition() + throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + return (long)m_nCurPos; + } + + // ---------------------------------------------------------- + public synchronized long getLength() + throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException + { + return (long)m_nCurSize; + } +}; + diff --git a/package/qa/storages/RegressionTest_114358.java b/package/qa/storages/RegressionTest_114358.java new file mode 100644 index 000000000000..51d3ecb4a8b4 --- /dev/null +++ b/package/qa/storages/RegressionTest_114358.java @@ -0,0 +1,190 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_114358 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_114358( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_114358: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // create a new storage based on the stream and change the substream + // as described in the bug description + // ================================================ + + byte pBytes2[] = { 2, 2 }; + + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the substream, set new "MediaType" and "Compressed" properties to it, truncate and write new contents + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType4", true, pBytes2 ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // create a new readonly storage based on the stream and check the contents + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType2", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + // the MediaType and the contents must be up to date + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream1", "MediaType4", true, pBytes2 ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_125919.java b/package/qa/storages/RegressionTest_125919.java new file mode 100644 index 000000000000..0a13fc63758c --- /dev/null +++ b/package/qa/storages/RegressionTest_125919.java @@ -0,0 +1,134 @@ +package complex.storages; + +import java.lang.Integer; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; +import complex.storages.BorderedStream; + +public class RegressionTest_125919 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + int nMinTestLen = 0; + int nMaxTestLen = 60000; + + public RegressionTest_125919( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_125919: " ); + } + + public boolean test() + { + try + { + byte[] pBytes0 = new byte[0]; + byte[] pBytes18 = new byte[18000]; + byte[] pBytes36 = new byte[36000]; + + for ( int nInitInd = 0; nInitInd < 36000; nInitInd++ ) + { + pBytes36[nInitInd] = ( new Integer( nInitInd >> ( ( nInitInd % 2 ) * 8 ) ) ).byteValue(); + if ( nInitInd < 18000 ) + pBytes18[nInitInd] = ( new Integer( 256 - pBytes36[nInitInd] ) ).byteValue(); + } + + System.out.println( "This test can take up to some hours. The file size currently is about 50000." ); + System.out.println( "Progress: " ); + for ( int nAvailableBytes = nMinTestLen; nAvailableBytes < nMaxTestLen; nAvailableBytes++ ) + { + Object oBStream = new BorderedStream( nAvailableBytes ); + XStream xBorderedStream = (XStream)UnoRuntime.queryInterface( XStream.class, oBStream ); + if ( xBorderedStream == null ) + { + m_aTestHelper.Error( "Can't create bordered stream!" ); + return false; + } + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xBorderedStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + XTransactedObject xTransact = (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xTempStorage ); + if ( xTransact == null ) + { + m_aTestHelper.Error( "This test is designed for storages in transacted mode!" ); + return false; + } + + + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream" + 0, "MediaType1", true, pBytes0 ) ) + return false; + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream" + 18, "MediaType2", true, pBytes18 ) ) + return false; + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream" + 36, "MediaType3", true, pBytes36 ) ) + return false; + + if ( nAvailableBytes > 0 && nAvailableBytes % 100 == 0 ) + System.out.println( " " + nAvailableBytes ); + + if ( nAvailableBytes > 0 && nAvailableBytes % 2 == 1 ) + System.out.print( "#" ); + + try + { + xTransact.commit(); + + System.out.println( "" ); + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // SUCCESS + return true; + } + catch( UseBackupException aExc ) + { + // when there is not enough place in the target location and the target file is empty + // the direct writing will fail and must throw this exception with empty URL + if ( aExc.TemporaryFileURL.length() != 0 ) + return false; + } + catch( Exception e ) + { + System.out.println( "" ); + m_aTestHelper.Error( "Unexpected exception: " + e + "\nnAvailableBytes = " + nAvailableBytes ); + return false; + } + } + + return false; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i26398.java b/package/qa/storages/RegressionTest_i26398.java new file mode 100644 index 000000000000..9116a7d9bafa --- /dev/null +++ b/package/qa/storages/RegressionTest_i26398.java @@ -0,0 +1,146 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i26398 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i26398( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i26398: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + + // ================================================ + // commit the substorage, dispose it, reopen readonly + // and dispose the reopened substorage + // ================================================ + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // open a new substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // ================================================ + // reopen the substorage in readwrite mode and check contents + // ================================================ + + // open a new substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType3", false, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType2", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // the root storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i27773.java b/package/qa/storages/RegressionTest_i27773.java new file mode 100644 index 000000000000..4e627a816167 --- /dev/null +++ b/package/qa/storages/RegressionTest_i27773.java @@ -0,0 +1,299 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; +import com.sun.star.beans.XPropertySet; +import com.sun.star.uno.AnyConverter; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +/////////////////////////////////// +// Tests also fix for i51352 +/////////////////////////////////// + +public class RegressionTest_i27773 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i27773( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i27773: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + if ( true ) + { + // for debugging proposes + + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xTempFileStream ); + if ( xPropSet != null ) + { + try + { + String sTempURL = AnyConverter.toString( xPropSet.getPropertyValue( "Uri" ) ); + // m_aTestHelper.Message( "URL: " + sTempURL ); + xPropSet.setPropertyValue( "RemoveFile", new Boolean( false ) ); + } + catch ( Exception e ) + { + } + } + } + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open an empty substorage + XStorage xEmptySubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "EmptySubStorage1", + ElementModes.WRITE ); + if ( xEmptySubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open an empty substorage + XStorage xEmptySubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "EmptySubSubStorage1", + ElementModes.WRITE ); + if ( xEmptySubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xEmptySubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xEmptySubSubStorage, + "MediaType5", + false, + ElementModes.WRITE ) ) + return false; + + + // make a copy of substorage + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "SubStorage1", xTempStorage, "SubStorage1_copy" ) ) + return false; + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "EmptySubStorage1", xTempStorage, "EmptySubStorage1_copy" ) ) + return false; + + // ================================================ + // copy all the changed and noncommited substorages + // and dispose them + // ================================================ + + if ( !m_aTestHelper.commitStorage( xEmptySubSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xEmptySubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorages + + if ( !m_aTestHelper.disposeStorage( xEmptySubSubStorage ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xEmptySubStorage ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // reopen the storage in readonly mode an check contents + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open original substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open copy of the original substorage + XStorage xTempSubStorage_copy = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1_copy", + ElementModes.READ ); + if ( xTempSubStorage_copy == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open empty substorage + xEmptySubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "EmptySubStorage1", + ElementModes.READ ); + if ( xEmptySubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open copy of empty substorage + XStorage xEmptySubStorage_copy = m_aTestHelper.openSubStorage( xTempStorage, + "EmptySubStorage1_copy", + ElementModes.READ ); + if ( xEmptySubStorage_copy == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open an empty substorage of the substorage + xEmptySubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "EmptySubSubStorage1", + ElementModes.READ ); + if ( xEmptySubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open an empty substorage of the substorage copy + XStorage xEmptySubSubStorage_inCopy = m_aTestHelper.openSubStorage( xTempSubStorage_copy, + "EmptySubSubStorage1", + ElementModes.READ ); + if ( xEmptySubSubStorage_inCopy == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + + // check contents + + if ( !m_aTestHelper.checkStorageProperties( xEmptySubSubStorage, "MediaType5", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xEmptySubSubStorage_inCopy, "MediaType5", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage_copy, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xEmptySubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xEmptySubStorage_copy, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType2", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage_copy, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // the root storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i29169.java b/package/qa/storages/RegressionTest_i29169.java new file mode 100644 index 000000000000..580ee510caf8 --- /dev/null +++ b/package/qa/storages/RegressionTest_i29169.java @@ -0,0 +1,369 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i29169 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i29169( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i29169: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // open a new substorage in the existing substorage + XStorage xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubSubStorage, "SubSubStream1", "MediaType2", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType5", + true, + ElementModes.WRITE ) ) + return false; + + // ================================================ + // commit the storages, and check the renaming in all stages + // ================================================ + + // rename the storage before it is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage1", "SubSubStorage2" ) ) + return false; + + // rename the stream + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream1", "SubStream2" ) ) + return false; + + // commit lowlevel substorage first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // rename the storage after it is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage2", "SubSubStorage3" ) ) + return false; + + // rename the stream one more time + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream2", "SubStream3" ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // rename the storage after it`s parent is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage3", "SubSubStorage4" ) ) + return false; + + // rename the stream after it`s parent is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream3", "SubStream4" ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // rename the storage after the package is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage4", "SubSubStorage5" ) ) + return false; + + // rename the stream after it`s parent is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream4", "SubStream5" ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // ================================================ + // dispose the storages + // ================================================ + + // dispose lowerest substorage + if ( !m_aTestHelper.disposeStorage( xTempSubSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // create a new storage based on the stream and check the substreams and substorages + // ================================================ + + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the lowlevel substorage + xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage5", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // check the storages and streams + + if ( !m_aTestHelper.checkStorageProperties( xTempSubSubStorage, "MediaType3", false, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType4", false, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType5", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream5", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage, "SubSubStream1", "MediaType2", true, pBytes1 ) ) + return false; + + // ================================================ + // rename the reopened storages and streams + // ================================================ + + // rename the storage before it is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage5", "SubSubStorage6" ) ) + return false; + + // rename the stream + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream5", "SubStream6" ) ) + return false; + + // commit lowlevel substorage first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // rename the storage after it is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage6", "SubSubStorage7" ) ) + return false; + + // rename the stream one more time + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream6", "SubStream7" ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // rename the storage after it`s parent is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage7", "SubSubStorage8" ) ) + return false; + + // rename the stream after it`s parent is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream7", "SubStream8" ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // rename the storage after the package is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubSubStorage8", "SubSubStorage9" ) ) + return false; + + // rename the stream after it`s parent is commited + if ( !m_aTestHelper.renameElement( xTempSubStorage, "SubStream8", "SubStream9" ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // ================================================ + // dispose the storages + // ================================================ + + // dispose lowerest substorage + if ( !m_aTestHelper.disposeStorage( xTempSubSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + + // ================================================ + // create a new readonly storage based on the stream and check the contents + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the lowlevel substorage + xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage9", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // check the storages and streams + + if ( !m_aTestHelper.checkStorageProperties( xTempSubSubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType5", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream9", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage, "SubSubStream1", "MediaType2", true, pBytes1 ) ) + return false; + + // the storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i29321.java b/package/qa/storages/RegressionTest_i29321.java new file mode 100644 index 000000000000..740f48ce59a3 --- /dev/null +++ b/package/qa/storages/RegressionTest_i29321.java @@ -0,0 +1,170 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i29321 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i29321( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i29321: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substorage + XStorage xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xTempSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "Stream1", "MediaType1", true, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType2", true, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubSubStorage, "SubSubStream1", "MediaType3", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType4", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType5", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubSubStorage, + "MediaType6", + false, + ElementModes.WRITE ) ) + return false; + + // ================================================ + // commit the storages twice to test the bug scenario + // ================================================ + + // commit lowlevel substorage first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // commit lowlevel substorage first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // ================================================ + // check the storages and streams without closing + // ================================================ + + if ( !m_aTestHelper.checkStorageProperties( xTempSubSubStorage, "MediaType6", false, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType5", false, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType4", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage, "SubSubStream1", "MediaType3", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream1", "MediaType2", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempStorage, "Stream1", "MediaType1", true, pBytes1 ) ) + return false; + + // the root storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i30400.java b/package/qa/storages/RegressionTest_i30400.java new file mode 100644 index 000000000000..5f82a7beb39e --- /dev/null +++ b/package/qa/storages/RegressionTest_i30400.java @@ -0,0 +1,435 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i30400 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i30400( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i30400: " ); + } + + public boolean test() + { + try + { + // ================================================ + // create a temporary stream and a storage based on it + // fill the storage with the data that will be used for testing + // ================================================ + + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + String pPass1 = "1, 2, 3, 4, 5"; + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "Stream1", "MediaType1", true, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "EncrStream1", "MediaType2", true, pBytes1, pPass1 ) ) + return false; + + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType3", true, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "SubEncrStream1", "MediaType4", true, pBytes1, pPass1 ) ) + return false; + + // open a new substorage in the existing substorage + XStorage xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubSubStorage, "SubSubStream1", "MediaType5", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubSubStorage, + "MediaType6", + false, + ElementModes.WRITE ) ) + return false; + + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType7", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType8", + true, + ElementModes.WRITE ) ) + return false; + + // ================================================ + // check the copying with renaming + // ================================================ + + if ( !TestCopyWithRenaming( xTempStorage, xTempSubStorage, xTempSubSubStorage ) ) + return false; + + // ================================================ + // commit the storages + // ================================================ + + // commit lowlevel substorage + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // ================================================ + // dispose the storages + // ================================================ + + // dispose lowerest substorage + if ( !m_aTestHelper.disposeStorage( xTempSubSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // reopen the target storage readonly, and check the copying with renaming + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorages + + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the lowlevel substorages + + xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.READ ); + if ( xTempSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // test the copying with renaming + if ( !TestCopyWithRenaming( xTempStorage, xTempSubStorage, xTempSubSubStorage ) ) + return false; + + + // the storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + + + public boolean TestCopyWithRenaming( XStorage xTempStorage, XStorage xTempSubStorage, XStorage xTempSubSubStorage ) + throws com.sun.star.uno.Exception + { + // ================================================ + // create a second temporary stream and copy all the staff there + // with renaming, check the success + // ================================================ + + XStream xTempFileStream2 = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream2 == null ) + return false; + + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream2; + pArgs[1] = new Integer( ElementModes.WRITE ); + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + String pPass1 = "1, 2, 3, 4, 5"; + + Object oTempStorage2 = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage2 = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage2 ); + if ( xTempStorage2 == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage2 = m_aTestHelper.openSubStorage( xTempStorage2, + "SubStorage1_target", + ElementModes.WRITE ); + if ( xTempSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substorage in the existing substorage + XStorage xTempSubSubStorage2 = m_aTestHelper.openSubStorage( xTempSubStorage2, + "SubSubStorage1_target", + ElementModes.WRITE ); + if ( xTempSubSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // make a copy with renaming on lowerest level + if ( !m_aTestHelper.copyElementTo( xTempSubSubStorage, "SubSubStream1", xTempSubSubStorage2, "SubSubStream1_renamed" ) ) + return false; + + // make a copy with renaming on the next level + + if ( !m_aTestHelper.copyElementTo( xTempSubStorage, "SubStream1", xTempSubStorage2, "SubStream1_renamed" ) ) + return false; + + if ( !m_aTestHelper.copyElementTo( xTempSubStorage, "SubEncrStream1", xTempSubStorage2, "SubEncrStream1_renamed" ) ) + return false; + + if ( !m_aTestHelper.copyElementTo( xTempSubStorage, "SubSubStorage1", xTempSubStorage2, "SubSubStorage1_renamed" ) ) + return false; + + // make a copy with renaming of subelements of the root storage + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "Stream1", xTempStorage2, "Stream1_renamed" ) ) + return false; + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "EncrStream1", xTempStorage2, "EncrStream1_renamed" ) ) + return false; + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "SubStorage1", xTempStorage2, "SubStorage1_renamed" ) ) + return false; + + // ================================================ + // commit the storages, and check the renaming in all stages + // ================================================ + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage2 ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempSubStorage2 ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage2 ) ) + return false; + + // ================================================ + // dispose the storages + // ================================================ + + // dispose lowerest substorage + if ( !m_aTestHelper.disposeStorage( xTempSubSubStorage2 ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage2 ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage2 ) ) + return false; + + // ================================================ + // reopen the target storage readonly, and check the contents + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + oTempStorage2 = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage2 = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage2 ); + if ( xTempStorage2 == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorages + + XStorage xTempSubStorage2_target = m_aTestHelper.openSubStorage( xTempStorage2, + "SubStorage1_target", + ElementModes.READ ); + if ( xTempSubStorage2_target == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + XStorage xTempSubStorage2_renamed = m_aTestHelper.openSubStorage( xTempStorage2, + "SubStorage1_renamed", + ElementModes.READ ); + if ( xTempSubStorage2_renamed == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the lowlevel substorages + + XStorage xTempSubSubStorage2_inRenamed = m_aTestHelper.openSubStorage( xTempSubStorage2_renamed, + "SubSubStorage1", + ElementModes.READ ); + if ( xTempSubSubStorage2_inRenamed == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + XStorage xTempSubSubStorage2_renamed = m_aTestHelper.openSubStorage( xTempSubStorage2_target, + "SubSubStorage1_renamed", + ElementModes.READ ); + if ( xTempSubSubStorage2_renamed == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + XStorage xTempSubSubStorage2_target = m_aTestHelper.openSubStorage( xTempSubStorage2_target, + "SubSubStorage1_target", + ElementModes.READ ); + if ( xTempSubSubStorage2_target == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // check the storages + + if ( !m_aTestHelper.checkStorageProperties( xTempSubSubStorage2_inRenamed, "MediaType6", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubSubStorage2_renamed, "MediaType6", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage2_renamed, "MediaType7", false, ElementModes.READ ) ) + return false; + + + // check the streams + + + // sub sub level + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage2_inRenamed, "SubSubStream1", "MediaType5", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage2_renamed, "SubSubStream1", "MediaType5", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage2_target, "SubSubStream1_renamed", "MediaType5", true, pBytes1 ) ) + return false; + + // sub level + + if ( !m_aTestHelper.checkStream( xTempSubStorage2_renamed, "SubStream1", "MediaType3", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xTempSubStorage2_renamed, "SubEncrStream1", "MediaType4", pBytes1, pPass1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage2_target, "SubStream1_renamed", "MediaType3", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xTempSubStorage2_target, "SubEncrStream1_renamed", "MediaType4", pBytes1, pPass1 ) ) + return false; + + // root storage level + + if ( !m_aTestHelper.checkStream( xTempStorage2, "Stream1_renamed", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xTempStorage2, "EncrStream1_renamed", "MediaType2", pBytes1, pPass1 ) ) + return false; + + // the storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } +} + diff --git a/package/qa/storages/RegressionTest_i30677.java b/package/qa/storages/RegressionTest_i30677.java new file mode 100644 index 000000000000..740c9e319313 --- /dev/null +++ b/package/qa/storages/RegressionTest_i30677.java @@ -0,0 +1,263 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i30677 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i30677( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i30677: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new subsubstorage + XStorage xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xTempSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubSubStorage, "SubSubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // ================================================ + // commit the storages + // ================================================ + + // commit lowlevel substorage first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // ================================================ + // dispose the storages + // ================================================ + + // dispose lowerest substorage + if ( !m_aTestHelper.disposeStorage( xTempSubSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // reopen the storage and rewrite the stream + // ================================================ + + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorages + + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the lowlevel substorages + + xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xTempSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubSubStorage, "SubSubStream1", "MediaType1", true, pBytes2 ) ) + return false; + + // ================================================ + // commit the storages + // ================================================ + + // commit lowlevel substorage first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit substorage to let the renaming take place + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // ================================================ + // dispose the storages + // ================================================ + + // dispose lowerest substorage + if ( !m_aTestHelper.disposeStorage( xTempSubSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // reopen the storages and check the contents + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorages + + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open the lowlevel substorages + + xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.READ ); + if ( xTempSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTempSubSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType2", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubSubStorage, "SubSubStream1", "MediaType1", true, pBytes2 ) ) + return false; + + // the root storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i35095.java b/package/qa/storages/RegressionTest_i35095.java new file mode 100644 index 000000000000..d98ec800a5a6 --- /dev/null +++ b/package/qa/storages/RegressionTest_i35095.java @@ -0,0 +1,166 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i35095 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i35095( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i35095: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBytes[] = new byte[36000]; + for ( int nInd = 0; nInd < 36000; nInd++ ) + pBytes[nInd] = (byte)( nInd % 128 ); + + String sPass = "12345"; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes, sPass ) ) + return false; + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "SubStream2", "MediaType2", false, pBytes, sPass ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // now check all the written information + // and the raw stream contents + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + // open input stream + // since no mode is provided the result storage must be opened readonly + Object pOneArg[] = new Object[1]; + pOneArg[0] = (Object) xTempInStream; + + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pOneArg ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.compareRawMethodsOnEncrStream( xResultStorage, "SubStream1" ) ) + return false; + + if ( !m_aTestHelper.compareRawMethodsOnEncrStream( xResultSubStorage, "SubStream2" ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/RegressionTest_i46848.java b/package/qa/storages/RegressionTest_i46848.java new file mode 100644 index 000000000000..438626e9a7ba --- /dev/null +++ b/package/qa/storages/RegressionTest_i46848.java @@ -0,0 +1,191 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i46848 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i46848( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i46848: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // create a new storage based on the stream and change the mediatype of the substorage + // as described in the bug description + // ================================================ + + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "ChangedMediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // dispose the temporary storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // create a new readonly storage based on the stream and check the contents + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open the substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.READ ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTempStorage, "MediaType2", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xTempSubStorage, "ChangedMediaType3", false, ElementModes.READ ) ) + return false; + + // the MediaType and the contents must be up to date + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i49755.java b/package/qa/storages/RegressionTest_i49755.java new file mode 100644 index 000000000000..7d3ee6c01cac --- /dev/null +++ b/package/qa/storages/RegressionTest_i49755.java @@ -0,0 +1,272 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i49755 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i49755( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i49755: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType1", + true, + ElementModes.WRITE ) ) + return false; + + + byte pBytes[] = new byte[36000]; + for ( int nInd = 0; nInd < 36000; nInd++ ) + pBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType2", + false, + ElementModes.WRITE ) ) + return false; + + // open a new substorage + XStorage xTempSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubStorage2", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubSubStorage, "SubStream1", "MediaType4", true, pBytes ) ) + return false; + + // open a new substorage + XStorage xTempSubStorage1 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage3", + ElementModes.WRITE ); + if ( xTempSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage1, + "MediaType5", + false, + ElementModes.WRITE ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage1, "SubStream2", "MediaType4", false, pBytes ) ) + return false; + + + // commit substorages first + if ( !m_aTestHelper.commitStorage( xTempSubSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage1 ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // now change the contents of the second substorage + // without changing of the contents of the first substorage + // ================================================ + + Object oStep2TempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xStep2TempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oStep2TempStorage ); + if ( xStep2TempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + XStorage xStep2TempSubStorage1 = m_aTestHelper.openSubStorage( xStep2TempStorage, + "SubStorage3", + ElementModes.WRITE ); + if ( xStep2TempSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xStep2TempSubStorage1, "SubStream2", "MediaType4", false, pBytes ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xStep2TempSubStorage1 ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xStep2TempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xStep2TempStorage ) ) + return false; + + + // ================================================ + // now check all the written information + // and the raw stream contents + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + // open input stream + // since no mode is provided the result storage must be opened readonly + Object pOneArg[] = new Object[1]; + pOneArg[0] = (Object) xTempInStream; + + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pOneArg ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType1", true, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType2", false, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResultSubSubStorage = m_aTestHelper.openSubStorage( xResultSubStorage, + "SubStorage2", + ElementModes.READ ); + if ( xResultSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubSubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubSubStorage, "SubStream1", "MediaType4", true, pBytes ) ) + return false; + + + + XStorage xResultSubStorage1 = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage3", + ElementModes.READ ); + if ( xResultSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage1, "MediaType5", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage1, "SubStream2", "MediaType4", false, pBytes ) ) + return false; + + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/RegressionTest_i55821.java b/package/qa/storages/RegressionTest_i55821.java new file mode 100644 index 000000000000..0803816427d6 --- /dev/null +++ b/package/qa/storages/RegressionTest_i55821.java @@ -0,0 +1,111 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i55821 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i55821( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i55821: " ); + } + + public boolean test() + { + try + { + // ================================================ + // create a temporary stream and a storage based on it + // fill the storage with the data that will be used for testing + // ================================================ + + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + String sPass = "12345"; + byte pBytes[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + // the stream will not be encrypted + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream1", "MediaType1", false, pBytes, sPass ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream2", "MediaType2", false, pBytes, sPass ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // reopen the target storage readonly, and check contents + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "SubStream1", "MediaType1", pBytes, sPass ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "SubStream2", "MediaType2", pBytes, sPass ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i59886.java b/package/qa/storages/RegressionTest_i59886.java new file mode 100644 index 000000000000..471149823c33 --- /dev/null +++ b/package/qa/storages/RegressionTest_i59886.java @@ -0,0 +1,243 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i59886 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i59886( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i59886: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBytes[] = new byte[36000]; + for ( int nInd = 0; nInd < 36000; nInd++ ) + pBytes[nInd] = (byte)( nInd % 128 ); + + String sPass = "12345"; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes, sPass ) ) + return false; + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "SubStream2", "MediaType2", false, pBytes, sPass ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // now reopen the storage, set the common storage key + // and copy the storage + // ================================================ + + Object oStep2TempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xStep2TempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oStep2TempStorage ); + if ( xStep2TempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + + XStorage xStep2TempSubStorage = m_aTestHelper.openSubStorage( xStep2TempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xStep2TempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // set the common storage password + XEncryptionProtectedSource xEncr = (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xStep2TempStorage ); + if ( xEncr == null ) + { + m_aTestHelper.Error( "The storage does not support encryption access!" ); + return false; + } + try + { + xEncr.setEncryptionPassword( sPass ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can not set the common storage password!" ); + return false; + } + + // open the stream for writing and read them so that the cache is created, but do not change + byte pDummyData[][] = new byte[1][3]; + XStream xTempStream1 = m_aTestHelper.OpenStream( xStep2TempStorage, "SubStream1", ElementModes.WRITE ); + XStream xTempStream2 = m_aTestHelper.OpenStream( xStep2TempSubStorage, "SubStream2", ElementModes.WRITE ); + if ( xTempStream1 == null || xTempStream2 == null ) + return false; + + XInputStream xTempInStream1 = xTempStream1.getInputStream(); + XInputStream xTempInStream2 = xTempStream2.getInputStream(); + if ( xTempInStream1 == null || xTempInStream2 == null ) + { + m_aTestHelper.Error( "No input stream is available!" ); + return false; + } + + xTempInStream1.readBytes( pDummyData, 3 ); + xTempInStream2.readBytes( pDummyData, 3 ); + + + // create temporary storage, it will be checked later + Object oTargetStorage = m_xStorageFactory.createInstance(); + XStorage xTargetStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTargetStorage ); + if ( xTargetStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // copy the current storage to the target + try + { + xStep2TempStorage.copyToStorage( xTargetStorage ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can not copy the storage with common storage password!" ); + return false; + } + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xStep2TempStorage ) ) + return false; + + // ================================================ + // now check all the information in the copy + // ================================================ + + if ( !m_aTestHelper.checkStorageProperties( xTargetStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + // open existing substorage + XStorage xTargetSubStorage = m_aTestHelper.openSubStorage( xTargetStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTargetSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTargetSubStorage, "MediaType4", false, ElementModes.WRITE ) ) + return false; + + // set the common storage password + XEncryptionProtectedSource xTargetEncr = (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xTargetStorage ); + if ( xTargetEncr == null ) + { + m_aTestHelper.Error( "The storage does not support encryption access!" ); + return false; + } + try + { + xTargetEncr.setEncryptionPassword( sPass ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can not set the common storage password!" ); + return false; + } + + // check the streams + if ( !m_aTestHelper.checkStream( xTargetStorage, "SubStream1", "MediaType1", true, pBytes ) ) + return false; + if ( !m_aTestHelper.checkStream( xTargetSubStorage, "SubStream2", "MediaType2", true, pBytes ) ) + return false; + + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTargetStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i61909.java b/package/qa/storages/RegressionTest_i61909.java new file mode 100644 index 000000000000..5f5c1572d79d --- /dev/null +++ b/package/qa/storages/RegressionTest_i61909.java @@ -0,0 +1,167 @@ +package complex.storages; + +import java.net.URI; +import java.io.File; +import java.io.FileInputStream; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipEntry; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i61909 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i61909( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i61909: " ); + } + + public boolean test() + { + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBytes[] = new byte[36000]; + for ( int nInd = 0; nInd < 36000; nInd++ ) + pBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes ) ) + return false; + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream2", "MediaType2", true, pBytes ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // now reopen the storage, and insert a new stream + // ================================================ + + Object oStep2TempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xStep2TempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oStep2TempStorage ); + if ( xStep2TempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xStep2TempStorage, "SubStream3", "MediaType5", true, pBytes ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xStep2TempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xStep2TempStorage ) ) + return false; + + // ================================================ + // now access the stream using ZipInputStream + // ================================================ + + URI aUri = new URI( sTempFileURL ); + File aFile = new File( aUri ); + FileInputStream aFileStream = new FileInputStream( aFile ); + ZipInputStream aZipStream = new ZipInputStream( aFileStream ); + + ZipEntry aEntry; + int nNumber = 0; + m_aTestHelper.Message( "Available entries:" ); + while ( ( aEntry = aZipStream.getNextEntry() ) != null ) + { + nNumber++; + m_aTestHelper.Message( aEntry.getName() ); + } + + if ( nNumber != 6 ) + { + m_aTestHelper.Error( "Wrong number of entries: " + nNumber + ", Expected: 6" ); + return false; + } + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/RegressionTest_i84234.java b/package/qa/storages/RegressionTest_i84234.java new file mode 100644 index 000000000000..16150690d882 --- /dev/null +++ b/package/qa/storages/RegressionTest_i84234.java @@ -0,0 +1,134 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class RegressionTest_i84234 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public RegressionTest_i84234( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "RegressionTest_i84234: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream1", "text/xml", false, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream2", "text/xml", false, pBytes1 ) ) + return false; + + + // ================================================ + // commit the storages and dispose them + // ================================================ + + // commit substorage + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // commit storage + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose storage + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // reopen the storages in readwrite mode and check Compressed flag + // ================================================ + + oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStream( xTempStorage, "SubStream1", "text/xml", false, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xTempSubStorage, "SubStream2", "text/xml", false, pBytes1 ) ) + return false; + + // the root storage is based on the temporary stream so it can be left undisposed, since it does not lock + // any resource, later the garbage collector will release the object and it must die by refcount + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/StorageTest.java b/package/qa/storages/StorageTest.java new file mode 100644 index 000000000000..4691564c23a0 --- /dev/null +++ b/package/qa/storages/StorageTest.java @@ -0,0 +1,7 @@ +package complex.storages; + +public interface StorageTest +{ + boolean test(); +} + diff --git a/package/qa/storages/StorageUnitTest.java b/package/qa/storages/StorageUnitTest.java new file mode 100644 index 000000000000..2ebfb2967e1d --- /dev/null +++ b/package/qa/storages/StorageUnitTest.java @@ -0,0 +1,329 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: StorageUnitTest.java,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +package complex.storages; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XMultiComponentFactory; +import com.sun.star.connection.XConnector; +import com.sun.star.connection.XConnection; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.XNamingService; +import com.sun.star.uno.XComponentContext; + +import com.sun.star.container.*; +import com.sun.star.beans.*; +import com.sun.star.lang.*; + +import complexlib.ComplexTestCase; + +import complex.storages.*; + +import util.utils; +import java.util.*; +import java.io.*; + +/* This unit test for storage objects is designed to + * test most important statements from storage service + * specification. + * + * Regression tests are added to extend the tested + * functionalities. + */ +public class StorageUnitTest extends ComplexTestCase +{ + private XMultiServiceFactory m_xMSF = null; + private XSingleServiceFactory m_xStorageFactory = null; + + public String[] getTestMethodNames() + { + return new String[] { + "ExecuteTest01", + "ExecuteTest02", + "ExecuteTest03", + "ExecuteTest04", + "ExecuteTest05", + "ExecuteTest06", + "ExecuteTest07", + "ExecuteTest08", + "ExecuteTest09", + "ExecuteTest10", + "ExecuteTest11", + "ExecuteTest12", + "ExecuteTest13", + "ExecuteTest14", + "ExecuteTest15", + "ExecuteTest16", + "ExecuteTest17", + "ExecuteTest18", + "ExecuteRegressionTest_114358", + "ExecuteRegressionTest_i29169", + "ExecuteRegressionTest_i30400", + "ExecuteRegressionTest_i29321", + "ExecuteRegressionTest_i30677", + "ExecuteRegressionTest_i27773", + "ExecuteRegressionTest_i46848", + "ExecuteRegressionTest_i55821", + "ExecuteRegressionTest_i35095", + "ExecuteRegressionTest_i49755", + "ExecuteRegressionTest_i59886", + "ExecuteRegressionTest_i61909", + "ExecuteRegressionTest_i84234", + "ExecuteRegressionTest_125919" + }; + } + + public String getTestObjectName() + { + return "StorageUnitTest"; + } + + public void before() + { + m_xMSF = (XMultiServiceFactory)param.getMSF(); + if ( m_xMSF == null ) + { + failed( "Can't create service factory!" ); + return; + } + + try { + Object oStorageFactory = m_xMSF.createInstance( "com.sun.star.embed.StorageFactory" ); + m_xStorageFactory = (XSingleServiceFactory)UnoRuntime.queryInterface( XSingleServiceFactory.class, + oStorageFactory ); + } + catch( Exception e ) + { + failed( "Can't create storage factory!" ); + return; + } + + if ( m_xStorageFactory == null ) + { + failed( "Can't create service factory!" ); + return; + } + } + + public void ExecuteTest01() + { + StorageTest aTest = new Test01( m_xMSF, m_xStorageFactory, log ); + assure( "Test01 failed!", aTest.test() ); + } + + public void ExecuteTest02() + { + StorageTest aTest = new Test02( m_xMSF, m_xStorageFactory, log ); + assure( "Test02 failed!", aTest.test() ); + } + + public void ExecuteTest03() + { + StorageTest aTest = new Test03( m_xMSF, m_xStorageFactory, log ); + assure( "Test03 failed!", aTest.test() ); + } + + public void ExecuteTest04() + { + StorageTest aTest = new Test04( m_xMSF, m_xStorageFactory, log ); + assure( "Test04 failed!", aTest.test() ); + } + + public void ExecuteTest05() + { + StorageTest aTest = new Test05( m_xMSF, m_xStorageFactory, log ); + assure( "Test05 failed!", aTest.test() ); + } + + public void ExecuteTest06() + { + StorageTest aTest = new Test06( m_xMSF, m_xStorageFactory, log ); + assure( "Test06 failed!", aTest.test() ); + } + + public void ExecuteTest07() + { + StorageTest aTest = new Test07( m_xMSF, m_xStorageFactory, log ); + assure( "Test07 failed!", aTest.test() ); + } + + public void ExecuteTest08() + { + StorageTest aTest = new Test08( m_xMSF, m_xStorageFactory, log ); + assure( "Test08 failed!", aTest.test() ); + } + + public void ExecuteTest09() + { + StorageTest aTest = new Test09( m_xMSF, m_xStorageFactory, log ); + assure( "Test09 failed!", aTest.test() ); + } + + public void ExecuteTest10() + { + StorageTest aTest = new Test10( m_xMSF, m_xStorageFactory, log ); + assure( "Test10 failed!", aTest.test() ); + } + + public void ExecuteTest11() + { + StorageTest aTest = new Test11( m_xMSF, m_xStorageFactory, log ); + assure( "Test11 failed!", aTest.test() ); + } + + public void ExecuteTest12() + { + StorageTest aTest = new Test12( m_xMSF, m_xStorageFactory, log ); + assure( "Test12 failed!", aTest.test() ); + } + + public void ExecuteTest13() + { + StorageTest aTest = new Test13( m_xMSF, m_xStorageFactory, log ); + assure( "Test13 failed!", aTest.test() ); + } + + public void ExecuteTest14() + { + StorageTest aTest = new Test14( m_xMSF, m_xStorageFactory, log ); + assure( "Test14 failed!", aTest.test() ); + } + + public void ExecuteTest15() + { + StorageTest aTest = new Test15( m_xMSF, m_xStorageFactory, log ); + assure( "Test15 failed!", aTest.test() ); + } + + public void ExecuteTest16() + { + StorageTest aTest = new Test16( m_xMSF, m_xStorageFactory, log ); + assure( "Test16 failed!", aTest.test() ); + } + + public void ExecuteTest17() + { + StorageTest aTest = new Test17( m_xMSF, m_xStorageFactory, log ); + assure( "Test17 failed!", aTest.test() ); + } + + public void ExecuteTest18() + { + StorageTest aTest = new Test18( m_xMSF, m_xStorageFactory, log ); + assure( "Test18 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_114358() + { + StorageTest aTest = new RegressionTest_114358( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_114358 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i29169() + { + StorageTest aTest = new RegressionTest_i29169( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i29169 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i30400() + { + StorageTest aTest = new RegressionTest_i30400( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i30400 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i29321() + { + StorageTest aTest = new RegressionTest_i29321( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i29321 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i30677() + { + StorageTest aTest = new RegressionTest_i30677( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i30677 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i27773() + { + StorageTest aTest = new RegressionTest_i27773( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i27773 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i46848() + { + StorageTest aTest = new RegressionTest_i46848( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i46848 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i55821() + { + StorageTest aTest = new RegressionTest_i55821( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i55821 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i35095() + { + StorageTest aTest = new RegressionTest_i35095( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i35095 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i49755() + { + StorageTest aTest = new RegressionTest_i49755( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i49755 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i59886() + { + StorageTest aTest = new RegressionTest_i59886( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i59886 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i61909() + { + StorageTest aTest = new RegressionTest_i61909( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i61909 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_i84234() + { + StorageTest aTest = new RegressionTest_i84234( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_i84234 failed!", aTest.test() ); + } + + public void ExecuteRegressionTest_125919() + { + StorageTest aTest = new RegressionTest_125919( m_xMSF, m_xStorageFactory, log ); + assure( "RegressionTest_125919 failed!", aTest.test() ); + } +} + diff --git a/package/qa/storages/Test01.java b/package/qa/storages/Test01.java new file mode 100644 index 000000000000..a793a2fd5809 --- /dev/null +++ b/package/qa/storages/Test01.java @@ -0,0 +1,177 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test01 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test01( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test01: " ); + } + + public boolean test() + { + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.WRITE ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test02.java b/package/qa/storages/Test02.java new file mode 100644 index 000000000000..668efbe6a509 --- /dev/null +++ b/package/qa/storages/Test02.java @@ -0,0 +1,163 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test02 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test02( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test02: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + + // ================================================ + // now check all the written information + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + + // open input stream + // since no mode is provided the result storage must be opened readonly + Object pOneArg[] = new Object[1]; + pOneArg[0] = (Object) xTempInStream; + + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pOneArg ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType2", true, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test03.java b/package/qa/storages/Test03.java new file mode 100644 index 000000000000..353cd4df8d14 --- /dev/null +++ b/package/qa/storages/Test03.java @@ -0,0 +1,231 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; +import com.sun.star.container.XNameAccess; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test03 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test03( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test03: " ); + } + + public boolean test() + { + try + { + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // ================================================ + // check storage hyerarchy tree + // ================================================ + + // check that isStorageElement() and isStreamElement reacts to nonexisting object correctly + try { + xTempStorage.isStorageElement( "does not exist" ); + m_aTestHelper.Error( "Nonexisting element doesn't detected by isStorageElement() call!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by isStorageElement() call: " + e ); + return false; + } + + try { + xTempStorage.isStreamElement( "does not exist" ); + m_aTestHelper.Error( "Nonexisting element doesn't detected by isStreamElement() call!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by isStreamElement() call: " + e ); + return false; + } + + XNameAccess xRootNameAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xTempStorage ); + if ( xRootNameAccess == null ) + { + m_aTestHelper.Error( "Root storage doesn't support XNameAccess!" ); + return false; + } + + try { + if ( !xTempStorage.isStorageElement( "SubStorage1" ) || xTempStorage.isStreamElement( "SubStorage1" ) ) + { + m_aTestHelper.Error( "Child 'SubStorage1' can not be detected as storage!" ); + return false; + } + + if ( xTempStorage.isStorageElement( "SubStream1" ) || !xTempStorage.isStreamElement( "SubStream1" ) ) + { + m_aTestHelper.Error( "Child 'SubStream1' can not be detected as stream!" ); + return false; + } + } + catch( Exception e ) + { + m_aTestHelper.Error( "Child's type can not be detected, exception: " + e ); + return false; + } + + + // check that root storage contents are represented correctly + String sRootCont[] = xRootNameAccess.getElementNames(); + + if ( sRootCont.length != 3 ) + { + m_aTestHelper.Error( "Root storage contains wrong amount of children!" ); + return false; + } + + int nFlag = 0; + for ( int nInd = 0; nInd < sRootCont.length; nInd++ ) + { + if ( sRootCont[nInd].equals( "SubStorage1" ) ) + nFlag |= 1; + else if ( sRootCont[nInd].equals( "SubStream1" ) ) + nFlag |= 2; + else if ( sRootCont[nInd].equals( "BigSubStream1" ) ) + nFlag |= 4; + } + + if ( nFlag != 7 || !( xRootNameAccess.hasByName( "BigSubStream1" ) && xRootNameAccess.hasByName( "SubStream1" ) && xRootNameAccess.hasByName( "SubStorage1" ) ) ) + { + m_aTestHelper.Error( "Root storage contains wrong list of children!" ); + return false; + } + + // get storage through XNameAccess + XStorage xResultSubStorage = getStorageFromNameAccess( xRootNameAccess, "SubStorage1" ); + if ( xResultSubStorage == null ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType3", false, ElementModes.READ ) ) + return false; + + XNameAccess xChildAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xResultSubStorage ); + if ( xChildAccess == null ) + { + m_aTestHelper.Error( "Child storage doesn't support XNameAccess!" ); + return false; + } + + if ( !( xChildAccess.hasByName( "SubStream2" ) && xChildAccess.hasByName( "BigSubStream2" ) ) + || !xResultSubStorage.isStreamElement( "SubStream2" ) + || !xResultSubStorage.isStreamElement( "BigSubStream2" ) ) + { + m_aTestHelper.Error( "'SubStream2' can not be detected as child stream element of 'SubStorage1'!" ); + return false; + } + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + + public XStorage getStorageFromNameAccess( XNameAccess xAccess, String sName ) + { + try + { + Object oStorage = xAccess.getByName( sName ); + XStorage xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oStorage ); + + if ( xResult != null ) + return xResult; + else + m_aTestHelper.Error( "Can't retrieve substorage '" + sName + "' through XNameAccess!" ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't retrieve substorage '" + sName + "' through XNameAccess, exception: " + e ); + } + + return null; + } + +} + diff --git a/package/qa/storages/Test04.java b/package/qa/storages/Test04.java new file mode 100644 index 000000000000..81f770f8ff9a --- /dev/null +++ b/package/qa/storages/Test04.java @@ -0,0 +1,307 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; +import com.sun.star.lang.DisposedException; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.container.XNameAccess; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test04 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test04( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test04: " ); + } + + public boolean test() + { + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open substorages and create streams there + + // first substorage of the root storage + XStorage xTempSubStorage1 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage1, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage1, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // second substorage of the root storage + XStorage xTempSubStorage2 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage2", + ElementModes.WRITE ); + if ( xTempSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage2, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage2, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage1, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage2, + "MediaType5", + false, + ElementModes.WRITE ) ) + return false; + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.copyElementTo( xTempStorage, "SubStorage1", xTempFileStorage ) ) + return false; + + // if storage is not commited before disposing all the changes will be lost + if ( !m_aTestHelper.commitStorage( xTempSubStorage2 ) ) + return false; + + // a storage must be disposed before moving/removing otherwise the access will be denied + if ( !m_aTestHelper.disposeStorage( xTempSubStorage2 ) ) + return false; + + if ( !m_aTestHelper.moveElementTo( xTempStorage, "SubStorage2", xTempFileStorage ) ) + return false; + + // SubStorage2 must be removed and disposed now + try + { + xTempSubStorage2.isStreamElement( "SubStream2" ); + m_aTestHelper.Error( "SubStorage2 must be disposed already!" ); + return false; + } + catch( com.sun.star.lang.DisposedException de ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception in case of disposed storage, exception: " + e ); + return false; + } + + if ( !m_aTestHelper.copyElementTo( xTempSubStorage1, "SubStream1", xTempFileStorage ) ) + return false; + + if ( !m_aTestHelper.renameElement( xTempFileStorage, "SubStream1", "SubStream1_copy" ) ) + return false; + + if ( !m_aTestHelper.moveElementTo( xTempSubStorage1, "SubStream1", xTempFileStorage ) ) + return false; + + if ( !m_aTestHelper.copyElementTo( xTempSubStorage1, "BigSubStream1", xTempFileStorage ) ) + return false; + + if ( !m_aTestHelper.renameElement( xTempFileStorage, "BigSubStream1", "BigSubStream1_copy" ) ) + return false; + + if ( !m_aTestHelper.moveElementTo( xTempSubStorage1, "BigSubStream1", xTempFileStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.WRITE ); + Object oResStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResStorage ); + if ( xResStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + // open and check SubStorage1 + XStorage xResSubStorage1 = m_aTestHelper.openSubStorage( xResStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResSubStorage1 == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubStorage1, "MediaType4", false, ElementModes.READ ) ) + return false; + + + // open and check SubStorage2 + XStorage xResSubStorage2 = m_aTestHelper.openSubStorage( xResStorage, + "SubStorage2", + ElementModes.READ ); + if ( xResSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubStorage2, "MediaType5", false, ElementModes.READ ) ) + return false; + + + // check all the result streams + + if ( !m_aTestHelper.checkStream( xResStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResStorage, "SubStream1_copy", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResStorage, "BigSubStream1_copy", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubStorage1, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubStorage1, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubStorage2, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubStorage2, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + // the storage must be disposed before removing + if ( !m_aTestHelper.disposeStorage( xResSubStorage2 ) ) + return false; + + // remove element and check that it was removed completelly + if ( !m_aTestHelper.removeElement( xResStorage, "SubStorage2" ) ) + return false; + + try + { + XNameAccess xResAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xResStorage ); + if ( xResAccess.hasByName( "SubStorage2" ) ) + m_aTestHelper.Error( "SubStorage2 must be removed already!" ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't get access to root storage, exception: " + e ); + return false; + } + + try + { + xResSubStorage2.isStreamElement( "SubStream2" ); + + m_aTestHelper.Error( "SubStorage2 must be disposed already!" ); + return false; + } + catch( com.sun.star.lang.DisposedException de ) + { + } + catch( Exception e ) + { + m_aTestHelper.Error( "Wrong exception in case of disposed storage, exception: " + e ); + return false; + } + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test05.java b/package/qa/storages/Test05.java new file mode 100644 index 000000000000..adf943c6ef12 --- /dev/null +++ b/package/qa/storages/Test05.java @@ -0,0 +1,299 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test05 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test05( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test05: " ); + } + + public boolean test() + { + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempFileStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substorage + XStorage xSubSubStorage = m_aTestHelper.openSubStorage( xTempSubStorage, + "SubSubStorage1", + ElementModes.WRITE ); + if ( xSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xSubSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xSubSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xSubSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xSubSubStorage, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempFileStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xSubSubStorage, + "MediaType5", + false, + ElementModes.WRITE ) ) + return false; + + + // commit all the storages + if ( !m_aTestHelper.commitStorage( xSubSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // try to open an opened substorage, open call must fail + if ( !m_aTestHelper.cantOpenStorage( xTempFileStorage, "SubStorage1" ) ) + return false; + + + // reopen created streams + XStream xSubStream1 = m_aTestHelper.OpenStream( xSubSubStorage, + "SubStream1", + ElementModes.WRITE | ElementModes.NOCREATE ); + XStream xBigSubStream1 = m_aTestHelper.OpenStream( xSubSubStorage, + "BigSubStream1", + ElementModes.WRITE | ElementModes.NOCREATE ); + XStream xSubStream2 = m_aTestHelper.OpenStream( xSubSubStorage, + "SubStream2", + ElementModes.READ | ElementModes.NOCREATE ); + XStream xBigSubStream2 = m_aTestHelper.OpenStream( xSubSubStorage, + "BigSubStream2", + ElementModes.READ | ElementModes.NOCREATE ); + + if ( xSubStream1 == null || xBigSubStream1 == null || xSubStream2 == null || xBigSubStream2 == null ) + return false; + + // it should be possible to have more then one copy of stream for reading + XStream xSubStream2clone = m_aTestHelper.OpenStream( xSubSubStorage, + "SubStream2", + ElementModes.READ | ElementModes.NOCREATE ); + XStream xBigSubStream2clone = m_aTestHelper.OpenStream( xSubSubStorage, + "BigSubStream2", + ElementModes.READ | ElementModes.NOCREATE ); + if ( xSubStream2clone == null || xBigSubStream2clone == null ) + return false; + + + // so now the first streams can not be open neither for reading nor for writing + if ( !m_aTestHelper.cantOpenStream( xSubSubStorage, "SubStream1", ElementModes.WRITE ) + || !m_aTestHelper.cantOpenStream( xSubSubStorage, "SubStream1", ElementModes.READ ) + || !m_aTestHelper.cantOpenStream( xSubSubStorage, "BigSubStream1", ElementModes.WRITE ) + || !m_aTestHelper.cantOpenStream( xSubSubStorage, "BigSubStream1", ElementModes.READ ) ) + return false; + + // the second streams can not be open for writing + if ( !m_aTestHelper.cantOpenStream( xSubSubStorage, "SubStream2", ElementModes.WRITE ) + || !m_aTestHelper.cantOpenStream( xSubSubStorage, "BigSubStream2", ElementModes.WRITE ) ) + return false; + + + // dispose xTestSubStorage, all the subtree must be disposed + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // check that subtree was disposed correctly + try + { + xSubSubStorage.isStreamElement( "SubStream1" ); + m_aTestHelper.Error( "Substorage was not disposed!" ); + return false; + } + catch ( com.sun.star.lang.DisposedException de ) + {} + catch ( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by disposed storage: " + e ); + return false; + } + + try + { + xSubStream1.getInputStream(); + m_aTestHelper.Error( "Writeable substream was not disposed!" ); + return false; + } + catch ( com.sun.star.lang.DisposedException de ) + {} + catch ( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by disposed stream: " + e ); + return false; + } + + try + { + xSubStream2.getInputStream(); + m_aTestHelper.Error( "Readonly substream was not disposed!" ); + return false; + } + catch ( com.sun.star.lang.DisposedException de ) + {} + catch ( Exception e ) + { + m_aTestHelper.Error( "Wrong exception is thrown by disposed stream: " + e ); + return false; + } + + + // dispose root storage + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + + // ================================================ + // now check all the written and copied information + // ================================================ + + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage 'SubSubStorage'!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResSubSubStorage = m_aTestHelper.openSubStorage( xResSubStorage, + "SubSubStorage1", + ElementModes.READ ); + if ( xResSubSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage 'SubSubStorage'!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResSubSubStorage, "MediaType5", false, ElementModes.READ ) ) + return false; + + // check substreams + if ( !m_aTestHelper.checkStream( xResSubSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubSubStorage, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResSubSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test06.java b/package/qa/storages/Test06.java new file mode 100644 index 000000000000..ef42c66335a5 --- /dev/null +++ b/package/qa/storages/Test06.java @@ -0,0 +1,279 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.ElementExistException; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test06 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test06( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test06: " ); + } + + public boolean test() + { + try + { + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + try + { + xTempStorage.copyToStorage( null ); + m_aTestHelper.Error( "The method must throw an exception because of illegal parameter!" ); + return false; + } + catch( com.sun.star.lang.IllegalArgumentException iae ) + {} + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion because of illegal parameter : " + e ); + return false; + } + + // open new substorages + XStorage xTempSubStorage1 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + XStorage xTempSubStorage2 = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage2", + ElementModes.WRITE ); + if ( xTempSubStorage1 == null || xTempSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // in case stream is open for reading it must exist + try + { + xTempSubStorage1.openStreamElement( "NonExistingStream", ElementModes.READ ); + m_aTestHelper.Error( "The method must throw an exception in case of try to open nonexistent stream for reading!" ); + return false; + } + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to open nonexistent stream for reading : " + e ); + return false; + } + + // in case a storage is open for reading it must exist + try + { + xTempSubStorage1.openStreamElement( "NonExistingStorage", ElementModes.READ ); + m_aTestHelper.Error( "The method must throw an exception in case of try to open nonexistent storage for reading!" ); + return false; + } + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to open nonexistent storage for reading : " + e ); + return false; + } + + // in case of removing nonexistent element an exception must be thrown + try + { + xTempSubStorage1.removeElement( "NonExistingElement" ); + m_aTestHelper.Error( "An exception must be thrown in case of removing nonexistent element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to remove nonexistent element : " + e ); + return false; + } + + // in case of renaming of nonexistent element an exception must be thrown + try + { + xTempSubStorage1.renameElement( "NonExistingElement", "NewName" ); + m_aTestHelper.Error( "An exception must be thrown in case of renaming nonexistent element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to rename nonexistent element : " + e ); + return false; + } + + // in case of renaming to a name of existent element an exception must be thrown + try + { + xTempStorage.renameElement( "SubStorage1", "SubStorage2" ); + m_aTestHelper.Error( "An exception must be thrown in case of renaming to the name of existent element!" ); + return false; + } + catch( com.sun.star.container.ElementExistException ee ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of try to rename to the name of existent element : " + e ); + return false; + } + + // in case of copying target storage must be provided + try + { + xTempStorage.copyElementTo( "SubStorage1", null, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case empty reference is provided as target for copying!" ); + return false; + } + catch( com.sun.star.lang.IllegalArgumentException iae ) + {} + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case empty reference is provieded as target for copying : " + e ); + return false; + } + + // in case of moving target storage must be provided + try + { + xTempStorage.moveElementTo( "SubStorage1", null, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case empty reference is provided as target for moving!" ); + return false; + } + catch( com.sun.star.lang.IllegalArgumentException iae ) + {} + catch( com.sun.star.uno.Exception ue ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case empty reference is provieded as target for moving : " + e ); + return false; + } + + + // prepare target for further testings + + // create new temporary storage based on arbitrary medium + Object oTargetStorage = m_xStorageFactory.createInstance(); + XStorage xTargetStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTargetStorage ); + if ( xTargetStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTargetSubStorage = m_aTestHelper.openSubStorage( xTargetStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTargetSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // in case of copying of nonexistent element an exception must be thrown + try + { + xTempStorage.copyElementTo( "Nonexistent element", xTargetStorage, "Target" ); + m_aTestHelper.Error( "An exception must be thrown in case of copying of nonexisting element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of copying of nonexistent element: " + e ); + return false; + } + + // in case of moving of nonexistent element an exception must be thrown + try + { + xTempStorage.moveElementTo( "Nonexistent element", xTargetStorage, "Target" ); + m_aTestHelper.Error( "An exception must be thrown in case of moving of nonexisting element!" ); + return false; + } + catch( com.sun.star.container.NoSuchElementException ne ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case of moving of nonexistent element: " + e ); + return false; + } + + // in case target for copying already exists an exception must be thrown + try + { + xTempStorage.copyElementTo( "SubStorage1", xTargetStorage, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case target for copying already exists!" ); + return false; + } + catch( com.sun.star.container.ElementExistException ee ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case target for copying already exists: " + e ); + return false; + } + + // in case target for moving already exists an exception must be thrown + try + { + xTempStorage.moveElementTo( "SubStorage1", xTargetStorage, "SubStorage1" ); + m_aTestHelper.Error( "An exception must be thrown in case target for moving already exists!" ); + return false; + } + catch( com.sun.star.container.ElementExistException ee ) + {} + catch( Exception e ) + { + m_aTestHelper.Error( "Unexpected excepion in case target for moving already exists: " + e ); + return false; + } + + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test07.java b/package/qa/storages/Test07.java new file mode 100644 index 000000000000..970c6f13ec09 --- /dev/null +++ b/package/qa/storages/Test07.java @@ -0,0 +1,162 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test07 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test07( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test07: " ); + } + + public boolean test() + { + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + String sPass1 = "12345"; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "BigSubStream1", "MediaType1", true, pBigBytes, sPass1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes1, sPass1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + String sPass2 = "54321"; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "BigSubStream2", "MediaType2", false, pBigBytes, sPass2 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream2", "MediaType2", false, pBytes2, sPass2 ) ) + return false; + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.WRITE ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + Object o2CopyStorage = m_xStorageFactory.createInstance(); + XStorage x2CopyStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, o2CopyStorage ); + if ( x2CopyStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + if ( !m_aTestHelper.copyStorage( xResultStorage, x2CopyStorage ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "SubStream1", "MediaType1", pBytes1, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "BigSubStream1", "MediaType1", pBigBytes, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "SubStream2", "MediaType2", pBytes2, sPass2 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "BigSubStream2", "MediaType2", pBigBytes, sPass2 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( x2CopyStorage, "SubStream1", "MediaType1", pBytes1, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( x2CopyStorage, "BigSubStream1", "MediaType1", pBigBytes, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( x2CopyStorage, "SubStream2", "MediaType2", pBytes2, sPass2 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( x2CopyStorage, "BigSubStream2", "MediaType2", pBigBytes, sPass2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test08.java b/package/qa/storages/Test08.java new file mode 100644 index 000000000000..5e024db588c8 --- /dev/null +++ b/package/qa/storages/Test08.java @@ -0,0 +1,230 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test08 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test08( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test08: " ); + } + + public boolean test() + { + try + { + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // set the global password for the root storage + XEncryptionProtectedSource xTempStorageEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xTempStorage ); + + if ( xTempStorageEncryption == null ) + { + m_aTestHelper.Message( "Optional interface XEncryptionProtectedSource is not implemented, feature can not be tested!" ); + return true; + } + + String sPass1 = "123"; + String sPass2 = "321"; + + try { + xTempStorageEncryption.setEncryptionPassword( sPass1 ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't set a common encryption key for the storage, exception:" + e ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + // the stream will be encrypted with common password + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + if ( !m_aTestHelper.WBToSubstrOfEncr( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1, true ) ) + return false; + if ( !m_aTestHelper.WBToSubstrOfEncr( xTempSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes, true ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + // the stream will not be encrypted + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + if ( !m_aTestHelper.WBToSubstrOfEncr( xTempSubStorage, "SubStream2", "MediaType2", false, pBytes2, false ) ) + return false; + if ( !m_aTestHelper.WBToSubstrOfEncr( xTempSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes, false ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + // the stream will be compressed with own password + byte pBytes3[] = { 3, 3, 3, 3, 3 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + // the stream will not be encrypted + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "SubStream3", "MediaType3", false, pBytes3, sPass2 ) ) + return false; + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "BigSubStream3", "MediaType3", false, pBigBytes, sPass2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType4", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType5", + false, + ElementModes.WRITE ) ) + return false; + + // create temporary file + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType4", true, ElementModes.READ ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType5", false, ElementModes.READ ) ) + return false; + + // set the global password for the root storage + XEncryptionProtectedSource xResultStorageEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xResultStorage ); + + if ( xResultStorageEncryption == null ) + { + m_aTestHelper.Error( "XEncryptionProtectedSource was successfully used already, so it must be supported!" ); + return false; + } + + try { + xResultStorageEncryption.setEncryptionPassword( sPass2 ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't set a common encryption key for the storage, exception:" + e ); + return false; + } + + if ( !m_aTestHelper.checkEncrStream( xResultSubStorage, "SubStream1", "MediaType1", pBytes1, sPass1 ) ) + return false; + if ( !m_aTestHelper.checkEncrStream( xResultSubStorage, "BigSubStream1", "MediaType1", pBigBytes, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream2", "MediaType2", false, pBytes2 ) ) + return false; + if ( !m_aTestHelper.checkStream( xResultSubStorage, "BigSubStream2", "MediaType2", false, pBigBytes ) ) + return false; + + // the common root storage password should allow to open this stream + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream3", "MediaType3", true, pBytes3 ) ) + return false; + if ( !m_aTestHelper.checkStream( xResultSubStorage, "BigSubStream3", "MediaType3", true, pBigBytes ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/Test09.java b/package/qa/storages/Test09.java new file mode 100644 index 000000000000..2ce2dfb1e484 --- /dev/null +++ b/package/qa/storages/Test09.java @@ -0,0 +1,138 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test09 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test09( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test09: " ); + } + + public boolean test() + { + try + { + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + String sPass1 = "123"; + String sPass2 = "321"; + byte pBytes[] = { 1, 1, 1, 1, 1 }; + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + // the stream will not be encrypted + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream1", "MediaType1", false, pBytes, sPass1 ) ) + return false; + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "BigSubStream1", "MediaType1", false, pBigBytes, sPass1 ) ) + return false; + + // create temporary file + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // change password of the substream of new storage based on file + int nResult = m_aTestHelper.ChangeStreamPass( xTempFileStorage, "SubStream1", sPass1, sPass2 ); + if ( nResult == 0 ) + return false; // test failed + else if ( nResult == -1 ) + return true; // tested optional feature is not supported + + // change password of the substream of new storage based on file + nResult = m_aTestHelper.ChangeStreamPass( xTempFileStorage, "BigSubStream1", sPass1, sPass2 ); + if ( nResult == 0 ) + return false; // test failed + else if ( nResult == -1 ) + return true; // tested optional feature is not supported + + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "SubStream1", "MediaType1", pBytes, sPass2 ) ) + return false; + if ( !m_aTestHelper.checkEncrStream( xResultStorage, "BigSubStream1", "MediaType1", pBigBytes, sPass2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/Test10.java b/package/qa/storages/Test10.java new file mode 100644 index 000000000000..162daa5abe29 --- /dev/null +++ b/package/qa/storages/Test10.java @@ -0,0 +1,232 @@ +package complex.storages; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.container.XNameAccess; +import com.sun.star.io.XStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test10 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test10( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test10: " ); + } + + public boolean test() + { + try + { + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream2", "MediaType2", true, pBytes2 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "BigSubStream2", "MediaType2", true, pBigBytes ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // ============================== + // check cloning at current state + // ============================== + + // the new storage still was not commited so the clone must be empty + XStorage xClonedSubStorage = m_aTestHelper.cloneSubStorage( m_xStorageFactory, xTempStorage, "SubStorage1" ); + + if ( xClonedSubStorage == null ) + { + m_aTestHelper.Error( "The result of clone is empty!" ); + return false; + } + + XNameAccess xClonedNameAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xClonedSubStorage ); + if ( xClonedNameAccess == null ) + { + m_aTestHelper.Error( "XNameAccess is not implemented by the clone!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xClonedSubStorage, "", true, ElementModes.WRITE ) ) + return false; + + if ( xClonedNameAccess.hasElements() ) + { + m_aTestHelper.Error( "The new substorage still was not commited so it must be empty!" ); + return false; + } + + if ( !m_aTestHelper.disposeStorage( xClonedSubStorage ) ) + return false; + + xClonedSubStorage = null; + xClonedNameAccess = null; + + // the new stream was opened, written and closed, that means flashed + // so the clone must contain all the information + XStream xClonedSubStream = m_aTestHelper.cloneSubStream( xTempStorage, "SubStream1" ); + if ( !m_aTestHelper.InternalCheckStream( xClonedSubStream, "SubStream1", "MediaType1", true, pBytes1, true ) ) + return false; + + XStream xClonedBigSubStream = m_aTestHelper.cloneSubStream( xTempStorage, "BigSubStream1" ); + if ( !m_aTestHelper.InternalCheckStream( xClonedBigSubStream, "BigSubStream1", "MediaType1", true, pBigBytes, true ) ) + return false; + + if ( !m_aTestHelper.disposeStream( xClonedSubStream, "SubStream1" ) ) + return false; + + if ( !m_aTestHelper.disposeStream( xClonedBigSubStream, "BigSubStream1" ) ) + return false; + + // ============================== + // commit substorage and check cloning + // ============================== + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + xClonedSubStorage = m_aTestHelper.cloneSubStorage( m_xStorageFactory, xTempStorage, "SubStorage1" ); + if ( xClonedSubStorage == null ) + { + m_aTestHelper.Error( "The result of clone is empty!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xClonedSubStorage, "MediaType4", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStream( xClonedSubStorage, "SubStream2", "MediaType2", true, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xClonedSubStorage, "BigSubStream2", "MediaType2", true, pBigBytes ) ) + return false; + + XStorage xCloneOfRoot = m_aTestHelper.cloneStorage( m_xStorageFactory, xTempStorage ); + if ( xCloneOfRoot == null ) + { + m_aTestHelper.Error( "The result of root clone is empty!" ); + return false; + } + + XNameAccess xCloneOfRootNA = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xCloneOfRoot ); + if ( xCloneOfRootNA == null ) + { + m_aTestHelper.Error( "XNameAccess is not implemented by the root clone!" ); + return false; + } + + if ( xCloneOfRootNA.hasElements() ) + { + m_aTestHelper.Error( "The root storage still was not commited so it's clone must be empty!" ); + return false; + } + + if ( !m_aTestHelper.disposeStorage( xCloneOfRoot ) ) + return false; + + xCloneOfRoot = null; + + // ============================== + // commit root storage and check cloning + // ============================== + + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + xCloneOfRoot = m_aTestHelper.cloneStorage( m_xStorageFactory, xTempStorage ); + if ( xCloneOfRoot == null ) + { + m_aTestHelper.Error( "The result of root clone is empty!" ); + return false; + } + + XStorage xSubStorageOfClone = xCloneOfRoot.openStorageElement( "SubStorage1", ElementModes.READ ); + if ( xSubStorageOfClone == null ) + { + m_aTestHelper.Error( "The result of root clone is wrong!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xSubStorageOfClone, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xSubStorageOfClone, "SubStream2", "MediaType2", true, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xSubStorageOfClone, "BigSubStream2", "MediaType2", true, pBigBytes ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/Test11.java b/package/qa/storages/Test11.java new file mode 100644 index 000000000000..198fa41fe588 --- /dev/null +++ b/package/qa/storages/Test11.java @@ -0,0 +1,218 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.container.XNameAccess; +import com.sun.star.io.XStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test11 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test11( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test11: " ); + } + + public boolean test() + { + try + { + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + String sPass1 = "111111111"; + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "SubStream1", "MediaType1", true, pBytes1, sPass1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempStorage, "BigSubStream1", "MediaType1", true, pBigBytes, sPass1 ) ) + return false; + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + String sPass2 = "2222222222"; + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "SubStream2", "MediaType2", true, pBytes2, sPass2 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToEncrSubstream( xTempSubStorage, "BigSubStream2", "MediaType2", true, pBigBytes, sPass2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // ============================== + // check cloning at current state + // ============================== + + // the new storage still was not commited so the clone must be empty + XStorage xClonedSubStorage = m_aTestHelper.cloneSubStorage( m_xStorageFactory, xTempStorage, "SubStorage1" ); + + if ( xClonedSubStorage == null ) + { + m_aTestHelper.Error( "The result of clone is empty!" ); + return false; + } + + XNameAccess xClonedNameAccess = (XNameAccess) UnoRuntime.queryInterface( XNameAccess.class, xClonedSubStorage ); + if ( xClonedNameAccess == null ) + { + m_aTestHelper.Error( "XNameAccess is not implemented by the clone!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xClonedSubStorage, "", true, ElementModes.WRITE ) ) + return false; + + if ( xClonedNameAccess.hasElements() ) + { + m_aTestHelper.Error( "The new substorage still was not commited so it must be empty!" ); + return false; + } + + if ( !m_aTestHelper.disposeStorage( xClonedSubStorage ) ) + return false; + + xClonedSubStorage = null; + xClonedNameAccess = null; + + // the new stream was opened, written and closed, that means flashed + // so the clone must contain all the information + XStream xClonedSubStream = m_aTestHelper.cloneEncrSubStream( xTempStorage, "SubStream1", sPass1 ); + if ( !m_aTestHelper.InternalCheckStream( xClonedSubStream, "SubStream1", "MediaType1", true, pBytes1, true ) ) + return false; + + XStream xClonedBigSubStream = m_aTestHelper.cloneEncrSubStream( xTempStorage, "BigSubStream1", sPass1 ); + if ( !m_aTestHelper.InternalCheckStream( xClonedBigSubStream, "BigSubStream1", "MediaType1", true, pBigBytes, true ) ) + return false; + + if ( !m_aTestHelper.disposeStream( xClonedSubStream, "SubStream1" ) ) + return false; + + if ( !m_aTestHelper.disposeStream( xClonedBigSubStream, "BigSubStream1" ) ) + return false; + + // ============================== + // commit substorage and check cloning + // ============================== + + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + xClonedSubStorage = m_aTestHelper.cloneSubStorage( m_xStorageFactory, xTempStorage, "SubStorage1" ); + if ( xClonedSubStorage == null ) + { + m_aTestHelper.Error( "The result of clone is empty!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xClonedSubStorage, "MediaType4", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xClonedSubStorage, "SubStream2", "MediaType2", pBytes2, sPass2 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xClonedSubStorage, "BigSubStream2", "MediaType2", pBigBytes, sPass2 ) ) + return false; + + // ============================== + // commit the root storage and check cloning + // ============================== + + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + XStorage xCloneOfRoot = m_aTestHelper.cloneStorage( m_xStorageFactory, xTempStorage ); + if ( xCloneOfRoot == null ) + { + m_aTestHelper.Error( "The result of root clone is empty!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xCloneOfRoot, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xCloneOfRoot, "SubStream1", "MediaType1", pBytes1, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xCloneOfRoot, "BigSubStream1", "MediaType1", pBigBytes, sPass1 ) ) + return false; + + XStorage xSubStorageOfClone = xCloneOfRoot.openStorageElement( "SubStorage1", ElementModes.READ ); + if ( xSubStorageOfClone == null ) + { + m_aTestHelper.Error( "The result of root clone is wrong!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xSubStorageOfClone, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xSubStorageOfClone, "SubStream2", "MediaType2", pBytes2, sPass2 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStream( xSubStorageOfClone, "BigSubStream2", "MediaType2", pBigBytes, sPass2 ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } +} + diff --git a/package/qa/storages/Test12.java b/package/qa/storages/Test12.java new file mode 100644 index 000000000000..05928cf76b0d --- /dev/null +++ b/package/qa/storages/Test12.java @@ -0,0 +1,240 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test12 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test12( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test12: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType2", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType3", + false, + ElementModes.WRITE ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose substorage + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + + // ================================================ + // check substorage + // ================================================ + + if ( !checkSubStorages( xTempStorage, pBytes1, pBigBytes ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + // ================================================ + // now check all the written information with readwrite access + // ================================================ + + Object oResWriteStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResWriteStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResWriteStorage ); + if ( xResWriteStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResWriteStorage, "MediaType2", true, ElementModes.WRITE ) ) + return false; + + if( !checkSubStorages( xResWriteStorage, pBytes1, pBigBytes ) ) + return false; + + // try to open for writing after opening for reading + XStorage xResWSubStorage = m_aTestHelper.openSubStorage( xResWriteStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xResWSubStorage == null ) + { + m_aTestHelper.Error( "Can't open substorage for writing after it was opened for reading!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResWSubStorage, "MediaType3", false, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResWSubStorage, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResWSubStorage, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xResWriteStorage ) ) + return false; + + + // ================================================ + // now check all the written information with readonly access + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + // open input stream + // since no mode is provided the result storage must be opened readonly + Object pOneArg[] = new Object[1]; + pOneArg[0] = (Object) xTempInStream; + + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pOneArg ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType2", true, ElementModes.READ ) ) + return false; + + if( !checkSubStorages( xResultStorage, pBytes1, pBigBytes ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + + private boolean checkSubStorages( XStorage xStorage, byte[] pBytes1, byte[] pBigBytes ) + { + XStorage xReadSubStorage1 = m_aTestHelper.openSubStorage( xStorage, + "SubStorage1", + ElementModes.READ ); + + XStorage xReadSubStorage2 = m_aTestHelper.openSubStorage( xStorage, + "SubStorage1", + ElementModes.READ ); + + if ( xReadSubStorage1 == null || xReadSubStorage2 == null ) + { + m_aTestHelper.Error( "Can't open substorage for reading!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xReadSubStorage1, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStorageProperties( xReadSubStorage2, "MediaType3", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xReadSubStorage1, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xReadSubStorage1, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStream( xReadSubStorage2, "SubStream1", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xReadSubStorage2, "BigSubStream1", "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xReadSubStorage1 ) ) + return false; + + if ( !m_aTestHelper.disposeStorage( xReadSubStorage2 ) ) + return false; + + return true; + } +} + diff --git a/package/qa/storages/Test13.java b/package/qa/storages/Test13.java new file mode 100644 index 000000000000..e8b05264f44d --- /dev/null +++ b/package/qa/storages/Test13.java @@ -0,0 +1,215 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test13 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test13( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test13: " ); + } + + public boolean test() + { + String aStreamPrefix = ""; + for ( int nInd = 0; nInd < 4; ++nInd, aStreamPrefix += "SubStorage" + nInd ) + if ( !testForPath( aStreamPrefix ) ) + return false; + + return true; + } + + public boolean testForPath( String aStreamPrefix ) + { + try + { + String aSubStream1Path = aStreamPrefix + "SubStream1"; + String aSubStream2Path = aStreamPrefix + "SubStream2"; + String aSubStream3Path = aStreamPrefix + "SubStream3"; + String aBigSubStream1Path = aStreamPrefix + "BigSubStream1"; + String aBigSubStream2Path = aStreamPrefix + "BigSubStream2"; + String aBigSubStream3Path = aStreamPrefix + "BigSubStream3"; + + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + byte pBigBytes[] = new byte[33000]; + for ( int nInd = 0; nInd < 33000; nInd++ ) + pBigBytes[nInd] = (byte)( nInd % 128 ); + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream1Path, "MediaType1", true, pBytes1, true ) ) + return false; + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aBigSubStream1Path, "MediaType1", true, pBigBytes, true ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream2Path, "MediaType2", false, pBytes2, true ) ) + return false; + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aBigSubStream2Path, "MediaType2", false, pBigBytes, true ) ) + return false; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and don't commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream3Path, "MediaType2", false, pBytes2, false ) ) + return false; + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aBigSubStream3Path, "MediaType2", false, pBigBytes, false ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempFileStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now reopen the storage, + // check all the written and copied information + // and change it + // ================================================ + + // the temporary file must not be locked any more after storage disposing + oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTempFileStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xTempFileStorage, aSubStream1Path, "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xTempFileStorage, aBigSubStream1Path, "MediaType1", true, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xTempFileStorage, aSubStream2Path, "MediaType2", false, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xTempFileStorage, aBigSubStream2Path, "MediaType2", false, pBigBytes ) ) + return false; + + if ( !m_aTestHelper.cantOpenStreamH( xTempFileStorage, aSubStream3Path, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.cantOpenStreamH( xTempFileStorage, aBigSubStream3Path, ElementModes.READ ) ) + return false; + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream1Path, "MediaType3", true, pBytes2, true ) ) + return false; + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aBigSubStream1Path, "MediaType3", true, pBigBytes, true ) ) + return false; + + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and don't commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream2Path, "MediaType3", true, pBytes1, false ) ) + return false; + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aBigSubStream2Path, "MediaType3", true, pBigBytes, false ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now reopen the storage, + // check all the written information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xResultStorage, aSubStream1Path, "MediaType3", true, pBytes2 ) ) + return false; + if ( !m_aTestHelper.checkStreamH( xResultStorage, aBigSubStream1Path, "MediaType3", true, pBigBytes ) ) + return false; + + // the following stream was not commited last time, so the last change must be lost + if ( !m_aTestHelper.checkStreamH( xResultStorage, aBigSubStream2Path, "MediaType2", false, pBigBytes ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test14.java b/package/qa/storages/Test14.java new file mode 100644 index 000000000000..1f35758af05a --- /dev/null +++ b/package/qa/storages/Test14.java @@ -0,0 +1,188 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test14 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test14( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test14: " ); + } + + public boolean test() + { + String aStreamPrefix = ""; + for ( int nInd = 0; nInd < 4; ++nInd, aStreamPrefix += "SubStorage" + nInd ) + if ( !testForPath( aStreamPrefix ) ) + return false; + + return true; + } + + public boolean testForPath( String aStreamPrefix ) + { + try + { + String aSubStream1Path = aStreamPrefix + "SubStream1"; + String aSubStream2Path = aStreamPrefix + "SubStream2"; + String aSubStream3Path = aStreamPrefix + "SubStream3"; + + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + String sPass1 = "12345"; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream1Path, "MediaType1", true, pBytes1, sPass1, true ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + String sPass2 = "54321"; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream2Path, "MediaType2", false, pBytes2, sPass2, true ) ) + return false; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and don't commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream3Path, "MediaType2", false, pBytes2, sPass2, false ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempFileStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now reopen the storage, + // check all the written and copied information + // and change it + // ================================================ + + // the temporary file must not be locked any more after storage disposing + oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xTempFileStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkEncrStreamH( xTempFileStorage, aSubStream1Path, "MediaType1", pBytes1, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStreamH( xTempFileStorage, aSubStream2Path, "MediaType2", pBytes2, sPass2 ) ) + return false; + + if ( !m_aTestHelper.cantOpenEncrStreamH( xTempFileStorage, aSubStream3Path, ElementModes.READ, sPass2 ) ) + return false; + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream1Path, "MediaType3", true, pBytes2, sPass1, true ) ) + return false; + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and don't commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream2Path, "MediaType3", true, pBytes1, sPass2, false ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now reopen the storage, + // check all the written information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkEncrStreamH( xResultStorage, aSubStream1Path, "MediaType3", pBytes2, sPass1 ) ) + return false; + + // the following stream was not commited last time, so the last change must be lost + if ( !m_aTestHelper.checkEncrStreamH( xResultStorage, aSubStream2Path, "MediaType2", pBytes2, sPass2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test15.java b/package/qa/storages/Test15.java new file mode 100644 index 000000000000..b58453f9a195 --- /dev/null +++ b/package/qa/storages/Test15.java @@ -0,0 +1,268 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test15 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test15( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test15: " ); + } + + public boolean test() + { + String aStreamPrefix = ""; + for ( int nInd = 0; nInd < 4; ++nInd, aStreamPrefix += "SubStorage" + nInd ) + if ( !testForPath( aStreamPrefix ) ) + return false; + + return true; + } + + public boolean testForPath( String aStreamPrefix ) + { + try + { + String aSubStream1Path = aStreamPrefix + "SubStream1"; + String aSubStream2Path = aStreamPrefix + "SubStream2"; + String aSubStream3Path = aStreamPrefix + "SubStream3"; + String aSubStream4Path = aStreamPrefix + "SubStream4"; + + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // set the global password for the root storage + XEncryptionProtectedSource xTempStorageEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xTempFileStorage ); + + if ( xTempStorageEncryption == null ) + { + m_aTestHelper.Message( "Optional interface XEncryptionProtectedSource is not implemented, feature can not be tested!" ); + return true; + } + + String sPass1 = "12345"; + String sPass2 = "54321"; + + try { + xTempStorageEncryption.setEncryptionPassword( sPass1 ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't set a common encryption key for the storage, exception:" + e ); + return false; + } + + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WBToSubstrOfEncrH( xTempFileStorage, aSubStream1Path, "MediaType1", true, pBytes1, true, true ) ) + return false; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream2Path, "MediaType2", false, pBytes2, sPass2, true ) ) + return false; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream3Path, "MediaType3", false, pBytes2, sPass2, true ) ) + return false; + + // open a new substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and dont commit + if ( !m_aTestHelper.WBToSubstrOfEncrH( xTempFileStorage, aSubStream4Path, "MediaType2", true, pBytes1, true, false ) ) + return false; + + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempFileStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now reopen the storage, + // check all the written and copied information + // and change it + // ================================================ + + // the temporary file must not be locked any more after storage disposing + oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // set the global password for the root storage + xTempStorageEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xTempFileStorage ); + + if ( xTempStorageEncryption == null ) + { + m_aTestHelper.Error( "XEncryptionProtectedSource is supported, but can not be retrieved!" ); + return false; + } + + try { + xTempStorageEncryption.setEncryptionPassword( sPass2 ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't set a common encryption key for the storage, exception:" + e ); + return false; + } + + + if ( !m_aTestHelper.checkStorageProperties( xTempFileStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + if ( !m_aTestHelper.checkEncrStreamH( xTempFileStorage, aSubStream1Path, "MediaType1", pBytes1, sPass1 ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xTempFileStorage, aSubStream2Path, "MediaType2", true, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xTempFileStorage, aSubStream3Path, "MediaType3", true, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.cantOpenEncrStreamH( xTempFileStorage, aSubStream4Path, ElementModes.READ, sPass1 ) ) + return false; + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and commit + if ( !m_aTestHelper.WriteBytesToEncrStreamH( xTempFileStorage, aSubStream1Path, "MediaType4", true, pBytes2, sPass1, true ) ) + return false; + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and don't commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream2Path, "MediaType5", true, pBytes1, true ) ) + return false; + + // change the password of the existing stream + if ( m_aTestHelper.ChangeStreamPassH( xTempFileStorage, aSubStream2Path, sPass2, sPass1, true ) != 1 ) + return false; + + // open existing substream hierarchically, set "MediaType" and "Compressed" properties to it, write some bytes + // and don't commit + if ( !m_aTestHelper.WriteBytesToStreamH( xTempFileStorage, aSubStream3Path, "MediaType5", true, pBytes1, false ) ) + return false; + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now reopen the storage, + // check all the written information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.READ ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + // set the global password for the root storage + xTempStorageEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xResultStorage ); + + if ( xTempStorageEncryption == null ) + { + m_aTestHelper.Error( "XEncryptionProtectedSource is supported, but can not be retrieved!" ); + return false; + } + + try { + xTempStorageEncryption.setEncryptionPassword( sPass1 ); + } + catch( Exception e ) + { + m_aTestHelper.Error( "Can't set a common encryption key for the storage, exception:" + e ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xResultStorage, aSubStream1Path, "MediaType4", true, pBytes2 ) ) + return false; + + if ( !m_aTestHelper.checkStreamH( xResultStorage, aSubStream2Path, "MediaType5", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkEncrStreamH( xResultStorage, aSubStream3Path, "MediaType3", pBytes2, sPass2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test16.java b/package/qa/storages/Test16.java new file mode 100644 index 000000000000..6f432b0da730 --- /dev/null +++ b/package/qa/storages/Test16.java @@ -0,0 +1,159 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test16 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test16( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test16: " ); + } + + public boolean test() + { + try + { + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage\u0442\u0435\u0441\u04421", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream\u0442\u0435\u0441\u04421", "MediaType1", true, pBytes1 ) ) + return false; + + byte pBytes2[] = { 2, 2, 2, 2, 2 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, "SubStream\u0442\u0435\u0441\u04422", "MediaType2", false, pBytes2 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.WRITE ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage\u0442\u0435\u0441\u04421", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream\u0442\u0435\u0441\u04421", "MediaType1", true, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream\u0442\u0435\u0441\u04422", "MediaType2", false, pBytes2 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test17.java b/package/qa/storages/Test17.java new file mode 100644 index 000000000000..009344cefbc4 --- /dev/null +++ b/package/qa/storages/Test17.java @@ -0,0 +1,142 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.io.XStream; +import com.sun.star.io.XInputStream; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test17 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test17( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test17: " ); + } + + public boolean test() + { + try + { + XStream xTempFileStream = m_aTestHelper.CreateTempFileStream( m_xMSF ); + if ( xTempFileStream == null ) + return false; + + // create storage based on the temporary stream + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) xTempFileStream; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + String pNames[] = { "SubStream1", "SubStream2", "SubStream3", "SubStream4", "SubStream5", "SubStream6", "SubStream7" }; + + for ( int nInd = 0; nInd < pNames.length; nInd++ ) + { + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstream( xTempSubStorage, pNames[nInd], "MediaType1", true, pBytes1 ) ) + return false; + + // commit substorage first + if ( !m_aTestHelper.commitStorage( xTempSubStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempSubStorage ) ) + return false; + } + + // commit the root storage so the contents must be stored now + if ( !m_aTestHelper.commitStorage( xTempStorage ) ) + return false; + + // dispose used storage to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) ) + return false; + + + // ================================================ + // now check all the written information + // ================================================ + + // close the output part of the temporary stream + // the output part must present since we already wrote to the stream + if ( !m_aTestHelper.closeOutput( xTempFileStream ) ) + return false; + + XInputStream xTempInStream = m_aTestHelper.getInputStream( xTempFileStream ); + if ( xTempInStream == null ) + return false; + + + // open input stream + // since no mode is provided the result storage must be opened readonly + Object pOneArg[] = new Object[1]; + pOneArg[0] = (Object) xTempInStream; + + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pOneArg ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't open storage based on input stream!" ); + return false; + } + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + for ( int nInd = 0; nInd < pNames.length; nInd++ ) + if ( !m_aTestHelper.checkStream( xResultSubStorage, pNames[nInd], "MediaType1", true, pBytes1 ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/Test18.java b/package/qa/storages/Test18.java new file mode 100644 index 000000000000..335a230027ce --- /dev/null +++ b/package/qa/storages/Test18.java @@ -0,0 +1,172 @@ +package complex.storages; + +import com.sun.star.uno.XInterface; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; + +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +import com.sun.star.embed.*; + +import share.LogWriter; +import complex.storages.TestHelper; +import complex.storages.StorageTest; + +public class Test18 implements StorageTest { + + XMultiServiceFactory m_xMSF; + XSingleServiceFactory m_xStorageFactory; + TestHelper m_aTestHelper; + + public Test18( XMultiServiceFactory xMSF, XSingleServiceFactory xStorageFactory, LogWriter aLogWriter ) + { + m_xMSF = xMSF; + m_xStorageFactory = xStorageFactory; + m_aTestHelper = new TestHelper( aLogWriter, "Test18: " ); + } + + public boolean test() + { + try + { + // test the default value of Compressed property + String sTempFileURL = m_aTestHelper.CreateTempFile( m_xMSF ); + if ( sTempFileURL == null || sTempFileURL == "" ) + { + m_aTestHelper.Error( "No valid temporary file was created!" ); + return false; + } + + // create temporary storage based on arbitrary medium + // after such a storage is closed it is lost + Object oTempStorage = m_xStorageFactory.createInstance(); + XStorage xTempStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xTempStorage == null ) + { + m_aTestHelper.Error( "Can't create temporary storage representation!" ); + return false; + } + + // open a new substorage + XStorage xTempSubStorage = m_aTestHelper.openSubStorage( xTempStorage, + "SubStorage1", + ElementModes.WRITE ); + if ( xTempSubStorage == null ) + { + m_aTestHelper.Error( "Can't create substorage!" ); + return false; + } + + byte pBytes1[] = { 1, 1, 1, 1, 1 }; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstreamDefaultCompressed( xTempSubStorage, "SubStream1", "image/jpeg", pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstreamDefaultCompressed( xTempSubStorage, "SubStream2", "image/png", pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstreamDefaultCompressed( xTempSubStorage, "SubStream3", "image/gif", pBytes1 ) ) + return false; + + // open a new substream, set "MediaType" and "Compressed" properties to it and write some bytes + if ( !m_aTestHelper.WriteBytesToSubstreamDefaultCompressed( xTempSubStorage, "SubStream4", "MediaType1", pBytes1 ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempStorage, + "MediaType3", + true, + ElementModes.WRITE ) ) + return false; + + // set "MediaType" property for storages and check that "IsRoot" and "OpenMode" properties are set correctly + if ( !m_aTestHelper.setStorageTypeAndCheckProps( xTempSubStorage, + "MediaType4", + false, + ElementModes.WRITE ) ) + return false; + + // create temporary storage based on a previously created temporary file + Object pArgs[] = new Object[2]; + pArgs[0] = (Object) sTempFileURL; + pArgs[1] = new Integer( ElementModes.WRITE ); + + Object oTempFileStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xTempFileStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oTempFileStorage ); + if ( xTempFileStorage == null ) + { + m_aTestHelper.Error( "Can't create storage based on temporary file!" ); + return false; + } + + // copy xTempStorage to xTempFileStorage + // xTempFileStorage will be automatically commited + if ( !m_aTestHelper.copyStorage( xTempStorage, xTempFileStorage ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xTempStorage ) || !m_aTestHelper.disposeStorage( xTempFileStorage ) ) + return false; + + // ================================================ + // now check all the written and copied information + // ================================================ + + // the temporary file must not be locked any more after storage disposing + pArgs[1] = new Integer( ElementModes.WRITE ); + Object oResultStorage = m_xStorageFactory.createInstanceWithArguments( pArgs ); + XStorage xResultStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oResultStorage ); + if ( xResultStorage == null ) + { + m_aTestHelper.Error( "Can't reopen storage based on temporary file!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultStorage, "MediaType3", true, ElementModes.WRITE ) ) + return false; + + // open existing substorage + XStorage xResultSubStorage = m_aTestHelper.openSubStorage( xResultStorage, + "SubStorage1", + ElementModes.READ ); + if ( xResultSubStorage == null ) + { + m_aTestHelper.Error( "Can't open existing substorage!" ); + return false; + } + + if ( !m_aTestHelper.checkStorageProperties( xResultSubStorage, "MediaType4", false, ElementModes.READ ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream1", "image/jpeg", false, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream2", "image/png", false, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream3", "image/gif", false, pBytes1 ) ) + return false; + + if ( !m_aTestHelper.checkStream( xResultSubStorage, "SubStream4", "MediaType1", true, pBytes1 ) ) + return false; + + // dispose used storages to free resources + if ( !m_aTestHelper.disposeStorage( xResultStorage ) ) + return false; + + return true; + } + catch( Exception e ) + { + m_aTestHelper.Error( "Exception: " + e ); + return false; + } + } + +} + diff --git a/package/qa/storages/TestHelper.java b/package/qa/storages/TestHelper.java new file mode 100644 index 000000000000..dc28786513b1 --- /dev/null +++ b/package/qa/storages/TestHelper.java @@ -0,0 +1,1661 @@ +package complex.storages; + +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.AnyConverter; + +import com.sun.star.lang.*; +import com.sun.star.embed.*; +import com.sun.star.packages.*; +import com.sun.star.io.*; +import com.sun.star.beans.*; + +import share.LogWriter; + +public class TestHelper { + + LogWriter m_aLogWriter; + String m_sTestPrefix; + + public TestHelper( LogWriter aLogWriter, String sTestPrefix ) + { + m_aLogWriter = aLogWriter; + m_sTestPrefix = sTestPrefix; + } + + public boolean WriteBytesToStream( XStream xStream, + String sStreamName, + String sMediaType, + boolean bCompressed, + byte[] pBytes ) + { + // get output stream of substream + XOutputStream xOutput = xStream.getOutputStream(); + if ( xOutput == null ) + { + Error( "Can't get XOutputStream implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // get XTrucate implementation from output stream + XTruncate xTruncate = (XTruncate) UnoRuntime.queryInterface( XTruncate.class, xOutput ); + if ( xTruncate == null ) + { + Error( "Can't get XTruncate implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // write requested byte sequence + try + { + xTruncate.truncate(); + xOutput.writeBytes( pBytes ); + } + catch( Exception e ) + { + Error( "Can't write to stream '" + sStreamName + "', exception: " + e ); + return false; + } + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStream ); + if ( xPropSet == null ) + { + Error( "Can't get XPropertySet implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // set properties to the stream + try + { + xPropSet.setPropertyValue( "MediaType", sMediaType ); + xPropSet.setPropertyValue( "Compressed", new Boolean( bCompressed ) ); + } + catch( Exception e ) + { + Error( "Can't set properties to substream '" + sStreamName + "', exception: " + e ); + return false; + } + + // check size property of the stream + try + { + int nSize = AnyConverter.toInt( xPropSet.getPropertyValue( "Size" ) ); + if ( nSize != pBytes.length ) + { + Error( "The 'Size' property of substream '" + sStreamName + "' contains wrong value!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't get 'Size' property from substream '" + sStreamName + "', exception: " + e ); + return false; + } + + return true; + } + + public boolean WriteBytesToSubstreamDefaultCompressed( XStorage xStorage, + String sStreamName, + String sMediaType, + byte[] pBytes ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openStreamElement( sStreamName, ElementModes.WRITE ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + return false; + } + + // get output stream of substream + XOutputStream xOutput = xSubStream.getOutputStream(); + if ( xOutput == null ) + { + Error( "Can't get XOutputStream implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // get XTrucate implementation from output stream + XTruncate xTruncate = (XTruncate) UnoRuntime.queryInterface( XTruncate.class, xOutput ); + if ( xTruncate == null ) + { + Error( "Can't get XTruncate implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // write requested byte sequence + try + { + xTruncate.truncate(); + xOutput.writeBytes( pBytes ); + } + catch( Exception e ) + { + Error( "Can't write to stream '" + sStreamName + "', exception: " + e ); + return false; + } + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xSubStream ); + if ( xPropSet == null ) + { + Error( "Can't get XPropertySet implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // set properties to the stream + // do not set the compressed property + try + { + xPropSet.setPropertyValue( "MediaType", sMediaType ); + } + catch( Exception e ) + { + Error( "Can't set properties to substream '" + sStreamName + "', exception: " + e ); + return false; + } + + // check size property of the stream + try + { + int nSize = AnyConverter.toInt( xPropSet.getPropertyValue( "Size" ) ); + if ( nSize != pBytes.length ) + { + Error( "The 'Size' property of substream '" + sStreamName + "' contains wrong value!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't get 'Size' property from substream '" + sStreamName + "', exception: " + e ); + return false; + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamName ) ) + return false; + + return true; + } + + public boolean WriteBytesToSubstream( XStorage xStorage, + String sStreamName, + String sMediaType, + boolean bCompressed, + byte[] pBytes ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openStreamElement( sStreamName, ElementModes.WRITE ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + return false; + } + + if ( !WriteBytesToStream( xSubStream, sStreamName, sMediaType, bCompressed, pBytes ) ) + return false; + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamName ) ) + return false; + + return true; + } + + public boolean WriteBytesToEncrSubstream( XStorage xStorage, + String sStreamName, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + String sPass ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openEncryptedStreamElement( sStreamName, ElementModes.WRITE, sPass ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + return false; + } + + if ( !WriteBytesToStream( xSubStream, sStreamName, sMediaType, bCompressed, pBytes ) ) + return false; + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamName ) ) + return false; + + return true; + } + + public boolean WBToSubstrOfEncr( XStorage xStorage, + String sStreamName, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + boolean bEncrypted ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openStreamElement( sStreamName, ElementModes.WRITE ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + return false; + } + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xSubStream ); + if ( xPropSet == null ) + { + Error( "Can't get XPropertySet implementation from substream '" + sStreamName + "'!" ); + return false; + } + + // set properties to the stream + try + { + xPropSet.setPropertyValue( "UseCommonStoragePasswordEncryption", new Boolean( bEncrypted ) ); + } + catch( Exception e ) + { + Error( "Can't set 'UseCommonStoragePasswordEncryption' property to substream '" + sStreamName + "', exception: " + e ); + return false; + } + + if ( !WriteBytesToStream( xSubStream, sStreamName, sMediaType, bCompressed, pBytes ) ) + return false; + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamName ) ) + return false; + + return true; + } + + public boolean WriteBytesToStreamH( XStorage xStorage, + String sStreamPath, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + boolean bCommit ) + { + // open substream element + XStream xSubStream = null; + try + { + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + Object oSubStream = xHStorage.openStreamElementByHierarchicalName( sStreamPath, ElementModes.WRITE ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamPath + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamPath + "', exception : " + e + "!" ); + return false; + } + + if ( !WriteBytesToStream( xSubStream, sStreamPath, sMediaType, bCompressed, pBytes ) ) + return false; + + XTransactedObject xTransact = + (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xSubStream ); + if ( xTransact == null ) + { + Error( "Substream '" + sStreamPath + "', stream opened for writing must be transacted!" ); + return false; + } + + if ( bCommit ) + { + try { + xTransact.commit(); + } catch( Exception e ) + { + Error( "Can't commit storage after substream '" + sStreamPath + "' change, exception : " + e + "!" ); + return false; + } + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamPath ) ) + return false; + + return true; + } + + public boolean WriteBytesToEncrStreamH( XStorage xStorage, + String sStreamPath, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + String sPass, + boolean bCommit ) + { + // open substream element + XStream xSubStream = null; + try + { + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + Object oSubStream = xHStorage.openEncryptedStreamElementByHierarchicalName( sStreamPath, + ElementModes.WRITE, + sPass ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamPath + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamPath + "', exception : " + e + "!" ); + return false; + } + + if ( !WriteBytesToStream( xSubStream, sStreamPath, sMediaType, bCompressed, pBytes ) ) + return false; + + XTransactedObject xTransact = + (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xSubStream ); + if ( xTransact == null ) + { + Error( "Substream '" + sStreamPath + "', stream opened for writing must be transacted!" ); + return false; + } + + if ( bCommit ) + { + try { + xTransact.commit(); + } catch( Exception e ) + { + Error( "Can't commit storage after substream '" + sStreamPath + "' change, exception : " + e + "!" ); + return false; + } + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamPath ) ) + return false; + + return true; + } + + public boolean WBToSubstrOfEncrH( XStorage xStorage, + String sStreamPath, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + boolean bEncrypted, + boolean bCommit ) + { + // open substream element + XStream xSubStream = null; + try + { + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + Object oSubStream = xHStorage.openStreamElementByHierarchicalName( sStreamPath, ElementModes.WRITE ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't create substream '" + sStreamPath + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamPath + "', exception : " + e + "!" ); + return false; + } + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xSubStream ); + if ( xPropSet == null ) + { + Error( "Can't get XPropertySet implementation from substream '" + sStreamPath + "'!" ); + return false; + } + + // set properties to the stream + try + { + xPropSet.setPropertyValue( "UseCommonStoragePasswordEncryption", new Boolean( bEncrypted ) ); + } + catch( Exception e ) + { + Error( "Can't set 'UseCommonStoragePasswordEncryption' property to substream '" + sStreamPath + "', exception: " + e ); + return false; + } + + if ( !WriteBytesToStream( xSubStream, sStreamPath, sMediaType, bCompressed, pBytes ) ) + return false; + + XTransactedObject xTransact = + (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xSubStream ); + if ( xTransact == null ) + { + Error( "Substream '" + sStreamPath + "', stream opened for writing must be transacted!" ); + return false; + } + + if ( bCommit ) + { + try { + xTransact.commit(); + } catch( Exception e ) + { + Error( "Can't commit storage after substream '" + sStreamPath + "' change, exception : " + e + "!" ); + return false; + } + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamPath ) ) + return false; + + return true; + } + + public int ChangeStreamPass( XStorage xStorage, + String sStreamName, + String sOldPass, + String sNewPass ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openEncryptedStreamElement( sStreamName, ElementModes.WRITE, sOldPass ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open substream '" + sStreamName + "'!" ); + return 0; + } + } + catch( Exception e ) + { + Error( "Can't open substream '" + sStreamName + "', exception : " + e + "!" ); + return 0; + } + + + // change the password for the stream + XEncryptionProtectedSource xStreamEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xSubStream ); + + if ( xStreamEncryption == null ) + { + Message( "Optional interface XEncryptionProtectedSource is not implemented, feature can not be tested!" ); + return -1; + } + + try { + xStreamEncryption.setEncryptionPassword( sNewPass ); + } + catch( Exception e ) + { + Error( "Can't change encryption key of the substream '" + sStreamName + "', exception:" + e ); + return 0; + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sStreamName ) ) + return 0; + + return 1; + } + + public int ChangeStreamPassH( XStorage xStorage, + String sPath, + String sOldPass, + String sNewPass, + boolean bCommit ) + { + // open substream element + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return 0; + } + + XStream xSubStream = null; + try + { + Object oSubStream = xHStorage.openEncryptedStreamElementByHierarchicalName( sPath, ElementModes.WRITE, sOldPass ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open encrypted substream '" + sPath + "'!" ); + return 0; + } + } + catch( Exception e ) + { + Error( "Can't open encrypted substream '" + sPath + "', exception : " + e + "!" ); + return 0; + } + + // change the password for the stream + XEncryptionProtectedSource xStreamEncryption = + (XEncryptionProtectedSource) UnoRuntime.queryInterface( XEncryptionProtectedSource.class, xSubStream ); + + if ( xStreamEncryption == null ) + { + Message( "Optional interface XEncryptionProtectedSource is not implemented, feature can not be tested!" ); + return -1; + } + + try { + xStreamEncryption.setEncryptionPassword( sNewPass ); + } + catch( Exception e ) + { + Error( "Can't change encryption key of the substream '" + sPath + "', exception:" + e ); + return 0; + } + + XTransactedObject xTransact = + (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xSubStream ); + if ( xTransact == null ) + { + Error( "Substream '" + sPath + "', stream opened for writing must be transacted!" ); + return 0; + } + + if ( bCommit ) + { + try { + xTransact.commit(); + } catch( Exception e ) + { + Error( "Can't commit storage after substream '" + sPath + "' change, exception : " + e + "!" ); + return 0; + } + } + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sPath ) ) + return 0; + + return 1; + } + + public boolean setStorageTypeAndCheckProps( XStorage xStorage, String sMediaType, boolean bIsRoot, int nMode ) + { + boolean bOk = false; + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStorage ); + if ( xPropSet != null ) + { + try + { + // set "MediaType" property to the stream + xPropSet.setPropertyValue( "MediaType", sMediaType ); + + // get "IsRoot" and "OpenMode" properties and control there values + boolean bPropIsRoot = AnyConverter.toBoolean( xPropSet.getPropertyValue( "IsRoot" ) ); + int nPropMode = AnyConverter.toInt( xPropSet.getPropertyValue( "OpenMode" ) ); + + bOk = true; + if ( bPropIsRoot != bIsRoot ) + { + Error( "'IsRoot' property contains wrong value!" ); + bOk = false; + } + + if ( ( bIsRoot + && ( nPropMode | ElementModes.READ ) != ( nMode | ElementModes.READ ) ) + || ( !bIsRoot && ( nPropMode & nMode ) != nMode ) ) + { + Error( "'OpenMode' property contains wrong value, expected " + nMode + ", in reality " + nPropMode + "!" ); + bOk = false; + } + } + catch( Exception e ) + { + Error( "Can't control properties of substorage, exception: " + e ); + } + } + else + { + Error( "Can't get XPropertySet implementation from storage!" ); + } + + return bOk; + } + + public boolean checkStorageProperties( XStorage xStorage, String sMediaType, boolean bIsRoot, int nMode ) + { + boolean bOk = false; + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStorage ); + if ( xPropSet != null ) + { + try + { + // get "MediaType", "IsRoot" and "OpenMode" properties and control there values + String sPropMediaType = AnyConverter.toString( xPropSet.getPropertyValue( "MediaType" ) ); + boolean bPropIsRoot = AnyConverter.toBoolean( xPropSet.getPropertyValue( "IsRoot" ) ); + int nPropMode = AnyConverter.toInt( xPropSet.getPropertyValue( "OpenMode" ) ); + + bOk = true; + if ( !sPropMediaType.equals( sMediaType ) ) + { + Error( "'MediaType' property contains wrong value, expected '" + + sMediaType + "', set '" + sPropMediaType + "' !" ); + bOk = false; + } + + if ( bPropIsRoot != bIsRoot ) + { + Error( "'IsRoot' property contains wrong value!" ); + bOk = false; + } + + if ( ( bIsRoot + && ( nPropMode | ElementModes.READ ) != ( nMode | ElementModes.READ ) ) + || ( !bIsRoot && ( nPropMode & nMode ) != nMode ) ) + { + Error( "'OpenMode' property contains wrong value, expected " + nMode + ", in reality " + nPropMode + "!" ); + bOk = false; + } + } + catch( Exception e ) + { + Error( "Can't get properties of substorage, exception: " + e ); + } + } + else + { + Error( "Can't get XPropertySet implementation from storage!" ); + } + + return bOk; + } + + public boolean InternalCheckStream( XStream xStream, + String sName, + String sMediaType, + boolean bCompressed, + byte[] pBytes, + boolean bCheckCompressed ) + { + // get input stream of substream + XInputStream xInput = xStream.getInputStream(); + if ( xInput == null ) + { + Error( "Can't get XInputStream implementation from substream '" + sName + "'!" ); + return false; + } + + byte pContents[][] = new byte[1][]; // ??? + + // read contents + try + { + xInput.readBytes( pContents, pBytes.length + 1 ); + } + catch( Exception e ) + { + Error( "Can't read from stream '" + sName + "', exception: " + e ); + return false; + } + + // check size of stream data + if ( pContents.length == 0 ) + { + Error( "SubStream '" + sName + "' reading produced disaster!" ); + return false; + } + + if ( pBytes.length != pContents[0].length ) + { + Error( "SubStream '" + sName + "' contains wrong amount of data! (" + pContents[0].length + "/" + pBytes.length + ")" ); + return false; + } + + // check stream data + for ( int ind = 0; ind < pBytes.length; ind++ ) + { + if ( pBytes[ind] != pContents[0][ind] ) + { + Error( "SubStream '" + sName + "' contains wrong data! ( byte num. " + + ind + " should be " + pBytes[ind] + " but it is " + pContents[0][ind] + ")" ); + return false; + } + } + + // check properties + boolean bOk = false; + + // get access to the XPropertySet interface + XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, xStream ); + if ( xPropSet != null ) + { + try + { + // get "MediaType" and "Size" properties and control there values + String sPropMediaType = AnyConverter.toString( xPropSet.getPropertyValue( "MediaType" ) ); + int nPropSize = AnyConverter.toInt( xPropSet.getPropertyValue( "Size" ) ); + boolean bPropCompress = AnyConverter.toBoolean( xPropSet.getPropertyValue( "Compressed" ) ); + + bOk = true; + if ( !sPropMediaType.equals( sMediaType ) ) + { + Error( "'MediaType' property contains wrong value for stream '" + sName + "',\nexpected: '" + + sMediaType + "', set: '" + sPropMediaType + "'!" ); + bOk = false; + } + + if ( nPropSize != pBytes.length ) + { + Error( "'Size' property contains wrong value for stream'" + sName + "'!" ); + bOk = false; + } + + if ( bCheckCompressed && bPropCompress != bCompressed ) + { + Error( "'Compressed' property contains wrong value for stream'" + sName + "'!" ); + bOk = false; + } + } + catch( Exception e ) + { + Error( "Can't get properties of substream '" + sName + "', exception: " + e ); + } + } + else + { + Error( "Can't get XPropertySet implementation from stream '" + sName + "'!" ); + } + + return bOk; + } + + public boolean checkStream( XStorage xParentStorage, + String sName, + String sMediaType, + boolean bCompressed, + byte[] pBytes ) + { + // open substream element first + XStream xSubStream = null; + try + { + Object oSubStream = xParentStorage.openStreamElement( sName, ElementModes.READ ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open substream '" + sName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't open substream '" + sName + "', exception : " + e + "!" ); + return false; + } + + boolean bResult = InternalCheckStream( xSubStream, sName, sMediaType, bCompressed, pBytes, true ); + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sName ) ) + return false; + + return bResult; + } + + public boolean checkEncrStream( XStorage xParentStorage, + String sName, + String sMediaType, + byte[] pBytes, + String sPass ) + { + // Important: a common password for any of parent storage should not be set or + // should be different from sPass + + try + { + Object oSubStream = xParentStorage.openStreamElement( sName, ElementModes.READ ); + Error( "Encrypted stream '" + sName + "' was opened without password!" ); + return false; + } + catch( WrongPasswordException wpe ) + {} + catch( Exception e ) + { + Error( "Unexpected exception in case of opening of encrypted stream '" + sName + "' without password: " + e + "!" ); + return false; + } + + String sWrongPass = "11"; + sWrongPass += sPass; + try + { + Object oSubStream = xParentStorage.openEncryptedStreamElement( sName, ElementModes.READ, sWrongPass ); + Error( "Encrypted stream '" + sName + "' was opened with wrong password!" ); + return false; + } + catch( WrongPasswordException wpe ) + {} + catch( Exception e ) + { + Error( "Unexpected exception in case of opening of encrypted stream '" + sName + "' with wrong password: " + e + "!" ); + return false; + } + + XStream xSubStream = null; + try + { + Object oSubStream = xParentStorage.openEncryptedStreamElement( sName, ElementModes.READ, sPass ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open encrypted substream '" + sName + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't open encrypted substream '" + sName + "', exception : " + e + "!" ); + return false; + } + + // encrypted streams will be compressed always, so after the storing this property is always true, + // although before the storing it can be set to false ( it is not always clear whether a stream is encrypted + // before the storing ) + boolean bResult = InternalCheckStream( xSubStream, sName, sMediaType, true, pBytes, false ); + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sName ) ) + return false; + + return bResult; + } + + public boolean checkStreamH( XStorage xParentStorage, + String sPath, + String sMediaType, + boolean bCompressed, + byte[] pBytes ) + { + // open substream element first + XStream xSubStream = null; + try + { + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xParentStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + Object oSubStream = xHStorage.openStreamElementByHierarchicalName( sPath, ElementModes.READ ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open substream '" + sPath + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't open substream '" + sPath + "', exception : " + e + "!" ); + return false; + } + + boolean bResult = InternalCheckStream( xSubStream, sPath, sMediaType, bCompressed, pBytes, true ); + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sPath ) ) + return false; + + return bResult; + } + + public boolean checkEncrStreamH( XStorage xParentStorage, + String sPath, + String sMediaType, + byte[] pBytes, + String sPass ) + { + // Important: a common password for any of parent storage should not be set or + // should be different from sPass + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xParentStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + try + { + Object oSubStream = xHStorage.openStreamElementByHierarchicalName( sPath, ElementModes.READ ); + XStream xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + Error( "Encrypted substream '" + sPath + "' was opened without password!" ); + return false; + } + catch( WrongPasswordException wpe ) + {} + catch( Exception e ) + { + Error( "Unexpected exception in case of opening of encrypted stream '" + sPath + "' without password: " + e + "!" ); + return false; + } + + String sWrongPass = "11"; + sWrongPass += sPass; + try + { + Object oSubStream = xHStorage.openEncryptedStreamElementByHierarchicalName( sPath, ElementModes.READ, sWrongPass ); + XStream xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + Error( "Encrypted substream '" + sPath + "' was opened with wrong password!" ); + return false; + } + catch( WrongPasswordException wpe ) + {} + catch( Exception e ) + { + Error( "Unexpected exception in case of opening of encrypted stream '" + sPath + "' with wrong password: " + e + "!" ); + return false; + } + + XStream xSubStream = null; + try + { + Object oSubStream = xHStorage.openEncryptedStreamElementByHierarchicalName( sPath, ElementModes.READ, sPass ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + { + Error( "Can't open encrypted substream '" + sPath + "'!" ); + return false; + } + } + catch( Exception e ) + { + Error( "Can't open encrypted substream '" + sPath + "', exception : " + e + "!" ); + return false; + } + + // encrypted streams will be compressed always, so after the storing this property is always true, + // although before the storing it can be set to false ( it is not always clear whether a stream is encrypted + // before the storing ) + boolean bResult = InternalCheckStream( xSubStream, sPath, sMediaType, true, pBytes, false ); + + // free the stream resources, garbage collector may remove the object too late + if ( !disposeStream( xSubStream, sPath ) ) + return false; + + return bResult; + } + + public boolean copyStorage( XStorage xSourceStorage, XStorage xDestStorage ) + { + // copy xSourceStorage to xDestStorage + try + { + xSourceStorage.copyToStorage( xDestStorage ); + } + catch( Exception e ) + { + Error( "Storage copying failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean commitStorage( XStorage xStorage ) + { + // XTransactedObject must be supported by storages + XTransactedObject xTransact = (XTransactedObject) UnoRuntime.queryInterface( XTransactedObject.class, xStorage ); + if ( xTransact == null ) + { + Error( "Storage doesn't implement transacted access!" ); + return false; + } + + try + { + xTransact.commit(); + } + catch( Exception e ) + { + Error( "Storage commit failed, exception:" + e ); + return false; + } + + return true; + } + + public boolean disposeStream( XStream xStream, String sStreamName ) + { + XComponent xComponent = (XComponent) UnoRuntime.queryInterface( XComponent.class, xStream ); + if ( xComponent == null ) + { + Error( "Can't get XComponent implementation from substream '" + sStreamName + "'!" ); + return false; + } + + try + { + xComponent.dispose(); + } + catch( Exception e ) + { + Error( "Substream '" + sStreamName + "' disposing throws exception: " + e ); + return false; + } + + return true; + } + + public boolean disposeStorage( XStorage xStorage ) + { + // dispose the storage + XComponent xComponent = (XComponent) UnoRuntime.queryInterface( XComponent.class, xStorage ); + if ( xComponent == null ) + { + Error( "Can't retrieve XComponent implementation from storage!" ); + return false; + } + + try + { + xComponent.dispose(); + } + catch( Exception e ) + { + Error( "Storage disposing failed!" ); + return false; + } + + return true; + } + + public XInputStream getInputStream( XStream xStream ) + { + XInputStream xInTemp = null; + try + { + xInTemp = xStream.getInputStream(); + if ( xInTemp == null ) + Error( "Can't get the input part of a stream!" ); + } + catch ( Exception e ) + { + Error( "Can't get the input part of a stream, exception :" + e ); + } + + return xInTemp; + } + + public boolean closeOutput( XStream xStream ) + { + XOutputStream xOutTemp = null; + try + { + xOutTemp = xStream.getOutputStream(); + if ( xOutTemp == null ) + { + Error( "Can't get the output part of a stream!" ); + return false; + } + } + catch ( Exception e ) + { + Error( "Can't get the output part of a stream, exception :" + e ); + return false; + } + + try + { + xOutTemp.closeOutput(); + } + catch ( Exception e ) + { + Error( "Can't close output part of a stream, exception :" + e ); + return false; + } + + return true; + } + + public XStorage openSubStorage( XStorage xStorage, String sName, int nMode ) + { + // open existing substorage + try + { + Object oSubStorage = xStorage.openStorageElement( sName, nMode ); + XStorage xSubStorage = (XStorage) UnoRuntime.queryInterface( XStorage.class, oSubStorage ); + return xSubStorage; + } + catch( Exception e ) + { + Error( "Can't open substorage '" + sName + "', exception: " + e ); + } + + return null; + } + + public XStream CreateTempFileStream( XMultiServiceFactory xMSF ) + { + // try to get temporary file representation + XStream xTempFileStream = null; + try + { + Object oTempFile = xMSF.createInstance( "com.sun.star.io.TempFile" ); + xTempFileStream = (XStream)UnoRuntime.queryInterface( XStream.class, oTempFile ); + } + catch( Exception e ) + {} + + if ( xTempFileStream == null ) + Error( "Can't create temporary file!" ); + + return xTempFileStream; + } + + public String CreateTempFile( XMultiServiceFactory xMSF ) + { + String sResult = null; + + // try to get temporary file representation + XPropertySet xTempFileProps = null; + try + { + Object oTempFile = xMSF.createInstance( "com.sun.star.io.TempFile" ); + xTempFileProps = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, oTempFile ); + } + catch( Exception e ) + {} + + if ( xTempFileProps != null ) + { + try + { + xTempFileProps.setPropertyValue( "RemoveFile", new Boolean( false ) ); + sResult = AnyConverter.toString( xTempFileProps.getPropertyValue( "Uri" ) ); + } + catch( Exception e ) + { + Error( "Can't control TempFile properties, exception: " + e ); + } + } + else + { + Error( "Can't create temporary file representation!" ); + } + + // close temporary file explicitly + try + { + XStream xStream = (XStream)UnoRuntime.queryInterface( XStream.class, xTempFileProps ); + if ( xStream != null ) + { + XOutputStream xOut = xStream.getOutputStream(); + if ( xOut != null ) + xOut.closeOutput(); + + XInputStream xIn = xStream.getInputStream(); + if ( xIn != null ) + xIn.closeInput(); + } + else + Error( "Can't close TempFile!" ); + } + catch( Exception e ) + { + Error( "Can't close TempFile, exception: " + e ); + } + + return sResult; + } + + public boolean copyElementTo( XStorage xSource, String sName, XStorage xDest ) + { + // copy element with name sName from xSource to xDest + try + { + xSource.copyElementTo( sName, xDest, sName ); + } + catch( Exception e ) + { + Error( "Element copying failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean copyElementTo( XStorage xSource, String sName, XStorage xDest, String sTargetName ) + { + // copy element with name sName from xSource to xDest + try + { + xSource.copyElementTo( sName, xDest, sTargetName ); + } + catch( Exception e ) + { + Error( "Element copying failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean moveElementTo( XStorage xSource, String sName, XStorage xDest ) + { + // move element with name sName from xSource to xDest + try + { + xSource.moveElementTo( sName, xDest, sName ); + } + catch( Exception e ) + { + Error( "Element moving failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean renameElement( XStorage xStorage, String sOldName, String sNewName ) + { + // rename element with name sOldName to sNewName + try + { + xStorage.renameElement( sOldName, sNewName ); + } + catch( Exception e ) + { + Error( "Element renaming failed, exception: " + e ); + return false; + } + + return true; + } + + public boolean removeElement( XStorage xStorage, String sName ) + { + // remove element with name sName + try + { + xStorage.removeElement( sName ); + } + catch( Exception e ) + { + Error( "Element removing failed, exception: " + e ); + return false; + } + + return true; + } + + public XStream OpenStream( XStorage xStorage, + String sStreamName, + int nMode ) + { + // open substream element + XStream xSubStream = null; + try + { + Object oSubStream = xStorage.openStreamElement( sStreamName, nMode ); + xSubStream = (XStream) UnoRuntime.queryInterface( XStream.class, oSubStream ); + if ( xSubStream == null ) + Error( "Can't create substream '" + sStreamName + "'!" ); + } + catch( Exception e ) + { + Error( "Can't create substream '" + sStreamName + "', exception : " + e + "!" ); + } + + return xSubStream; + } + + public boolean compareRawMethodsOnEncrStream( XStorage xStorage, String sStreamName ) + { + + XStorageRawAccess xRawStorage; + try + { + xRawStorage = (XStorageRawAccess) UnoRuntime.queryInterface( XStorageRawAccess.class, xStorage ); + } + catch( Exception e ) + { + Error( "Can't get raw access to the storage, exception : " + e + "!" ); + return false; + } + + if ( xRawStorage == null ) + { + Error( "Can't get raw access to the storage!" ); + return false; + } + + XInputStream xHeadRawStream = null; + try + { + xHeadRawStream = xRawStorage.getRawEncrStreamElement( sStreamName ); + } + catch( Exception e ) + { + Error( "Can't open encrypted stream '" + sStreamName + "' in raw mode with header, exception : " + e + "!" ); + } + + XInputStream xPlainRawStream = null; + try + { + xPlainRawStream = xRawStorage.getPlainRawStreamElement( sStreamName ); + } + catch( Exception e ) + { + Error( "Can't open encrypted stream '" + sStreamName + "' in raw mode with header, exception : " + e + "!" ); + } + + if ( xHeadRawStream == null || xPlainRawStream == null ) + { + Error( "Can't open encrypted stream '" + sStreamName + "' in raw modes!" ); + return false; + } + + try + { + byte pData[][] = new byte[1][22]; + if ( xHeadRawStream.readBytes( pData, 22 ) != 22 ) + { + Error( "Can't read header of encrypted stream '" + sStreamName + "' raw representations!" ); + return false; + } + + if ( pData[0][0] != 0x4d || pData[0][1] != 0x47 || pData[0][2] != 0x02 || pData[0][3] != 0x05 ) + { + Error( "No signature in the header of encrypted stream '" + sStreamName + "' raw representations!" ); + return false; + } + + int nVariableHeaderLength = + ( pData[0][14] + pData[0][15] * 0x100 ) // salt length + + ( pData[0][16] + pData[0][17] * 0x100 ) // iv length + + ( pData[0][18] + pData[0][19] * 0x100 ) // digest length + + ( pData[0][20] + pData[0][21] * 0x100 ); // mediatype length + + xHeadRawStream.skipBytes( nVariableHeaderLength ); + + byte pRawData1[][] = new byte[1][32000]; + byte pRawData2[][] = new byte[1][32000]; + int nRead1 = 0; + int nRead2 = 0; + + do + { + nRead1 = xHeadRawStream.readBytes( pRawData1, 32000 ); + nRead2 = xPlainRawStream.readBytes( pRawData2, 32000 ); + + if ( nRead1 != nRead2 ) + { + Error( "The encrypted stream '" + sStreamName + "' raw representations have different size!" ); + return false; + } + + for ( int nInd = 0; nInd < nRead1; nInd++ ) + if ( pRawData1[0][nInd] != pRawData2[0][nInd] ) + { + Error( "The encrypted stream '" + sStreamName + "' raw representations have different data!" ); + return false; + } + } + while( nRead1 == 32000 ); + } + catch ( Exception e ) + { + Error( "Can't compare stream '" + sStreamName + "' raw representations, exception : " + e + "!" ); + return false; + } + + return true; + } + + public boolean cantOpenStorage( XStorage xStorage, String sName ) + { + // try to open an opened substorage, open call must fail + try + { + Object oDummyStorage = xStorage.openStorageElement( sName, ElementModes.READ ); + Error( "The trying to reopen opened substorage '" + sName + "' must fail!" ); + } + catch( Exception e ) + { + return true; + } + + return false; + } + + public boolean cantOpenStream( XStorage xStorage, String sName, int nMode ) + { + // try to open the substream with specified mode must fail + try + { + Object oDummyStream = xStorage.openStreamElement( sName, nMode ); + Error( "The trying to open substream '" + sName + "' must fail!" ); + } + catch( Exception e ) + { + return true; + } + + return false; + } + + public boolean cantOpenStreamH( XStorage xStorage, String sPath, int nMode ) + { + // try to open the substream with specified mode must fail + + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + try + { + Object oDummyStream = xHStorage.openStreamElementByHierarchicalName( sPath, nMode ); + Error( "The trying to open substream '" + sPath + "' must fail!" ); + } + catch( Exception e ) + { + return true; + } + + return false; + } + + public boolean cantOpenEncrStreamH( XStorage xStorage, String sPath, int nMode, String aPass ) + { + // try to open the substream with specified mode must fail + + XHierarchicalStorageAccess xHStorage = + (XHierarchicalStorageAccess) UnoRuntime.queryInterface( XHierarchicalStorageAccess.class, xStorage ); + if ( xHStorage == null ) + { + Error( "The storage does not support hierarchical access!" ); + return false; + } + + try + { + Object oDummyStream = xHStorage.openEncryptedStreamElementByHierarchicalName( sPath, nMode, aPass ); + Error( "The trying to open substream '" + sPath + "' must fail!" ); + } + catch( WrongPasswordException wpe ) + { + Error( "The substream '" + sPath + "' must not exist!" ); + return false; + } + catch( Exception e ) + { + return true; + } + + return false; + } + + public XStorage cloneStorage( XSingleServiceFactory xFactory, XStorage xStorage ) + { + // create a copy of a last commited version of specified storage + XStorage xResult = null; + try + { + Object oTempStorage = xFactory.createInstance(); + xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xResult != null ) + xStorage.copyLastCommitTo( xResult ); + } + catch( Exception e ) + { + Error( "Can't clone storage, exception: " + e ); + return null; + } + + return xResult; + } + + public XStorage cloneSubStorage( XSingleServiceFactory xFactory, XStorage xStorage, String sName ) + { + // create a copy of a last commited version of specified substorage + XStorage xResult = null; + try + { + Object oTempStorage = xFactory.createInstance(); + xResult = (XStorage) UnoRuntime.queryInterface( XStorage.class, oTempStorage ); + if ( xResult != null ) + xStorage.copyStorageElementLastCommitTo( sName, xResult ); + } + catch( Exception e ) + { + Error( "Can't clone substorage '" + sName + "', exception: " + e ); + return null; + } + + return xResult; + } + + public XStream cloneSubStream( XStorage xStorage, String sName ) + { + // clone existing substream + try + { + XStream xStream = xStorage.cloneStreamElement( sName ); + return xStream; + } + catch( Exception e ) + { + Error( "Can't clone substream '" + sName + "', exception: " + e ); + } + + return null; + } + + public XStream cloneEncrSubStream( XStorage xStorage, String sName, String sPass ) + { + // clone existing substream + try + { + XStream xStream = xStorage.cloneEncryptedStreamElement( sName, sPass ); + return xStream; + } + catch( Exception e ) + { + Error( "Can't clone encrypted substream '" + sName + "', exception: " + e ); + } + + return null; + } + + public void Error( String sError ) + { + m_aLogWriter.println( m_sTestPrefix + "Error: " + sError ); + } + + public void Message( String sMessage ) + { + m_aLogWriter.println( m_sTestPrefix + sMessage ); + } +} + diff --git a/package/qa/storages/makefile.mk b/package/qa/storages/makefile.mk new file mode 100644 index 000000000000..81cacb939510 --- /dev/null +++ b/package/qa/storages/makefile.mk @@ -0,0 +1,120 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.15.18.1 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/.. +TARGET = StorageUnitTest +PRJNAME = package +PACKAGE = complex$/storages + +# --- Settings ----------------------------------------------------- +.INCLUDE: settings.mk + + +#----- compile .java files ----------------------------------------- + +JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar OOoRunner.jar + +JAVAFILES =\ + StorageUnitTest.java\ + StorageTest.java\ + TestHelper.java\ + BorderedStream.java\ + Test01.java\ + Test02.java\ + Test03.java\ + Test04.java\ + Test05.java\ + Test06.java\ + Test07.java\ + Test08.java\ + Test09.java\ + Test10.java\ + Test11.java\ + Test12.java\ + Test13.java\ + Test14.java\ + Test15.java\ + Test16.java\ + Test17.java\ + Test18.java\ + RegressionTest_114358.java\ + RegressionTest_i29169.java\ + RegressionTest_i30400.java\ + RegressionTest_i29321.java\ + RegressionTest_i30677.java\ + RegressionTest_i27773.java\ + RegressionTest_i46848.java\ + RegressionTest_i55821.java\ + RegressionTest_i35095.java\ + RegressionTest_i49755.java\ + RegressionTest_i59886.java\ + RegressionTest_i61909.java\ + RegressionTest_i84234.java\ + RegressionTest_125919.java + +JAVACLASSFILES = $(foreach,i,$(JAVAFILES) $(CLASSDIR)$/$(PACKAGE)$/$(i:b).class) + +#----- make a jar from compiled files ------------------------------ + +MAXLINELENGTH = 100000 + +JARCLASSDIRS = $(PACKAGE) +JARTARGET = $(TARGET).jar +JARCOMPRESS = TRUE + +# --- Parameters for the test -------------------------------------- + +# start an office if the parameter is set for the makefile +.IF "$(OFFICE)" == "" +CT_APPEXECCOMMAND = +.ELSE +CT_APPEXECCOMMAND = -AppExecutionCommand "$(OFFICE)$/soffice -accept=socket,host=localhost,port=8100;urp;" +.ENDIF + +# test base is java complex +CT_TESTBASE = -TestBase java_complex + +# test looks something like the.full.package.TestName +CT_TEST = -o $(PACKAGE:s\$/\.\).$(JAVAFILES:b) + +# start the runner application +CT_APP = org.openoffice.Runner + +# --- Targets ------------------------------------------------------ + +.INCLUDE: target.mk + +RUN: run + +run: + java -cp $(CLASSPATH) $(CT_APP) $(CT_TESTBASE) $(CT_APPEXECCOMMAND) $(CT_TEST) + + diff --git a/package/source/manifest/Base64Codec.cxx b/package/source/manifest/Base64Codec.cxx new file mode 100644 index 000000000000..3b27a0bd05a6 --- /dev/null +++ b/package/source/manifest/Base64Codec.cxx @@ -0,0 +1,207 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Base64Codec.cxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include "Base64Codec.hxx" +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +using namespace rtl; +using namespace osl; +using namespace com::sun::star; + +const + sal_Char aBase64EncodeTable[] = + { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; + +const + sal_uInt8 aBase64DecodeTable[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, // 32-47 +// + / + + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, // 48-63 +// 0 1 2 3 4 5 6 7 8 9 = + + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79 +// A B C D E F G H I J K L M N O + + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, // 80-95 +// P Q R S T U V W X Y Z + + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111 +// a b c d e f g h i j k l m n o + + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, // 112-127 +// p q r s t u v w x y z + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +void ThreeByteToFourByte (const sal_uInt8* pBuffer, const sal_Int32 nStart, const sal_Int32 nFullLen, rtl::OUStringBuffer& sBuffer) +{ + sal_Int32 nLen(nFullLen - nStart); + if (nLen > 3) + nLen = 3; + if (nLen == 0) + { + sBuffer.setLength(0); + return; + } + + sal_Int32 nBinaer; + switch (nLen) + { + case 1: + { + nBinaer = ((sal_uInt8)pBuffer[nStart + 0]) << 16; + } + break; + case 2: + { + nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) + + (((sal_uInt8)pBuffer[nStart + 1]) << 8); + } + break; + default: + { + nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) + + (((sal_uInt8)pBuffer[nStart + 1]) << 8) + + ((sal_uInt8)pBuffer[nStart + 2]); + } + break; + } + + sBuffer.appendAscii("===="); + + sal_uInt8 nIndex = static_cast< sal_uInt8 >((nBinaer & 0xFC0000) >> 18); + sBuffer.setCharAt(0, aBase64EncodeTable [nIndex]); + + nIndex = static_cast< sal_uInt8 >((nBinaer & 0x3F000) >> 12); + sBuffer.setCharAt(1, aBase64EncodeTable [nIndex]); + if (nLen == 1) + return; + + nIndex = static_cast< sal_uInt8 >((nBinaer & 0xFC0) >> 6); + sBuffer.setCharAt(2, aBase64EncodeTable [nIndex]); + if (nLen == 2) + return; + + nIndex = static_cast< sal_uInt8 >(nBinaer & 0x3F); + sBuffer.setCharAt(3, aBase64EncodeTable [nIndex]); +} + +void Base64Codec::encodeBase64(rtl::OUStringBuffer& aStrBuffer, const uno::Sequence < sal_uInt8 >& aPass) +{ + sal_Int32 i(0); + sal_Int32 nBufferLength(aPass.getLength()); + const sal_uInt8* pBuffer = aPass.getConstArray(); + while (i < nBufferLength) + { + rtl::OUStringBuffer sBuffer; + ThreeByteToFourByte (pBuffer, i, nBufferLength, sBuffer); + aStrBuffer.append(sBuffer); + i += 3; + } +} + +const rtl::OUString s2equal(RTL_CONSTASCII_USTRINGPARAM("==")); +const rtl::OUString s1equal(RTL_CONSTASCII_USTRINGPARAM("=")); + +void FourByteToThreeByte (sal_uInt8* pBuffer, sal_Int32& nLength, const sal_Int32 nStart, const rtl::OUString& sString) +{ + nLength = 0; + sal_Int32 nLen (sString.getLength()); + + OSL_ASSERT( nLen == 4 ); + if (nLen != 4) + return; + + if (sString.indexOf(s2equal) == 2) + nLength = 1; + else if (sString.indexOf(s1equal) == 3) + nLength = 2; + else + nLength = 3; + + sal_Int32 nBinaer ((aBase64DecodeTable [sString [0]] << 18) + + (aBase64DecodeTable [sString [1]] << 12) + + (aBase64DecodeTable [sString [2]] << 6) + + (aBase64DecodeTable [sString [3]])); + + sal_uInt8 OneByte = static_cast< sal_uInt8 >((nBinaer & 0xFF0000) >> 16); + pBuffer[nStart + 0] = (sal_uInt8)OneByte; + + if (nLength == 1) + return; + + OneByte = static_cast< sal_uInt8 >((nBinaer & 0xFF00) >> 8); + pBuffer[nStart + 1] = OneByte; + + if (nLength == 2) + return; + + OneByte = static_cast< sal_uInt8 >(nBinaer & 0xFF); + pBuffer[nStart + 2] = OneByte; +} + +void Base64Codec::decodeBase64(uno::Sequence< sal_uInt8 >& aBuffer, const rtl::OUString& sBuffer) +{ + sal_Int32 nFirstLength((sBuffer.getLength() / 4) * 3); + sal_uInt8* pBuffer = new sal_uInt8[nFirstLength]; + sal_Int32 nSecondLength(0); + sal_Int32 nLength(0); + sal_Int32 i = 0; + sal_Int32 k = 0; + while (i < sBuffer.getLength()) + { + FourByteToThreeByte (pBuffer, nLength, k, sBuffer.copy(i, 4)); + nSecondLength += nLength; + nLength = 0; + i += 4; + k += 3; + } + aBuffer = uno::Sequence<sal_uInt8>(pBuffer, nSecondLength); + delete[] pBuffer; +} diff --git a/package/source/manifest/Base64Codec.hxx b/package/source/manifest/Base64Codec.hxx new file mode 100644 index 000000000000..f09b95ffc82f --- /dev/null +++ b/package/source/manifest/Base64Codec.hxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Base64Codec.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _BASE64_CODEC_HXX +#define _BASE64_CODEC_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +namespace rtl +{ +class OUString; +class OUStringBuffer; +} + +class Base64Codec +{ +public: + static void encodeBase64(rtl::OUStringBuffer& aStrBuffer, const com::sun::star::uno::Sequence<sal_uInt8>& aPass); + static void decodeBase64(com::sun::star::uno::Sequence<sal_uInt8>& aPass, const rtl::OUString& sBuffer); +}; +#endif diff --git a/package/source/manifest/ManifestDefines.hxx b/package/source/manifest/ManifestDefines.hxx new file mode 100644 index 000000000000..e64c650a386c --- /dev/null +++ b/package/source/manifest/ManifestDefines.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestDefines.hxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _MANIFEST_DEFINES_HXX +#define _MANIFEST_DEFINES_HXX + +#include <PackageConstants.hxx> + +#define MANIFEST_NSPREFIX "manifest:" +#define ELEMENT_MANIFEST "manifest:manifest" +#define ATTRIBUTE_XMLNS "xmlns:manifest" +#define MANIFEST_NAMESPACE "http://openoffice.org/2001/manifest" +#define MANIFEST_OASIS_NAMESPACE "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" +#define MANIFEST_DOCTYPE "<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">" +#define ATTRIBUTE_CDATA "CDATA" + +#define ELEMENT_FILE_ENTRY "manifest:file-entry" +#define ATTRIBUTE_FULL_PATH "manifest:full-path" +#define ATTRIBUTE_VERSION "manifest:version" +#define ATTRIBUTE_MEDIA_TYPE "manifest:media-type" +#define ATTRIBUTE_SIZE "manifest:size" + +#define ELEMENT_ENCRYPTION_DATA "manifest:encryption-data" +#define ATTRIBUTE_CHECKSUM_TYPE "manifest:checksum-type" +#define ATTRIBUTE_CHECKSUM "manifest:checksum" + +#define ELEMENT_ALGORITHM "manifest:algorithm" +#define ATTRIBUTE_ALGORITHM_NAME "manifest:algorithm-name" +#define ATTRIBUTE_INITIALISATION_VECTOR "manifest:initialisation-vector" + +#define ELEMENT_START_KEY_GENERATION "manifest:start-key-generation" +#define ATTRIBUTE_START_KEY_GENERATION_NAME "manifest:start-key-generation-name" +#define ALGORITHM_SHA1 "SHA1" +#define ATTRIBUTE_KEY_SIZE "manifest:key-size" +#define START_KEY_SIZE "20" + +#define ELEMENT_KEY_DERIVATION "manifest:key-derivation" +#define ATTRIBUTE_KEY_DERIVATION_NAME "manifest:key-derivation-name" +#define ATTRIBUTE_SALT "manifest:salt" +#define ATTRIBUTE_ITERATION_COUNT "manifest:iteration-count" +#define CHECKSUM_TYPE "SHA1/1K" +#define DERIVED_KEY_SIZE "16" + +#endif diff --git a/package/source/manifest/ManifestExport.cxx b/package/source/manifest/ManifestExport.cxx new file mode 100644 index 000000000000..4ae1785a0d8b --- /dev/null +++ b/package/source/manifest/ManifestExport.cxx @@ -0,0 +1,326 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestExport.cxx,v $ + * $Revision: 1.18 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ManifestExport.hxx> +#include <ManifestDefines.hxx> +#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HXX +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#endif +#include <rtl/ustrbuf.hxx> +#ifndef _BASE64_CODEC_HXX_ +#include <Base64Codec.hxx> +#endif +#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> +#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HXX +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_BEANS_PROPERTYVALUE_HPP +#include <com/sun/star/beans/PropertyValue.hpp> +#endif + +#include <comphelper/documentconstants.hxx> +#include <comphelper/attributelist.hxx> + +using namespace rtl; +using namespace com::sun::star::beans; +using namespace com::sun::star::uno; +using namespace com::sun::star::xml::sax; + +ManifestExport::ManifestExport(Reference < XDocumentHandler > xHandler, const Sequence < Sequence < PropertyValue > > &rManList ) +{ + const OUString sFileEntryElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_FILE_ENTRY ) ); + const OUString sManifestElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_MANIFEST ) ); + const OUString sEncryptionDataElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ENCRYPTION_DATA ) ); + const OUString sAlgorithmElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ALGORITHM ) ); + const OUString sStartKeyGenerationElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_START_KEY_GENERATION ) ); + const OUString sKeyDerivationElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_KEY_DERIVATION ) ); + + const OUString sCdataAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CDATA ) ); + const OUString sMediaTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_MEDIA_TYPE ) ); + const OUString sVersionAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_VERSION ) ); + const OUString sFullPathAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_FULL_PATH ) ); + const OUString sSizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SIZE ) ); + const OUString sKeySizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_SIZE ) ); + const OUString sSaltAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SALT ) ); + const OUString sInitialisationVectorAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_INITIALISATION_VECTOR ) ); + const OUString sIterationCountAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ITERATION_COUNT ) ); + const OUString sAlgorithmNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ALGORITHM_NAME ) ); + const OUString sStartKeyGenerationNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_START_KEY_GENERATION_NAME ) ); + const OUString sKeyDerivationNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_DERIVATION_NAME ) ); + const OUString sChecksumTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM_TYPE ) ); + const OUString sChecksumAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM) ); + + const OUString sFullPathProperty ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); + const OUString sVersionProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); + const OUString sMediaTypeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); + const OUString sIterationCountProperty ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) ); + const OUString sSaltProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) ); + const OUString sInitialisationVectorProperty( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) ); + const OUString sSizeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) ); + const OUString sDigestProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) ); + + const OUString sWhiteSpace ( RTL_CONSTASCII_USTRINGPARAM ( " " ) ); + const OUString sBlowfish ( RTL_CONSTASCII_USTRINGPARAM ( "Blowfish CFB" ) ); + const OUString sPBKDF2 ( RTL_CONSTASCII_USTRINGPARAM ( "PBKDF2" ) ); + const OUString sChecksumType ( RTL_CONSTASCII_USTRINGPARAM ( CHECKSUM_TYPE ) ); + const OUString sStartKeySize ( RTL_CONSTASCII_USTRINGPARAM ( START_KEY_SIZE ) ); + const OUString sDerivedKeySize ( RTL_CONSTASCII_USTRINGPARAM ( DERIVED_KEY_SIZE ) ); + const OUString sSHA1 ( RTL_CONSTASCII_USTRINGPARAM ( ALGORITHM_SHA1 ) ); + + ::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList; + const Sequence < PropertyValue > *pSequence = rManList.getConstArray(); + const sal_uInt32 nManLength = rManList.getLength(); + + // find the mediatype of the document if any + OUString aDocMediaType; + OUString aDocVersion; + for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ ) + { + OUString aMediaType; + OUString aPath; + OUString aVersion; + + const PropertyValue *pValue = pSequence[nInd].getConstArray(); + for (sal_uInt32 j = 0, nNum = pSequence[nInd].getLength(); j < nNum; j++, pValue++) + { + if (pValue->Name.equals (sMediaTypeProperty) ) + { + pValue->Value >>= aMediaType; + } + else if (pValue->Name.equals (sFullPathProperty) ) + { + pValue->Value >>= aPath; + } + else if (pValue->Name.equals (sVersionProperty) ) + { + pValue->Value >>= aVersion; + } + + if ( aPath.getLength() && aMediaType.getLength() && aVersion.getLength() ) + break; + } + + if ( aPath.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) ) ) + { + aDocMediaType = aMediaType; + aDocVersion = aVersion; + break; + } + } + + sal_Bool bProvideDTD = sal_False; + sal_Bool bAcceptNonemptyVersion = sal_False; + sal_Bool bStoreStartKeyGeneration = sal_False; + if ( aDocMediaType.getLength() ) + { + if ( aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII ) ) ) + + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII ) ) ) + || aDocMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM( MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII ) ) ) ) + + { + // oasis format + pRootAttrList->AddAttribute ( OUString( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_XMLNS ) ), + sCdataAttribute, + OUString( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_OASIS_NAMESPACE ) ) ); + bAcceptNonemptyVersion = sal_True; + if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 ) + { + // this is ODF12 generation, let encrypted streams contain start-key-generation entry + bStoreStartKeyGeneration = sal_True; + } + } + else + { + // even if it is no SO6 format the namespace must be specified + // thus SO6 format is used as default one + pRootAttrList->AddAttribute ( OUString( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_XMLNS ) ), + sCdataAttribute, + OUString( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_NAMESPACE ) ) ); + + bProvideDTD = sal_True; + } + } + + Reference < XAttributeList > xRootAttrList (pRootAttrList); + + xHandler->startDocument(); + Reference < XExtendedDocumentHandler > xExtHandler ( xHandler, UNO_QUERY ); + if ( xExtHandler.is() && bProvideDTD ) + { + OUString aDocType ( RTL_CONSTASCII_USTRINGPARAM ( MANIFEST_DOCTYPE ) ); + xExtHandler->unknown ( aDocType ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + } + xHandler->startElement( sManifestElement, xRootAttrList ); + + for (sal_uInt32 i = 0 ; i < nManLength ; i++) + { + ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList; + const PropertyValue *pValue = pSequence[i].getConstArray(); + OUString aString; + const PropertyValue *pVector = NULL, *pSalt = NULL, *pIterationCount = NULL, *pDigest = NULL; + for (sal_uInt32 j = 0, nNum = pSequence[i].getLength(); j < nNum; j++, pValue++) + { + if (pValue->Name.equals (sMediaTypeProperty) ) + { + pValue->Value >>= aString; + pAttrList->AddAttribute ( sMediaTypeAttribute, sCdataAttribute, aString ); + } + else if (pValue->Name.equals (sVersionProperty) ) + { + pValue->Value >>= aString; + // the version is stored only if it is not empty + if ( bAcceptNonemptyVersion && aString.getLength() ) + pAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aString ); + } + else if (pValue->Name.equals (sFullPathProperty) ) + { + pValue->Value >>= aString; + pAttrList->AddAttribute ( sFullPathAttribute, sCdataAttribute, aString ); + } + else if (pValue->Name.equals (sSizeProperty) ) + { + sal_Int32 nSize = 0; + pValue->Value >>= nSize; + OUStringBuffer aBuffer; + aBuffer.append ( nSize ); + pAttrList->AddAttribute ( sSizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + } + else if (pValue->Name.equals (sInitialisationVectorProperty) ) + pVector = pValue; + else if (pValue->Name.equals (sSaltProperty) ) + pSalt = pValue; + else if (pValue->Name.equals (sIterationCountProperty) ) + pIterationCount = pValue; + else if (pValue->Name.equals ( sDigestProperty ) ) + pDigest = pValue; + } + xHandler->ignorableWhitespace ( sWhiteSpace ); + Reference < XAttributeList > xAttrList ( pAttrList ); + xHandler->startElement( sFileEntryElement , xAttrList); + if ( pVector && pSalt && pIterationCount ) + { + // ==== Encryption Data + ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList; + Reference < XAttributeList > xNewAttrList (pNewAttrList); + OUStringBuffer aBuffer; + Sequence < sal_uInt8 > aSequence; + + xHandler->ignorableWhitespace ( sWhiteSpace ); + if ( pDigest ) + { + pNewAttrList->AddAttribute ( sChecksumTypeAttribute, sCdataAttribute, sChecksumType ); + pDigest->Value >>= aSequence; + Base64Codec::encodeBase64 ( aBuffer, aSequence ); + pNewAttrList->AddAttribute ( sChecksumAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + } + xHandler->startElement( sEncryptionDataElement , xNewAttrList); + + // ==== Algorithm + pNewAttrList = new ::comphelper::AttributeList; + xNewAttrList = pNewAttrList; + + pNewAttrList->AddAttribute ( sAlgorithmNameAttribute, sCdataAttribute, sBlowfish ); + + pVector->Value >>= aSequence; + Base64Codec::encodeBase64 ( aBuffer, aSequence ); + pNewAttrList->AddAttribute ( sInitialisationVectorAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sAlgorithmElement , xNewAttrList); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sAlgorithmElement ); + + // ==== Key Derivation + pNewAttrList = new ::comphelper::AttributeList; + xNewAttrList = pNewAttrList; + + pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2 ); + + if ( bStoreStartKeyGeneration ) + pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, sDerivedKeySize ); + + sal_Int32 nCount = 0; + pIterationCount->Value >>= nCount; + aBuffer.append (nCount); + pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + + pSalt->Value >>= aSequence; + Base64Codec::encodeBase64 ( aBuffer, aSequence ); + pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sKeyDerivationElement , xNewAttrList); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sKeyDerivationElement ); + + // we have to store start-key-generation element as the last one to workaround the parsing problem + // in OOo3.1 and older versions + if ( bStoreStartKeyGeneration ) + { + // ==== Start Key Generation + pNewAttrList = new ::comphelper::AttributeList; + xNewAttrList = pNewAttrList; + + // currently SHA1 is used to generate 20-bytes start key + pNewAttrList->AddAttribute ( sStartKeyGenerationNameAttribute, sCdataAttribute, sSHA1 ); + pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, sStartKeySize ); + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->startElement( sStartKeyGenerationElement , xNewAttrList); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sStartKeyGenerationElement ); + } + + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sEncryptionDataElement ); + } + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sFileEntryElement ); + } + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sManifestElement ); + xHandler->endDocument(); +} diff --git a/package/source/manifest/ManifestExport.hxx b/package/source/manifest/ManifestExport.hxx new file mode 100644 index 000000000000..7958e3ea4cb9 --- /dev/null +++ b/package/source/manifest/ManifestExport.hxx @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestExport.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MANIFEST_EXPORT_HXX +#define _MANIFEST_EXPORT_HXX + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Reference.h> +#include <rtl/ustring.hxx> + +namespace com { namespace sun { namespace star { + namespace beans { struct PropertyValue;} + namespace xml { namespace sax { class XDocumentHandler; } } +} } } +class ManifestExport +{ +public: + ManifestExport(com::sun::star::uno::Reference < com::sun::star::xml::sax::XDocumentHandler > xHandler, const com::sun::star::uno::Sequence < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList ); +}; + +#endif + diff --git a/package/source/manifest/ManifestImport.cxx b/package/source/manifest/ManifestImport.cxx new file mode 100644 index 000000000000..5a7f1788d632 --- /dev/null +++ b/package/source/manifest/ManifestImport.cxx @@ -0,0 +1,335 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestImport.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * ( a copy is included in the LICENSE file that accompanied this code ). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER( update_precomp.py ): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ManifestImport.hxx> +#include <ManifestDefines.hxx> +#ifndef _BASE64_CODEC_HXX_ +#include <Base64Codec.hxx> +#endif +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star; +using namespace rtl; +using namespace std; + +// --------------------------------------------------- +ManifestImport::ManifestImport( vector < Sequence < PropertyValue > > & rNewManVector ) +: nNumProperty ( 0 ) +, bIgnoreEncryptData ( sal_False ) +, rManVector ( rNewManVector ) + +, sFileEntryElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_FILE_ENTRY ) ) +, sManifestElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_MANIFEST ) ) +, sEncryptionDataElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ENCRYPTION_DATA ) ) +, sAlgorithmElement ( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_ALGORITHM ) ) +, sKeyDerivationElement( RTL_CONSTASCII_USTRINGPARAM ( ELEMENT_KEY_DERIVATION ) ) + +, sCdataAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CDATA ) ) +, sMediaTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_MEDIA_TYPE ) ) +, sVersionAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_VERSION ) ) +, sFullPathAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_FULL_PATH ) ) +, sSizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SIZE ) ) +, sSaltAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SALT ) ) +, sInitialisationVectorAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_INITIALISATION_VECTOR ) ) +, sIterationCountAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ITERATION_COUNT ) ) +, sAlgorithmNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ALGORITHM_NAME ) ) +, sKeyDerivationNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_DERIVATION_NAME ) ) +, sChecksumAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM ) ) +, sChecksumTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM_TYPE ) ) + +, sFullPathProperty ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ) +, sMediaTypeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ) +, sVersionProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ) +, sIterationCountProperty ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) ) +, sSaltProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) ) +, sInitialisationVectorProperty ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) ) +, sSizeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) ) +, sDigestProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) ) + +, sWhiteSpace ( RTL_CONSTASCII_USTRINGPARAM ( " " ) ) +, sBlowfish ( RTL_CONSTASCII_USTRINGPARAM ( "Blowfish CFB" ) ) +, sPBKDF2 ( RTL_CONSTASCII_USTRINGPARAM ( "PBKDF2" ) ) +, sChecksumType ( RTL_CONSTASCII_USTRINGPARAM ( CHECKSUM_TYPE ) ) +{ + aStack.reserve( 10 ); +} + +// --------------------------------------------------- +ManifestImport::~ManifestImport ( void ) +{ +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::startDocument( ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::endDocument( ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + StringHashMap aConvertedAttribs; + ::rtl::OUString aConvertedName = PushNameAndNamespaces( aName, xAttribs, aConvertedAttribs ); + + if ( aConvertedName == sFileEntryElement ) + { + aSequence.realloc ( PKG_SIZE_ENCR_MNFST ); + + // Put full-path property first for MBA + aSequence[nNumProperty].Name = sFullPathProperty; + aSequence[nNumProperty++].Value <<= aConvertedAttribs[sFullPathAttribute]; + aSequence[nNumProperty].Name = sMediaTypeProperty; + aSequence[nNumProperty++].Value <<= aConvertedAttribs[sMediaTypeAttribute]; + + OUString sVersion = aConvertedAttribs[sVersionAttribute]; + if ( sVersion.getLength() ) + { + aSequence[nNumProperty].Name = sVersionProperty; + aSequence[nNumProperty++].Value <<= sVersion; + } + + OUString sSize = aConvertedAttribs[sSizeAttribute]; + if ( sSize.getLength() ) + { + sal_Int32 nSize; + nSize = sSize.toInt32(); + aSequence[nNumProperty].Name = sSizeProperty; + aSequence[nNumProperty++].Value <<= nSize; + } + } + else if ( aStack.size() > 1 ) + { + ManifestStack::reverse_iterator aIter = aStack.rbegin(); + aIter++; + + if ( aIter->m_aConvertedName.equals( sFileEntryElement ) ) + { + if ( aConvertedName.equals( sEncryptionDataElement ) ) + { + // If this element exists, then this stream is encrypted and we need + // to store the initialisation vector, salt and iteration count used + OUString aString = aConvertedAttribs[sChecksumTypeAttribute]; + if ( aString == sChecksumType && !bIgnoreEncryptData ) + { + aString = aConvertedAttribs[sChecksumAttribute]; + Sequence < sal_uInt8 > aDecodeBuffer; + Base64Codec::decodeBase64 ( aDecodeBuffer, aString ); + aSequence[nNumProperty].Name = sDigestProperty; + aSequence[nNumProperty++].Value <<= aDecodeBuffer; + } + } + } + else if ( aIter->m_aConvertedName.equals( sEncryptionDataElement ) ) + { + if ( aConvertedName == sAlgorithmElement ) + { + OUString aString = aConvertedAttribs[sAlgorithmNameAttribute]; + if ( aString == sBlowfish && !bIgnoreEncryptData ) + { + aString = aConvertedAttribs[sInitialisationVectorAttribute]; + Sequence < sal_uInt8 > aDecodeBuffer; + Base64Codec::decodeBase64 ( aDecodeBuffer, aString ); + aSequence[nNumProperty].Name = sInitialisationVectorProperty; + aSequence[nNumProperty++].Value <<= aDecodeBuffer; + } + else + // If we don't recognise the algorithm, then the key derivation info + // is useless to us + bIgnoreEncryptData = sal_True; + } + else if ( aConvertedName == sKeyDerivationElement ) + { + OUString aString = aConvertedAttribs[sKeyDerivationNameAttribute]; + if ( aString == sPBKDF2 && !bIgnoreEncryptData ) + { + aString = aConvertedAttribs[sSaltAttribute]; + Sequence < sal_uInt8 > aDecodeBuffer; + Base64Codec::decodeBase64 ( aDecodeBuffer, aString ); + aSequence[nNumProperty].Name = sSaltProperty; + aSequence[nNumProperty++].Value <<= aDecodeBuffer; + + aString = aConvertedAttribs[sIterationCountAttribute]; + aSequence[nNumProperty].Name = sIterationCountProperty; + aSequence[nNumProperty++].Value <<= aString.toInt32(); + } + else + // If we don't recognise the key derivation technique, then the + // algorithm info is useless to us + bIgnoreEncryptData = sal_True; + } + } + } +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::endElement( const OUString& aName ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ + ::rtl::OUString aConvertedName = ConvertName( aName ); + if ( !aStack.empty() && aStack.rbegin()->m_aConvertedName.equals( aConvertedName ) ) + { + if ( aConvertedName.equals( sFileEntryElement ) ) + { + aSequence.realloc ( nNumProperty ); + bIgnoreEncryptData = sal_False; + rManVector.push_back ( aSequence ); + nNumProperty = 0; + } + + aStack.pop_back(); + } +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::characters( const OUString& /*aChars*/ ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::ignorableWhitespace( const OUString& /*aWhitespaces*/ ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ +} + +// --------------------------------------------------- +void SAL_CALL ManifestImport::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) + throw( xml::sax::SAXException, uno::RuntimeException ) +{ +} + +// --------------------------------------------------- +::rtl::OUString ManifestImport::PushNameAndNamespaces( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs, StringHashMap& o_aConvertedAttribs ) +{ + StringHashMap aNamespaces; + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > aAttribsStrs; + + if ( xAttribs.is() ) + { + sal_Int16 nAttrCount = xAttribs.is() ? xAttribs->getLength() : 0; + aAttribsStrs.reserve( nAttrCount ); + + for( sal_Int16 nInd = 0; nInd < nAttrCount; nInd++ ) + { + ::rtl::OUString aAttrName = xAttribs->getNameByIndex( nInd ); + ::rtl::OUString aAttrValue = xAttribs->getValueByIndex( nInd ); + if ( aAttrName.getLength() >= 5 + && aAttrName.compareToAscii( "xmlns", 5 ) == 0 + && ( aAttrName.getLength() == 5 || aAttrName.getStr()[5] == ( sal_Unicode )':' ) ) + { + // this is a namespace declaration + ::rtl::OUString aNsName( ( aAttrName.getLength() == 5 ) ? ::rtl::OUString() : aAttrName.copy( 6 ) ); + aNamespaces[aNsName] = aAttrValue; + } + else + { + // this is no namespace declaration + aAttribsStrs.push_back( pair< ::rtl::OUString, ::rtl::OUString >( aAttrName, aAttrValue ) ); + } + } + } + + ::rtl::OUString aConvertedName = ConvertNameWithNamespace( aName, aNamespaces ); + if ( !aConvertedName.getLength() ) + aConvertedName = ConvertName( aName ); + + aStack.push_back( ManifestScopeEntry( aConvertedName, aNamespaces ) ); + + for ( sal_uInt16 nInd = 0; nInd < aAttribsStrs.size(); nInd++ ) + { + // convert the attribute names on filling + o_aConvertedAttribs[ConvertName( aAttribsStrs[nInd].first )] = aAttribsStrs[nInd].second; + } + + return aConvertedName; +} + +// --------------------------------------------------- +::rtl::OUString ManifestImport::ConvertNameWithNamespace( const ::rtl::OUString& aName, const StringHashMap& aNamespaces ) +{ + ::rtl::OUString aNsAlias; + ::rtl::OUString aPureName = aName; + + sal_Int32 nInd = aName.indexOf( ( sal_Unicode )':' ); + if ( nInd != -1 && nInd < aName.getLength() ) + { + aNsAlias = aName.copy( 0, nInd ); + aPureName = aName.copy( nInd + 1 ); + } + + ::rtl::OUString aResult; + + StringHashMap::const_iterator aIter = aNamespaces.find( aNsAlias ); + if ( aIter != aNamespaces.end() + && ( aIter->second.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( MANIFEST_NAMESPACE ) ) ) + || aIter->second.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( MANIFEST_OASIS_NAMESPACE ) ) ) ) ) + { + // no check for manifest.xml consistency currently since the old versions have supported inconsistent documents as well + aResult = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( MANIFEST_NSPREFIX ) ); + aResult += aPureName; + } + + return aResult; +} + +// --------------------------------------------------- +::rtl::OUString ManifestImport::ConvertName( const ::rtl::OUString& aName ) +{ + ::rtl::OUString aConvertedName; + for ( ManifestStack::reverse_iterator aIter = aStack.rbegin(); !aConvertedName.getLength() && aIter != aStack.rend(); aIter++ ) + { + if ( !aIter->m_aNamespaces.empty() ) + aConvertedName = ConvertNameWithNamespace( aName, aIter->m_aNamespaces ); + } + + if ( !aConvertedName.getLength() ) + aConvertedName = aName; + + return aConvertedName; +} + diff --git a/package/source/manifest/ManifestImport.hxx b/package/source/manifest/ManifestImport.hxx new file mode 100644 index 000000000000..b07e4070a425 --- /dev/null +++ b/package/source/manifest/ManifestImport.hxx @@ -0,0 +1,134 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestImport.hxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MANIFEST_IMPORT_HXX +#define _MANIFEST_IMPORT_HXX + +#include <cppuhelper/implbase1.hxx> // helper for implementations +#ifndef _COM_SUN_STAR_XML_SAX_XDUCUMENTHANDLER_HPP_ +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#include <vector> + +#include <HashMaps.hxx> + +namespace com { namespace sun { namespace star { + namespace xml { namespace sax { class XAttributeList; } } + namespace beans { struct PropertyValue; } +} } } + +typedef ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash, eqFunc > StringHashMap; + +struct ManifestScopeEntry +{ + ::rtl::OUString m_aConvertedName; + StringHashMap m_aNamespaces; + + ManifestScopeEntry( const ::rtl::OUString& aConvertedName, const StringHashMap& aNamespaces ) + : m_aConvertedName( aConvertedName ) + , m_aNamespaces( aNamespaces ) + {} + + ~ManifestScopeEntry() + {} +}; + +typedef ::std::vector< ManifestScopeEntry > ManifestStack; + +class ManifestImport : public cppu::WeakImplHelper1 < com::sun::star::xml::sax::XDocumentHandler > +{ +protected: + com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aSequence; + sal_Int16 nNumProperty; + ManifestStack aStack; + sal_Bool bIgnoreEncryptData; + ::std::vector < ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue > > & rManVector; + + const ::rtl::OUString sFileEntryElement; + const ::rtl::OUString sManifestElement; + const ::rtl::OUString sEncryptionDataElement; + const ::rtl::OUString sAlgorithmElement; + const ::rtl::OUString sKeyDerivationElement; + + const ::rtl::OUString sCdataAttribute; + const ::rtl::OUString sMediaTypeAttribute; + const ::rtl::OUString sVersionAttribute; + const ::rtl::OUString sFullPathAttribute; + const ::rtl::OUString sSizeAttribute; + const ::rtl::OUString sSaltAttribute; + const ::rtl::OUString sInitialisationVectorAttribute; + const ::rtl::OUString sIterationCountAttribute; + const ::rtl::OUString sAlgorithmNameAttribute; + const ::rtl::OUString sKeyDerivationNameAttribute; + const ::rtl::OUString sChecksumAttribute; + const ::rtl::OUString sChecksumTypeAttribute; + + const ::rtl::OUString sFullPathProperty; + const ::rtl::OUString sMediaTypeProperty; + const ::rtl::OUString sVersionProperty; + const ::rtl::OUString sIterationCountProperty; + const ::rtl::OUString sSaltProperty; + const ::rtl::OUString sInitialisationVectorProperty; + const ::rtl::OUString sSizeProperty; + const ::rtl::OUString sDigestProperty; + + const ::rtl::OUString sWhiteSpace; + const ::rtl::OUString sBlowfish; + const ::rtl::OUString sPBKDF2; + const ::rtl::OUString sChecksumType; + + + ::rtl::OUString PushNameAndNamespaces( const ::rtl::OUString& aName, + const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttribs, + StringHashMap& o_aConvertedAttribs ); + ::rtl::OUString ConvertNameWithNamespace( const ::rtl::OUString& aName, const StringHashMap& aNamespaces ); + ::rtl::OUString ConvertName( const ::rtl::OUString& aName ); + +public: + ManifestImport( std::vector < ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue > > & rNewVector ); + ~ManifestImport( void ); + virtual void SAL_CALL startDocument( ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL endDocument( ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttribs ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setDocumentLocator( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XLocator >& xLocator ) + throw(::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/manifest/ManifestReader.cxx b/package/source/manifest/ManifestReader.cxx new file mode 100644 index 000000000000..b7733433b005 --- /dev/null +++ b/package/source/manifest/ManifestReader.cxx @@ -0,0 +1,153 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestReader.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ManifestReader.hxx> +#include <ManifestImport.hxx> +#include <cppuhelper/factory.hxx> +#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_SAXPARSEEXCEPTION_HPP +#include <com/sun/star/xml/sax/SAXParseException.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_XPARSER_HPP +#include <com/sun/star/xml/sax/XParser.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif +#include <vector> + +using namespace ::rtl; +using namespace ::std; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::packages; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::packages::manifest; + +ManifestReader::ManifestReader( const Reference < XMultiServiceFactory > & xNewFactory ) +: xFactory ( xNewFactory ) +{ +} +ManifestReader::~ManifestReader() +{ +} +Sequence< Sequence< PropertyValue > > SAL_CALL ManifestReader::readManifestSequence( const Reference< XInputStream >& rStream ) + throw (::com::sun::star::uno::RuntimeException) +{ + Sequence < Sequence < PropertyValue > > aManifestSequence; + Reference < XParser > xParser (xFactory->createInstance ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.xml.sax.Parser" ) ) ), UNO_QUERY ); + if (xParser.is()) + { + try + { + vector < Sequence < PropertyValue > > aManVector; + Reference < XDocumentHandler > xFilter = new ManifestImport( aManVector ); + InputSource aParserInput; + aParserInput.aInputStream = rStream; + aParserInput.sSystemId = OUString ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml" ) ); + xParser->setDocumentHandler ( xFilter ); + xParser->parseStream( aParserInput ); + aManifestSequence.realloc ( aManVector.size() ); + Sequence < PropertyValue > * pSequence = aManifestSequence.getArray(); + ::std::vector < Sequence < PropertyValue > >::const_iterator aIter = aManVector.begin(); + ::std::vector < Sequence < PropertyValue > >::const_iterator aEnd = aManVector.end(); + while( aIter != aEnd ) + *pSequence++ = (*aIter++); + } + catch (SAXParseException& ) + { + } + catch (SAXException& ) + { + } + catch (IOException& ) + { + } + } + xParser->setDocumentHandler ( Reference < XDocumentHandler > () ); + return aManifestSequence; +} +// Component functions + +Reference < XInterface > SAL_CALL ManifestReader_createInstance( Reference< XMultiServiceFactory > const & rServiceFactory ) +{ + return *new ManifestReader( rServiceFactory ); +} +OUString ManifestReader::static_getImplementationName() +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.comp.ManifestReader" ) ); +} + +sal_Bool SAL_CALL ManifestReader::static_supportsService(OUString const & rServiceName) +{ + return rServiceName == getSupportedServiceNames()[0]; +} + +Sequence < OUString > ManifestReader::static_getSupportedServiceNames() +{ + Sequence < OUString > aNames(1); + aNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) ); + return aNames; +} + +OUString ManifestReader::getImplementationName() + throw (RuntimeException) +{ + return static_getImplementationName(); +} + +sal_Bool SAL_CALL ManifestReader::supportsService(OUString const & rServiceName) + throw (RuntimeException) +{ + return static_supportsService ( rServiceName ); +} + +Sequence < OUString > ManifestReader::getSupportedServiceNames() + throw (RuntimeException) +{ + return static_getSupportedServiceNames(); +} +Reference < XSingleServiceFactory > ManifestReader::createServiceFactory( Reference < XMultiServiceFactory > const & rServiceFactory ) +{ + return cppu::createSingleFactory (rServiceFactory, + static_getImplementationName(), + ManifestReader_createInstance, + static_getSupportedServiceNames()); +} diff --git a/package/source/manifest/ManifestReader.hxx b/package/source/manifest/ManifestReader.hxx new file mode 100644 index 000000000000..cb594d0e9718 --- /dev/null +++ b/package/source/manifest/ManifestReader.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestReader.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MANIFEST_READER_HXX +#define _MANIFEST_READER_HXX + +#include <cppuhelper/implbase2.hxx> +#ifndef _COM_SUN_STAR_PACKAGES_MANIFEST_XMANIFESTREADER_HPP +#include <com/sun/star/packages/manifest/XManifestReader.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif + +namespace com { namespace sun { namespace star { + namespace lang { class XMultiServiceFactory; class XSingleServiceFactory; } +} } } + +class ManifestReader: public ::cppu::WeakImplHelper2 +< + ::com::sun::star::packages::manifest::XManifestReader, + ::com::sun::star::lang::XServiceInfo +> +{ +protected: + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory; +public: + ManifestReader( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xNewFactory ); + virtual ~ManifestReader(); + + // XManifestReader + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > > SAL_CALL readManifestSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& rStream ) + throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); + + // Component constructor + static ::rtl::OUString static_getImplementationName(); + static ::com::sun::star::uno::Sequence < ::rtl::OUString > static_getSupportedServiceNames(); + sal_Bool SAL_CALL static_supportsService(rtl::OUString const & rServiceName); + static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleServiceFactory > createServiceFactory( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory ); +}; +#endif diff --git a/package/source/manifest/ManifestWriter.cxx b/package/source/manifest/ManifestWriter.cxx new file mode 100644 index 000000000000..c4564fa7ff8b --- /dev/null +++ b/package/source/manifest/ManifestWriter.cxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestWriter.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ManifestWriter.hxx> +#include <ManifestExport.hxx> +#include <cppuhelper/factory.hxx> +#ifndef _COM_SUN_STAR_IO_XACTIVEDATASOURCE_HPP +#include <com/sun/star/io/XActiveDataSource.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_XML_SAX_SAXEXCEPTION_HPP +#include <com/sun/star/xml/sax/SAXException.hpp> +#endif + +#include <osl/diagnose.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::packages; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::packages::manifest; + +ManifestWriter::ManifestWriter( const Reference < XMultiServiceFactory > & xNewFactory ) +: xFactory ( xNewFactory ) +{ +} +ManifestWriter::~ManifestWriter() +{ +} + +// XManifestWriter methods +void SAL_CALL ManifestWriter::writeManifestSequence( const Reference< XOutputStream >& rStream, const Sequence< Sequence< PropertyValue > >& rSequence ) + throw (RuntimeException) +{ + OUString sSaxWriter ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.xml.sax.Writer" ) ); + Reference < XActiveDataSource > xSource ( xFactory->createInstance ( sSaxWriter ), UNO_QUERY ); + if (xSource.is()) + { + xSource->setOutputStream ( rStream ); + Reference < XDocumentHandler > xHandler ( xSource, UNO_QUERY ); + if (xHandler.is()) + try { + ManifestExport aExporter ( xHandler, rSequence); + } + catch( SAXException& ) + { + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + } +} + +// Component methods +Reference < XInterface > SAL_CALL ManifestWriter_createInstance( Reference< XMultiServiceFactory > const & rServiceFactory ) +{ + return *new ManifestWriter( rServiceFactory ); +} + +OUString ManifestWriter::static_getImplementationName() +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.comp.ManifestWriter" ) ); +} + +sal_Bool SAL_CALL ManifestWriter::static_supportsService(OUString const & rServiceName) +{ + return rServiceName == getSupportedServiceNames()[0]; +} +Sequence < OUString > ManifestWriter::static_getSupportedServiceNames() +{ + Sequence < OUString > aNames(1); + aNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) ); + return aNames; +} + +OUString ManifestWriter::getImplementationName() + throw (RuntimeException) +{ + return static_getImplementationName(); +} + +sal_Bool SAL_CALL ManifestWriter::supportsService(OUString const & rServiceName) + throw (RuntimeException) +{ + return static_supportsService ( rServiceName ); +} +Sequence < OUString > ManifestWriter::getSupportedServiceNames() + throw (RuntimeException) +{ + return static_getSupportedServiceNames(); +} +Reference < XSingleServiceFactory > ManifestWriter::createServiceFactory( Reference < XMultiServiceFactory > const & rServiceFactory ) +{ + return cppu::createSingleFactory (rServiceFactory, + static_getImplementationName(), + ManifestWriter_createInstance, + static_getSupportedServiceNames()); +} diff --git a/package/source/manifest/ManifestWriter.hxx b/package/source/manifest/ManifestWriter.hxx new file mode 100644 index 000000000000..97a1b339351f --- /dev/null +++ b/package/source/manifest/ManifestWriter.hxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ManifestWriter.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MANIFEST_WRITER_HXX +#define _MANIFEST_WRITER_HXX + +#include <cppuhelper/implbase2.hxx> +#ifndef _COM_SUN_STAR_PACKAGES_MANIFEST_XMANIFESTWRITER_HPP +#include <com/sun/star/packages/manifest/XManifestWriter.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif + +namespace com { namespace sun { namespace star { + namespace lang { class XMultiServiceFactory; class XSingleServiceFactory; } +} } } + +class ManifestWriter: public ::cppu::WeakImplHelper2 +< + ::com::sun::star::packages::manifest::XManifestWriter, + ::com::sun::star::lang::XServiceInfo +> +{ +protected: + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory; +public: + ManifestWriter( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xNewFactory ); + virtual ~ManifestWriter(); + + // XManifestWriter + virtual void SAL_CALL writeManifestSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& rStream, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > >& rSequence ) + throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); + + // Component constructor + static ::rtl::OUString static_getImplementationName(); + static ::com::sun::star::uno::Sequence < ::rtl::OUString > static_getSupportedServiceNames(); + static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleServiceFactory > createServiceFactory( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory ); + sal_Bool SAL_CALL static_supportsService(rtl::OUString const & rServiceName); +}; +#endif + diff --git a/package/source/manifest/UnoRegister.cxx b/package/source/manifest/UnoRegister.cxx new file mode 100644 index 000000000000..b05b7525ba9a --- /dev/null +++ b/package/source/manifest/UnoRegister.cxx @@ -0,0 +1,157 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: UnoRegister.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ManifestReader.hxx> +#include <ManifestWriter.hxx> +#include <cppuhelper/factory.hxx> +#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP +#include <com/sun/star/registry/XRegistryKey.hpp> +#endif +#include <vos/diagnose.hxx> +#include <ZipPackage.hxx> + +#include <zipfileaccess.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::com::sun::star::packages; +using namespace ::com::sun::star::packages::manifest; + +static sal_Bool writeInfo( void * pRegistryKey, + const OUString & rImplementationName, + Sequence< OUString > const & rServiceNames ) +{ + OUString aKeyName( OUString::createFromAscii( "/" ) ); + aKeyName += rImplementationName; + aKeyName += OUString::createFromAscii( "/UNO/SERVICES" ); + + Reference< XRegistryKey > xKey; + try + { + xKey = static_cast< XRegistryKey * >( + pRegistryKey )->createKey( aKeyName ); + } + catch ( InvalidRegistryException const & ) + { + } + + if ( !xKey.is() ) + return sal_False; + + sal_Bool bSuccess = sal_True; + + for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n ) + { + try + { + xKey->createKey( rServiceNames[ n ] ); + } + catch ( InvalidRegistryException const & ) + { + bSuccess = sal_False; + break; + } + } + return bSuccess; +} +// C functions to implement this as a component + +extern "C" void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +/** + * This function creates an implementation section in the registry and another subkey + * for each supported service. + * @param pServiceManager generic uno interface providing a service manager + * @param pRegistryKey generic uno interface providing registry key to write + */ +extern "C" sal_Bool SAL_CALL component_writeInfo( void* /*pServiceManager*/, void* pRegistryKey ) +{ + return pRegistryKey && + writeInfo (pRegistryKey, + ManifestReader::static_getImplementationName(), + ManifestReader::static_getSupportedServiceNames() ) && + writeInfo (pRegistryKey, + ManifestWriter::static_getImplementationName(), + ManifestWriter::static_getSupportedServiceNames() ) && + writeInfo (pRegistryKey, + ZipPackage::static_getImplementationName(), + ZipPackage::static_getSupportedServiceNames() ) && + + writeInfo (pRegistryKey, + OZipFileAccess::impl_staticGetImplementationName(), + OZipFileAccess::impl_staticGetSupportedServiceNames() ); + +} + + +/** + * This function is called to get service factories for an implementation. + * @param pImplName name of implementation + * @param pServiceManager generic uno interface providing a service manager to instantiate components + * @param pRegistryKey registry data key to read and write component persistent data + * @return a component factory (generic uno interface) + */ +extern "C" void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = 0; + Reference< XMultiServiceFactory > xSMgr( + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ) ); + Reference< XSingleServiceFactory > xFactory; + + if (ManifestReader::static_getImplementationName().compareToAscii( pImplName ) == 0) + xFactory = ManifestReader::createServiceFactory ( xSMgr ); + else if (ManifestWriter::static_getImplementationName().compareToAscii( pImplName ) == 0) + xFactory = ManifestWriter::createServiceFactory ( xSMgr ); + else if (ZipPackage::static_getImplementationName().compareToAscii( pImplName ) == 0) + xFactory = ZipPackage::createServiceFactory ( xSMgr ); + else if ( OZipFileAccess::impl_staticGetImplementationName().compareToAscii( pImplName ) == 0 ) + xFactory = ::cppu::createSingleFactory( xSMgr, + OZipFileAccess::impl_staticGetImplementationName(), + OZipFileAccess::impl_staticCreateSelfInstance, + OZipFileAccess::impl_staticGetSupportedServiceNames() ); + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} + diff --git a/package/source/manifest/makefile.mk b/package/source/manifest/makefile.mk new file mode 100644 index 000000000000..197ace20479e --- /dev/null +++ b/package/source/manifest/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.7 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=package +TARGET=manifest +AUTOSEG=true + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +.IF "$(L10N_framework)"=="" + +SLOFILES= \ + $(SLO)$/ManifestReader.obj \ + $(SLO)$/ManifestWriter.obj \ + $(SLO)$/ManifestImport.obj \ + $(SLO)$/ManifestExport.obj \ + $(SLO)$/Base64Codec.obj \ + $(SLO)$/UnoRegister.obj + +.ENDIF # L10N_framework + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/package/source/xstor/disposelistener.cxx b/package/source/xstor/disposelistener.cxx new file mode 100644 index 000000000000..0fcd360b38a7 --- /dev/null +++ b/package/source/xstor/disposelistener.cxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: disposelistener.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" + +#include "disposelistener.hxx" +#include "xstorage.hxx" + +using namespace ::com::sun::star; + +OChildDispListener_Impl::OChildDispListener_Impl( OStorage& aStorage ) +: m_pStorage( &aStorage ) +{} + +OChildDispListener_Impl::~OChildDispListener_Impl() +{} + +void OChildDispListener_Impl::OwnerIsDisposed() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + m_pStorage = NULL; +} + +void SAL_CALL OChildDispListener_Impl::disposing( const lang::EventObject& Source ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // ObjectIsDisposed must not contain any locking! + if ( m_pStorage && Source.Source.is() ) + m_pStorage->ChildIsDisposed( Source.Source ); +} + diff --git a/package/source/xstor/disposelistener.hxx b/package/source/xstor/disposelistener.hxx new file mode 100644 index 000000000000..dcac256fca07 --- /dev/null +++ b/package/source/xstor/disposelistener.hxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: disposelistener.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __DISPOSELISTENER_HXX_ +#define __DISPOSELISTENER_HXX_ + +#include <com/sun/star/lang/XEventListener.hpp> +#include <cppuhelper/implbase1.hxx> +#include <osl/mutex.hxx> + +class OStorage; +class OChildDispListener_Impl : public ::cppu::WeakImplHelper1 < ::com::sun::star::lang::XEventListener > +{ + ::osl::Mutex m_aMutex; + OStorage* m_pStorage; + +public: + OChildDispListener_Impl( OStorage& aStorage ); + virtual ~OChildDispListener_Impl(); + + void OwnerIsDisposed(); + + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); +}; + +#endif + diff --git a/package/source/xstor/makefile.mk b/package/source/xstor/makefile.mk new file mode 100644 index 000000000000..703873f9ca71 --- /dev/null +++ b/package/source/xstor/makefile.mk @@ -0,0 +1,79 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.9 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=package +TARGET=xstor + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +.IF "$(L10N_framework)"=="" + +SLOFILES = \ + $(SLO)$/ohierarchyholder.obj\ + $(SLO)$/ocompinstream.obj\ + $(SLO)$/oseekinstream.obj\ + $(SLO)$/owriteablestream.obj\ + $(SLO)$/xstorage.obj\ + $(SLO)$/xfactory.obj\ + $(SLO)$/disposelistener.obj\ + $(SLO)$/selfterminatefilestream.obj\ + $(SLO)$/switchpersistencestream.obj\ + $(SLO)$/register.obj + +SHL1TARGET=$(TARGET) +SHL1STDLIBS=\ + $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(COMPHELPERLIB) + +SHL1OBJS=$(SLOFILES) +SHL1DEF=$(MISC)$/$(TARGET).def + +SHL1IMPLIB=i$(SHL1TARGET) + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=$(SHL1TARGET).dxp + +.ENDIF # L10N_framework + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/package/source/xstor/ocompinstream.cxx b/package/source/xstor/ocompinstream.cxx new file mode 100644 index 000000000000..a75915dacfbe --- /dev/null +++ b/package/source/xstor/ocompinstream.cxx @@ -0,0 +1,761 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ocompinstream.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" + +#include "ocompinstream.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#include <osl/diagnose.h> + +#include "owriteablestream.hxx" +#include "xstorage.hxx" + +using namespace ::com::sun::star; + +//----------------------------------------------- +OInputCompStream::OInputCompStream( OWriteStream_Impl& aImpl, + uno::Reference < io::XInputStream > xStream, + const uno::Sequence< beans::PropertyValue >& aProps, + sal_Int16 nStorageType ) +: m_pImpl( &aImpl ) +, m_rMutexRef( m_pImpl->m_rMutexRef ) +, m_xStream( xStream ) +, m_pInterfaceContainer( NULL ) +, m_aProperties( aProps ) +, m_bDisposed( sal_False ) +, m_nStorageType( nStorageType ) +{ + OSL_ENSURE( m_pImpl->m_rMutexRef.Is(), "No mutex is provided!\n" ); + if ( !m_pImpl->m_rMutexRef.Is() ) + throw uno::RuntimeException(); // just a disaster + + OSL_ENSURE( xStream.is(), "No stream is provided!\n" ); +} + +//----------------------------------------------- +OInputCompStream::OInputCompStream( uno::Reference < io::XInputStream > xStream, + const uno::Sequence< beans::PropertyValue >& aProps, + sal_Int16 nStorageType ) +: m_pImpl( NULL ) +, m_rMutexRef( new SotMutexHolder ) +, m_xStream( xStream ) +, m_pInterfaceContainer( NULL ) +, m_aProperties( aProps ) +, m_bDisposed( sal_False ) +, m_nStorageType( nStorageType ) +{ + OSL_ENSURE( xStream.is(), "No stream is provided!\n" ); +} + +//----------------------------------------------- +OInputCompStream::~OInputCompStream() +{ + { + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_bDisposed ) + { + m_refCount++; + dispose(); + } + + if ( m_pInterfaceContainer ) + delete m_pInterfaceContainer; + } +} + +//----------------------------------------------- +uno::Any SAL_CALL OInputCompStream::queryInterface( const uno::Type& rType ) + throw( uno::RuntimeException ) +{ + uno::Any aReturn; + + // common interfaces + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<io::XInputStream*> ( this ) + , static_cast<io::XStream*> ( this ) + , static_cast<lang::XComponent*> ( this ) + , static_cast<beans::XPropertySet*> ( this ) + , static_cast<embed::XExtendedStorageStream*> ( this ) ); + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + + if ( m_nStorageType == OFOPXML_STORAGE ) + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XRelationshipAccess*> ( this ) ); + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + } + + return OWeakObject::queryInterface( rType ); +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OInputCompStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xStream.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No stream!" ) ) ); + throw uno::RuntimeException(); + } + + return m_xStream->readBytes( aData, nBytesToRead ); +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OInputCompStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xStream.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No stream!" ) ) ); + throw uno::RuntimeException(); + } + + return m_xStream->readSomeBytes( aData, nMaxBytesToRead ); + +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::skipBytes( sal_Int32 nBytesToSkip ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xStream.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No stream!" ) ) ); + throw uno::RuntimeException(); + } + + m_xStream->skipBytes( nBytesToSkip ); + +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OInputCompStream::available( ) + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xStream.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No stream!" ) ) ); + throw uno::RuntimeException(); + } + + return m_xStream->available(); + +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::closeInput( ) + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + dispose(); +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL OInputCompStream::getInputStream() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xStream.is() ) + return uno::Reference< io::XInputStream >(); + + return uno::Reference< io::XInputStream >( static_cast< io::XInputStream* >( this ), uno::UNO_QUERY ); +} + +//----------------------------------------------- +uno::Reference< io::XOutputStream > SAL_CALL OInputCompStream::getOutputStream() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + return uno::Reference< io::XOutputStream >(); +} + +//----------------------------------------------- +void OInputCompStream::InternalDispose() +{ + // can be called only by OWriteStream_Impl + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + // the source object is also a kind of locker for the current object + // since the listeners could dispose the object while being notified + lang::EventObject aSource( static_cast< ::cppu::OWeakObject*>( this ) ); + + if ( m_pInterfaceContainer ) + m_pInterfaceContainer->disposeAndClear( aSource ); + + try + { + m_xStream->closeInput(); + } + catch( uno::Exception& ) + {} + + m_pImpl = NULL; + m_bDisposed = sal_True; +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::dispose( ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pInterfaceContainer ) + { + lang::EventObject aSource( static_cast< ::cppu::OWeakObject*>( this ) ); + m_pInterfaceContainer->disposeAndClear( aSource ); + } + + m_xStream->closeInput(); + + if ( m_pImpl ) + { + m_pImpl->InputStreamDisposed( this ); + m_pImpl = NULL; + } + + m_bDisposed = sal_True; +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_pInterfaceContainer ) + m_pInterfaceContainer = new ::cppu::OInterfaceContainerHelper( m_rMutexRef->GetMutex() ); + + m_pInterfaceContainer->addInterface( xListener ); +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pInterfaceContainer ) + m_pInterfaceContainer->removeInterface( xListener ); +} + +//----------------------------------------------- +sal_Bool SAL_CALL OInputCompStream::hasByID( const ::rtl::OUString& sID ) + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + try + { + getRelationshipByID( sID ); + return sal_True; + } + catch( container::NoSuchElementException& ) + {} + + return sal_False; +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL OInputCompStream::getTargetByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID ); + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( aSeq[nInd].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Target" ) ) ) + return aSeq[nInd].Second; + + return ::rtl::OUString(); +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL OInputCompStream::getTypeByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID ); + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( aSeq[nInd].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Type" ) ) ) + return aSeq[nInd].Second; + + return ::rtl::OUString(); +} + +//----------------------------------------------- +uno::Sequence< beans::StringPair > SAL_CALL OInputCompStream::getRelationshipByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Id" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + return aSeq[nInd1]; + break; + } + + throw container::NoSuchElementException(); +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OInputCompStream::getRelationshipsByType( const ::rtl::OUString& sType ) + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< uno::Sequence< beans::StringPair > > aResult; + sal_Int32 nEntriesNum = 0; + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Type" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sType ) ) + { + aResult.realloc( nEntriesNum ); + aResult[nEntriesNum-1] = aSeq[nInd1]; + } + break; + } + + return aResult; +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OInputCompStream::getAllRelationships() + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + // TODO/LATER: in future the information could be taken directly from m_pImpl when possible + uno::Sequence< uno::Sequence< beans::StringPair > > aResult; + for ( sal_Int32 aInd = 0; aInd < m_aProperties.getLength(); aInd++ ) + if ( m_aProperties[aInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "RelationsInfo" ) ) ) + { + if ( m_aProperties[aInd].Value >>= aResult ) + return aResult; + + break; + } + + throw io::IOException(); // the relations info could not be read +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::insertRelationshipByID( const ::rtl::OUString& /*sID*/, const uno::Sequence< beans::StringPair >& /*aEntry*/, ::sal_Bool /*bReplace*/ ) + throw ( container::ElementExistException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + throw io::IOException(); // TODO: Access denied +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::removeRelationshipByID( const ::rtl::OUString& /*sID*/ ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + throw io::IOException(); // TODO: Access denied +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::insertRelationships( const uno::Sequence< uno::Sequence< beans::StringPair > >& /*aEntries*/, ::sal_Bool /*bReplace*/ ) + throw ( container::ElementExistException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + throw io::IOException(); // TODO: Access denied +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::clearRelationships() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + throw io::IOException(); // TODO: Access denied +} + +//----------------------------------------------- +uno::Reference< beans::XPropertySetInfo > SAL_CALL OInputCompStream::getPropertySetInfo() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: + return uno::Reference< beans::XPropertySetInfo >(); +} + +//----------------------------------------------- +void SAL_CALL OInputCompStream::setPropertyValue( const ::rtl::OUString& aPropertyName, const uno::Any& /*aValue*/ ) + throw ( beans::UnknownPropertyException, + beans::PropertyVetoException, + lang::IllegalArgumentException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + // all the provided properties are accessible + for ( sal_Int32 aInd = 0; aInd < m_aProperties.getLength(); aInd++ ) + { + if ( m_aProperties[aInd].Name.equals( aPropertyName ) ) + { + throw beans::PropertyVetoException(); // TODO + } + } + + throw beans::UnknownPropertyException(); // TODO +} + + +//----------------------------------------------- +uno::Any SAL_CALL OInputCompStream::getPropertyValue( const ::rtl::OUString& aProp ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + ::rtl::OUString aPropertyName; + if ( aProp.equalsAscii( "IsEncrypted" ) ) + aPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Encrypted" ) ); + else + aPropertyName = aProp; + + if ( aPropertyName.equalsAscii( "RelationsInfo" ) ) + throw beans::UnknownPropertyException(); // TODO + + // all the provided properties are accessible + for ( sal_Int32 aInd = 0; aInd < m_aProperties.getLength(); aInd++ ) + { + if ( m_aProperties[aInd].Name.equals( aPropertyName ) ) + { + return m_aProperties[aInd].Value; + } + } + + throw beans::UnknownPropertyException(); // TODO +} + + +//----------------------------------------------- +void SAL_CALL OInputCompStream::addPropertyChangeListener( + const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OInputCompStream::removePropertyChangeListener( + const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OInputCompStream::addVetoableChangeListener( + const ::rtl::OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OInputCompStream::removeVetoableChangeListener( + const ::rtl::OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + diff --git a/package/source/xstor/ocompinstream.hxx b/package/source/xstor/ocompinstream.hxx new file mode 100644 index 000000000000..cf19fbdd4d8c --- /dev/null +++ b/package/source/xstor/ocompinstream.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ocompinstream.hxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _INPUTCOMPSTREAM_HXX_ +#define _INPUTCOMPSTREAM_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/embed/XExtendedStorageStream.hpp> +#include <com/sun/star/embed/XRelationshipAccess.hpp> +#include <cppuhelper/implbase4.hxx> +#include <cppuhelper/interfacecontainer.h> + +#include "mutexholder.hxx" + +struct OWriteStream_Impl; + +class OInputCompStream : public cppu::WeakImplHelper4 < ::com::sun::star::io::XInputStream + ,::com::sun::star::embed::XExtendedStorageStream + ,::com::sun::star::embed::XRelationshipAccess + ,::com::sun::star::beans::XPropertySet > +{ +protected: + OWriteStream_Impl* m_pImpl; + + SotMutexHolderRef m_rMutexRef; + + ::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > m_xStream; + + ::cppu::OInterfaceContainerHelper* m_pInterfaceContainer; + + ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue > m_aProperties; + + sal_Bool m_bDisposed; + + sal_Int16 m_nStorageType; + +public: + OInputCompStream( OWriteStream_Impl& pImpl, + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > xStream, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps, + sal_Int16 nStorageType ); + + OInputCompStream( ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > xStream, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps, + sal_Int16 nStorageType ); + + virtual ~OInputCompStream(); + + void InternalDispose(); + + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& rType ) + throw( ::com::sun::star::uno::RuntimeException ); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XStream + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream( ) throw (::com::sun::star::uno::RuntimeException); + + //XComponent + virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + //XRelationshipAccess + virtual ::sal_Bool SAL_CALL hasByID( const ::rtl::OUString& sID ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTargetByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTypeByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > SAL_CALL getRelationshipByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > SAL_CALL getRelationshipsByType( const ::rtl::OUString& sType ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > SAL_CALL getAllRelationships( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRelationshipByID( const ::rtl::OUString& sID, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aEntry, ::sal_Bool bReplace ) throw (::com::sun::star::container::ElementExistException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeRelationshipByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRelationships( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > >& aEntries, ::sal_Bool bReplace ) throw (::com::sun::star::container::ElementExistException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL clearRelationships( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() throw ( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + +}; + +#endif + diff --git a/package/source/xstor/ohierarchyholder.cxx b/package/source/xstor/ohierarchyholder.cxx new file mode 100644 index 000000000000..e91379951475 --- /dev/null +++ b/package/source/xstor/ohierarchyholder.cxx @@ -0,0 +1,359 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ohierarchyholder.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> + +#include "ohierarchyholder.hxx" + +using namespace ::com::sun::star; + +//=============================================== +// OHierarchyHolder_Impl +//=============================================== + +//----------------------------------------------- +uno::Reference< embed::XExtendedStorageStream > OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, OStringList_Impl& aListPath, sal_Int32 nStreamMode, const ::rtl::OUString& aPass ) +{ + uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW ); + + if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) ) + throw io::IOException(); + + uno::Reference< embed::XExtendedStorageStream > xResult = + m_xChild->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aPass ); + if ( !xResult.is() ) + throw uno::RuntimeException(); + + return xResult; +} + +//----------------------------------------------- +void OHierarchyHolder_Impl::RemoveStreamHierarchically( OStringList_Impl& aListPath ) +{ + uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW ); + + m_xChild->RemoveStreamHierarchically( aListPath ); +} + +//----------------------------------------------- +// static +OStringList_Impl OHierarchyHolder_Impl::GetListPathFromString( const ::rtl::OUString& aPath ) +{ + OStringList_Impl aResult; + sal_Int32 nIndex = 0; + do + { + ::rtl::OUString aName = aPath.getToken( 0, '/', nIndex ); + if ( !aName.getLength() ) + throw lang::IllegalArgumentException(); + + aResult.push_back( aName ); + } + while ( nIndex >= 0 ); + + return aResult; +} + +//=============================================== +// OHierarchyElement_Impl +//=============================================== + +//----------------------------------------------- +uno::Reference< embed::XExtendedStorageStream > OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, OStringList_Impl& aListPath, sal_Int32 nStreamMode, const ::rtl::OUString& aPass ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) ) + throw io::IOException(); + + if ( !aListPath.size() ) + throw uno::RuntimeException(); + + ::rtl::OUString aNextName = *(aListPath.begin()); + aListPath.erase( aListPath.begin() ); + + uno::Reference< embed::XExtendedStorageStream > xResult; + + uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage + : uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY ); + if ( !xOwnStor.is() ) + throw uno::RuntimeException(); + + if ( !aListPath.size() ) + { + uno::Reference< embed::XHierarchicalStorageAccess > xHStorage( xOwnStor, uno::UNO_QUERY_THROW ); + if ( !aPass.getLength() ) + xResult = xHStorage->openStreamElementByHierarchicalName( aNextName, nStreamMode ); + else + xResult = xHStorage->openEncryptedStreamElementByHierarchicalName( aNextName, nStreamMode, aPass ); + + uno::Reference< embed::XTransactedObject > xTransact( xResult, uno::UNO_QUERY ); + if ( xTransact.is() ) + { + // the existance of the transacted object means that the stream is opened for writing also + // so the whole chain must be commited + uno::Reference< embed::XTransactionBroadcaster > xTrBroadcast( xTransact, uno::UNO_QUERY_THROW ); + xTrBroadcast->addTransactionListener( static_cast< embed::XTransactionListener* >( this ) ); + } + else + { + uno::Reference< lang::XComponent > xStreamComp( xResult, uno::UNO_QUERY_THROW ); + xStreamComp->addEventListener( static_cast< lang::XEventListener* >( this ) ); + } + + m_aOpenStreams.push_back( uno::WeakReference< embed::XExtendedStorageStream >( xResult ) ); + } + else + { + sal_Bool bNewElement = sal_False; + ::rtl::Reference< OHierarchyElement_Impl > aElement; + OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName ); + if ( aIter != m_aChildren.end() ) + aElement = aIter->second; + + if ( !aElement.is() ) + { + bNewElement = sal_True; + uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName, nStorageMode ); + if ( !xChildStorage.is() ) + throw uno::RuntimeException(); + + aElement = new OHierarchyElement_Impl( NULL, xChildStorage ); + } + + xResult = aElement->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aPass ); + if ( !xResult.is() ) + throw uno::RuntimeException(); + + if ( bNewElement ) + { + m_aChildren[aNextName] = aElement; + aElement->SetParent( this ); + } + } + + // the subelement was opened successfuly, remember the storage to let it be locked + m_xOwnStorage = xOwnStor; + + return xResult; +} + +//----------------------------------------------- +void OHierarchyElement_Impl::RemoveStreamHierarchically( OStringList_Impl& aListPath ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !aListPath.size() ) + throw uno::RuntimeException(); + + ::rtl::OUString aNextName = *(aListPath.begin()); + aListPath.erase( aListPath.begin() ); + + uno::Reference< embed::XExtendedStorageStream > xResult; + + uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage + : uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY ); + if ( !xOwnStor.is() ) + throw uno::RuntimeException(); + + if ( !aListPath.size() ) + { + xOwnStor->removeElement( aNextName ); + } + else + { + sal_Bool bNewElement = sal_False; + ::rtl::Reference< OHierarchyElement_Impl > aElement; + OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName ); + if ( aIter != m_aChildren.end() ) + aElement = aIter->second; + + if ( !aElement.is() ) + { + bNewElement = sal_True; + uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName, + embed::ElementModes::READWRITE ); + if ( !xChildStorage.is() ) + throw uno::RuntimeException(); + + aElement = new OHierarchyElement_Impl( NULL, xChildStorage ); + } + + aElement->RemoveStreamHierarchically( aListPath ); + } + + uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY ); + if ( xTransact.is() ) + xTransact->commit(); + + TestForClosing(); +} + +//----------------------------------------------- +void OHierarchyElement_Impl::Commit() +{ + ::rtl::Reference< OHierarchyElement_Impl > aLocker( this ); + ::rtl::Reference< OHierarchyElement_Impl > aParent; + uno::Reference< embed::XStorage > xOwnStor; + + { + ::osl::MutexGuard aGuard( m_aMutex ); + aParent = m_rParent; + xOwnStor = m_xOwnStorage; + } + + if ( xOwnStor.is() ) + { + uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY_THROW ); + xTransact->commit(); + if ( aParent.is() ) + aParent->Commit(); + } +} + +//----------------------------------------------- +void OHierarchyElement_Impl::TestForClosing() +{ + ::rtl::Reference< OHierarchyElement_Impl > aLocker( this ); + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_aOpenStreams.size() && !m_aChildren.size() ) + { + if ( m_rParent.is() ) + { + // only the root storage should not be disposed, other storages can be disposed + if ( m_xOwnStorage.is() ) + { + try + { + m_xOwnStorage->dispose(); + } + catch( uno::Exception& ) + {} + } + + m_rParent->RemoveElement( this ); + } + + m_xOwnStorage = uno::Reference< embed::XStorage >(); + } + } +} + +//----------------------------------------------- +void SAL_CALL OHierarchyElement_Impl::disposing( const lang::EventObject& Source ) + throw ( uno::RuntimeException ) +{ + uno::Sequence< embed::XStorage > aStoragesToCommit; + + try + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + uno::Reference< embed::XExtendedStorageStream > xStream( Source.Source, uno::UNO_QUERY ); + + for ( OWeakStorRefList_Impl::iterator pStorageIter = m_aOpenStreams.begin(); + pStorageIter != m_aOpenStreams.end(); ) + { + OWeakStorRefList_Impl::iterator pTmp = pStorageIter++; + if ( !pTmp->get().is() || pTmp->get() == xStream ) + m_aOpenStreams.erase( pTmp ); + } + + aGuard.clear(); + + TestForClosing(); + } + catch( uno::Exception& ) + { + throw uno::RuntimeException(); // no exception must happen here, usually an exception means disaster + } +} + +//----------------------------------------------- +void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + for ( OHierarchyElementList_Impl::iterator aIter = m_aChildren.begin(); + aIter != m_aChildren.end(); /* increment is done in body */) + { + OHierarchyElementList_Impl::iterator aTmpIter = aIter; + aIter++; + + if ( aTmpIter->second == aRef ) + m_aChildren.erase( aTmpIter ); + } + } + + TestForClosing(); +} + +// XTransactionListener +//----------------------------------------------- +void SAL_CALL OHierarchyElement_Impl::preCommit( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void SAL_CALL OHierarchyElement_Impl::commited( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) + throw (::com::sun::star::uno::RuntimeException) +{ + try + { + Commit(); + } + catch( uno::Exception& e ) + { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Can not commit storage sequence!" ) ), + uno::Reference< uno::XInterface >(), + uno::makeAny( e ) ); + } +} + +//----------------------------------------------- +void SAL_CALL OHierarchyElement_Impl::preRevert( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void SAL_CALL OHierarchyElement_Impl::reverted( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) + throw (::com::sun::star::uno::RuntimeException) +{ +} + diff --git a/package/source/xstor/ohierarchyholder.hxx b/package/source/xstor/ohierarchyholder.hxx new file mode 100644 index 000000000000..3abab1f85d90 --- /dev/null +++ b/package/source/xstor/ohierarchyholder.hxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ohierarchyholder.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OHIERARCHYHOLDER_HXX_ +#define _OHIERARCHYHOLDER_HXX_ + +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactionListener.hpp> +#include <com/sun/star/embed/XExtendedStorageStream.hpp> +#include <cppuhelper/implbase1.hxx> + +#include <rtl/ref.hxx> + +#include <hash_map> +#include <list> +#include <vector> + +struct OHierarchyElement_Impl; + +struct eqFunc +{ + sal_Bool operator()( const rtl::OUString &r1, + const rtl::OUString &r2) const + { + return r1 == r2; + } +}; +typedef ::std::hash_map< ::rtl::OUString, + ::rtl::Reference< OHierarchyElement_Impl >, + ::rtl::OUStringHash, + eqFunc > OHierarchyElementList_Impl; + +typedef ::std::vector< ::rtl::OUString > OStringList_Impl; +typedef ::std::list< ::com::sun::star::uno::WeakReference< ::com::sun::star::embed::XExtendedStorageStream > > + OWeakStorRefList_Impl; + +struct OHierarchyElement_Impl : public cppu::WeakImplHelper1< ::com::sun::star::embed::XTransactionListener > +{ + ::osl::Mutex m_aMutex; + + ::rtl::Reference< OHierarchyElement_Impl > m_rParent; + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > m_xOwnStorage; + ::com::sun::star::uno::WeakReference< ::com::sun::star::embed::XStorage > m_xWeakOwnStorage; + + OHierarchyElementList_Impl m_aChildren; + + OWeakStorRefList_Impl m_aOpenStreams; + +public: + OHierarchyElement_Impl( OHierarchyElement_Impl* pParent, const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage ) + : m_rParent( pParent ) + , m_xOwnStorage( xStorage ) + {} + + OHierarchyElement_Impl( const ::com::sun::star::uno::WeakReference< ::com::sun::star::embed::XStorage >& xWeakStorage ) + : m_rParent( NULL ) + , m_xWeakOwnStorage( xWeakStorage ) + {} + + void Commit(); + + void SetParent( const ::rtl::Reference< OHierarchyElement_Impl >& rParent ) { m_rParent = rParent; } + + void TestForClosing(); + + void RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef ); + + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XExtendedStorageStream > + GetStreamHierarchically( sal_Int32 nStorageMode, + OStringList_Impl& aPath, + sal_Int32 nStreamMode, + const ::rtl::OUString& aPassword = ::rtl::OUString() ); + + void RemoveStreamHierarchically( OStringList_Impl& aListPath ); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) + throw (::com::sun::star::uno::RuntimeException); + + + // XTransactionListener + virtual void SAL_CALL preCommit( const ::com::sun::star::lang::EventObject& aEvent ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL commited( const ::com::sun::star::lang::EventObject& aEvent ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL preRevert( const ::com::sun::star::lang::EventObject& aEvent ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL reverted( const ::com::sun::star::lang::EventObject& aEvent ) + throw (::com::sun::star::uno::RuntimeException); + +}; + +class OHierarchyHolder_Impl : public ::cppu::OWeakObject +{ + ::com::sun::star::uno::WeakReference< ::com::sun::star::embed::XStorage > m_xWeakOwnStorage; + ::rtl::Reference< OHierarchyElement_Impl > m_xChild; +public: + OHierarchyHolder_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xOwnStorage ) + : m_xWeakOwnStorage( xOwnStorage ) + , m_xChild( new OHierarchyElement_Impl( ::com::sun::star::uno::WeakReference< ::com::sun::star::embed::XStorage >( xOwnStorage ) ) ) + {} + + static OStringList_Impl GetListPathFromString( const ::rtl::OUString& aPath ); + + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XExtendedStorageStream > + GetStreamHierarchically( sal_Int32 nStorageMode, + OStringList_Impl& aListPath, + sal_Int32 nStreamMode, + const ::rtl::OUString& aPassword = ::rtl::OUString() ); + + void RemoveStreamHierarchically( OStringList_Impl& aListPath ); +}; + +#endif // _OHIERARCHYHOLDER + diff --git a/package/source/xstor/oseekinstream.cxx b/package/source/xstor/oseekinstream.cxx new file mode 100644 index 000000000000..6dd6ee4bea0a --- /dev/null +++ b/package/source/xstor/oseekinstream.cxx @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: oseekinstream.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <osl/diagnose.h> + +#include "oseekinstream.hxx" +#include "owriteablestream.hxx" + +using namespace ::com::sun::star; + +OInputSeekStream::OInputSeekStream( OWriteStream_Impl& pImpl, + uno::Reference < io::XInputStream > xStream, + const uno::Sequence< beans::PropertyValue >& aProps, + sal_Int16 nStorageType ) +: OInputCompStream( pImpl, xStream, aProps, nStorageType ) +{ + if ( m_xStream.is() ) + { + m_xSeekable = uno::Reference< io::XSeekable >( m_xStream, uno::UNO_QUERY ); + OSL_ENSURE( m_xSeekable.is(), "No seeking support!\n" ); + } +} + +OInputSeekStream::OInputSeekStream( uno::Reference < io::XInputStream > xStream, + const uno::Sequence< beans::PropertyValue >& aProps, + sal_Int16 nStorageType ) +: OInputCompStream( xStream, aProps, nStorageType ) +{ + if ( m_xStream.is() ) + { + m_xSeekable = uno::Reference< io::XSeekable >( m_xStream, uno::UNO_QUERY ); + OSL_ENSURE( m_xSeekable.is(), "No seeking support!\n" ); + } +} + +OInputSeekStream::~OInputSeekStream() +{ +} + +uno::Sequence< uno::Type > SAL_CALL OInputSeekStream::getTypes() + throw ( uno::RuntimeException ) +{ + static ::cppu::OTypeCollection* pTypeCollection = NULL ; + + if ( pTypeCollection == NULL ) + { + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + if ( pTypeCollection == NULL ) + { + static ::cppu::OTypeCollection aTypeCollection( + ::getCppuType(( const uno::Reference< io::XSeekable >* )NULL ), + OInputCompStream::getTypes() ); + + pTypeCollection = &aTypeCollection ; + } + } + + return pTypeCollection->getTypes() ; +} + +uno::Any SAL_CALL OInputSeekStream::queryInterface( const uno::Type& rType ) + throw( uno::RuntimeException ) +{ + // Attention: + // Don't use mutex or guard in this method!!! Is a method of XInterface. + + uno::Any aReturn( ::cppu::queryInterface( rType, + static_cast< io::XSeekable* >( this ) ) ); + + if ( aReturn.hasValue() == sal_True ) + { + return aReturn ; + } + + return OInputCompStream::queryInterface( rType ) ; +} + +void SAL_CALL OInputSeekStream::acquire() + throw() +{ + OInputCompStream::acquire(); +} + +void SAL_CALL OInputSeekStream::release() + throw() +{ + OInputCompStream::release(); +} + + +void SAL_CALL OInputSeekStream::seek( sal_Int64 location ) + throw ( lang::IllegalArgumentException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xSeekable.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No seekable!" ) ) ); + throw uno::RuntimeException(); + } + + m_xSeekable->seek( location ); +} + +sal_Int64 SAL_CALL OInputSeekStream::getPosition() + throw ( io::IOException, + uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xSeekable.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No seekable!" ) ) ); + throw uno::RuntimeException(); + } + + return m_xSeekable->getPosition(); +} + +sal_Int64 SAL_CALL OInputSeekStream::getLength() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_bDisposed ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xSeekable.is() ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No seekable!" ) ) ); + throw uno::RuntimeException(); + } + + return m_xSeekable->getLength(); +} + diff --git a/package/source/xstor/oseekinstream.hxx b/package/source/xstor/oseekinstream.hxx new file mode 100644 index 000000000000..326c50b9579b --- /dev/null +++ b/package/source/xstor/oseekinstream.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: oseekinstream.hxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _INPUTSEEKSTREAM_HXX_ +#define _INPUTSEEKSTREAM_HXX_ + +#include <com/sun/star/io/XSeekable.hpp> + +#include "ocompinstream.hxx" + +class OInputSeekStream : public OInputCompStream + , public ::com::sun::star::io::XSeekable +{ +protected: + ::com::sun::star::uno::Reference < ::com::sun::star::io::XSeekable > m_xSeekable; + +public: + OInputSeekStream( OWriteStream_Impl& pImpl, + ::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xStream, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps, + sal_Int16 nStorageType ); + + OInputSeekStream( ::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xStream, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps, + sal_Int16 nStorageType ); + + virtual ~OInputSeekStream(); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes() throw (::com::sun::star::uno::RuntimeException); + + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& rType ) throw( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + //XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/package/source/xstor/owriteablestream.cxx b/package/source/xstor/owriteablestream.cxx new file mode 100644 index 000000000000..4f3a912b8c0b --- /dev/null +++ b/package/source/xstor/owriteablestream.cxx @@ -0,0 +1,3615 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: owriteablestream.cxx,v $ + * $Revision: 1.23 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <osl/diagnose.h> + +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/ofopxmlhelper.hxx> + +#include "selfterminatefilestream.hxx" +#include "owriteablestream.hxx" +#include "oseekinstream.hxx" +#include "mutexholder.hxx" +#include "xstorage.hxx" + +#include <rtl/digest.h> +#include <rtl/logfile.hxx> + +// since the copying uses 32000 blocks usually, it makes sense to have a smaller size +#define MAX_STORCACHE_SIZE 30000 + + +using namespace ::com::sun::star; + +namespace package +{ +//----------------------------------------------- +uno::Sequence< sal_Int8 > MakeKeyFromPass( const ::rtl::OUString& aPass, sal_Bool bUseUTF ) +{ + // MS_1252 encoding was used for SO60 document format password encoding, + // this encoding supports only a minor subset of nonascii characters, + // but for compatibility reasons it has to be used for old document formats + + ::rtl::OString aByteStrPass; + if ( bUseUTF ) + aByteStrPass = ::rtl::OUStringToOString( aPass, RTL_TEXTENCODING_UTF8 ); + else + aByteStrPass = ::rtl::OUStringToOString( aPass, RTL_TEXTENCODING_MS_1252 ); + + sal_uInt8 pBuffer[RTL_DIGEST_LENGTH_SHA1]; + rtlDigestError nError = rtl_digest_SHA1( aByteStrPass.getStr(), + aByteStrPass.getLength(), + pBuffer, + RTL_DIGEST_LENGTH_SHA1 ); + + if ( nError != rtl_Digest_E_None ) + throw uno::RuntimeException(); + + return uno::Sequence< sal_Int8 >( (sal_Int8*)pBuffer, RTL_DIGEST_LENGTH_SHA1 ); + +} + +//----------------------------------------------- +void StaticAddLog( const ::rtl::OUString& aMessage ) +{ + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + if ( aContext.is() ) + { + uno::Reference< logging::XSimpleLogRing > xLogRing( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), uno::UNO_QUERY_THROW ); + xLogRing->logString( aMessage ); + } + } + catch( uno::Exception& ) + { + // No log + } +} +} // namespace package + +// ================================================================ +namespace +{ +//----------------------------------------------- +void SetEncryptionKeyProperty_Impl( const uno::Reference< beans::XPropertySet >& xPropertySet, + const uno::Sequence< sal_Int8 >& aKey ) +{ + OSL_ENSURE( xPropertySet.is(), "No property set is provided!\n" ); + if ( !xPropertySet.is() ) + throw uno::RuntimeException(); + + ::rtl::OUString aString_EncryptionKey = ::rtl::OUString::createFromAscii( "EncryptionKey" ); + try { + xPropertySet->setPropertyValue( aString_EncryptionKey, uno::makeAny( aKey ) ); + } + catch ( uno::Exception& aException ) + { + ::package::StaticAddLog( aException.Message ); + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't set encryption" ) ) ); + OSL_ENSURE( sal_False, "Can't write encryption related properties!\n" ); + throw io::IOException(); // TODO + } +} + +//----------------------------------------------- +uno::Any GetEncryptionKeyProperty_Impl( const uno::Reference< beans::XPropertySet >& xPropertySet ) +{ + OSL_ENSURE( xPropertySet.is(), "No property set is provided!\n" ); + if ( !xPropertySet.is() ) + throw uno::RuntimeException(); + + ::rtl::OUString aString_EncryptionKey = ::rtl::OUString::createFromAscii( "EncryptionKey" ); + try { + return xPropertySet->getPropertyValue( aString_EncryptionKey ); + } + catch ( uno::Exception& aException ) + { + ::package::StaticAddLog( aException.Message ); + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't get encryption property" ) ) ); + + OSL_ENSURE( sal_False, "Can't get encryption related properties!\n" ); + throw io::IOException(); // TODO + } +} + +//----------------------------------------------- +sal_Bool SequencesEqual( uno::Sequence< sal_Int8 > aSequence1, uno::Sequence< sal_Int8 > aSequence2 ) +{ + if ( aSequence1.getLength() != aSequence2.getLength() ) + return sal_False; + + for ( sal_Int32 nInd = 0; nInd < aSequence1.getLength(); nInd++ ) + if ( aSequence1[nInd] != aSequence2[nInd] ) + return sal_False; + + return sal_True; +} + +//----------------------------------------------- +sal_Bool KillFile( const ::rtl::OUString& aURL, const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +{ + if ( !xFactory.is() ) + return sal_False; + + sal_Bool bRet = sal_False; + + try + { + uno::Reference < ucb::XSimpleFileAccess > xAccess( + xFactory->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( xAccess.is() ) + { + xAccess->kill( aURL ); + bRet = sal_True; + } + } + catch( uno::Exception& aException ) + { + ::package::StaticAddLog( aException.Message ); + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + + return bRet; +} + +const sal_Int32 n_ConstBufferSize = 32000; + +//----------------------------------------------- +::rtl::OUString GetNewTempFileURL( const uno::Reference< lang::XMultiServiceFactory > xFactory ) +{ + ::rtl::OUString aTempURL; + + uno::Reference < beans::XPropertySet > xTempFile( + xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY ); + + if ( !xTempFile.is() ) + throw uno::RuntimeException(); // TODO + + try { + xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ), uno::makeAny( sal_False ) ); + uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) ); + aUrl >>= aTempURL; + } + catch ( uno::Exception& aException ) + { + ::package::StaticAddLog( aException.Message ); + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + + if ( !aTempURL.getLength() ) + throw uno::RuntimeException(); // TODO: can not create tempfile + + return aTempURL; +} + +//----------------------------------------------- +uno::Reference< io::XStream > CreateMemoryStream( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +{ + if ( !xFactory.is() ) + throw uno::RuntimeException(); + + return uno::Reference< io::XStream >( xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.comp.MemoryStream" ) ), uno::UNO_QUERY_THROW ); +} + +} // anonymous namespace +// ================================================================ + +//----------------------------------------------- +OWriteStream_Impl::OWriteStream_Impl( OStorage_Impl* pParent, + const uno::Reference< packages::XDataSinkEncrSupport >& xPackageStream, + const uno::Reference< lang::XSingleServiceFactory >& xPackage, + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bForceEncrypted, + sal_Int16 nStorageType, + sal_Bool bDefaultCompress, + const uno::Reference< io::XInputStream >& xRelInfoStream ) +: m_pAntiImpl( NULL ) +, m_bHasDataToFlush( sal_False ) +, m_bFlushed( sal_False ) +, m_xPackageStream( xPackageStream ) +, m_xFactory( xFactory ) +, m_pParent( pParent ) +, m_bForceEncrypted( bForceEncrypted ) +, m_bUseCommonPass( !bForceEncrypted && nStorageType == PACKAGE_STORAGE ) +, m_bHasCachedPassword( sal_False ) +, m_bCompressedSetExplicit( !bDefaultCompress ) +, m_xPackage( xPackage ) +, m_bHasInsertedStreamOptimization( sal_False ) +, m_nStorageType( nStorageType ) +, m_xOrigRelInfoStream( xRelInfoStream ) +, m_bOrigRelInfoBroken( sal_False ) +, m_nRelInfoStatus( RELINFO_NO_INIT ) +, m_nRelId( 1 ) +{ + OSL_ENSURE( xPackageStream.is(), "No package stream is provided!\n" ); + OSL_ENSURE( xPackage.is(), "No package component is provided!\n" ); + OSL_ENSURE( m_xFactory.is(), "No package stream is provided!\n" ); + OSL_ENSURE( pParent, "No parent storage is provided!\n" ); + OSL_ENSURE( m_nStorageType == OFOPXML_STORAGE || !m_xOrigRelInfoStream.is(), "The Relations info makes sence only for OFOPXML format!\n" ); +} + +//----------------------------------------------- +OWriteStream_Impl::~OWriteStream_Impl() +{ + DisposeWrappers(); + + if ( m_aTempURL.getLength() ) + { + KillFile( m_aTempURL, GetServiceFactory() ); + m_aTempURL = ::rtl::OUString(); + } + + CleanCacheStream(); +} + +//----------------------------------------------- +void OWriteStream_Impl::CleanCacheStream() +{ + if ( m_xCacheStream.is() ) + { + try + { + uno::Reference< io::XInputStream > xInputCache = m_xCacheStream->getInputStream(); + if ( xInputCache.is() ) + xInputCache->closeInput(); + } + catch( uno::Exception& ) + {} + + try + { + uno::Reference< io::XOutputStream > xOutputCache = m_xCacheStream->getOutputStream(); + if ( xOutputCache.is() ) + xOutputCache->closeOutput(); + } + catch( uno::Exception& ) + {} + + m_xCacheStream = uno::Reference< io::XStream >(); + m_xCacheSeek = uno::Reference< io::XSeekable >(); + } +} + +//----------------------------------------------- +void OWriteStream_Impl::AddLog( const ::rtl::OUString& aMessage ) +{ + if ( !m_xLogRing.is() ) + { + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + if ( aContext.is() ) + m_xLogRing.set( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), uno::UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + { + // No log + } + } + + if ( m_xLogRing.is() ) + m_xLogRing->logString( aMessage ); +} + + +//----------------------------------------------- +void OWriteStream_Impl::InsertIntoPackageFolder( const ::rtl::OUString& aName, + const uno::Reference< container::XNameContainer >& xParentPackageFolder ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + OSL_ENSURE( m_bFlushed, "This method must not be called for nonflushed streams!\n" ); + if ( m_bFlushed ) + { + OSL_ENSURE( m_xPackageStream.is(), "An inserted stream is incomplete!\n" ); + uno::Reference< lang::XUnoTunnel > xTunnel( m_xPackageStream, uno::UNO_QUERY ); + if ( !xTunnel.is() ) + throw uno::RuntimeException(); // TODO + + xParentPackageFolder->insertByName( aName, uno::makeAny( xTunnel ) ); + + m_bFlushed = sal_False; + m_bHasInsertedStreamOptimization = sal_False; + } +} +//----------------------------------------------- +sal_Bool OWriteStream_Impl::IsEncrypted() +{ + if ( m_nStorageType != PACKAGE_STORAGE ) + return sal_False; + + if ( m_bForceEncrypted || m_bHasCachedPassword ) + return sal_True; + + if ( m_aTempURL.getLength() || m_xCacheStream.is() ) + return sal_False; + + GetStreamProperties(); + + // the following value can not be cached since it can change after root commit + sal_Bool bWasEncr = sal_False; + uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY ); + if ( xPropSet.is() ) + { + uno::Any aValue = xPropSet->getPropertyValue( ::rtl::OUString::createFromAscii( "WasEncrypted" ) ); + if ( !( aValue >>= bWasEncr ) ) + { + OSL_ENSURE( sal_False, "The property WasEncrypted has wrong type!\n" ); + } + } + + sal_Bool bToBeEncr = sal_False; + for ( sal_Int32 nInd = 0; nInd < m_aProps.getLength(); nInd++ ) + { + if ( m_aProps[nInd].Name.equalsAscii( "Encrypted" ) ) + { + if ( !( m_aProps[nInd].Value >>= bToBeEncr ) ) + { + OSL_ENSURE( sal_False, "The property has wrong type!\n" ); + } + } + } + + // since a new key set to the package stream it should not be removed except the case when + // the stream becomes nonencrypted + uno::Sequence< sal_Int8 > aKey; + if ( bToBeEncr ) + GetEncryptionKeyProperty_Impl( xPropSet ) >>= aKey; + + // If the properties must be investigated the stream is either + // was never changed or was changed, the parent was commited + // and the stream was closed. + // That means that if it is intended to use common storage key + // it is already has no encryption but is marked to be stored + // encrypted and the key is empty. + if ( !bWasEncr && bToBeEncr && !aKey.getLength() ) + { + // the stream is intended to use common storage password + m_bUseCommonPass = sal_True; + return sal_False; + } + else + return bToBeEncr; +} + +//----------------------------------------------- +void OWriteStream_Impl::SetDecrypted() +{ + OSL_ENSURE( m_nStorageType == PACKAGE_STORAGE, "The encryption is supported only for package storages!\n" ); + if ( m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException(); + + GetStreamProperties(); + + // let the stream be modified + FillTempGetFileName(); + m_bHasDataToFlush = sal_True; + + // remove encryption + m_bForceEncrypted = sal_False; + m_bHasCachedPassword = sal_False; + m_aPass = ::rtl::OUString(); + + for ( sal_Int32 nInd = 0; nInd < m_aProps.getLength(); nInd++ ) + { + if ( m_aProps[nInd].Name.equalsAscii( "Encrypted" ) ) + m_aProps[nInd].Value <<= sal_False; + } +} + +//----------------------------------------------- +void OWriteStream_Impl::SetEncryptedWithPass( const ::rtl::OUString& aPass ) +{ + OSL_ENSURE( m_nStorageType == PACKAGE_STORAGE, "The encryption is supported only for package storages!\n" ); + if ( m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException(); + + GetStreamProperties(); + + // let the stream be modified + FillTempGetFileName(); + m_bHasDataToFlush = sal_True; + + // introduce encryption info + for ( sal_Int32 nInd = 0; nInd < m_aProps.getLength(); nInd++ ) + { + if ( m_aProps[nInd].Name.equalsAscii( "Encrypted" ) ) + m_aProps[nInd].Value <<= sal_True; + } + + m_bUseCommonPass = sal_False; // very important to set it to false + + m_bHasCachedPassword = sal_True; + m_aPass = aPass; +} + +//----------------------------------------------- +void OWriteStream_Impl::DisposeWrappers() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_pAntiImpl ) + { + try { + m_pAntiImpl->dispose(); + } + catch ( uno::RuntimeException& aRuntimeException ) + { + AddLog( aRuntimeException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + + m_pAntiImpl = NULL; + } + m_pParent = NULL; + + if ( !m_aInputStreamsList.empty() ) + { + for ( InputStreamsList_Impl::iterator pStreamIter = m_aInputStreamsList.begin(); + pStreamIter != m_aInputStreamsList.end(); pStreamIter++ ) + { + if ( (*pStreamIter) ) + { + (*pStreamIter)->InternalDispose(); + (*pStreamIter) = NULL; + } + } + + m_aInputStreamsList.clear(); + } +} + +//----------------------------------------------- +uno::Reference< lang::XMultiServiceFactory > OWriteStream_Impl::GetServiceFactory() +{ + if ( m_xFactory.is() ) + return m_xFactory; + + return ::comphelper::getProcessServiceFactory(); +} + +//----------------------------------------------- +::rtl::OUString OWriteStream_Impl::GetFilledTempFileIfNo( const uno::Reference< io::XInputStream >& xStream ) +{ + if ( !m_aTempURL.getLength() ) + { + ::rtl::OUString aTempURL = GetNewTempFileURL( GetServiceFactory() ); + + try { + if ( aTempURL && xStream.is() ) + { + uno::Reference < ucb::XSimpleFileAccess > xTempAccess( + GetServiceFactory()->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( !xTempAccess.is() ) + throw uno::RuntimeException(); // TODO: + + uno::Reference< io::XOutputStream > xTempOutStream = xTempAccess->openFileWrite( aTempURL ); + if ( xTempOutStream.is() ) + { + // the current position of the original stream should be still OK, copy further + ::comphelper::OStorageHelper::CopyInputToOutput( xStream, xTempOutStream ); + xTempOutStream->closeOutput(); + xTempOutStream = uno::Reference< io::XOutputStream >(); + } + else + throw io::IOException(); // TODO: + } + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + AddLog( aWrongPasswordException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + KillFile( aTempURL, GetServiceFactory() ); + throw; + } + catch( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + KillFile( aTempURL, GetServiceFactory() ); + throw; + } + + if ( aTempURL.getLength() ) + CleanCacheStream(); + + m_aTempURL = aTempURL; + } + + return m_aTempURL; +} + +//----------------------------------------------- +::rtl::OUString OWriteStream_Impl::FillTempGetFileName() +{ + // should try to create cache first, if the amount of contents is too big, the temp file should be taken + if ( !m_xCacheStream.is() && !m_aTempURL.getLength() ) + { + uno::Reference< io::XInputStream > xOrigStream = m_xPackageStream->getDataStream(); + if ( !xOrigStream.is() ) + { + // in case of new inserted package stream it is possible that input stream still was not set + uno::Reference< io::XStream > xCacheStream = CreateMemoryStream( GetServiceFactory() ); + OSL_ENSURE( xCacheStream.is(), "If the stream can not be created an exception must be thrown!\n" ); + m_xCacheSeek.set( xCacheStream, uno::UNO_QUERY_THROW ); + m_xCacheStream = xCacheStream; + } + else + { + sal_Int32 nRead = 0; + uno::Sequence< sal_Int8 > aData( MAX_STORCACHE_SIZE + 1 ); + nRead = xOrigStream->readBytes( aData, MAX_STORCACHE_SIZE + 1 ); + if ( aData.getLength() > nRead ) + aData.realloc( nRead ); + + if ( nRead <= MAX_STORCACHE_SIZE ) + { + uno::Reference< io::XStream > xCacheStream = CreateMemoryStream( GetServiceFactory() ); + OSL_ENSURE( xCacheStream.is(), "If the stream can not be created an exception must be thrown!\n" ); + + if ( nRead ) + { + uno::Reference< io::XOutputStream > xOutStream( xCacheStream->getOutputStream(), uno::UNO_SET_THROW ); + xOutStream->writeBytes( aData ); + } + m_xCacheSeek.set( xCacheStream, uno::UNO_QUERY_THROW ); + m_xCacheStream = xCacheStream; + m_xCacheSeek->seek( 0 ); + } + else if ( !m_aTempURL.getLength() ) + { + m_aTempURL = GetNewTempFileURL( GetServiceFactory() ); + + try { + if ( m_aTempURL.getLength() ) + { + uno::Reference < ucb::XSimpleFileAccess > xTempAccess( + GetServiceFactory()->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( !xTempAccess.is() ) + throw uno::RuntimeException(); // TODO: + + + uno::Reference< io::XOutputStream > xTempOutStream = xTempAccess->openFileWrite( m_aTempURL ); + if ( xTempOutStream.is() ) + { + // copy stream contents to the file + xTempOutStream->writeBytes( aData ); + + // the current position of the original stream should be still OK, copy further + ::comphelper::OStorageHelper::CopyInputToOutput( xOrigStream, xTempOutStream ); + xTempOutStream->closeOutput(); + xTempOutStream = uno::Reference< io::XOutputStream >(); + } + else + throw io::IOException(); // TODO: + } + } + catch( packages::WrongPasswordException& ) + { + KillFile( m_aTempURL, GetServiceFactory() ); + m_aTempURL = ::rtl::OUString(); + + throw; + } + catch( uno::Exception& ) + { + KillFile( m_aTempURL, GetServiceFactory() ); + m_aTempURL = ::rtl::OUString(); + } + } + } + } + + return m_aTempURL; +} + +//----------------------------------------------- +uno::Reference< io::XStream > OWriteStream_Impl::GetTempFileAsStream() +{ + uno::Reference< io::XStream > xTempStream; + + if ( !m_xCacheStream.is() ) + { + if ( !m_aTempURL.getLength() ) + m_aTempURL = FillTempGetFileName(); + + if ( m_aTempURL.getLength() ) + { + // the temporary file is not used if the cache is used + uno::Reference < ucb::XSimpleFileAccess > xTempAccess( + GetServiceFactory()->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( !xTempAccess.is() ) + throw uno::RuntimeException(); // TODO: + + try + { + xTempStream = xTempAccess->openFileReadWrite( m_aTempURL ); + } + catch( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + } + } + + if ( m_xCacheStream.is() ) + xTempStream = m_xCacheStream; + + // the method must always return a stream + // in case the stream can not be open + // an exception should be thrown + if ( !xTempStream.is() ) + throw io::IOException(); //TODO: + + return xTempStream; +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > OWriteStream_Impl::GetTempFileAsInputStream() +{ + uno::Reference< io::XInputStream > xInputStream; + + if ( !m_xCacheStream.is() ) + { + if ( !m_aTempURL.getLength() ) + m_aTempURL = FillTempGetFileName(); + + if ( m_aTempURL.getLength() ) + { + // the temporary file is not used if the cache is used + uno::Reference < ucb::XSimpleFileAccess > xTempAccess( + GetServiceFactory()->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( !xTempAccess.is() ) + throw uno::RuntimeException(); // TODO: + + try + { + xInputStream = xTempAccess->openFileRead( m_aTempURL ); + } + catch( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + } + } + + if ( m_xCacheStream.is() ) + xInputStream = m_xCacheStream->getInputStream(); + + // the method must always return a stream + // in case the stream can not be open + // an exception should be thrown + if ( !xInputStream.is() ) + throw io::IOException(); // TODO: + + return xInputStream; +} + +// ================================================================================================= + +//----------------------------------------------- +void OWriteStream_Impl::InsertStreamDirectly( const uno::Reference< io::XInputStream >& xInStream, + const uno::Sequence< beans::PropertyValue >& aProps ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + // this call can be made only during parent storage commit + // the parent storage is responsible for the correct handling + // of deleted and renamed contents + + OSL_ENSURE( m_xPackageStream.is(), "No package stream is set!\n" ); + + if ( m_bHasDataToFlush ) + throw io::IOException(); + + OSL_ENSURE( !m_aTempURL.getLength() && !m_xCacheStream.is(), "The temporary must not exist!\n" ); + + // use new file as current persistent representation + // the new file will be removed after it's stream is closed + m_xPackageStream->setDataStream( xInStream ); + + // copy properties to the package stream + uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY ); + if ( !xPropertySet.is() ) + throw uno::RuntimeException(); + + // The storage-package communication has a problem + // the storage caches properties, thus if the package changes one of them itself + // the storage does not know about it + + // Depending from MediaType value the package can change the compressed property itself + // Thus if Compressed property is provided it must be set as the latest one + sal_Bool bCompressedIsSet = sal_False; + sal_Bool bCompressed = sal_False; + ::rtl::OUString aComprPropName( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ); + ::rtl::OUString aMedTypePropName( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + for ( sal_Int32 nInd = 0; nInd < aProps.getLength(); nInd++ ) + { + if ( aProps[nInd].Name.equals( aComprPropName ) ) + { + bCompressedIsSet = sal_True; + aProps[nInd].Value >>= bCompressed; + } + else if ( ( m_nStorageType == OFOPXML_STORAGE || m_nStorageType == PACKAGE_STORAGE ) + && aProps[nInd].Name.equals( aMedTypePropName ) ) + { + xPropertySet->setPropertyValue( aProps[nInd].Name, aProps[nInd].Value ); + } + else if ( m_nStorageType == PACKAGE_STORAGE && aProps[nInd].Name.equalsAscii( "UseCommonStoragePasswordEncryption" ) ) + aProps[nInd].Value >>= m_bUseCommonPass; + else + throw lang::IllegalArgumentException(); + + // if there are cached properties update them + if ( aProps[nInd].Name.equals( aMedTypePropName ) || aProps[nInd].Name.equals( aComprPropName ) ) + for ( sal_Int32 nMemInd = 0; nMemInd < m_aProps.getLength(); nMemInd++ ) + { + if ( aProps[nInd].Name.equals( m_aProps[nMemInd].Name ) ) + m_aProps[nMemInd].Value = aProps[nInd].Value; + } + } + + if ( bCompressedIsSet ) + { + xPropertySet->setPropertyValue( aComprPropName, uno::makeAny( (sal_Bool)bCompressed ) ); + m_bCompressedSetExplicit = sal_True; + } + + if ( m_bUseCommonPass ) + { + if ( m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException(); + + // set to be encrypted but do not use encryption key + xPropertySet->setPropertyValue( ::rtl::OUString::createFromAscii( "EncryptionKey" ), + uno::makeAny( uno::Sequence< sal_Int8 >() ) ); + xPropertySet->setPropertyValue( ::rtl::OUString::createFromAscii( "Encrypted" ), + uno::makeAny( sal_True ) ); + } + + // the stream should be free soon, after package is stored + m_bHasDataToFlush = sal_False; + m_bFlushed = sal_True; // will allow to use transaction on stream level if will need it + m_bHasInsertedStreamOptimization = sal_True; +} + +//----------------------------------------------- +void OWriteStream_Impl::Commit() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + OSL_ENSURE( m_xPackageStream.is(), "No package stream is set!\n" ); + + if ( !m_bHasDataToFlush ) + return; + + uno::Reference< packages::XDataSinkEncrSupport > xNewPackageStream; + uno::Sequence< uno::Any > aSeq( 1 ); + aSeq[0] <<= sal_False; + + if ( m_xCacheStream.is() ) + { + if ( m_pAntiImpl ) + m_pAntiImpl->DeInit(); + + uno::Reference< io::XInputStream > xInStream( m_xCacheStream->getInputStream(), uno::UNO_SET_THROW ); + + xNewPackageStream = uno::Reference< packages::XDataSinkEncrSupport >( + m_xPackage->createInstanceWithArguments( aSeq ), + uno::UNO_QUERY_THROW ); + + xNewPackageStream->setDataStream( xInStream ); + + m_xCacheStream = uno::Reference< io::XStream >(); + m_xCacheSeek = uno::Reference< io::XSeekable >(); + + } + else if ( m_aTempURL.getLength() ) + { + if ( m_pAntiImpl ) + m_pAntiImpl->DeInit(); + + uno::Reference< io::XInputStream > xInStream; + try + { + xInStream.set( static_cast< io::XInputStream* >( new OSelfTerminateFileStream( GetServiceFactory(), m_aTempURL ) ), uno::UNO_QUERY ); + } + catch( uno::Exception& ) + { + } + + if ( !xInStream.is() ) + throw io::IOException(); + + xNewPackageStream = uno::Reference< packages::XDataSinkEncrSupport >( + m_xPackage->createInstanceWithArguments( aSeq ), + uno::UNO_QUERY_THROW ); + + // TODO/NEW: Let the temporary file be removed after commit + xNewPackageStream->setDataStream( xInStream ); + m_aTempURL = ::rtl::OUString(); + } + else // if ( m_bHasInsertedStreamOptimization ) + { + // if the optimization is used the stream can be accessed directly + xNewPackageStream = m_xPackageStream; + } + + // copy properties to the package stream + uno::Reference< beans::XPropertySet > xPropertySet( xNewPackageStream, uno::UNO_QUERY ); + if ( !xPropertySet.is() ) + throw uno::RuntimeException(); + + for ( sal_Int32 nInd = 0; nInd < m_aProps.getLength(); nInd++ ) + { + if ( m_aProps[nInd].Name.equalsAscii( "Size" ) ) + { + if ( m_pAntiImpl && !m_bHasInsertedStreamOptimization && m_pAntiImpl->m_xSeekable.is() ) + { + m_aProps[nInd].Value <<= ((sal_Int32)m_pAntiImpl->m_xSeekable->getLength()); + xPropertySet->setPropertyValue( m_aProps[nInd].Name, m_aProps[nInd].Value ); + } + } + else + xPropertySet->setPropertyValue( m_aProps[nInd].Name, m_aProps[nInd].Value ); + } + + if ( m_bUseCommonPass ) + { + if ( m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException(); + + // set to be encrypted but do not use encryption key + xPropertySet->setPropertyValue( ::rtl::OUString::createFromAscii( "EncryptionKey" ), + uno::makeAny( uno::Sequence< sal_Int8 >() ) ); + xPropertySet->setPropertyValue( ::rtl::OUString::createFromAscii( "Encrypted" ), + uno::makeAny( sal_True ) ); + } + else if ( m_bHasCachedPassword ) + { + if ( m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException(); + + xPropertySet->setPropertyValue( ::rtl::OUString::createFromAscii( "EncryptionKey" ), + uno::makeAny( ::package::MakeKeyFromPass( m_aPass, sal_True ) ) ); + } + + // the stream should be free soon, after package is stored + m_xPackageStream = xNewPackageStream; + m_bHasDataToFlush = sal_False; + m_bFlushed = sal_True; // will allow to use transaction on stream level if will need it +} + +//----------------------------------------------- +void OWriteStream_Impl::Revert() +{ + // can be called only from parent storage + // means complete reload of the stream + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + if ( !m_bHasDataToFlush ) + return; // nothing to do + + OSL_ENSURE( m_aTempURL.getLength() || m_xCacheStream.is(), "The temporary must exist!\n" ); + + if ( m_xCacheStream.is() ) + { + m_xCacheStream = uno::Reference< io::XStream >(); + m_xCacheSeek = uno::Reference< io::XSeekable >(); + } + + if ( m_aTempURL.getLength() ) + { + KillFile( m_aTempURL, GetServiceFactory() ); + m_aTempURL = ::rtl::OUString(); + } + + m_aProps.realloc( 0 ); + + m_bHasDataToFlush = sal_False; + + m_bUseCommonPass = sal_True; + m_bHasCachedPassword = sal_False; + m_aPass = ::rtl::OUString(); + + if ( m_nStorageType == OFOPXML_STORAGE ) + { + // currently the relations storage is changed only on commit + m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + if ( m_xOrigRelInfoStream.is() ) + { + // the original stream is still here, that means that it was not parsed + m_aOrigRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_nRelInfoStatus = RELINFO_NO_INIT; + } + else + { + // the original stream was aready parsed + if ( !m_bOrigRelInfoBroken ) + m_nRelInfoStatus = RELINFO_READ; + else + m_nRelInfoStatus = RELINFO_BROKEN; + } + } +} + +//----------------------------------------------- +uno::Sequence< beans::PropertyValue > OWriteStream_Impl::GetStreamProperties() +{ + if ( !m_aProps.getLength() ) + m_aProps = ReadPackageStreamProperties(); + + return m_aProps; +} + +//----------------------------------------------- +uno::Sequence< beans::PropertyValue > OWriteStream_Impl::InsertOwnProps( + const uno::Sequence< beans::PropertyValue >& aProps, + sal_Bool bUseCommonPass ) +{ + uno::Sequence< beans::PropertyValue > aResult( aProps ); + sal_Int32 nLen = aResult.getLength(); + + if ( m_nStorageType == PACKAGE_STORAGE ) + { + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aResult[nInd].Name.equalsAscii( "UseCommonStoragePasswordEncryption" ) ) + { + aResult[nInd].Value <<= bUseCommonPass; + return aResult; + } + + aResult.realloc( ++nLen ); + aResult[nLen - 1].Name = ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ); + aResult[nLen - 1].Value <<= bUseCommonPass; + } + else if ( m_nStorageType == OFOPXML_STORAGE ) + { + ReadRelInfoIfNecessary(); + + uno::Any aValue; + if ( m_nRelInfoStatus == RELINFO_READ ) + aValue <<= m_aOrigRelInfo; + else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ || m_nRelInfoStatus == RELINFO_CHANGED ) + aValue <<= m_aNewRelInfo; + else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Wrong relinfo stream!" ) ), + uno::Reference< uno::XInterface >() ); + + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aResult[nInd].Name.equalsAscii( "RelationsInfo" ) ) + { + aResult[nInd].Value = aValue; + return aResult; + } + + aResult.realloc( ++nLen ); + aResult[nLen - 1].Name = ::rtl::OUString::createFromAscii( "RelationsInfo" ); + aResult[nLen - 1].Value = aValue; + } + + return aResult; +} + +//----------------------------------------------- +sal_Bool OWriteStream_Impl::IsTransacted() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + return ( m_pAntiImpl && m_pAntiImpl->m_bTransacted ); +} + +void OWriteStream_Impl::ReadRelInfoIfNecessary() +{ + if ( m_nStorageType != OFOPXML_STORAGE ) + return; + + if ( m_nRelInfoStatus == RELINFO_NO_INIT ) + { + try + { + // Init from original stream + if ( m_xOrigRelInfoStream.is() ) + m_aOrigRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence( + m_xOrigRelInfoStream, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels/*.rels" ) ), + m_xFactory ); + + // in case of success the stream must be thrown away, that means that the OrigRelInfo is initialized + // the reason for this is that the original stream might not be seekable ( at the same time the new + // provided stream must be seekable ), so it must be read only once + m_xOrigRelInfoStream = uno::Reference< io::XInputStream >(); + m_nRelInfoStatus = RELINFO_READ; + } + catch( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + + m_nRelInfoStatus = RELINFO_BROKEN; + m_bOrigRelInfoBroken = sal_True; + } + } + else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + // Init from the new stream + try + { + if ( m_xNewRelInfoStream.is() ) + m_aNewRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence( + m_xNewRelInfoStream, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels/*.rels" ) ), + m_xFactory ); + + m_nRelInfoStatus = RELINFO_CHANGED_STREAM_READ; + } + catch( uno::Exception ) + { + m_nRelInfoStatus = RELINFO_CHANGED_BROKEN; + } + } +} + +//----------------------------------------------- +uno::Sequence< beans::PropertyValue > OWriteStream_Impl::ReadPackageStreamProperties() +{ + sal_Int32 nPropNum = 0; + if ( m_nStorageType == ZIP_STORAGE ) + nPropNum = 2; + else if ( m_nStorageType == OFOPXML_STORAGE ) + nPropNum = 3; + else if ( m_nStorageType == PACKAGE_STORAGE ) + nPropNum = 4; + uno::Sequence< beans::PropertyValue > aResult( nPropNum ); + + // The "Compressed" property must be set after "MediaType" property, + // since the setting of the last one can change the value of the first one + + if ( m_nStorageType == OFOPXML_STORAGE || m_nStorageType == PACKAGE_STORAGE ) + { + aResult[0].Name = ::rtl::OUString::createFromAscii("MediaType"); + aResult[1].Name = ::rtl::OUString::createFromAscii("Compressed"); + aResult[2].Name = ::rtl::OUString::createFromAscii("Size"); + + if ( m_nStorageType == PACKAGE_STORAGE ) + aResult[3].Name = ::rtl::OUString::createFromAscii("Encrypted"); + } + else + { + aResult[0].Name = ::rtl::OUString::createFromAscii("Compressed"); + aResult[1].Name = ::rtl::OUString::createFromAscii("Size"); + + } + + // TODO: may be also raw stream should be marked + + uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY ); + if ( xPropSet.is() ) + { + for ( sal_Int32 nInd = 0; nInd < aResult.getLength(); nInd++ ) + { + try { + aResult[nInd].Value = xPropSet->getPropertyValue( aResult[nInd].Name ); + } + catch( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + + OSL_ENSURE( sal_False, "A property can't be retrieved!\n" ); + } + } + } + else + { + OSL_ENSURE( sal_False, "Can not get properties from a package stream!\n" ); + throw uno::RuntimeException(); + } + + return aResult; +} + +//----------------------------------------------- +void OWriteStream_Impl::CopyInternallyTo_Impl( const uno::Reference< io::XStream >& xDestStream, + const ::rtl::OUString& aPass ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + OSL_ENSURE( !m_bUseCommonPass, "The stream can not be encrypted!" ); + + if ( m_nStorageType != PACKAGE_STORAGE ) + throw packages::NoEncryptionException(); + + if ( m_pAntiImpl ) + { + m_pAntiImpl->CopyToStreamInternally_Impl( xDestStream ); + } + else + { + uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, aPass, sal_False ); + if ( !xOwnStream.is() ) + throw io::IOException(); // TODO + + OStorage_Impl::completeStorageStreamCopy_Impl( xOwnStream, xDestStream, m_nStorageType, GetAllRelationshipsIfAny() ); + } + + uno::Reference< embed::XEncryptionProtectedSource > xEncr( xDestStream, uno::UNO_QUERY ); + if ( xEncr.is() ) + xEncr->setEncryptionPassword( aPass ); +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > OWriteStream_Impl::GetAllRelationshipsIfAny() +{ + if ( m_nStorageType != OFOPXML_STORAGE ) + return uno::Sequence< uno::Sequence< beans::StringPair > >(); + + ReadRelInfoIfNecessary(); + + if ( m_nRelInfoStatus == RELINFO_READ ) + return m_aOrigRelInfo; + else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ || m_nRelInfoStatus == RELINFO_CHANGED ) + return m_aNewRelInfo; + else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Wrong relinfo stream!" ) ), + uno::Reference< uno::XInterface >() ); +} + +//----------------------------------------------- +void OWriteStream_Impl::CopyInternallyTo_Impl( const uno::Reference< io::XStream >& xDestStream ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + if ( m_pAntiImpl ) + { + m_pAntiImpl->CopyToStreamInternally_Impl( xDestStream ); + } + else + { + uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, sal_False ); + if ( !xOwnStream.is() ) + throw io::IOException(); // TODO + + OStorage_Impl::completeStorageStreamCopy_Impl( xOwnStream, xDestStream, m_nStorageType, GetAllRelationshipsIfAny() ); + } +} + +//----------------------------------------------- +uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMode, const ::rtl::OUString& aPass, sal_Bool bHierarchyAccess ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + OSL_ENSURE( m_xPackageStream.is(), "No package stream is set!\n" ); + + if ( m_pAntiImpl ) + throw io::IOException(); // TODO: + + if ( !IsEncrypted() ) + throw packages::NoEncryptionException(); + + uno::Reference< io::XStream > xResultStream; + + uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY ); + if ( !xPropertySet.is() ) + throw uno::RuntimeException(); + + if ( m_bHasCachedPassword ) + { + if ( !m_aPass.equals( aPass ) ) + throw packages::WrongPasswordException(); + + // the correct key must be set already + xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess ); + } + else + { + SetEncryptionKeyProperty_Impl( xPropertySet, ::package::MakeKeyFromPass( aPass, sal_True ) ); + + try { + xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess ); + + m_bUseCommonPass = sal_False; // very important to set it to false + m_bHasCachedPassword = sal_True; + m_aPass = aPass; + } + catch( packages::WrongPasswordException& ) + { + // retry with different encoding + SetEncryptionKeyProperty_Impl( xPropertySet, ::package::MakeKeyFromPass( aPass, sal_False ) ); + try { + // the stream must be cashed to be resaved + xResultStream = GetStream_Impl( nStreamMode | embed::ElementModes::SEEKABLE, bHierarchyAccess ); + + m_bUseCommonPass = sal_False; // very important to set it to false + m_bHasCachedPassword = sal_True; + m_aPass = aPass; + + // the stream must be resaved with new password encryption + if ( nStreamMode & embed::ElementModes::WRITE ) + { + FillTempGetFileName(); + m_bHasDataToFlush = sal_True; + + // TODO/LATER: should the notification be done? + if ( m_pParent ) + m_pParent->m_bIsModified = sal_True; + } + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + AddLog( aWrongPasswordException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + + OSL_ENSURE( sal_False, "Can't write encryption related properties!\n" ); + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + throw io::IOException(); // TODO: + } + } + catch( uno::Exception& aException ) + { + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + + } + + OSL_ENSURE( xResultStream.is(), "In case stream can not be retrieved an exception must be thrown!\n" ); + + return xResultStream; +} + +//----------------------------------------------- +uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMode, sal_Bool bHierarchyAccess ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + OSL_ENSURE( m_xPackageStream.is(), "No package stream is set!\n" ); + + if ( m_pAntiImpl ) + throw io::IOException(); // TODO: + + uno::Reference< io::XStream > xResultStream; + + if ( IsEncrypted() ) + { + ::rtl::OUString aGlobalPass; + try + { + aGlobalPass = GetCommonRootPass(); + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + AddLog( aNoEncryptionException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + throw packages::WrongPasswordException(); + } + + xResultStream = GetStream( nStreamMode, aGlobalPass, bHierarchyAccess ); + } + else + xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess ); + + return xResultStream; +} + +//----------------------------------------------- +uno::Reference< io::XStream > OWriteStream_Impl::GetStream_Impl( sal_Int32 nStreamMode, sal_Bool bHierarchyAccess ) +{ + // private method, no mutex is used + GetStreamProperties(); + + // TODO/LATER: this info might be read later, on demand in future + ReadRelInfoIfNecessary(); + + if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::READ ) + { + uno::Reference< io::XInputStream > xInStream; + if ( m_xCacheStream.is() || m_aTempURL.getLength() ) + xInStream = GetTempFileAsInputStream(); //TODO: + else + xInStream = m_xPackageStream->getDataStream(); + + // The stream does not exist in the storage + if ( !xInStream.is() ) + throw io::IOException(); + + OInputCompStream* pStream = new OInputCompStream( *this, xInStream, InsertOwnProps( m_aProps, m_bUseCommonPass ), m_nStorageType ); + uno::Reference< io::XStream > xCompStream( + static_cast< ::cppu::OWeakObject* >( pStream ), + uno::UNO_QUERY ); + OSL_ENSURE( xCompStream.is(), + "OInputCompStream MUST provide XStream interfaces!\n" ); + + m_aInputStreamsList.push_back( pStream ); + return xCompStream; + } + else if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::SEEKABLEREAD ) + { + if ( !m_xCacheStream.is() && !m_aTempURL.getLength() && !( m_xPackageStream->getDataStream().is() ) ) + { + // The stream does not exist in the storage + throw io::IOException(); + } + + uno::Reference< io::XInputStream > xInStream; + + xInStream = GetTempFileAsInputStream(); //TODO: + + if ( !xInStream.is() ) + throw io::IOException(); + + OInputSeekStream* pStream = new OInputSeekStream( *this, xInStream, InsertOwnProps( m_aProps, m_bUseCommonPass ), m_nStorageType ); + uno::Reference< io::XStream > xSeekStream( + static_cast< ::cppu::OWeakObject* >( pStream ), + uno::UNO_QUERY ); + OSL_ENSURE( xSeekStream.is(), + "OInputSeekStream MUST provide XStream interfaces!\n" ); + + m_aInputStreamsList.push_back( pStream ); + return xSeekStream; + } + else if ( ( nStreamMode & embed::ElementModes::WRITE ) == embed::ElementModes::WRITE ) + { + if ( !m_aInputStreamsList.empty() ) + throw io::IOException(); // TODO: + + uno::Reference< io::XStream > xStream; + if ( ( nStreamMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE ) + { + if ( m_aTempURL.getLength() ) + { + KillFile( m_aTempURL, GetServiceFactory() ); + m_aTempURL = ::rtl::OUString(); + } + if ( m_xCacheStream.is() ) + CleanCacheStream(); + + m_bHasDataToFlush = sal_True; + + // this call is triggered by the parent and it will recognize the change of the state + if ( m_pParent ) + m_pParent->m_bIsModified = sal_True; + + xStream = CreateMemoryStream( GetServiceFactory() ); + m_xCacheSeek.set( xStream, uno::UNO_QUERY_THROW ); + m_xCacheStream = xStream; + } + else if ( !m_bHasInsertedStreamOptimization ) + { + if ( !m_aTempURL.getLength() && !m_xCacheStream.is() && !( m_xPackageStream->getDataStream().is() ) ) + { + // The stream does not exist in the storage + m_bHasDataToFlush = sal_True; + + // this call is triggered by the parent and it will recognize the change of the state + if ( m_pParent ) + m_pParent->m_bIsModified = sal_True; + xStream = GetTempFileAsStream(); + } + + // if the stream exists the temporary file is created on demand + // xStream = GetTempFileAsStream(); + } + + if ( !xStream.is() ) + m_pAntiImpl = new OWriteStream( this, bHierarchyAccess ); + else + m_pAntiImpl = new OWriteStream( this, xStream, bHierarchyAccess ); + + uno::Reference< io::XStream > xWriteStream = + uno::Reference< io::XStream >( static_cast< ::cppu::OWeakObject* >( m_pAntiImpl ), + uno::UNO_QUERY ); + + OSL_ENSURE( xWriteStream.is(), "OWriteStream MUST implement XStream && XComponent interfaces!\n" ); + + return xWriteStream; + } + + throw lang::IllegalArgumentException(); // TODO +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > OWriteStream_Impl::GetPlainRawInStream() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + OSL_ENSURE( m_xPackageStream.is(), "No package stream is set!\n" ); + + // this method is used only internally, this stream object should not go outside of this implementation + // if ( m_pAntiImpl ) + // throw io::IOException(); // TODO: + + return m_xPackageStream->getPlainRawStream(); +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > OWriteStream_Impl::GetRawInStream() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + OSL_ENSURE( m_xPackageStream.is(), "No package stream is set!\n" ); + + if ( m_pAntiImpl ) + throw io::IOException(); // TODO: + + OSL_ENSURE( IsEncrypted(), "Impossible to get raw representation for nonencrypted stream!\n" ); + if ( !IsEncrypted() ) + throw packages::NoEncryptionException(); + + return m_xPackageStream->getRawStream(); +} + +//----------------------------------------------- +::rtl::OUString OWriteStream_Impl::GetCommonRootPass() + throw ( packages::NoEncryptionException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + if ( m_nStorageType != PACKAGE_STORAGE || !m_pParent ) + throw packages::NoEncryptionException(); + + return m_pParent->GetCommonRootPass(); +} + +//----------------------------------------------- +void OWriteStream_Impl::InputStreamDisposed( OInputCompStream* pStream ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + m_aInputStreamsList.remove( pStream ); +} + +//----------------------------------------------- +void OWriteStream_Impl::CreateReadonlyCopyBasedOnData( const uno::Reference< io::XInputStream >& xDataToCopy, const uno::Sequence< beans::PropertyValue >& aProps, sal_Bool, uno::Reference< io::XStream >& xTargetStream ) +{ + uno::Reference < io::XStream > xTempFile; + if ( !xTargetStream.is() ) + xTempFile = uno::Reference < io::XStream >( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY ); + else + xTempFile = xTargetStream; + + uno::Reference < io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY ); + if ( !xTempSeek.is() ) + throw uno::RuntimeException(); // TODO + + uno::Reference < io::XOutputStream > xTempOut = xTempFile->getOutputStream(); + if ( !xTempOut.is() ) + throw uno::RuntimeException(); + + if ( xDataToCopy.is() ) + ::comphelper::OStorageHelper::CopyInputToOutput( xDataToCopy, xTempOut ); + + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + uno::Reference< io::XInputStream > xInStream = xTempFile->getInputStream(); + if ( !xInStream.is() ) + throw io::IOException(); + + // TODO: remember last state of m_bUseCommonPass + if ( !xTargetStream.is() ) + xTargetStream = uno::Reference< io::XStream > ( + static_cast< ::cppu::OWeakObject* >( + new OInputSeekStream( xInStream, InsertOwnProps( aProps, m_bUseCommonPass ), m_nStorageType ) ), + uno::UNO_QUERY_THROW ); +} + +//----------------------------------------------- +void OWriteStream_Impl::GetCopyOfLastCommit( uno::Reference< io::XStream >& xTargetStream ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + OSL_ENSURE( m_xPackageStream.is(), "The source stream for copying is incomplete!\n" ); + if ( !m_xPackageStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XInputStream > xDataToCopy; + if ( IsEncrypted() ) + { + // an encrypted stream must contain input stream + ::rtl::OUString aGlobalPass; + try + { + aGlobalPass = GetCommonRootPass(); + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + AddLog( aNoEncryptionException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No Element" ) ) ); + + throw packages::WrongPasswordException(); + } + + GetCopyOfLastCommit( xTargetStream, aGlobalPass ); + } + else + { + xDataToCopy = m_xPackageStream->getDataStream(); + + // in case of new inserted package stream it is possible that input stream still was not set + GetStreamProperties(); + + CreateReadonlyCopyBasedOnData( xDataToCopy, m_aProps, m_bUseCommonPass, xTargetStream ); + } +} + +//----------------------------------------------- +void OWriteStream_Impl::GetCopyOfLastCommit( uno::Reference< io::XStream >& xTargetStream, const ::rtl::OUString& aPass ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + OSL_ENSURE( m_xPackageStream.is(), "The source stream for copying is incomplete!\n" ); + if ( !m_xPackageStream.is() ) + throw uno::RuntimeException(); + + if ( !IsEncrypted() ) + throw packages::NoEncryptionException(); + + uno::Reference< io::XInputStream > xDataToCopy; + + if ( m_bHasCachedPassword ) + { + // TODO: introduce last commited cashed password information and use it here + // that means "use common pass" also should be remembered on flash + uno::Sequence< sal_Int8 > aNewKey = ::package::MakeKeyFromPass( aPass, sal_True ); + uno::Sequence< sal_Int8 > aOldKey = ::package::MakeKeyFromPass( aPass, sal_False ); + + uno::Reference< beans::XPropertySet > xProps( m_xPackageStream, uno::UNO_QUERY ); + if ( !xProps.is() ) + throw uno::RuntimeException(); + + sal_Bool bEncr = sal_False; + xProps->getPropertyValue( ::rtl::OUString::createFromAscii( "Encrypted" ) ) >>= bEncr; + if ( !bEncr ) + throw packages::NoEncryptionException(); + + uno::Sequence< sal_Int8 > aEncrKey; + xProps->getPropertyValue( ::rtl::OUString::createFromAscii( "EncryptionKey" ) ) >>= aEncrKey; + if ( !SequencesEqual( aNewKey, aEncrKey ) && !SequencesEqual( aOldKey, aEncrKey ) ) + throw packages::WrongPasswordException(); + + // the correct key must be set already + xDataToCopy = m_xPackageStream->getDataStream(); + } + else + { + uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY ); + SetEncryptionKeyProperty_Impl( xPropertySet, ::package::MakeKeyFromPass( aPass, sal_True ) ); + + try { + xDataToCopy = m_xPackageStream->getDataStream(); + + if ( !xDataToCopy.is() ) + { + OSL_ENSURE( sal_False, "Encrypted ZipStream must already have input stream inside!\n" ); + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + } + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + SetEncryptionKeyProperty_Impl( xPropertySet, ::package::MakeKeyFromPass( aPass, sal_False ) ); + try { + xDataToCopy = m_xPackageStream->getDataStream(); + + if ( !xDataToCopy.is() ) + { + OSL_ENSURE( sal_False, "Encrypted ZipStream must already have input stream inside!\n" ); + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + AddLog( aWrongPasswordException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + } + catch( uno::Exception& aException ) + { + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + } + catch( uno::Exception& aException ) + { + OSL_ENSURE( sal_False, "Can't open encrypted stream!\n" ); + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + + SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< sal_Int8 >() ); + } + + // in case of new inserted package stream it is possible that input stream still was not set + GetStreamProperties(); + + CreateReadonlyCopyBasedOnData( xDataToCopy, m_aProps, m_bUseCommonPass, xTargetStream ); +} + +//----------------------------------------------- +void OWriteStream_Impl::CommitStreamRelInfo( const uno::Reference< embed::XStorage >& xRelStorage, const ::rtl::OUString& aOrigStreamName, const ::rtl::OUString& aNewStreamName ) +{ + // at this point of time the old stream must be already cleaned + OSL_ENSURE( m_nStorageType == OFOPXML_STORAGE, "The method should be used only with OFOPXML format!\n" ); + + if ( m_nStorageType == OFOPXML_STORAGE ) + { + OSL_ENSURE( aOrigStreamName.getLength() && aNewStreamName.getLength() && xRelStorage.is(), + "Wrong relation persistence information is provided!\n" ); + + if ( !xRelStorage.is() || !aOrigStreamName.getLength() || !aNewStreamName.getLength() ) + throw uno::RuntimeException(); + + if ( m_nRelInfoStatus == RELINFO_BROKEN || m_nRelInfoStatus == RELINFO_CHANGED_BROKEN ) + throw io::IOException(); // TODO: + + ::rtl::OUString aOrigRelStreamName = aOrigStreamName; + aOrigRelStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".rels" ) ); + + ::rtl::OUString aNewRelStreamName = aNewStreamName; + aNewRelStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".rels" ) ); + + sal_Bool bRenamed = !aOrigRelStreamName.equals( aNewRelStreamName ); + if ( m_nRelInfoStatus == RELINFO_CHANGED + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + if ( bRenamed && xRelStorage->hasByName( aOrigRelStreamName ) ) + xRelStorage->removeElement( aOrigRelStreamName ); + + if ( m_nRelInfoStatus == RELINFO_CHANGED ) + { + if ( m_aNewRelInfo.getLength() ) + { + uno::Reference< io::XStream > xRelsStream = + xRelStorage->openStreamElement( aNewRelStreamName, + embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE ); + + uno::Reference< io::XOutputStream > xOutStream = xRelsStream->getOutputStream(); + if ( !xOutStream.is() ) + throw uno::RuntimeException(); + + ::comphelper::OFOPXMLHelper::WriteRelationsInfoSequence( xOutStream, m_aNewRelInfo, m_xFactory ); + + // set the mediatype + uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW ); + xPropSet->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), + uno::makeAny( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "application/vnd.openxmlformats-package.relationships+xml" ) ) ) ); + + m_nRelInfoStatus = RELINFO_READ; + } + } + else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + uno::Reference< io::XStream > xRelsStream = + xRelStorage->openStreamElement( aNewRelStreamName, + embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE ); + + uno::Reference< io::XOutputStream > xOutputStream = xRelsStream->getOutputStream(); + if ( !xOutputStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XSeekable > xSeek( m_xNewRelInfoStream, uno::UNO_QUERY_THROW ); + xSeek->seek( 0 ); + ::comphelper::OStorageHelper::CopyInputToOutput( m_xNewRelInfoStream, xOutputStream ); + xSeek->seek( 0 ); + + // set the mediatype + uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW ); + xPropSet->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), + uno::makeAny( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "application/vnd.openxmlformats-package.relationships+xml" ) ) ) ); + + if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + m_nRelInfoStatus = RELINFO_NO_INIT; + else + { + // the information is already parsed and the stream is stored, no need in temporary stream any more + m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_nRelInfoStatus = RELINFO_READ; + } + } + + // the original stream makes no sence after this step + m_xOrigRelInfoStream = m_xNewRelInfoStream; + m_aOrigRelInfo = m_aNewRelInfo; + m_bOrigRelInfoBroken = sal_False; + m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + } + else + { + // the stream is not changed but it might be renamed + if ( bRenamed && xRelStorage->hasByName( aOrigRelStreamName ) ) + xRelStorage->renameElement( aOrigRelStreamName, aNewRelStreamName ); + } + } +} + +//=============================================== +// OWriteStream implementation +//=============================================== + +//----------------------------------------------- +OWriteStream::OWriteStream( OWriteStream_Impl* pImpl, sal_Bool bTransacted ) +: m_pImpl( pImpl ) +, m_bInStreamDisconnected( sal_False ) +, m_bInitOnDemand( sal_True ) +, m_nInitPosition( 0 ) +, m_bTransacted( bTransacted ) +{ + OSL_ENSURE( pImpl, "No base implementation!\n" ); + OSL_ENSURE( m_pImpl->m_rMutexRef.Is(), "No mutex!\n" ); + + if ( !m_pImpl || !m_pImpl->m_rMutexRef.Is() ) + throw uno::RuntimeException(); // just a disaster + + m_pData = new WSInternalData_Impl( pImpl->m_rMutexRef, m_pImpl->m_nStorageType ); +} + +//----------------------------------------------- +OWriteStream::OWriteStream( OWriteStream_Impl* pImpl, uno::Reference< io::XStream > xStream, sal_Bool bTransacted ) +: m_pImpl( pImpl ) +, m_bInStreamDisconnected( sal_False ) +, m_bInitOnDemand( sal_False ) +, m_nInitPosition( 0 ) +, m_bTransacted( bTransacted ) +{ + OSL_ENSURE( pImpl && xStream.is(), "No base implementation!\n" ); + OSL_ENSURE( m_pImpl->m_rMutexRef.Is(), "No mutex!\n" ); + + if ( !m_pImpl || !m_pImpl->m_rMutexRef.Is() ) + throw uno::RuntimeException(); // just a disaster + + m_pData = new WSInternalData_Impl( pImpl->m_rMutexRef, m_pImpl->m_nStorageType ); + + if ( xStream.is() ) + { + m_xInStream = xStream->getInputStream(); + m_xOutStream = xStream->getOutputStream(); + m_xSeekable = uno::Reference< io::XSeekable >( xStream, uno::UNO_QUERY ); + OSL_ENSURE( m_xInStream.is() && m_xOutStream.is() && m_xSeekable.is(), "Stream implementation is incomplete!\n" ); + } +} + +//----------------------------------------------- +OWriteStream::~OWriteStream() +{ + { + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + if ( m_pImpl ) + { + m_refCount++; + try { + dispose(); + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + } + } + + if ( m_pData && m_pData->m_pTypeCollection ) + delete m_pData->m_pTypeCollection; + + if ( m_pData ) + delete m_pData; +} + +//----------------------------------------------- +void OWriteStream::DeInit() +{ + if ( !m_pImpl ) + return; // do nothing + + if ( m_xSeekable.is() ) + m_nInitPosition = m_xSeekable->getPosition(); + + m_xInStream = uno::Reference< io::XInputStream >(); + m_xOutStream = uno::Reference< io::XOutputStream >(); + m_xSeekable = uno::Reference< io::XSeekable >(); + m_bInitOnDemand = sal_True; +} + +//----------------------------------------------- +void OWriteStream::CheckInitOnDemand() +{ + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_bInitOnDemand ) + { + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" ); + uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream(); + if ( xStream.is() ) + { + m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW ); + m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW ); + m_xSeekable.set( xStream, uno::UNO_QUERY_THROW ); + m_xSeekable->seek( m_nInitPosition ); + + m_nInitPosition = 0; + m_bInitOnDemand = sal_False; + } + } +} + +//----------------------------------------------- +void OWriteStream::CopyToStreamInternally_Impl( const uno::Reference< io::XStream >& xDest ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_xInStream.is() ) + throw uno::RuntimeException(); + + if ( !m_xSeekable.is() ) + throw uno::RuntimeException(); + + uno::Reference< beans::XPropertySet > xDestProps( xDest, uno::UNO_QUERY ); + if ( !xDestProps.is() ) + throw uno::RuntimeException(); //TODO + + uno::Reference< io::XOutputStream > xDestOutStream = xDest->getOutputStream(); + if ( !xDestOutStream.is() ) + throw io::IOException(); // TODO + + sal_Int64 nCurPos = m_xSeekable->getPosition(); + m_xSeekable->seek( 0 ); + + uno::Exception eThrown; + sal_Bool bThrown = sal_False; + try { + ::comphelper::OStorageHelper::CopyInputToOutput( m_xInStream, xDestOutStream ); + } + catch ( uno::Exception& e ) + { + eThrown = e; + bThrown = sal_True; + } + + // position-related section below is critical + // if it fails the stream will become invalid + try { + m_xSeekable->seek( nCurPos ); + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + + // TODO: set the stoream in invalid state or dispose + OSL_ENSURE( sal_False, "The stream become invalid during copiing!\n" ); + throw uno::RuntimeException(); + } + + if ( bThrown ) + throw eThrown; + + // now the properties can be copied + // the order of the properties setting is not important for StorageStream API + ::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "Compressed" ); + xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) ); + if ( m_pData->m_nStorageType == PACKAGE_STORAGE || m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + aPropName = ::rtl::OUString::createFromAscii( "MediaType" ); + xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) ); + + if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + aPropName = ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ); + xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) ); + } + } +} + +//----------------------------------------------- +void OWriteStream::ModifyParentUnlockMutex_Impl( ::osl::ResettableMutexGuard& aGuard ) +{ + if ( m_pImpl->m_pParent ) + { + if ( m_pImpl->m_pParent->m_pAntiImpl ) + { + uno::Reference< util::XModifiable > xParentModif( (util::XModifiable*)(m_pImpl->m_pParent->m_pAntiImpl) ); + aGuard.clear(); + xParentModif->setModified( sal_True ); + } + else + m_pImpl->m_pParent->m_bIsModified = sal_True; + } +} + +//----------------------------------------------- +uno::Any SAL_CALL OWriteStream::queryInterface( const uno::Type& rType ) + throw( uno::RuntimeException ) +{ + uno::Any aReturn; + + // common interfaces + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<lang::XTypeProvider*> ( this ) + , static_cast<io::XInputStream*> ( this ) + , static_cast<io::XOutputStream*> ( this ) + , static_cast<io::XStream*> ( this ) + , static_cast<embed::XExtendedStorageStream*> ( this ) + , static_cast<io::XSeekable*> ( this ) + , static_cast<io::XTruncate*> ( this ) + , static_cast<lang::XComponent*> ( this ) + , static_cast<beans::XPropertySet*> ( this ) ); + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + + if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XEncryptionProtectedSource*> ( this ) ); + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XRelationshipAccess*> ( this ) ); + } + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + + if ( m_bTransacted ) + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XTransactedObject*> ( this ) + , static_cast<embed::XTransactionBroadcaster*> ( this ) ); + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + } + + return OWeakObject::queryInterface( rType ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::acquire() throw() +{ + OWeakObject::acquire(); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::release() throw() +{ + OWeakObject::release(); +} + +//----------------------------------------------- +uno::Sequence< uno::Type > SAL_CALL OWriteStream::getTypes() + throw( uno::RuntimeException ) +{ + if ( m_pData->m_pTypeCollection == NULL ) + { + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( m_pData->m_pTypeCollection == NULL ) + { + if ( m_bTransacted ) + { + if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XOutputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XSeekable >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XTruncate >* )NULL ) + , ::getCppuType( ( const uno::Reference< lang::XComponent >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XEncryptionProtectedSource >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XExtendedStorageStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XOutputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XSeekable >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XTruncate >* )NULL ) + , ::getCppuType( ( const uno::Reference< lang::XComponent >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XRelationshipAccess >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XExtendedStorageStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + else // if ( m_pData->m_nStorageType == ZIP_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XOutputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XSeekable >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XTruncate >* )NULL ) + , ::getCppuType( ( const uno::Reference< lang::XComponent >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XExtendedStorageStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + } + else + { + if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XOutputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XSeekable >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XTruncate >* )NULL ) + , ::getCppuType( ( const uno::Reference< lang::XComponent >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XEncryptionProtectedSource >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XOutputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XSeekable >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XTruncate >* )NULL ) + , ::getCppuType( ( const uno::Reference< lang::XComponent >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XRelationshipAccess >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + else // if ( m_pData->m_nStorageType == ZIP_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XOutputStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XStream >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XSeekable >* )NULL ) + , ::getCppuType( ( const uno::Reference< io::XTruncate >* )NULL ) + , ::getCppuType( ( const uno::Reference< lang::XComponent >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + } + } + } + + return m_pData->m_pTypeCollection->getTypes() ; +} + +//----------------------------------------------- +uno::Sequence< sal_Int8 > SAL_CALL OWriteStream::getImplementationId() + throw( uno::RuntimeException ) +{ + static ::cppu::OImplementationId* pID = NULL ; + + if ( pID == NULL ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ; + + if ( pID == NULL ) + { + static ::cppu::OImplementationId aID( sal_False ) ; + pID = &aID ; + } + } + + return pID->getImplementationId() ; + +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OWriteStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xInStream.is() ) + throw io::NotConnectedException(); + + return m_xInStream->readBytes( aData, nBytesToRead ); +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OWriteStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xInStream.is() ) + throw io::NotConnectedException(); + + return m_xInStream->readSomeBytes( aData, nMaxBytesToRead ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::skipBytes( sal_Int32 nBytesToSkip ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xInStream.is() ) + throw io::NotConnectedException(); + + m_xInStream->skipBytes( nBytesToSkip ); +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OWriteStream::available( ) + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xInStream.is() ) + throw io::NotConnectedException(); + + return m_xInStream->available(); + +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::closeInput( ) + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bInitOnDemand && ( m_bInStreamDisconnected || !m_xInStream.is() ) ) + throw io::NotConnectedException(); + + // the input part of the stream stays open for internal purposes ( to allow reading during copiing ) + // since it can not be reopened until output part is closed, it will be closed with output part. + m_bInStreamDisconnected = sal_True; + // m_xInStream->closeInput(); + // m_xInStream = uno::Reference< io::XInputStream >(); + + if ( !m_xOutStream.is() ) + dispose(); +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL OWriteStream::getInputStream() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bInitOnDemand && ( m_bInStreamDisconnected || !m_xInStream.is() ) ) + return uno::Reference< io::XInputStream >(); + + return uno::Reference< io::XInputStream >( static_cast< io::XInputStream* >( this ), uno::UNO_QUERY ); +} + +//----------------------------------------------- +uno::Reference< io::XOutputStream > SAL_CALL OWriteStream::getOutputStream() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xOutStream.is() ) + return uno::Reference< io::XOutputStream >(); + + return uno::Reference< io::XOutputStream >( static_cast< io::XOutputStream* >( this ), uno::UNO_QUERY ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::writeBytes( const uno::Sequence< sal_Int8 >& aData ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + // the write method makes initialization itself, since it depends from the aData length + // NO CheckInitOnDemand()! + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bInitOnDemand ) + { + if ( !m_xOutStream.is() || !m_xSeekable.is()) + throw io::NotConnectedException(); + + if ( m_pImpl->m_xCacheStream.is() ) + { + // check whether the cache should be turned off + sal_Int64 nPos = m_xSeekable->getPosition(); + if ( nPos + aData.getLength() > MAX_STORCACHE_SIZE ) + { + // disconnect the cache and copy the data to the temporary file + m_xSeekable->seek( 0 ); + + // it is enough to copy the cached stream, the cache should already contain everything + if ( m_pImpl->GetFilledTempFileIfNo( m_xInStream ).getLength() ) + { + DeInit(); + // the last position is known and it is differs from the current stream position + m_nInitPosition = nPos; + } + } + } + } + + if ( m_bInitOnDemand ) + { + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" ); + uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream(); + if ( xStream.is() ) + { + m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW ); + m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW ); + m_xSeekable.set( xStream, uno::UNO_QUERY_THROW ); + m_xSeekable->seek( m_nInitPosition ); + + m_nInitPosition = 0; + m_bInitOnDemand = sal_False; + } + } + + + if ( !m_xOutStream.is() ) + throw io::NotConnectedException(); + + m_xOutStream->writeBytes( aData ); + m_pImpl->m_bHasDataToFlush = sal_True; + + ModifyParentUnlockMutex_Impl( aGuard ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::flush() + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + // In case stream is flushed it's current version becomes visible + // to the parent storage. Usually parent storage flushes the stream + // during own commit but a user can explicitly flush the stream + // so the changes will be available through cloning functionality. + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bInitOnDemand ) + { + if ( !m_xOutStream.is() ) + throw io::NotConnectedException(); + + m_xOutStream->flush(); + m_pImpl->Commit(); + } +} + +//----------------------------------------------- +void OWriteStream::CloseOutput_Impl() +{ + // all the checks must be done in calling method + + m_xOutStream->closeOutput(); + m_xOutStream = uno::Reference< io::XOutputStream >(); + + if ( !m_bInitOnDemand ) + { + // after the stream is disposed it can be commited + // so transport correct size property + if ( !m_xSeekable.is() ) + throw uno::RuntimeException(); + + for ( sal_Int32 nInd = 0; nInd < m_pImpl->m_aProps.getLength(); nInd++ ) + { + if ( m_pImpl->m_aProps[nInd].Name.equalsAscii( "Size" ) ) + m_pImpl->m_aProps[nInd].Value <<= ((sal_Int32)m_xSeekable->getLength()); + } + } +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::closeOutput() + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xOutStream.is() ) + throw io::NotConnectedException(); + + CloseOutput_Impl(); + + if ( m_bInStreamDisconnected || !m_xInStream.is() ) + dispose(); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::seek( sal_Int64 location ) + throw ( lang::IllegalArgumentException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xSeekable.is() ) + throw uno::RuntimeException(); + + m_xSeekable->seek( location ); +} + +//----------------------------------------------- +sal_Int64 SAL_CALL OWriteStream::getPosition() + throw ( io::IOException, + uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xSeekable.is() ) + throw uno::RuntimeException(); + + return m_xSeekable->getPosition(); +} + +//----------------------------------------------- +sal_Int64 SAL_CALL OWriteStream::getLength() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xSeekable.is() ) + throw uno::RuntimeException(); + + return m_xSeekable->getLength(); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::truncate() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_xOutStream.is() ) + throw uno::RuntimeException(); + + uno::Reference< io::XTruncate > xTruncate( m_xOutStream, uno::UNO_QUERY ); + + if ( !xTruncate.is() ) + { + OSL_ENSURE( sal_False, "The output stream must support XTruncate interface!\n" ); + throw uno::RuntimeException(); + } + + xTruncate->truncate(); + + m_pImpl->m_bHasDataToFlush = sal_True; + + ModifyParentUnlockMutex_Impl( aGuard ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::dispose() + throw ( uno::RuntimeException ) +{ + // should be an internal method since it can be called only from parent storage + { + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_xOutStream.is() ) + CloseOutput_Impl(); + + if ( m_xInStream.is() ) + { + m_xInStream->closeInput(); + m_xInStream = uno::Reference< io::XInputStream >(); + } + + m_xSeekable = uno::Reference< io::XSeekable >(); + + m_pImpl->m_pAntiImpl = NULL; + + if ( !m_bInitOnDemand ) + { + try + { + if ( !m_bTransacted ) + { + m_pImpl->Commit(); + } + else + { + // throw away all the changes + m_pImpl->Revert(); + } + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( "Can not commit/revert the storage!\n" ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } + } + + m_pImpl = NULL; + } + + // the listener might try to get rid of parent storage, and the storage would delete this object; + // for now the listener is just notified at the end of the method to workaround the problem + // in future a more elegant way should be found + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + m_pData->m_aListenersContainer.disposeAndClear( aSource ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::addEventListener( + const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + m_pData->m_aListenersContainer.addInterface( ::getCppuType((const uno::Reference< lang::XEventListener >*)0), + xListener ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::removeEventListener( + const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + m_pData->m_aListenersContainer.removeInterface( ::getCppuType((const uno::Reference< lang::XEventListener >*)0), + xListener ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::setEncryptionPassword( const ::rtl::OUString& aPass ) + throw ( uno::RuntimeException, + io::IOException ) +{ + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!\n" ); + + m_pImpl->SetEncryptedWithPass( aPass ); + + ModifyParentUnlockMutex_Impl( aGuard ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::removeEncryption() + throw ( uno::RuntimeException, + io::IOException ) +{ + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + CheckInitOnDemand(); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!\n" ); + + m_pImpl->SetDecrypted(); + + ModifyParentUnlockMutex_Impl( aGuard ); +} + +//----------------------------------------------- +sal_Bool SAL_CALL OWriteStream::hasByID( const ::rtl::OUString& sID ) + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + try + { + getRelationshipByID( sID ); + return sal_True; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No Element" ) ) ); + } + + return sal_False; +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL OWriteStream::getTargetByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID ); + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( aSeq[nInd].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Target" ) ) ) + return aSeq[nInd].Second; + + return ::rtl::OUString(); +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL OWriteStream::getTypeByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID ); + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( aSeq[nInd].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Type" ) ) ) + return aSeq[nInd].Second; + + return ::rtl::OUString(); +} + +//----------------------------------------------- +uno::Sequence< beans::StringPair > SAL_CALL OWriteStream::getRelationshipByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Id" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + return aSeq[nInd1]; + break; + } + + throw container::NoSuchElementException(); +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OWriteStream::getRelationshipsByType( const ::rtl::OUString& sType ) + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< uno::Sequence< beans::StringPair > > aResult; + sal_Int32 nEntriesNum = 0; + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Type" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sType ) ) + { + aResult.realloc( nEntriesNum ); + aResult[nEntriesNum-1] = aSeq[nInd1]; + } + break; + } + + return aResult; +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OWriteStream::getAllRelationships() + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + return m_pImpl->GetAllRelationshipsIfAny(); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::insertRelationshipByID( const ::rtl::OUString& sID, const uno::Sequence< beans::StringPair >& aEntry, ::sal_Bool bReplace ) + throw ( container::ElementExistException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + ::rtl::OUString aIDTag( RTL_CONSTASCII_USTRINGPARAM( "Id" ) ); + + sal_Int32 nIDInd = -1; + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equals( aIDTag ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + nIDInd = nInd1; + + break; + } + + if ( nIDInd == -1 || bReplace ) + { + if ( nIDInd == -1 ) + { + nIDInd = aSeq.getLength(); + aSeq.realloc( nIDInd + 1 ); + } + + aSeq[nIDInd].realloc( aEntry.getLength() + 1 ); + + aSeq[nIDInd][0].First = aIDTag; + aSeq[nIDInd][0].Second = sID; + sal_Int32 nIndTarget = 1; + for ( sal_Int32 nIndOrig = 0; + nIndOrig < aEntry.getLength(); + nIndOrig++ ) + { + if ( !aEntry[nIndOrig].First.equals( aIDTag ) ) + aSeq[nIDInd][nIndTarget++] = aEntry[nIndOrig]; + } + + aSeq[nIDInd].realloc( nIndTarget ); + } + else + throw container::ElementExistException(); // TODO + + + m_pImpl->m_aNewRelInfo = aSeq; + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::removeRelationshipByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Id" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + { + sal_Int32 nLength = aSeq.getLength(); + aSeq[nInd1] = aSeq[nLength-1]; + aSeq.realloc( nLength - 1 ); + + m_pImpl->m_aNewRelInfo = aSeq; + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; + + // TODO/LATER: in future the unification of the ID could be checked + return; + } + + break; + } + + throw container::NoSuchElementException(); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::insertRelationships( const uno::Sequence< uno::Sequence< beans::StringPair > >& aEntries, ::sal_Bool bReplace ) + throw ( container::ElementExistException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + ::rtl::OUString aIDTag( RTL_CONSTASCII_USTRINGPARAM( "Id" ) ); + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + uno::Sequence< uno::Sequence< beans::StringPair > > aResultSeq( aSeq.getLength() + aEntries.getLength() ); + sal_Int32 nResultInd = 0; + + for ( sal_Int32 nIndTarget1 = 0; nIndTarget1 < aSeq.getLength(); nIndTarget1++ ) + for ( sal_Int32 nIndTarget2 = 0; nIndTarget2 < aSeq[nIndTarget1].getLength(); nIndTarget2++ ) + if ( aSeq[nIndTarget1][nIndTarget2].First.equals( aIDTag ) ) + { + sal_Int32 nIndSourceSame = -1; + + for ( sal_Int32 nIndSource1 = 0; nIndSource1 < aEntries.getLength(); nIndSource1++ ) + for ( sal_Int32 nIndSource2 = 0; nIndSource2 < aEntries[nIndSource1].getLength(); nIndSource2++ ) + { + if ( aEntries[nIndSource1][nIndSource2].First.equals( aIDTag ) ) + { + if ( aEntries[nIndSource1][nIndSource2].Second.equals( aSeq[nIndTarget1][nIndTarget2].Second ) ) + { + if ( !bReplace ) + throw container::ElementExistException(); + + nIndSourceSame = nIndSource1; + } + + break; + } + } + + if ( nIndSourceSame == -1 ) + { + // no such element in the provided sequence + aResultSeq[nResultInd++] = aSeq[nIndTarget1]; + } + + break; + } + + for ( sal_Int32 nIndSource1 = 0; nIndSource1 < aEntries.getLength(); nIndSource1++ ) + { + aResultSeq[nResultInd].realloc( aEntries[nIndSource1].getLength() ); + sal_Bool bHasID = sal_False; + sal_Int32 nResInd2 = 1; + + for ( sal_Int32 nIndSource2 = 0; nIndSource2 < aEntries[nIndSource1].getLength(); nIndSource2++ ) + if ( aEntries[nIndSource1][nIndSource2].First.equals( aIDTag ) ) + { + aResultSeq[nResultInd][0] = aEntries[nIndSource1][nIndSource2]; + bHasID = sal_True; + } + else if ( nResInd2 < aResultSeq[nResultInd].getLength() ) + aResultSeq[nResultInd][nResInd2++] = aEntries[nIndSource1][nIndSource2]; + else + throw io::IOException(); // TODO: illegal relation ( no ID ) + + if ( !bHasID ) + throw io::IOException(); // TODO: illegal relations + + nResultInd++; + } + + aResultSeq.realloc( nResultInd ); + m_pImpl->m_aNewRelInfo = aResultSeq; + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::clearRelationships() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException(); + + m_pImpl->m_aNewRelInfo.realloc( 0 ); + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; +} + +//----------------------------------------------- +uno::Reference< beans::XPropertySetInfo > SAL_CALL OWriteStream::getPropertySetInfo() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + //TODO: + return uno::Reference< beans::XPropertySetInfo >(); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::setPropertyValue( const ::rtl::OUString& aPropertyName, const uno::Any& aValue ) + throw ( beans::UnknownPropertyException, + beans::PropertyVetoException, + lang::IllegalArgumentException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + m_pImpl->GetStreamProperties(); + ::rtl::OUString aCompressedString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ); + ::rtl::OUString aMediaTypeString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + if ( m_pData->m_nStorageType == PACKAGE_STORAGE && aPropertyName.equals( aMediaTypeString ) ) + { + // if the "Compressed" property is not set explicitly, the MediaType can change the default value + sal_Bool bCompressedValueFromType = sal_True; + ::rtl::OUString aType; + aValue >>= aType; + + if ( !m_pImpl->m_bCompressedSetExplicit ) + { + if ( aType.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "image/jpeg" ) ) ) + || aType.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "image/png" ) ) ) + || aType.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "image/gif" ) ) ) ) + bCompressedValueFromType = sal_False; + } + + for ( sal_Int32 nInd = 0; nInd < m_pImpl->m_aProps.getLength(); nInd++ ) + { + if ( aPropertyName.equals( m_pImpl->m_aProps[nInd].Name ) ) + m_pImpl->m_aProps[nInd].Value = aValue; + else if ( !m_pImpl->m_bCompressedSetExplicit && aCompressedString.equals( m_pImpl->m_aProps[nInd].Name ) ) + m_pImpl->m_aProps[nInd].Value <<= bCompressedValueFromType; + } + } + else if ( aPropertyName.equals( aCompressedString ) ) + { + // if the "Compressed" property is not set explicitly, the MediaType can change the default value + m_pImpl->m_bCompressedSetExplicit = sal_True; + for ( sal_Int32 nInd = 0; nInd < m_pImpl->m_aProps.getLength(); nInd++ ) + { + if ( aPropertyName.equals( m_pImpl->m_aProps[nInd].Name ) ) + m_pImpl->m_aProps[nInd].Value = aValue; + } + } + else if ( m_pData->m_nStorageType == PACKAGE_STORAGE + && aPropertyName.equalsAscii( "UseCommonStoragePasswordEncryption" ) ) + { + sal_Bool bUseCommonPass = sal_False; + if ( aValue >>= bUseCommonPass ) + { + if ( m_bInitOnDemand && m_pImpl->m_bHasInsertedStreamOptimization ) + { + // the data stream is provided to the packagestream directly + m_pImpl->m_bUseCommonPass = bUseCommonPass; + } + else if ( bUseCommonPass ) + { + if ( !m_pImpl->m_bUseCommonPass ) + { + m_pImpl->SetDecrypted(); + m_pImpl->m_bUseCommonPass = sal_True; + } + } + else + m_pImpl->m_bUseCommonPass = sal_False; + } + else + throw lang::IllegalArgumentException(); //TODO + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE && aPropertyName.equals( aMediaTypeString ) ) + { + for ( sal_Int32 nInd = 0; nInd < m_pImpl->m_aProps.getLength(); nInd++ ) + { + if ( aPropertyName.equals( m_pImpl->m_aProps[nInd].Name ) ) + m_pImpl->m_aProps[nInd].Value = aValue; + } + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE && aPropertyName.equalsAscii( "RelationsInfoStream" ) ) + { + uno::Reference< io::XInputStream > xInRelStream; + if ( ( aValue >>= xInRelStream ) && xInRelStream.is() ) + { + uno::Reference< io::XSeekable > xSeek( xInRelStream, uno::UNO_QUERY ); + if ( !xSeek.is() ) + { + // currently this is an internal property that is used for optimization + // and the stream must support XSeekable interface + // TODO/LATER: in future it can be changed if property is used from outside + throw lang::IllegalArgumentException(); // TODO + } + + m_pImpl->m_xNewRelInfoStream = xInRelStream; + m_pImpl->m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED_STREAM; + } + else + throw lang::IllegalArgumentException(); // TODO + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE && aPropertyName.equalsAscii( "RelationsInfo" ) ) + { + if ( aValue >>= m_pImpl->m_aNewRelInfo ) + { + } + else + throw lang::IllegalArgumentException(); // TODO + } + else if ( aPropertyName.equalsAscii( "Size" ) ) + throw beans::PropertyVetoException(); // TODO + else if ( m_pData->m_nStorageType == PACKAGE_STORAGE + && ( aPropertyName.equalsAscii( "IsEncrypted" ) || aPropertyName.equalsAscii( "Encrypted" ) ) ) + throw beans::PropertyVetoException(); // TODO + else + throw beans::UnknownPropertyException(); // TODO + + m_pImpl->m_bHasDataToFlush = sal_True; + ModifyParentUnlockMutex_Impl( aGuard ); +} + + +//----------------------------------------------- +uno::Any SAL_CALL OWriteStream::getPropertyValue( const ::rtl::OUString& aProp ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( aProp.equalsAscii( "RelId" ) ) + { + return uno::makeAny( m_pImpl->GetNewRelId() ); + } + + ::rtl::OUString aPropertyName; + if ( aProp.equalsAscii( "IsEncrypted" ) ) + aPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Encrypted" ) ); + else + aPropertyName = aProp; + + if ( ( ( m_pData->m_nStorageType == PACKAGE_STORAGE || m_pData->m_nStorageType == OFOPXML_STORAGE ) + && aPropertyName.equalsAscii( "MediaType" ) ) + || m_pData->m_nStorageType == PACKAGE_STORAGE && aPropertyName.equalsAscii( "Encrypted" ) + || aPropertyName.equalsAscii( "Compressed" ) ) + { + m_pImpl->GetStreamProperties(); + + for ( sal_Int32 nInd = 0; nInd < m_pImpl->m_aProps.getLength(); nInd++ ) + { + if ( aPropertyName.equals( m_pImpl->m_aProps[nInd].Name ) ) + return m_pImpl->m_aProps[nInd].Value; + } + } + else if ( m_pData->m_nStorageType == PACKAGE_STORAGE + && aPropertyName.equalsAscii( "UseCommonStoragePasswordEncryption" ) ) + return uno::makeAny( m_pImpl->m_bUseCommonPass ); + else if ( aPropertyName.equalsAscii( "Size" ) ) + { + CheckInitOnDemand(); + + if ( !m_xSeekable.is() ) + throw uno::RuntimeException(); + + return uno::makeAny( (sal_Int32)m_xSeekable->getLength() ); + } + + throw beans::UnknownPropertyException(); // TODO +} + + +//----------------------------------------------- +void SAL_CALL OWriteStream::addPropertyChangeListener( + const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OWriteStream::removePropertyChangeListener( + const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OWriteStream::addVetoableChangeListener( + const ::rtl::OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OWriteStream::removeVetoableChangeListener( + const ::rtl::OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + //TODO: +} + +//____________________________________________________________________________________________________ +// XTransactedObject +//____________________________________________________________________________________________________ + +//----------------------------------------------- +void OWriteStream::BroadcastTransaction( sal_Int8 nMessage ) +/* + 1 - preCommit + 2 - commited + 3 - preRevert + 4 - reverted +*/ +{ + // no need to lock mutex here for the checking of m_pImpl, and m_pData is alive until the object is destructed + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + + ::cppu::OInterfaceContainerHelper* pContainer = + m_pData->m_aListenersContainer.getContainer( + ::getCppuType( ( const uno::Reference< embed::XTransactionListener >*) NULL ) ); + if ( pContainer ) + { + ::cppu::OInterfaceIteratorHelper pIterator( *pContainer ); + while ( pIterator.hasMoreElements( ) ) + { + OSL_ENSURE( nMessage >= 1 && nMessage <= 4, "Wrong internal notification code is used!\n" ); + + switch( nMessage ) + { + case STOR_MESS_PRECOMMIT: + ( ( embed::XTransactionListener* )pIterator.next( ) )->preCommit( aSource ); + break; + case STOR_MESS_COMMITED: + ( ( embed::XTransactionListener* )pIterator.next( ) )->commited( aSource ); + break; + case STOR_MESS_PREREVERT: + ( ( embed::XTransactionListener* )pIterator.next( ) )->preRevert( aSource ); + break; + case STOR_MESS_REVERTED: + ( ( embed::XTransactionListener* )pIterator.next( ) )->reverted( aSource ); + break; + } + } + } +} +//----------------------------------------------- +void SAL_CALL OWriteStream::commit() + throw ( io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OWriteStream::commit" ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bTransacted ) + throw uno::RuntimeException(); + + try { + BroadcastTransaction( STOR_MESS_PRECOMMIT ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + m_pImpl->Commit(); + + // when the storage is commited the parent is modified + ModifyParentUnlockMutex_Impl( aGuard ); + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString::createFromAscii( "Problems on commit!" ), + uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >( this ) ), + aCaught ); + } + + BroadcastTransaction( STOR_MESS_COMMITED ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::revert() + throw ( io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OWriteStream::revert" ); + + // the method removes all the changes done after last commit + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bTransacted ) + throw uno::RuntimeException(); + + BroadcastTransaction( STOR_MESS_PREREVERT ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + try { + m_pImpl->Revert(); + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString::createFromAscii( "Problems on revert!" ), + uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >( this ) ), + aCaught ); + } + + aGuard.clear(); + + BroadcastTransaction( STOR_MESS_REVERTED ); +} + +//____________________________________________________________________________________________________ +// XTransactionBroadcaster +//____________________________________________________________________________________________________ + +//----------------------------------------------- +void SAL_CALL OWriteStream::addTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bTransacted ) + throw uno::RuntimeException(); + + m_pData->m_aListenersContainer.addInterface( ::getCppuType((const uno::Reference< embed::XTransactionListener >*)0), + aListener ); +} + +//----------------------------------------------- +void SAL_CALL OWriteStream::removeTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException(); + } + + if ( !m_bTransacted ) + throw uno::RuntimeException(); + + m_pData->m_aListenersContainer.removeInterface( ::getCppuType((const uno::Reference< embed::XTransactionListener >*)0), + aListener ); +} + + diff --git a/package/source/xstor/owriteablestream.hxx b/package/source/xstor/owriteablestream.hxx new file mode 100644 index 000000000000..9e4c00d5a45d --- /dev/null +++ b/package/source/xstor/owriteablestream.hxx @@ -0,0 +1,414 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: owriteablestream.hxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WRITESTREAM_HXX_ +#define _WRITESTREAM_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/packages/XDataSinkEncrSupport.hpp> +#include <com/sun/star/packages/NoEncryptionException.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/embed/XEncryptionProtectedSource.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XRelationshipAccess.hpp> +#include <com/sun/star/embed/XExtendedStorageStream.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/StringPair.hpp> +#include <com/sun/star/logging/XSimpleLogRing.hpp> + + +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/interfacecontainer.h> + +#include <list> + +#include "ocompinstream.hxx" +#include "mutexholder.hxx" + + +struct PreCreationStruct +{ + SotMutexHolderRef m_rMutexRef; + + PreCreationStruct() + : m_rMutexRef( new SotMutexHolder ) + {} + +}; + +namespace cppu { + class OTypeCollection; +} + +namespace package { + void StaticAddLog( const ::rtl::OUString& aMessage ); + ::com::sun::star::uno::Sequence< sal_Int8 > MakeKeyFromPass( const ::rtl::OUString& aPass, sal_Bool bUseUTF ); +} + +struct WSInternalData_Impl +{ + SotMutexHolderRef m_rSharedMutexRef; + ::cppu::OTypeCollection* m_pTypeCollection; + ::cppu::OMultiTypeInterfaceContainerHelper m_aListenersContainer; // list of listeners + sal_Int16 m_nStorageType; + + // the mutex reference MUST NOT be empty + WSInternalData_Impl( const SotMutexHolderRef rMutexRef, sal_Int16 nStorageType ) + : m_rSharedMutexRef( rMutexRef ) + , m_pTypeCollection( NULL ) + , m_aListenersContainer( rMutexRef->GetMutex() ) + , m_nStorageType( nStorageType ) + {} +}; + +typedef ::std::list< OInputCompStream* > InputStreamsList_Impl; + +struct OStorage_Impl; +class OWriteStream; + +struct OWriteStream_Impl : public PreCreationStruct +{ + friend struct OStorage_Impl; + friend class OWriteStream; + friend class OInputCompStream; + + OWriteStream* m_pAntiImpl; + ::rtl::OUString m_aTempURL; + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > m_xCacheStream; + ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > m_xCacheSeek; + + InputStreamsList_Impl m_aInputStreamsList; + + sal_Bool m_bHasDataToFlush; // only modified elements will be sent to the original content + sal_Bool m_bFlushed; // sending the streams is coordinated by the root storage of the package + + ::com::sun::star::uno::Reference< ::com::sun::star::packages::XDataSinkEncrSupport > m_xPackageStream; + ::com::sun::star::uno::Reference< ::com::sun::star::logging::XSimpleLogRing > m_xLogRing; + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory; + + OStorage_Impl* m_pParent; + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_aProps; + + sal_Bool m_bForceEncrypted; + + sal_Bool m_bUseCommonPass; + sal_Bool m_bHasCachedPassword; + ::rtl::OUString m_aPass; + + sal_Bool m_bCompressedSetExplicit; + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > m_xPackage; + + sal_Bool m_bHasInsertedStreamOptimization; + + sal_Int16 m_nStorageType; + + // Relations info related data, stored in *.rels file in OFOPXML format + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xOrigRelInfoStream; + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > m_aOrigRelInfo; + sal_Bool m_bOrigRelInfoBroken; + + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > m_aNewRelInfo; + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xNewRelInfoStream; + sal_Int16 m_nRelInfoStatus; + sal_Int32 m_nRelId; + + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > GetServiceFactory(); + + ::rtl::OUString GetFilledTempFileIfNo( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xStream ); + ::rtl::OUString FillTempGetFileName(); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > GetTempFileAsStream(); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetTempFileAsInputStream(); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > GetStream_Impl( sal_Int32 nStreamMode, + sal_Bool bHierarchyAccess ); + + ::rtl::OUString GetCommonRootPass() throw ( ::com::sun::star::packages::NoEncryptionException ); + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > ReadPackageStreamProperties(); + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > InsertOwnProps( + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps, + sal_Bool bUseCommonPass ); + +public: + OWriteStream_Impl( + OStorage_Impl* pParent, + const ::com::sun::star::uno::Reference< ::com::sun::star::packages::XDataSinkEncrSupport >& xPackageStream, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory >& xPackage, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory, + sal_Bool bForceEncrypted, + sal_Int16 nStorageType, + sal_Bool bDefaultCompress, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xRelInfoStream = + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >() ); + + ~OWriteStream_Impl(); + + void CleanCacheStream(); + + void AddLog( const ::rtl::OUString& aMessage ); + + sal_Bool UsesCommonPass_Impl() { return m_bUseCommonPass; } + sal_Bool HasTempFile_Impl() { return ( m_aTempURL.getLength() != 0 ); } + sal_Bool IsTransacted(); + + sal_Bool HasWriteOwner_Impl() { return ( m_pAntiImpl != NULL ); } + + void InsertIntoPackageFolder( + const ::rtl::OUString& aName, + const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& xParentPackageFolder ); + + void SetToBeCommited() { m_bFlushed = sal_True; } + + sal_Bool HasCachedPassword() { return m_bHasCachedPassword; } + ::rtl::OUString GetCachedPassword() { return m_aPass; } + sal_Bool IsModified() { return m_bHasDataToFlush || m_bFlushed; } + + sal_Bool IsEncrypted(); + void SetDecrypted(); + void SetEncryptedWithPass( const ::rtl::OUString& aPass ); + + void DisposeWrappers(); + + void InsertStreamDirectly( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps ); + + void Commit(); + void Revert(); + + void Free( sal_Bool bMust ); // allows to try to disconnect from the temporary stream + // in case bMust is set to sal_True the method + // will throw exception in case the file is still busy + + void SetModified(); // can be done only by parent storage after renaming + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > GetStreamProperties(); + + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > GetAllRelationshipsIfAny(); + + void CopyInternallyTo_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xDestStream, + const ::rtl::OUString& aPass ); + void CopyInternallyTo_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xDestStream ); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > GetStream( + sal_Int32 nStreamMode, + const ::rtl::OUString& aPass, + sal_Bool bHierarchyAccess ); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > GetStream( + sal_Int32 nStreamMode, + sal_Bool bHierarchyAccess ); + + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetRawInStream(); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetPlainRawInStream(); + + void InputStreamDisposed( OInputCompStream* pStream ); + + void CreateReadonlyCopyBasedOnData( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xDataToCopy, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps, + sal_Bool bUseCommonPass, + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xTargetStream ); + + void GetCopyOfLastCommit( ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xTargetStream ); + void GetCopyOfLastCommit( + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xTargetStream, + const ::rtl::OUString& aPass ); + + + void CommitStreamRelInfo( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xRelStorage, + const ::rtl::OUString& aOrigStreamName, + const ::rtl::OUString& aNewStreamName ); + + void ReadRelInfoIfNecessary(); + + sal_Int32 GetNewRelId() { return m_nRelId ++; } +}; + +class OWriteStream : ::com::sun::star::lang::XTypeProvider + , public ::com::sun::star::io::XInputStream + , public ::com::sun::star::io::XOutputStream + , public ::com::sun::star::embed::XExtendedStorageStream + , public ::com::sun::star::io::XSeekable + , public ::com::sun::star::io::XTruncate + , public ::com::sun::star::embed::XEncryptionProtectedSource + , public ::com::sun::star::embed::XRelationshipAccess + , public ::com::sun::star::embed::XTransactedObject + , public ::com::sun::star::embed::XTransactionBroadcaster + , public ::com::sun::star::beans::XPropertySet + , public ::cppu::OWeakObject +{ + friend struct OWriteStream_Impl; + +protected: + ::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > m_xInStream; + ::com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > m_xOutStream; + ::com::sun::star::uno::Reference < ::com::sun::star::io::XSeekable > m_xSeekable; + + OWriteStream_Impl* m_pImpl; + WSInternalData_Impl* m_pData; + + sal_Bool m_bInStreamDisconnected; + sal_Bool m_bInitOnDemand; + sal_Int64 m_nInitPosition; + + sal_Bool m_bTransacted; + + OWriteStream( OWriteStream_Impl* pImpl, sal_Bool bTransacted ); + OWriteStream( OWriteStream_Impl* pImpl, ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xStream, sal_Bool bTransacted ); + + void CloseOutput_Impl(); + + void CopyToStreamInternally_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + + void ModifyParentUnlockMutex_Impl( ::osl::ResettableMutexGuard& aGuard ); + + void BroadcastTransaction( sal_Int8 nMessage ); + +public: + + virtual ~OWriteStream(); + + void CheckInitOnDemand(); + void DeInit(); + + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& rType ) + throw( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + // XTypeProvider + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes() + throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() + throw( ::com::sun::star::uno::RuntimeException ); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + // XOutputStream + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL flush( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeOutput( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XStream + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream( ) throw (::com::sun::star::uno::RuntimeException); + + // XTruncate + virtual void SAL_CALL truncate() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XComponent + virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + //XEncryptionProtectedSource + virtual void SAL_CALL setEncryptionPassword( const ::rtl::OUString& aPass ) + throw ( ::com::sun::star::uno::RuntimeException, + ::com::sun::star::io::IOException ); + virtual void SAL_CALL removeEncryption() + throw ( ::com::sun::star::uno::RuntimeException, + ::com::sun::star::io::IOException ); + + //XRelationshipAccess + virtual ::sal_Bool SAL_CALL hasByID( const ::rtl::OUString& sID ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTargetByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTypeByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > SAL_CALL getRelationshipByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > SAL_CALL getRelationshipsByType( const ::rtl::OUString& sType ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > SAL_CALL getAllRelationships( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRelationshipByID( const ::rtl::OUString& sID, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aEntry, ::sal_Bool bReplace ) throw (::com::sun::star::container::ElementExistException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeRelationshipByID( const ::rtl::OUString& sID ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRelationships( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > >& aEntries, ::sal_Bool bReplace ) throw (::com::sun::star::container::ElementExistException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL clearRelationships( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() throw ( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw ( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ); + + // XTransactedObject + virtual void SAL_CALL commit() + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL revert() + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + // XTransactionBroadcaster + virtual void SAL_CALL addTransactionListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XTransactionListener >& aListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL removeTransactionListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XTransactionListener >& aListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + +}; + +#endif + diff --git a/package/source/xstor/register.cxx b/package/source/xstor/register.cxx new file mode 100644 index 000000000000..8fc10a4a64b4 --- /dev/null +++ b/package/source/xstor/register.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: register.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" + + +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/registry/InvalidRegistryException.hpp> +#include <cppuhelper/factory.hxx> + +#include "xfactory.hxx" + +using namespace ::com::sun::star; + + +extern "C" { + +void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +void * SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = 0; + + ::rtl::OUString aImplName( ::rtl::OUString::createFromAscii( pImplName ) ); + uno::Reference< lang::XSingleServiceFactory > xFactory; + + if ( pServiceManager && aImplName.equals( OStorageFactory::impl_staticGetImplementationName() ) ) + { + xFactory= ::cppu::createOneInstanceFactory( reinterpret_cast< lang::XMultiServiceFactory*>( pServiceManager ), + OStorageFactory::impl_staticGetImplementationName(), + OStorageFactory::impl_staticCreateSelfInstance, + OStorageFactory::impl_staticGetSupportedServiceNames() ); + } + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + +sal_Bool SAL_CALL component_writeInfo( void * /*pServiceManager*/, void * pRegistryKey ) +{ + if (pRegistryKey) + { + try + { + uno::Reference< registry::XRegistryKey > xKey( reinterpret_cast< registry::XRegistryKey* >( pRegistryKey ) ); + + uno::Reference< registry::XRegistryKey > xNewKey; + + xNewKey = xKey->createKey( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("/") ) + + OStorageFactory::impl_staticGetImplementationName() + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/UNO/SERVICES") ) ); + + const uno::Sequence< ::rtl::OUString > aServices = OStorageFactory::impl_staticGetSupportedServiceNames(); + for( sal_Int32 ind = 0; ind < aServices.getLength(); ind++ ) + xNewKey->createKey( aServices.getConstArray()[ind] ); + + return sal_True; + } + catch (registry::InvalidRegistryException &) + { + OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); + } + } + return sal_False; +} + +} // extern "C" + diff --git a/package/source/xstor/selfterminatefilestream.cxx b/package/source/xstor/selfterminatefilestream.cxx new file mode 100644 index 000000000000..ebb707e59de6 --- /dev/null +++ b/package/source/xstor/selfterminatefilestream.cxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ocompinstream.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" + +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> + +#include "selfterminatefilestream.hxx" +#include <comphelper/processfactory.hxx> + +using namespace ::com::sun::star; + +//----------------------------------------------- +OSelfTerminateFileStream::OSelfTerminateFileStream( const uno::Reference< lang::XMultiServiceFactory > xFactory, const ::rtl::OUString& aURL ) +: m_aURL( aURL ) +{ + uno::Reference< lang::XMultiServiceFactory > xOwnFactory = xFactory; + if ( !xOwnFactory.is() ) + xOwnFactory.set( ::comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); + + // IMPORTANT: The implementation is based on idea that m_xFileAccess, m_xInputStream and m_xSeekable are always set + // otherwise an exception is thrown in constructor + + m_xFileAccess.set( xOwnFactory->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY_THROW ); + + m_xInputStream.set( m_xFileAccess->openFileRead( aURL ), uno::UNO_SET_THROW ); + m_xSeekable.set( m_xInputStream, uno::UNO_QUERY_THROW ); +} + +//----------------------------------------------- +OSelfTerminateFileStream::~OSelfTerminateFileStream() +{ + CloseStreamDeleteFile(); +} + +//----------------------------------------------- +void OSelfTerminateFileStream::CloseStreamDeleteFile() +{ + try + { + m_xInputStream->closeInput(); + } + catch( uno::Exception& ) + {} + + try + { + m_xFileAccess->kill( m_aURL ); + } + catch( uno::Exception& ) + {} +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OSelfTerminateFileStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + return m_xInputStream->readBytes( aData, nBytesToRead ); +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OSelfTerminateFileStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + return m_xInputStream->readSomeBytes( aData, nMaxBytesToRead ); +} + +//----------------------------------------------- +void SAL_CALL OSelfTerminateFileStream::skipBytes( sal_Int32 nBytesToSkip ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + return m_xInputStream->skipBytes( nBytesToSkip ); +} + +//----------------------------------------------- +sal_Int32 SAL_CALL OSelfTerminateFileStream::available( ) + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + return m_xInputStream->available(); +} + +//----------------------------------------------- +void SAL_CALL OSelfTerminateFileStream::closeInput( ) + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + CloseStreamDeleteFile(); +} + +//----------------------------------------------- +void SAL_CALL OSelfTerminateFileStream::seek( sal_Int64 location ) + throw ( lang::IllegalArgumentException, + io::IOException, + uno::RuntimeException ) +{ + m_xSeekable->seek( location ); +} + +//----------------------------------------------- +sal_Int64 SAL_CALL OSelfTerminateFileStream::getPosition() + throw ( io::IOException, + uno::RuntimeException) +{ + return m_xSeekable->getPosition(); +} + +//----------------------------------------------- +sal_Int64 SAL_CALL OSelfTerminateFileStream::getLength() + throw ( io::IOException, + uno::RuntimeException ) +{ + return m_xSeekable->getLength(); +} + diff --git a/package/source/xstor/selfterminatefilestream.hxx b/package/source/xstor/selfterminatefilestream.hxx new file mode 100644 index 000000000000..6f95ba17ec42 --- /dev/null +++ b/package/source/xstor/selfterminatefilestream.hxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ocompinstream.hxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SELFTERMINATEFILESTREAM_HXX_ +#define _SELFTERMINATEFILESTREAM_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <cppuhelper/implbase2.hxx> + +struct OWriteStream_Impl; + +class OSelfTerminateFileStream : public cppu::WeakImplHelper2< ::com::sun::star::io::XInputStream, + ::com::sun::star::io::XSeekable > +{ +protected: + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > m_xFileAccess; + + ::rtl::OUString m_aURL; + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xInputStream; + ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > m_xSeekable; + +public: + OSelfTerminateFileStream( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, const ::rtl::OUString& aURL ); + + virtual ~OSelfTerminateFileStream(); + + void CloseStreamDeleteFile(); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available() + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput() + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + //XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/package/source/xstor/switchpersistencestream.cxx b/package/source/xstor/switchpersistencestream.cxx new file mode 100644 index 000000000000..1409a1a5efac --- /dev/null +++ b/package/source/xstor/switchpersistencestream.cxx @@ -0,0 +1,491 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: switchpersistencestream.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <osl/diagnose.h> + +#include <comphelper/storagehelper.hxx> +#include <switchpersistencestream.hxx> + +using namespace ::com::sun::star; + +// ======================================================================== +struct SPStreamData_Impl +{ + uno::Reference< lang::XMultiServiceFactory > m_xFactory; + + sal_Bool m_bInStreamBased; + + // the streams below are not visible from outside so there is no need to remember position + + // original stream related members + uno::Reference< io::XStream > m_xOrigStream; + uno::Reference< io::XTruncate > m_xOrigTruncate; + uno::Reference< io::XSeekable > m_xOrigSeekable; + uno::Reference< io::XInputStream > m_xOrigInStream; + uno::Reference< io::XOutputStream > m_xOrigOutStream; + + sal_Bool m_bInOpen; + sal_Bool m_bOutOpen; + + + SPStreamData_Impl( + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + sal_Bool bInStreamBased, + const uno::Reference< io::XStream >& xOrigStream, + const uno::Reference< io::XTruncate >& xOrigTruncate, + const uno::Reference< io::XSeekable >& xOrigSeekable, + const uno::Reference< io::XInputStream >& xOrigInStream, + const uno::Reference< io::XOutputStream >& xOrigOutStream, + sal_Bool bInOpen, + sal_Bool bOutOpen ) + : m_xFactory( xFactory ) + , m_bInStreamBased( bInStreamBased ) + , m_xOrigStream( xOrigStream ) + , m_xOrigTruncate( xOrigTruncate ) + , m_xOrigSeekable( xOrigSeekable ) + , m_xOrigInStream( xOrigInStream ) + , m_xOrigOutStream( xOrigOutStream ) + , m_bInOpen( bInOpen ) + , m_bOutOpen( bOutOpen ) + { + } +}; + +// ======================================================================== +// ------------------------------------------------------------------------ +SwitchablePersistenceStream::SwitchablePersistenceStream( + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + const uno::Reference< io::XStream >& xStream ) +: m_xFactory( xFactory ) +, m_pStreamData( NULL ) +{ + SwitchPersistenceTo( xStream ); +} + +// ------------------------------------------------------------------------ +SwitchablePersistenceStream::SwitchablePersistenceStream( + const uno::Reference< lang::XMultiServiceFactory >& xFactory, + const uno::Reference< io::XInputStream >& xInputStream ) +: m_xFactory( xFactory ) +, m_pStreamData( NULL ) +{ + SwitchPersistenceTo( xInputStream ); +} + +// ------------------------------------------------------------------------ +SwitchablePersistenceStream::~SwitchablePersistenceStream() +{ + CloseAll_Impl(); +} + +// ------------------------------------------------------------------------ +void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XStream >& xStream ) +{ + uno::Reference< io::XTruncate > xNewTruncate( xStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XSeekable > xNewSeekable( xStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XInputStream > xNewInStream = xStream->getInputStream(); + uno::Reference< io::XOutputStream > xNewOutStream = xStream->getOutputStream(); + if ( !xNewInStream.is() || !xNewOutStream.is() ) + throw uno::RuntimeException(); + + sal_Int64 nPos = 0; + sal_Bool bInOpen = sal_False; + sal_Bool bOutOpen = sal_False; + + if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() ) + { + // check that the length is the same + if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() ) + throw uno::RuntimeException(); + + // get the current position + nPos = m_pStreamData->m_xOrigSeekable->getPosition(); + bInOpen = m_pStreamData->m_bInOpen; + bOutOpen = m_pStreamData->m_bOutOpen; + } + + xNewSeekable->seek( nPos ); + + CloseAll_Impl(); + + m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_False, + xStream, xNewTruncate, xNewSeekable, xNewInStream, xNewOutStream, + bInOpen, bOutOpen ); +} + +// ------------------------------------------------------------------------ +void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XInputStream >& xInputStream ) +{ + uno::Reference< io::XStream > xNewStream; + uno::Reference< io::XTruncate > xNewTruncate; + uno::Reference< io::XSeekable > xNewSeekable( xInputStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XOutputStream > xNewOutStream; + if ( !xInputStream.is() ) + throw uno::RuntimeException(); + + sal_Int64 nPos = 0; + sal_Bool bInOpen = sal_False; + sal_Bool bOutOpen = sal_False; + + if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() ) + { + // check that the length is the same + if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() ) + throw uno::RuntimeException(); + + // get the current position + nPos = m_pStreamData->m_xOrigSeekable->getPosition(); + bInOpen = m_pStreamData->m_bInOpen; + bOutOpen = m_pStreamData->m_bOutOpen; + } + + xNewSeekable->seek( nPos ); + + CloseAll_Impl(); + + m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_True, + xNewStream, xNewTruncate, xNewSeekable, xInputStream, xNewOutStream, + bInOpen, bOutOpen ); + +} + +// ------------------------------------------------------------------------ +void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference< io::XStream >& xStream ) +{ + uno::Reference< io::XStream > xTargetStream = xStream; + uno::Reference< io::XSeekable > xTargetSeek; + + if ( !xTargetStream.is() ) + { + xTargetStream = uno::Reference < io::XStream >( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY_THROW ); + + xTargetSeek = uno::Reference< io::XSeekable >( xTargetStream, uno::UNO_QUERY_THROW ); + } + else + { + // the provided stream must be empty + xTargetSeek = uno::Reference< io::XSeekable >( xTargetStream, uno::UNO_QUERY_THROW ); + if ( xTargetSeek->getLength() ) + throw io::IOException(); + } + + uno::Reference< io::XTruncate > xTargetTruncate( xTargetStream, uno::UNO_QUERY_THROW ); + uno::Reference< io::XInputStream > xTargetInStream = xTargetStream->getInputStream(); + uno::Reference< io::XOutputStream > xTargetOutStream = xTargetStream->getOutputStream(); + if ( !xTargetInStream.is() || !xTargetOutStream.is() ) + throw uno::RuntimeException(); + + if ( !m_pStreamData->m_xOrigInStream.is() || !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + sal_Int64 nPos = m_pStreamData->m_xOrigSeekable->getPosition(); + m_pStreamData->m_xOrigSeekable->seek( 0 ); + ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData->m_xOrigInStream, xTargetOutStream ); + xTargetOutStream->flush(); + xTargetSeek->seek( nPos ); + + sal_Bool bInOpen = m_pStreamData->m_bInOpen; + sal_Bool bOutOpen = m_pStreamData->m_bOutOpen; + + CloseAll_Impl(); + + m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_False, + xTargetStream, xTargetTruncate, xTargetSeek, xTargetInStream, xTargetOutStream, + bInOpen, bOutOpen ); +} + +// ------------------------------------------------------------------------ +void SwitchablePersistenceStream::CloseAll_Impl() +{ + if ( m_pStreamData ) + { + delete m_pStreamData; + m_pStreamData = NULL; + } +} + +// com::sun::star::io::XStream +// ------------------------------------------------------------------------ +uno::Reference< io::XInputStream > SAL_CALL SwitchablePersistenceStream::getInputStream( ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pStreamData ) + m_pStreamData->m_bInOpen = sal_True; + return static_cast< io::XInputStream* >( this ); +} + + +// ------------------------------------------------------------------------ +uno::Reference< io::XOutputStream > SAL_CALL SwitchablePersistenceStream::getOutputStream( ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pStreamData ) + m_pStreamData->m_bOutOpen = sal_True; + return static_cast< io::XOutputStream* >( this ); +} + + + +// com::sun::star::io::XInputStream +// ------------------------------------------------------------------------ +::sal_Int32 SAL_CALL SwitchablePersistenceStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead ); +} + + +// ------------------------------------------------------------------------ +::sal_Int32 SAL_CALL SwitchablePersistenceStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigInStream->readBytes( aData, nMaxBytesToRead ); +} + +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip ); +} + + +// ------------------------------------------------------------------------ +::sal_Int32 SAL_CALL SwitchablePersistenceStream::available( ) + throw (io::NotConnectedException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigInStream.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigInStream->available(); +} + + +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::closeInput() + throw (io::NotConnectedException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + m_pStreamData->m_bInOpen = sal_False; + if ( !m_pStreamData->m_bOutOpen ) + CloseAll_Impl(); +} + + + +// com::sun::star::io::XOutputStream +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bInStreamBased ) + throw io::IOException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigOutStream->writeBytes( aData ); +} + + +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::flush( ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData || m_pStreamData->m_bInStreamBased ) + { + OSL_ENSURE( sal_False, "flush() is not acceptable!\n" ); + return; + // in future throw exception, for now some code might call flush() on closed stream + // since file ucp implementation allows it + // throw io::NotConnectedException(); + } + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigOutStream.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigOutStream->flush(); +} + + +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::closeOutput( ) + throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + m_pStreamData->m_bOutOpen = sal_False; + if ( !m_pStreamData->m_bInOpen ) + CloseAll_Impl(); +} + + + +// com::sun::star::io::XTruncate +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::truncate( ) + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + if ( m_pStreamData->m_bInStreamBased ) + throw io::IOException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigTruncate.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigTruncate->truncate(); +} + + +// com::sun::star::io::XSeekable +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::seek( ::sal_Int64 location ) + throw (lang::IllegalArgumentException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + m_pStreamData->m_xOrigSeekable->seek( location ); +} + + +// ------------------------------------------------------------------------ +::sal_Int64 SAL_CALL SwitchablePersistenceStream::getPosition( ) + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigSeekable->getPosition(); +} + + +// ------------------------------------------------------------------------ +::sal_Int64 SAL_CALL SwitchablePersistenceStream::getLength( ) + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + // the original stream data should be provided + if ( !m_pStreamData->m_xOrigSeekable.is() ) + throw uno::RuntimeException(); + + return m_pStreamData->m_xOrigSeekable->getLength(); +} + +// ------------------------------------------------------------------------ +void SAL_CALL SwitchablePersistenceStream::waitForCompletion() + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + if ( !m_pStreamData ) + throw io::NotConnectedException(); + + uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY ); + if ( asyncOutputMonitor.is() ) + asyncOutputMonitor->waitForCompletion(); +} + diff --git a/package/source/xstor/switchpersistencestream.hxx b/package/source/xstor/switchpersistencestream.hxx new file mode 100644 index 000000000000..abc42175d9dd --- /dev/null +++ b/package/source/xstor/switchpersistencestream.hxx @@ -0,0 +1,123 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: switchpersistencestream.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SPSTREAM_HXX +#define _SPSTREAM_HXX + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/io/XAsyncOutputMonitor.hpp> +#include <osl/mutex.hxx> +#include <cppuhelper/implbase6.hxx> + +//================================================================== +// SwitchablePersistenceStream +// +// Allows to switch the stream persistence on the fly. The target +// stream ( if not filled by the implementation ) MUST have the same +// size as the original one! +//================================================================== + +struct SPStreamData_Impl; +class SwitchablePersistenceStream + : public ::cppu::WeakImplHelper6 < + ::com::sun::star::io::XStream, + ::com::sun::star::io::XInputStream, + ::com::sun::star::io::XOutputStream, + ::com::sun::star::io::XTruncate, + ::com::sun::star::io::XSeekable, + ::com::sun::star::io::XAsyncOutputMonitor > +{ + ::osl::Mutex m_aMutex; + + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory; + + SPStreamData_Impl* m_pStreamData; + + void CloseAll_Impl(); + +public: + + SwitchablePersistenceStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + + SwitchablePersistenceStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream ); + + ~SwitchablePersistenceStream(); + + void SwitchPersistenceTo( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + + void SwitchPersistenceTo( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInputStream ); + + void CopyAndSwitchPersistenceTo( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ); + +// com::sun::star::io::XStream + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream( ) throw (::com::sun::star::uno::RuntimeException); + +// com::sun::star::io::XInputStream + virtual ::sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL available( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +// com::sun::star::io::XOutputStream + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL flush( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeOutput( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +// com::sun::star::io::XTruncate + virtual void SAL_CALL truncate( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +// com::sun::star::io::XSeekable + virtual void SAL_CALL seek( ::sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int64 SAL_CALL getPosition( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int64 SAL_CALL getLength( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +// ::com::sun::star::io::XAsyncOutputMonitor + virtual void SAL_CALL waitForCompletion( ) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +}; + +#endif //_SPSTREAM_HXX + + diff --git a/package/source/xstor/xfactory.cxx b/package/source/xstor/xfactory.cxx new file mode 100644 index 000000000000..1c94efafdf05 --- /dev/null +++ b/package/source/xstor/xfactory.cxx @@ -0,0 +1,311 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xfactory.cxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/io/XSeekable.hpp> + + +#include "xfactory.hxx" +#include "xstorage.hxx" + + +using namespace ::com::sun::star; + +//------------------------------------------------------------------------- +sal_Bool CheckPackageSignature_Impl( const uno::Reference< io::XInputStream >& xInputStream, + const uno::Reference< io::XSeekable >& xSeekable ) +{ + if ( !xInputStream.is() || !xSeekable.is() ) + throw uno::RuntimeException(); + + if ( xSeekable->getLength() ) + { + uno::Sequence< sal_Int8 > aData( 4 ); + xSeekable->seek( 0 ); + sal_Int32 nRead = xInputStream->readBytes( aData, 4 ); + xSeekable->seek( 0 ); + + // TODO/LATER: should the disk spanned files be supported? + // 0x50, 0x4b, 0x07, 0x08 + return ( nRead == 4 && aData[0] == 0x50 && aData[1] == 0x4b && aData[2] == 0x03 && aData[3] == 0x04 ); + } + else + return sal_True; // allow to create a storage based on empty stream +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OStorageFactory::impl_staticGetSupportedServiceNames() +{ + uno::Sequence< ::rtl::OUString > aRet(2); + aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.embed.StorageFactory"); + aRet[1] = ::rtl::OUString::createFromAscii("com.sun.star.comp.embed.StorageFactory"); + return aRet; +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OStorageFactory::impl_staticGetImplementationName() +{ + return ::rtl::OUString::createFromAscii("com.sun.star.comp.embed.StorageFactory"); +} + +//------------------------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::impl_staticCreateSelfInstance( + const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) +{ + return uno::Reference< uno::XInterface >( *new OStorageFactory( xServiceManager ) ); +} + +//------------------------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstance() + throw ( uno::Exception, + uno::RuntimeException ) +{ + // TODO: reimplement TempStream service to support XStream interface + uno::Reference < io::XStream > xTempStream( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY ); + + if ( !xTempStream.is() ) + throw uno::RuntimeException(); // TODO: + + return uno::Reference< uno::XInterface >( + static_cast< OWeakObject* >( new OStorage( xTempStream, + embed::ElementModes::READWRITE, + uno::Sequence< beans::PropertyValue >(), + m_xFactory, + PACKAGE_STORAGE ) ), + uno::UNO_QUERY ); +} + +//------------------------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstanceWithArguments( + const uno::Sequence< uno::Any >& aArguments ) + throw ( uno::Exception, + uno::RuntimeException ) +{ + // The request for storage can be done with up to three arguments + + // The first argument specifies a source for the storage + // it can be URL, XStream, XInputStream. + // The second value is a mode the storage should be open in. + // And the third value is a media descriptor. + + sal_Int32 nArgNum = aArguments.getLength(); + OSL_ENSURE( nArgNum < 4, "Wrong parameter number" ); + + if ( !nArgNum ) + return createInstance(); + + // first try to retrieve storage open mode if any + // by default the storage will be open in readonly mode + sal_Int32 nStorageMode = embed::ElementModes::READ; + if ( nArgNum >= 2 ) + { + if( !( aArguments[1] >>= nStorageMode ) ) + { + OSL_ENSURE( sal_False, "Wrong second argument!\n" ); + throw lang::IllegalArgumentException(); // TODO: + } + // it's allways possible to read written storage in this implementation + nStorageMode |= embed::ElementModes::READ; + } + + if ( ( nStorageMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE + && ( nStorageMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE ) + throw lang::IllegalArgumentException(); // TODO: + + // retrieve storage source stream + ::rtl::OUString aURL; + uno::Reference< io::XStream > xStream; + uno::Reference< io::XInputStream > xInputStream; + + if ( aArguments[0] >>= aURL ) + { + if ( !aURL.getLength() ) + { + OSL_ENSURE( sal_False, "Empty URL is provided!\n" ); + throw lang::IllegalArgumentException(); // TODO: + } + + if ( aURL.equalsIgnoreAsciiCaseAsciiL( "vnd.sun.star.pkg", 16 ) ) + { + OSL_ENSURE( sal_False, "Packages URL's are not valid for storages!\n" ); // ??? + throw lang::IllegalArgumentException(); // TODO: + } + + uno::Reference < ::com::sun::star::ucb::XSimpleFileAccess > xTempAccess( + m_xFactory->createInstance ( + ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + + if ( !xTempAccess.is() ) + throw uno::RuntimeException(); // TODO: + + if ( nStorageMode & embed::ElementModes::WRITE ) + xStream = xTempAccess->openFileReadWrite( aURL ); + else + xInputStream = xTempAccess->openFileRead( aURL ); + } + else if ( !( aArguments[0] >>= xStream ) && !( aArguments[0] >>= xInputStream ) ) + { + OSL_ENSURE( sal_False, "Wrong first argument!\n" ); + throw uno::Exception(); // TODO: Illegal argument + } + + // retrieve mediadescriptor and set storage properties + uno::Sequence< beans::PropertyValue > aDescr; + uno::Sequence< beans::PropertyValue > aPropsToSet; + + sal_Int16 nStorageType = PACKAGE_STORAGE; + + if ( nArgNum >= 3 ) + { + if( aArguments[2] >>= aDescr ) + { + if ( aURL.getLength() ) + { + aPropsToSet.realloc(1); + aPropsToSet[0].Name = ::rtl::OUString::createFromAscii( "URL" ); + aPropsToSet[0].Value <<= aURL; + } + + for ( sal_Int32 nInd = 0, nNumArgs = 1; nInd < aDescr.getLength(); nInd++ ) + { + if ( aDescr[nInd].Name.equalsAscii( "InteractionHandler" ) + || aDescr[nInd].Name.equalsAscii( "Password" ) + || aDescr[nInd].Name.equalsAscii( "RepairPackage" ) + || aDescr[nInd].Name.equalsAscii( "StatusIndicator" ) ) + // || aDescr[nInd].Name.equalsAscii( "Unpacked" ) // TODO: + { + aPropsToSet.realloc( ++nNumArgs ); + aPropsToSet[nNumArgs-1].Name = aDescr[nInd].Name; + aPropsToSet[nNumArgs-1].Value = aDescr[nInd].Value; + } + else if ( aDescr[nInd].Name.equalsAscii( "StorageFormat" ) ) + { + ::rtl::OUString aFormatName; + aDescr[nInd].Value >>= aFormatName; + if ( aFormatName.equalsAscii( "PackageFormat" ) ) + nStorageType = PACKAGE_STORAGE; + else if ( aFormatName.equalsAscii( "ZipFormat" ) ) + nStorageType = ZIP_STORAGE; + else if ( aFormatName.equalsAscii( "OFOPXMLFormat" ) ) + nStorageType = OFOPXML_STORAGE; + else + throw lang::IllegalArgumentException(); // TODO: + } + else + OSL_ENSURE( sal_False, "Unacceptable property, will be ignored!\n" ); + } + } + else + { + OSL_ENSURE( sal_False, "Wrong third argument!\n" ); + throw uno::Exception(); // TODO: Illegal argument + } + + } + + // create storage based on source + if ( xInputStream.is() ) + { + // if xInputStream is set the storage should be open from it + if ( ( nStorageMode & embed::ElementModes::WRITE ) ) + throw uno::Exception(); // TODO: access denied + + uno::Reference< io::XSeekable > xSeekable( xInputStream, uno::UNO_QUERY ); + if ( !xSeekable.is() ) + { + // TODO: wrap stream to let it be seekable + OSL_ENSURE( sal_False, "Nonseekable streams are not supported for now!\n" ); + } + + if ( !CheckPackageSignature_Impl( xInputStream, xSeekable ) ) + throw io::IOException(); // TODO: this is not a package file + + return uno::Reference< uno::XInterface >( + static_cast< OWeakObject* >( new OStorage( xInputStream, nStorageMode, aPropsToSet, m_xFactory, nStorageType ) ), + uno::UNO_QUERY ); + } + else if ( xStream.is() ) + { + if ( ( nStorageMode & embed::ElementModes::WRITE ) && !xStream->getOutputStream().is() + || !xStream->getInputStream().is() ) + throw uno::Exception(); // TODO: access denied + + uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY ); + if ( !xSeekable.is() ) + { + // TODO: wrap stream to let it be seekable + OSL_ENSURE( sal_False, "Nonseekable streams are not supported for now!\n" ); + } + + if ( !CheckPackageSignature_Impl( xStream->getInputStream(), xSeekable ) ) + throw io::IOException(); // TODO: this is not a package file + + return uno::Reference< uno::XInterface >( + static_cast< OWeakObject* >( new OStorage( xStream, nStorageMode, aPropsToSet, m_xFactory, nStorageType ) ), + uno::UNO_QUERY ); + } + + throw uno::Exception(); // general error during creation +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OStorageFactory::getImplementationName() + throw ( uno::RuntimeException ) +{ + return impl_staticGetImplementationName(); +} + +//------------------------------------------------------------------------- +sal_Bool SAL_CALL OStorageFactory::supportsService( const ::rtl::OUString& ServiceName ) + throw ( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OStorageFactory::getSupportedServiceNames() + throw ( uno::RuntimeException ) +{ + return impl_staticGetSupportedServiceNames(); +} + diff --git a/package/source/xstor/xfactory.hxx b/package/source/xstor/xfactory.hxx new file mode 100644 index 000000000000..aec3b5ad0bd4 --- /dev/null +++ b/package/source/xstor/xfactory.hxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xfactory.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __XFACTORY_HXX_ +#define __XFACTORY_HXX_ + +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + + +#include <cppuhelper/implbase2.hxx> + + +class OStorage; + +class OStorageFactory : public ::cppu::WeakImplHelper2< ::com::sun::star::lang::XSingleServiceFactory, + ::com::sun::star::lang::XServiceInfo > +{ + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory; + +public: + OStorageFactory( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory ) + : m_xFactory( xFactory ) + { + OSL_ENSURE( xFactory.is(), "No service manager is provided!\n" ); + } + + static ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + impl_staticGetSupportedServiceNames(); + + static ::rtl::OUString SAL_CALL impl_staticGetImplementationName(); + + static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL + impl_staticCreateSelfInstance( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ); + + + // XSingleServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance() throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw (::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/package/source/xstor/xstor.dxp b/package/source/xstor/xstor.dxp new file mode 100644 index 000000000000..9630d7e06768 --- /dev/null +++ b/package/source/xstor/xstor.dxp @@ -0,0 +1,3 @@ +component_getImplementationEnvironment +component_writeInfo +component_getFactory diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx new file mode 100644 index 000000000000..74c30049e9bd --- /dev/null +++ b/package/source/xstor/xstorage.cxx @@ -0,0 +1,6177 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xstorage.cxx,v $ + * $Revision: 1.33 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/UseBackupException.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/util/XCloneable.hpp> + + +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/beans/NamedValue.hpp> + + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <rtl/logfile.hxx> + +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/ofopxmlhelper.hxx> + +#include "xstorage.hxx" +#include "owriteablestream.hxx" +#include "disposelistener.hxx" +#include "switchpersistencestream.hxx" +#include "ohierarchyholder.hxx" + +using namespace ::com::sun::star; + +//========================================================= + +typedef ::std::list< uno::WeakReference< lang::XComponent > > WeakComponentList; + +struct StorInternalData_Impl +{ + SotMutexHolderRef m_rSharedMutexRef; + ::cppu::OMultiTypeInterfaceContainerHelper m_aListenersContainer; // list of listeners + ::cppu::OTypeCollection* m_pTypeCollection; + sal_Bool m_bIsRoot; + sal_Int16 m_nStorageType; // the mode in wich the storage is used + sal_Bool m_bReadOnlyWrap; + + OChildDispListener_Impl* m_pSubElDispListener; + + WeakComponentList m_aOpenSubComponentsList; + + ::rtl::Reference< OHierarchyHolder_Impl > m_rHierarchyHolder; + + // the mutex reference MUST NOT be empty + StorInternalData_Impl( const SotMutexHolderRef& rMutexRef, sal_Bool bRoot, sal_Int16 nStorType, sal_Bool bReadOnlyWrap ) + : m_rSharedMutexRef( rMutexRef ) + , m_aListenersContainer( rMutexRef->GetMutex() ) + , m_pTypeCollection( NULL ) + , m_bIsRoot( bRoot ) + , m_nStorageType( nStorType ) + , m_bReadOnlyWrap( bReadOnlyWrap ) + , m_pSubElDispListener( NULL ) + {} + + ~StorInternalData_Impl(); +}; + +//========================================================= +::rtl::OUString GetNewTempFileURL( const uno::Reference< lang::XMultiServiceFactory > xFactory ); + +// static +void OStorage_Impl::completeStorageStreamCopy_Impl( + const uno::Reference< io::XStream >& xSource, + const uno::Reference< io::XStream >& xDest, + sal_Int16 nStorageType, + const uno::Sequence< uno::Sequence< beans::StringPair > >& aRelInfo ) +{ + uno::Reference< beans::XPropertySet > xSourceProps( xSource, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xDestProps( xDest, uno::UNO_QUERY ); + if ( !xSourceProps.is() || !xDestProps.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XOutputStream > xDestOutStream = xDest->getOutputStream(); + if ( !xDestOutStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XInputStream > xSourceInStream = xSource->getInputStream(); + if ( !xSourceInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // TODO: headers of encripted streams should be copied also + ::comphelper::OStorageHelper::CopyInputToOutput( xSourceInStream, xDestOutStream ); + + uno::Sequence< ::rtl::OUString > aPropNames( 1 ); + aPropNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ); + + if ( nStorageType == PACKAGE_STORAGE ) + { + aPropNames.realloc( 3 ); + aPropNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + aPropNames[2] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) ); + } + else if ( nStorageType == OFOPXML_STORAGE ) + { + // TODO/LATER: in future it might make sence to provide the stream if there is one + uno::Reference< embed::XRelationshipAccess > xRelAccess( xDest, uno::UNO_QUERY_THROW ); + xRelAccess->clearRelationships(); + xRelAccess->insertRelationships( aRelInfo, sal_False ); + + aPropNames.realloc( 2 ); + aPropNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + } + + for ( int ind = 0; ind < aPropNames.getLength(); ind++ ) + xDestProps->setPropertyValue( aPropNames[ind], xSourceProps->getPropertyValue( aPropNames[ind] ) ); +} + +uno::Reference< io::XInputStream > GetSeekableTempCopy( uno::Reference< io::XInputStream > xInStream, + uno::Reference< lang::XMultiServiceFactory > xFactory ) +{ + uno::Reference < io::XOutputStream > xTempOut( + xFactory->createInstance ( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + uno::Reference < io::XInputStream > xTempIn( xTempOut, uno::UNO_QUERY ); + + if ( !xTempOut.is() || !xTempIn.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOut ); + xTempOut->closeOutput(); + + return xTempIn; +} + +StorInternalData_Impl::~StorInternalData_Impl() +{ + if ( m_pTypeCollection ) + delete m_pTypeCollection; +} + + +SotElement_Impl::SotElement_Impl( const ::rtl::OUString& rName, sal_Bool bStor, sal_Bool bNew ) +: m_aName( rName ) +, m_aOriginalName( rName ) +, m_bIsRemoved( sal_False ) +, m_bIsInserted( bNew ) +, m_bIsStorage( bStor ) +, m_pStorage( NULL ) +, m_pStream( NULL ) +{ +} + +SotElement_Impl::~SotElement_Impl() +{ + if ( m_pStorage ) + delete m_pStorage; + + if ( m_pStream ) + delete m_pStream; +} + +//----------------------------------------------- +// most of properties are holt by the storage but are not used +OStorage_Impl::OStorage_Impl( uno::Reference< io::XInputStream > xInputStream, + sal_Int32 nMode, + uno::Sequence< beans::PropertyValue > xProperties, + uno::Reference< lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ) +: m_rMutexRef( new SotMutexHolder ) +, m_pAntiImpl( NULL ) +, m_nStorageMode( nMode & ~embed::ElementModes::SEEKABLE ) +, m_bIsModified( ( nMode & ( embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE ) ) == ( embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE ) ) +, m_bBroadcastModified( sal_False ) +, m_bCommited( sal_False ) +, m_bIsRoot( sal_True ) +, m_bListCreated( sal_False ) +, m_xFactory( xFactory ) +, m_xProperties( xProperties ) +, m_bHasCommonPassword( sal_False ) +, m_pParent( NULL ) +, m_bControlMediaType( sal_False ) +, m_bMTFallbackUsed( sal_False ) +, m_bControlVersion( sal_False ) +, m_pSwitchStream( NULL ) +, m_nStorageType( nStorageType ) +, m_pRelStorElement( NULL ) +, m_nRelInfoStatus( RELINFO_NO_INIT ) +{ + // all the checks done below by assertion statements must be done by factory + OSL_ENSURE( xInputStream.is(), "No input stream is provided!\n" ); + + m_pSwitchStream = (SwitchablePersistenceStream*) new SwitchablePersistenceStream( xFactory, xInputStream ); + m_xInputStream = m_pSwitchStream->getInputStream(); + + if ( m_nStorageMode & embed::ElementModes::WRITE ) + { + // check that the stream allows to write + OSL_ENSURE( sal_False, "No stream for writing is provided!\n" ); + } +} + +//----------------------------------------------- +// most of properties are holt by the storage but are not used +OStorage_Impl::OStorage_Impl( uno::Reference< io::XStream > xStream, + sal_Int32 nMode, + uno::Sequence< beans::PropertyValue > xProperties, + uno::Reference< lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ) +: m_rMutexRef( new SotMutexHolder ) +, m_pAntiImpl( NULL ) +, m_nStorageMode( nMode & ~embed::ElementModes::SEEKABLE ) +, m_bIsModified( ( nMode & ( embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE ) ) == ( embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE ) ) +, m_bBroadcastModified( sal_False ) +, m_bCommited( sal_False ) +, m_bIsRoot( sal_True ) +, m_bListCreated( sal_False ) +, m_xFactory( xFactory ) +, m_xProperties( xProperties ) +, m_bHasCommonPassword( sal_False ) +, m_pParent( NULL ) +, m_bControlMediaType( sal_False ) +, m_bMTFallbackUsed( sal_False ) +, m_bControlVersion( sal_False ) +, m_pSwitchStream( NULL ) +, m_nStorageType( nStorageType ) +, m_pRelStorElement( NULL ) +, m_nRelInfoStatus( RELINFO_NO_INIT ) +{ + // all the checks done below by assertion statements must be done by factory + OSL_ENSURE( xStream.is(), "No stream is provided!\n" ); + + if ( m_nStorageMode & embed::ElementModes::WRITE ) + { + m_pSwitchStream = (SwitchablePersistenceStream*) new SwitchablePersistenceStream( xFactory, xStream ); + m_xStream = static_cast< io::XStream* >( m_pSwitchStream ); + } + else + { + m_pSwitchStream = (SwitchablePersistenceStream*) new SwitchablePersistenceStream( xFactory, + xStream->getInputStream() ); + m_xInputStream = m_pSwitchStream->getInputStream(); + } +} + +//----------------------------------------------- +OStorage_Impl::OStorage_Impl( OStorage_Impl* pParent, + sal_Int32 nMode, + uno::Reference< container::XNameContainer > xPackageFolder, + uno::Reference< lang::XSingleServiceFactory > xPackage, + uno::Reference< lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ) +: m_rMutexRef( new SotMutexHolder ) +, m_pAntiImpl( NULL ) +, m_nStorageMode( nMode & ~embed::ElementModes::SEEKABLE ) +, m_bIsModified( ( nMode & ( embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE ) ) == ( embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE ) ) +, m_bBroadcastModified( sal_False ) +, m_bCommited( sal_False ) +, m_bIsRoot( sal_False ) +, m_bListCreated( sal_False ) +, m_xPackageFolder( xPackageFolder ) +, m_xPackage( xPackage ) +, m_xFactory( xFactory ) +, m_bHasCommonPassword( sal_False ) +, m_pParent( pParent ) // can be empty in case of temporary readonly substorages and relation storage +, m_bControlMediaType( sal_False ) +, m_bMTFallbackUsed( sal_False ) +, m_bControlVersion( sal_False ) +, m_pSwitchStream( NULL ) +, m_nStorageType( nStorageType ) +, m_pRelStorElement( NULL ) +, m_nRelInfoStatus( RELINFO_NO_INIT ) +{ + OSL_ENSURE( xPackageFolder.is(), "No package folder!\n" ); +} + +//----------------------------------------------- +OStorage_Impl::~OStorage_Impl() +{ + { + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + if ( m_pAntiImpl ) // root storage wrapper must set this member to NULL before destruction of object + { + OSL_ENSURE( !m_bIsRoot, "The root storage wrapper must be disposed already" ); + + try { + m_pAntiImpl->InternalDispose( sal_False ); + } + catch ( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + m_pAntiImpl = NULL; + } + else if ( !m_aReadOnlyWrapList.empty() ) + { + for ( OStorageList_Impl::iterator pStorageIter = m_aReadOnlyWrapList.begin(); + pStorageIter != m_aReadOnlyWrapList.end(); pStorageIter++ ) + { + uno::Reference< embed::XStorage > xTmp = pStorageIter->m_xWeakRef; + if ( xTmp.is() ) + try { + pStorageIter->m_pPointer->InternalDispose( sal_False ); + } catch( uno::Exception& aException ) + { + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + } + + m_aReadOnlyWrapList.clear(); + } + + m_pParent = NULL; + } + + for ( SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + pElementIter != m_aChildrenList.end(); pElementIter++ ) + delete *pElementIter; + + m_aChildrenList.clear(); + + for ( SotElementList_Impl::iterator pDeletedIter = m_aDeletedList.begin(); + pDeletedIter != m_aDeletedList.end(); pDeletedIter++ ) + delete *pDeletedIter; + + m_aDeletedList.clear(); + + if ( m_nStorageType == OFOPXML_STORAGE && m_pRelStorElement ) + { + delete m_pRelStorElement; + m_pRelStorElement = NULL; + } + + m_xPackageFolder = uno::Reference< container::XNameContainer >(); + m_xPackage = uno::Reference< lang::XSingleServiceFactory >(); + + ::rtl::OUString aPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ); + for ( sal_Int32 aInd = 0; aInd < m_xProperties.getLength(); aInd++ ) + { + if ( m_xProperties[aInd].Name.equals( aPropertyName ) ) + { + // the storage is URL based so all the streams are opened by factory and should be closed + try + { + if ( m_xInputStream.is() ) + { + m_xInputStream->closeInput(); + m_xInputStream = uno::Reference< io::XInputStream >(); + } + + if ( m_xStream.is() ) + { + uno::Reference< io::XInputStream > xInStr = m_xStream->getInputStream(); + if ( xInStr.is() ) + xInStr->closeInput(); + + uno::Reference< io::XOutputStream > xOutStr = m_xStream->getOutputStream(); + if ( xOutStr.is() ) + xOutStr->closeOutput(); + + m_xStream = uno::Reference< io::XStream >(); + } + } + catch( uno::Exception& aException ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + AddLog( aException.Message ); + } + } + } +} + +//----------------------------------------------- +void OStorage_Impl::AddLog( const ::rtl::OUString& aMessage ) +{ + if ( !m_xLogRing.is() ) + { + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + if ( aContext.is() ) + m_xLogRing.set( aContext.getSingleton( "com.sun.star.logging.DocumentIOLogRing" ), uno::UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + { + // No log + } + } + + if ( m_xLogRing.is() ) + m_xLogRing->logString( aMessage ); +} + +//----------------------------------------------- +void OStorage_Impl::SetReadOnlyWrap( OStorage& aStorage ) +{ + // Weak reference is used inside the holder so the refcount must not be zero at this point + OSL_ENSURE( aStorage.GetRefCount_Impl(), "There must be a reference alive to use this method!\n" ); + m_aReadOnlyWrapList.push_back( StorageHolder_Impl( &aStorage ) ); +} + +//----------------------------------------------- +void OStorage_Impl::RemoveReadOnlyWrap( OStorage& aStorage ) +{ + for ( OStorageList_Impl::iterator pStorageIter = m_aReadOnlyWrapList.begin(); + pStorageIter != m_aReadOnlyWrapList.end();) + { + uno::Reference< embed::XStorage > xTmp = pStorageIter->m_xWeakRef; + if ( !xTmp.is() || pStorageIter->m_pPointer == &aStorage ) + { + try { + pStorageIter->m_pPointer->InternalDispose( sal_False ); + } catch( uno::Exception& aException ) + { + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + AddLog( aException.Message ); + } + + OStorageList_Impl::iterator pIterToDelete( pStorageIter ); + pStorageIter++; + m_aReadOnlyWrapList.erase( pIterToDelete ); + } + else + pStorageIter++; + } +} + +//----------------------------------------------- +void OStorage_Impl::OpenOwnPackage() +{ + OSL_ENSURE( m_bIsRoot, "Opening of the package has no sence!\n" ); + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xPackageFolder.is() ) + { + if ( !m_xPackage.is() ) + { + uno::Sequence< uno::Any > aArguments( 2 ); + if ( m_nStorageMode & embed::ElementModes::WRITE ) + aArguments[ 0 ] <<= m_xStream; + else + { + OSL_ENSURE( m_xInputStream.is(), "Input stream must be set for readonly access!\n" ); + aArguments[ 0 ] <<= m_xInputStream; + // TODO: if input stream is not seekable or XSeekable interface is supported + // on XStream object a wrapper must be used + } + + // do not allow elements to remove themself from the old container in case of insertion to another container + aArguments[ 1 ] <<= beans::NamedValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AllowRemoveOnInsert" ) ), + uno::makeAny( (sal_Bool)sal_False ) ); + + sal_Int32 nArgNum = 2; + for ( sal_Int32 aInd = 0; aInd < m_xProperties.getLength(); aInd++ ) + { + if ( m_xProperties[aInd].Name.equalsAscii( "RepairPackage" ) + || m_xProperties[aInd].Name.equalsAscii( "ProgressHandler" ) ) + { + beans::NamedValue aNamedValue( m_xProperties[aInd].Name, + m_xProperties[aInd].Value ); + aArguments.realloc( ++nArgNum ); + aArguments[nArgNum-1] <<= aNamedValue; + } + else if ( m_xProperties[aInd].Name.equalsAscii( "Password" ) ) + { + // TODO: implement password setting for documents + // the password entry must be removed after setting + } + } + + if ( m_nStorageType == ZIP_STORAGE ) + { + // let the package support only plain zip format + beans::NamedValue aNamedValue; + aNamedValue.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) ); + aNamedValue.Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ZipFormat" ) ); + aArguments.realloc( ++nArgNum ); + aArguments[nArgNum-1] <<= aNamedValue; + } + else if ( m_nStorageType == OFOPXML_STORAGE ) + { + // let the package support OFOPXML media type handling + beans::NamedValue aNamedValue; + aNamedValue.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) ); + aNamedValue.Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OFOPXMLFormat" ) ); + aArguments.realloc( ++nArgNum ); + aArguments[nArgNum-1] <<= aNamedValue; + } + + m_xPackage = uno::Reference< lang::XSingleServiceFactory > ( + GetServiceFactory()->createInstanceWithArguments( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.packages.comp.ZipPackage" ) ), + aArguments ), + uno::UNO_QUERY ); + } + + uno::Reference< container::XHierarchicalNameAccess > xHNameAccess( m_xPackage, uno::UNO_QUERY ); + OSL_ENSURE( xHNameAccess.is(), "The package could not be created!\n" ); + + if ( xHNameAccess.is() ) + { + uno::Any aFolder = xHNameAccess->getByHierarchicalName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) ); + aFolder >>= m_xPackageFolder; + } + } + + OSL_ENSURE( m_xPackageFolder.is(), "The package root folder can not be opened!\n" ); + if ( !m_xPackageFolder.is() ) + throw embed::InvalidStorageException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//----------------------------------------------- +uno::Reference< lang::XMultiServiceFactory > OStorage_Impl::GetServiceFactory() +{ + if ( m_xFactory.is() ) + return m_xFactory; + + return ::comphelper::getProcessServiceFactory(); +} + +//----------------------------------------------- +SotElementList_Impl& OStorage_Impl::GetChildrenList() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + ReadContents(); + return m_aChildrenList; +} + +//----------------------------------------------- +void OStorage_Impl::GetStorageProperties() +{ + if ( m_nStorageType == PACKAGE_STORAGE ) + { + uno::Reference< beans::XPropertySet > xProps( m_xPackageFolder, uno::UNO_QUERY_THROW ); + + if ( !m_bControlMediaType ) + { + uno::Reference< beans::XPropertySet > xPackageProps( m_xPackage, uno::UNO_QUERY_THROW ); + xPackageProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaTypeFallbackUsed" ) ) ) >>= m_bMTFallbackUsed; + + xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ) ) >>= m_aMediaType; + m_bControlMediaType = sal_True; + } + + if ( !m_bControlVersion ) + { + xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= m_aVersion; + m_bControlVersion = sal_True; + } + } + + // the properties of OFOPXML will be handled directly +} + +//----------------------------------------------- +void OStorage_Impl::ReadRelInfoIfNecessary() +{ + if ( m_nStorageType != OFOPXML_STORAGE ) + return; + + if ( m_nRelInfoStatus == RELINFO_NO_INIT ) + { + // Init from original stream + uno::Reference< io::XInputStream > xRelInfoStream = GetRelInfoStreamForName( ::rtl::OUString() ); + if ( xRelInfoStream.is() ) + m_aRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence( + xRelInfoStream, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels/.rels" ) ), + m_xFactory ); + + m_nRelInfoStatus = RELINFO_READ; + } + else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + // Init from the new stream + try + { + if ( m_xNewRelInfoStream.is() ) + m_aRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence( + m_xNewRelInfoStream, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels/.rels" ) ), + m_xFactory ); + + m_nRelInfoStatus = RELINFO_CHANGED_STREAM_READ; + } + catch( uno::Exception ) + { + m_nRelInfoStatus = RELINFO_CHANGED_BROKEN; + } + } +} + +//----------------------------------------------- +void OStorage_Impl::ReadContents() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( m_bListCreated ) + return; + + if ( m_bIsRoot ) + OpenOwnPackage(); + + uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xPackageFolder, uno::UNO_QUERY ); + if ( !xEnumAccess.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration(); + if ( !xEnum.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_bListCreated = sal_True; + + while( xEnum->hasMoreElements() ) + { + try { + uno::Reference< container::XNamed > xNamed; + xEnum->nextElement() >>= xNamed; + + if ( !xNamed.is() ) + { + OSL_ENSURE( sal_False, "XNamed is not supported!\n" ); + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + ::rtl::OUString aName = xNamed->getName(); + OSL_ENSURE( aName.getLength(), "Empty name!\n" ); + + uno::Reference< container::XNameContainer > xNameContainer( xNamed, uno::UNO_QUERY ); + + SotElement_Impl* pNewElement = new SotElement_Impl( aName, xNameContainer.is(), sal_False ); + if ( m_nStorageType == OFOPXML_STORAGE && aName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + { + if ( !pNewElement->m_bIsStorage ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: Unexpected format + + m_pRelStorElement = pNewElement; + CreateRelStorage(); + } + else + { + if ( ( m_nStorageMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE ) + { + // if a storage is truncated all of it elements are marked as deleted + pNewElement->m_bIsRemoved = sal_True; + } + + m_aChildrenList.push_back( pNewElement ); + } + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + AddLog( aNoSuchElementException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "NoSuchElement" ) ) ); + + OSL_ENSURE( sal_False, "hasMoreElements() implementation has problems!\n" ); + break; + } + } + if ( ( m_nStorageMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE ) + { + // if a storage is truncated the relations information should be cleaned + m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_aRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_nRelInfoStatus = RELINFO_CHANGED; + } + + // cache changeable folder properties + GetStorageProperties(); +} + +//----------------------------------------------- +void OStorage_Impl::CopyToStorage( const uno::Reference< embed::XStorage >& xDest, sal_Bool bDirect ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + uno::Reference< beans::XPropertySet > xPropSet( xDest, uno::UNO_QUERY ); + if ( !xPropSet.is() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + sal_Int32 nDestMode = embed::ElementModes::READ; + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) ) >>= nDestMode; + + if ( !( nDestMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + + ReadContents(); + + if ( !m_xPackageFolder.is() ) + throw embed::InvalidStorageException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + for ( SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + pElementIter != m_aChildrenList.end(); pElementIter++ ) + { + if ( !(*pElementIter)->m_bIsRemoved ) + CopyStorageElement( *pElementIter, xDest, (*pElementIter)->m_aName, bDirect ); + } + + // move storage properties to the destination one ( means changeable properties ) + if ( m_nStorageType == PACKAGE_STORAGE ) + { + ::rtl::OUString aMediaTypeString = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ); + ::rtl::OUString aVersionString = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ); + xPropSet->setPropertyValue( aMediaTypeString, uno::makeAny( m_aMediaType ) ); + xPropSet->setPropertyValue( aVersionString, uno::makeAny( m_aVersion ) ); + } + + if ( m_nStorageType == PACKAGE_STORAGE ) + { + // if this is a root storage, the common key from current one should be moved there + sal_Bool bIsRoot = sal_False; + ::rtl::OUString aRootString = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsRoot" ) ); + if ( ( xPropSet->getPropertyValue( aRootString ) >>= bIsRoot ) && bIsRoot ) + { + try + { + ::rtl::OUString aCommonPass = GetCommonRootPass(); + uno::Reference< embed::XEncryptionProtectedSource > xEncr( xDest, uno::UNO_QUERY ); + if ( xEncr.is() ) + xEncr->setEncryptionPassword( aCommonPass ); + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + AddLog( aNoEncryptionException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No Encryption" ) ) ); + } + } + } + else if ( m_nStorageType == OFOPXML_STORAGE ) + { + + // TODO/LATER: currently the optimization is not active + // uno::Reference< io::XInputStream > xRelInfoStream = GetRelInfoStreamForName( ::rtl::OUString() ); // own stream + // if ( xRelInfoStream.is() ) + // { + // // Relations info stream is a writeonly property, introduced only to optimyze copying + // // Should be used carefuly since no check for stream consistency is done, and the stream must not stay locked + // + // ::rtl::OUString aRelInfoString = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RelationsInfoStream" ) ); + // xPropSet->setPropertyValue( aRelInfoString, uno::makeAny( GetSeekableTempCopy( xRelInfoStream, m_xFactory ) ) ); + // } + + uno::Reference< embed::XRelationshipAccess > xRels( xDest, uno::UNO_QUERY ); + if ( !xRels.is() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + xRels->insertRelationships( GetAllRelationshipsIfAny(), sal_False ); + } + + // if possible the destination storage should be commited after successful copying + uno::Reference< embed::XTransactedObject > xObjToCommit( xDest, uno::UNO_QUERY ); + if ( xObjToCommit.is() ) + xObjToCommit->commit(); +} + +//----------------------------------------------- +void OStorage_Impl::CopyStorageElement( SotElement_Impl* pElement, + uno::Reference< embed::XStorage > xDest, + ::rtl::OUString aName, + sal_Bool bDirect ) +{ + OSL_ENSURE( xDest.is(), "No destination storage!\n" ); + OSL_ENSURE( aName.getLength(), "Empty element name!\n" ); + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + uno::Reference< container::XNameAccess > xDestAccess( xDest, uno::UNO_QUERY ); + if ( !xDestAccess.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( xDestAccess->hasByName( aName ) + && !( pElement->m_bIsStorage && xDest->isStorageElement( aName ) ) ) + xDest->removeElement( aName ); + + if ( pElement->m_bIsStorage ) + { + uno::Reference< embed::XStorage > xSubDest = + xDest->openStorageElement( aName, + embed::ElementModes::WRITE ); + + OSL_ENSURE( xSubDest.is(), "No destination substorage!\n" ); + + if ( !pElement->m_pStorage ) + { + OpenSubStorage( pElement, embed::ElementModes::READ ); + if ( !pElement->m_pStorage ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + pElement->m_pStorage->CopyToStorage( xSubDest, bDirect ); + } + else + { + if ( !pElement->m_pStream ) + { + OpenSubStream( pElement ); + if ( !pElement->m_pStream ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !pElement->m_pStream->IsEncrypted() ) + { + if ( bDirect ) + { + // fill in the properties for the stream + uno::Sequence< beans::PropertyValue > aStrProps(0); + uno::Sequence< beans::PropertyValue > aSrcPkgProps = pElement->m_pStream->GetStreamProperties(); + sal_Int32 nNum = 0; + for ( int ind = 0; ind < aSrcPkgProps.getLength(); ind++ ) + { + if ( aSrcPkgProps[ind].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ) ) + || aSrcPkgProps[ind].Name.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "Compressed" ) ) ) ) + { + aStrProps.realloc( ++nNum ); + aStrProps[nNum-1].Name = aSrcPkgProps[ind].Name; + aStrProps[nNum-1].Value = aSrcPkgProps[ind].Value; + } + } + + if ( m_nStorageType == PACKAGE_STORAGE ) + { + aStrProps.realloc( ++nNum ); + aStrProps[nNum-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) ); + aStrProps[nNum-1].Value <<= (sal_Bool)( pElement->m_pStream->UsesCommonPass_Impl() ); + } + else if ( m_nStorageType == OFOPXML_STORAGE ) + { + // TODO/LATER: currently the optimization is not active + // uno::Reference< io::XInputStream > xInStream = GetRelInfoStreamForName( ::rtl::OUString() ); // own rels stream + // if ( xInStream.is() ) + // { + // aStrProps.realloc( ++nNum ); + // aStrProps[nNum-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RelationsInfoStream" ) ); + // aStrProps[nNum-1].Value <<= GetSeekableTempCopy( xInStream, m_xFactory ); + // } + + uno::Reference< embed::XRelationshipAccess > xRels( xDest, uno::UNO_QUERY ); + if ( !xRels.is() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + + xRels->insertRelationships( GetAllRelationshipsIfAny(), sal_False ); + } + + uno::Reference< embed::XOptimizedStorage > xOptDest( xDest, uno::UNO_QUERY_THROW ); + uno::Reference < io::XInputStream > xInputToInsert; + + if ( pElement->m_pStream->HasTempFile_Impl() || !pElement->m_pStream->m_xPackageStream.is() ) + { + OSL_ENSURE( pElement->m_pStream->m_xPackageStream.is(), "No package stream!" ); + + // if the stream is modified - the temporary file must be used for insertion + xInputToInsert = pElement->m_pStream->GetTempFileAsInputStream(); + } + else + { + // for now get just nonseekable access to the stream + // TODO/LATER: the raw stream can be used + + xInputToInsert = pElement->m_pStream->m_xPackageStream->getDataStream(); + } + + if ( !xInputToInsert.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + xOptDest->insertStreamElementDirect( aName, xInputToInsert, aStrProps ); + } + else + { + uno::Reference< io::XStream > xSubStr = + xDest->openStreamElement( aName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + OSL_ENSURE( xSubStr.is(), "No destination substream!\n" ); + + pElement->m_pStream->CopyInternallyTo_Impl( xSubStr ); + } + } + else if ( m_nStorageType != PACKAGE_STORAGE ) + { + OSL_ENSURE( sal_False, "Encryption is only supported in package storage!\n" ); + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + else if ( pElement->m_pStream->HasCachedPassword() + && ( pElement->m_pStream->IsModified() || pElement->m_pStream->HasWriteOwner_Impl() ) ) + { + ::rtl::OUString aCommonPass; + sal_Bool bHasCommonPass = sal_False; + try + { + aCommonPass = GetCommonRootPass(); + bHasCommonPass = sal_True; + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + AddLog( aNoEncryptionException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No Encryption" ) ) ); + } + + if ( bHasCommonPass && pElement->m_pStream->GetCachedPassword().equals( aCommonPass ) ) + { + // If the stream can be opened with the common storage password + // it must be stored with the common storage password as well + uno::Reference< io::XStream > xDestStream = + xDest->openStreamElement( aName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + + pElement->m_pStream->CopyInternallyTo_Impl( xDestStream ); + + uno::Reference< beans::XPropertySet > xProps( xDestStream, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) ), + uno::Any( (sal_Bool) sal_True ) ); + } + else + { + // the stream is already opened for writing or was changed + uno::Reference< io::XStream > xSubStr = + xDest->openEncryptedStreamElement( aName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE, + pElement->m_pStream->GetCachedPassword() ); + OSL_ENSURE( xSubStr.is(), "No destination substream!\n" ); + + pElement->m_pStream->CopyInternallyTo_Impl( xSubStr, pElement->m_pStream->GetCachedPassword() ); + } + } + else + { + // the stream is not opened at all, so it can be just opened for reading + try + { + // If the stream can be opened with the common storage password + // it must be stored with the common storage password as well + + uno::Reference< io::XStream > xOwnStream = pElement->m_pStream->GetStream( embed::ElementModes::READ, + sal_False ); + uno::Reference< io::XStream > xDestStream = + xDest->openStreamElement( aName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + OSL_ENSURE( xDestStream.is(), "No destination substream!\n" ); + completeStorageStreamCopy_Impl( xOwnStream, xDestStream, m_nStorageType, GetAllRelationshipsIfAny() ); + + uno::Reference< beans::XPropertySet > xProps( xDestStream, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseCommonStoragePasswordEncryption" ) ), + uno::Any( (sal_Bool) sal_True ) ); + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + AddLog( aWrongPasswordException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Handled exception" ) ) ); + + // If the common storage password does not allow to open the stream + // it must be copyed in raw way + uno::Reference< embed::XStorageRawAccess > xRawDest( xDest, uno::UNO_QUERY_THROW ); + uno::Reference< io::XInputStream > xRawInStream = pElement->m_pStream->GetRawInStream(); + xRawDest->insertRawEncrStreamElement( aName, xRawInStream ); + } + } + } +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > OStorage_Impl::GetAllRelationshipsIfAny() +{ + if ( m_nStorageType != OFOPXML_STORAGE ) + return uno::Sequence< uno::Sequence< beans::StringPair > >(); + + ReadRelInfoIfNecessary(); + + if ( m_nRelInfoStatus == RELINFO_READ + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ || m_nRelInfoStatus == RELINFO_CHANGED ) + return m_aRelInfo; + else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong relinfo stream!" ) ), + uno::Reference< uno::XInterface >() ); +} + +//----------------------------------------------- +void OStorage_Impl::CopyLastCommitTo( const uno::Reference< embed::XStorage >& xNewStor ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + OSL_ENSURE( m_xPackageFolder.is(), "A commited storage is incomplete!\n" ); + if ( !m_xPackageFolder.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + OStorage_Impl aTempRepresent( NULL, + embed::ElementModes::READ, + m_xPackageFolder, + m_xPackage, + m_xFactory, + m_nStorageType); + + // TODO/LATER: could use direct copying + aTempRepresent.CopyToStorage( xNewStor, sal_False ); +} + +//----------------------------------------------- +void OStorage_Impl::InsertIntoPackageFolder( const ::rtl::OUString& aName, + const uno::Reference< container::XNameContainer >& xParentPackageFolder ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + OSL_ENSURE( m_xPackageFolder.is(), "An inserted storage is incomplete!\n" ); + uno::Reference< lang::XUnoTunnel > xTunnel( m_xPackageFolder, uno::UNO_QUERY ); + if ( !xTunnel.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + xParentPackageFolder->insertByName( aName, uno::makeAny( xTunnel ) ); + + m_bCommited = sal_False; +} + +//----------------------------------------------- +void OStorage_Impl::Commit() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_bIsModified ) + return; + + // in case of a new empty storage it is possible that the contents are still not read + // ( the storage of course has no contents, but the initialization is postponed till the first use, + // thus if a new storage was created and commited immediatelly it must be initialized here ) + ReadContents(); + + // if storage is commited it should have a valid Package representation + OSL_ENSURE( m_xPackageFolder.is(), "The package representation should exist!\n" ); + if ( !m_xPackageFolder.is() ) + throw embed::InvalidStorageException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + OSL_ENSURE( m_nStorageMode & embed::ElementModes::WRITE, + "Commit of readonly storage, should be detected before!\n" ); + + uno::Reference< container::XNameContainer > xNewPackageFolder; + + // here the storage will switch to the temporary package folder + // if the storage was already commited and the parent was not commited after that + // the switch should not be done since the package folder in use is a temporary one; + // it can be detected by m_bCommited flag ( root storage doesn't need temporary representation ) + if ( !m_bCommited && !m_bIsRoot ) + { + uno::Sequence< uno::Any > aSeq( 1 ); + aSeq[0] <<= sal_True; + + xNewPackageFolder = uno::Reference< container::XNameContainer >( + m_xPackage->createInstanceWithArguments( aSeq ), + uno::UNO_QUERY ); + } + else + xNewPackageFolder = m_xPackageFolder; + + // remove replaced removed elements + for ( SotElementList_Impl::iterator pDeletedIter = m_aDeletedList.begin(); + pDeletedIter != m_aDeletedList.end(); + pDeletedIter++ ) + { + + if ( m_nStorageType == OFOPXML_STORAGE && !(*pDeletedIter)->m_bIsStorage ) + RemoveStreamRelInfo( (*pDeletedIter)->m_aOriginalName ); + + // the removed elements are not in new temporary storage + if ( m_bCommited || m_bIsRoot ) + xNewPackageFolder->removeByName( (*pDeletedIter)->m_aOriginalName ); + delete *pDeletedIter; + *pDeletedIter = NULL; + } + m_aDeletedList.clear(); + + // remove removed elements + SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + while ( pElementIter != m_aChildrenList.end() ) + { + // renamed and inserted elements must be really inserted to package later + // since thay can conflict with removed elements + + if ( (*pElementIter)->m_bIsRemoved ) + { + if ( m_nStorageType == OFOPXML_STORAGE && !(*pElementIter)->m_bIsStorage ) + RemoveStreamRelInfo( (*pElementIter)->m_aOriginalName ); + + // the removed elements are not in new temporary storage + if ( m_bCommited || m_bIsRoot ) + xNewPackageFolder->removeByName( (*pElementIter)->m_aOriginalName ); + + SotElement_Impl* pToDelete = *pElementIter; + + pElementIter++; // to let the iterator be valid it should be increased before removing + + m_aChildrenList.remove( pToDelete ); + delete pToDelete; + } + else + pElementIter++; + } + + // there should be no more deleted elements + for ( pElementIter = m_aChildrenList.begin(); pElementIter != m_aChildrenList.end(); pElementIter++ ) + { + // if it is a 'duplicate commit' inserted elements must be really inserted to package later + // since thay can conflict with renamed elements + + if ( !(*pElementIter)->m_bIsInserted ) + { + // for now stream is opened in direct mode that means that in case + // storage is commited all the streams from it are commited in current state. + // following two steps are separated to allow easily implement transacted mode + // for streams if we need it in future. + // Only hierarchical access uses transacted streams currently + if ( !(*pElementIter)->m_bIsStorage && (*pElementIter)->m_pStream + && !(*pElementIter)->m_pStream->IsTransacted() ) + (*pElementIter)->m_pStream->Commit(); + + // if the storage was not open, there is no need to commit it ??? + // the storage should be checked that it is commited + if ( (*pElementIter)->m_bIsStorage && (*pElementIter)->m_pStorage && (*pElementIter)->m_pStorage->m_bCommited ) + { + // it's temporary PackageFolder should be inserted instead of current one + // also the new copy of PackageFolder should be used by the children storages + + // the renamed elements are not in new temporary storage + if ( m_bCommited || m_bIsRoot ) + xNewPackageFolder->removeByName( (*pElementIter)->m_aOriginalName ); + + (*pElementIter)->m_pStorage->InsertIntoPackageFolder( (*pElementIter)->m_aName, xNewPackageFolder ); + } + else if ( !(*pElementIter)->m_bIsStorage && (*pElementIter)->m_pStream && (*pElementIter)->m_pStream->m_bFlushed ) + { + if ( m_nStorageType == OFOPXML_STORAGE ) + CommitStreamRelInfo( *pElementIter ); + + // the renamed elements are not in new temporary storage + if ( m_bCommited || m_bIsRoot ) + xNewPackageFolder->removeByName( (*pElementIter)->m_aOriginalName ); + + (*pElementIter)->m_pStream->InsertIntoPackageFolder( (*pElementIter)->m_aName, xNewPackageFolder ); + } + else if ( !m_bCommited && !m_bIsRoot ) + { + // the element must be just copied to the new temporary package folder + // the connection with the original package should not be lost just because + // the element is still refered by the folder in the original hierarchy + uno::Any aPackageElement = m_xPackageFolder->getByName( (*pElementIter)->m_aOriginalName ); + xNewPackageFolder->insertByName( (*pElementIter)->m_aName, aPackageElement ); + } + else if ( (*pElementIter)->m_aName.compareTo( (*pElementIter)->m_aOriginalName ) ) + { + // this is the case when xNewPackageFolder refers to m_xPackageFolder + // in case the name was changed and it is not a changed storage - rename the element + uno::Reference< container::XNamed > xNamed; + uno::Any aPackageElement = xNewPackageFolder->getByName( (*pElementIter)->m_aOriginalName ); + xNewPackageFolder->removeByName( (*pElementIter)->m_aOriginalName ); + xNewPackageFolder->insertByName( (*pElementIter)->m_aName, aPackageElement ); + + if ( m_nStorageType == OFOPXML_STORAGE && !(*pElementIter)->m_bIsStorage ) + { + if ( !(*pElementIter)->m_pStream ) + { + OpenSubStream( *pElementIter ); + if ( !(*pElementIter)->m_pStream ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + CommitStreamRelInfo( *pElementIter ); + } + } + + (*pElementIter)->m_aOriginalName = (*pElementIter)->m_aName; + } + } + + for ( pElementIter = m_aChildrenList.begin(); pElementIter != m_aChildrenList.end(); pElementIter++ ) + { + // now inserted elements can be inserted to the package + if ( (*pElementIter)->m_bIsInserted ) + { + (*pElementIter)->m_aOriginalName = (*pElementIter)->m_aName; + uno::Reference< lang::XUnoTunnel > xNewElement; + + if ( (*pElementIter)->m_bIsStorage ) + { + if ( (*pElementIter)->m_pStorage->m_bCommited ) + { + OSL_ENSURE( (*pElementIter)->m_pStorage, "An inserted storage is incomplete!\n" ); + if ( !(*pElementIter)->m_pStorage ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + (*pElementIter)->m_pStorage->InsertIntoPackageFolder( (*pElementIter)->m_aName, xNewPackageFolder ); + + (*pElementIter)->m_bIsInserted = sal_False; + } + } + else + { + OSL_ENSURE( (*pElementIter)->m_pStream, "An inserted stream is incomplete!\n" ); + if ( !(*pElementIter)->m_pStream ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !(*pElementIter)->m_pStream->IsTransacted() ) + (*pElementIter)->m_pStream->Commit(); + + if ( (*pElementIter)->m_pStream->m_bFlushed ) + { + if ( m_nStorageType == OFOPXML_STORAGE ) + CommitStreamRelInfo( *pElementIter ); + + (*pElementIter)->m_pStream->InsertIntoPackageFolder( (*pElementIter)->m_aName, xNewPackageFolder ); + + (*pElementIter)->m_bIsInserted = sal_False; + } + } + } + } + + if ( m_nStorageType == PACKAGE_STORAGE ) + { + // move properties to the destination package folder + uno::Reference< beans::XPropertySet > xProps( xNewPackageFolder, uno::UNO_QUERY ); + if ( !xProps.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), uno::makeAny( m_aMediaType ) ); + xProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ), uno::makeAny( m_aVersion ) ); + } + + if ( m_nStorageType == OFOPXML_STORAGE ) + CommitRelInfo( xNewPackageFolder ); // store own relations and commit complete relations storage + + if ( m_bIsRoot ) + { + uno::Reference< util::XChangesBatch > xChangesBatch( m_xPackage, uno::UNO_QUERY ); + + OSL_ENSURE( xChangesBatch.is(), "Impossible to commit package!\n" ); + if ( !xChangesBatch.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + try + { + xChangesBatch->commitChanges(); + } + catch( lang::WrappedTargetException& r ) + { + // the wrapped UseBackupException means that the target medium can be corrupted + embed::UseBackupException aException; + if ( r.TargetException >>= aException ) + { + m_xStream = uno::Reference< io::XStream >(); + m_xInputStream = uno::Reference< io::XInputStream >(); + throw aException; + } + + AddLog( aException.Message ); + AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + } + else if ( !m_bCommited ) + { + m_xPackageFolder = xNewPackageFolder; + m_bCommited = sal_True; + } + + // after commit the mediatype treated as the correct one + m_bMTFallbackUsed = sal_False; +} + +//----------------------------------------------- +void OStorage_Impl::Revert() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !( m_nStorageMode & embed::ElementModes::WRITE ) ) + return; // nothing to do + + // all the children must be removed + // they will be created later on demand + + SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + while ( pElementIter != m_aChildrenList.end() ) + { + if ( (*pElementIter)->m_bIsInserted ) + { + SotElement_Impl* pToDelete = *pElementIter; + + pElementIter++; // to let the iterator be valid it should be increased before removing + + m_aChildrenList.remove( pToDelete ); + delete pToDelete; + } + else + { + ClearElement( *pElementIter ); + + (*pElementIter)->m_aName = (*pElementIter)->m_aOriginalName; + (*pElementIter)->m_bIsRemoved = sal_False; + + pElementIter++; + } + } + + // return replaced removed elements + for ( SotElementList_Impl::iterator pDeletedIter = m_aDeletedList.begin(); + pDeletedIter != m_aDeletedList.end(); + pDeletedIter++ ) + { + m_aChildrenList.push_back( (*pDeletedIter) ); + + ClearElement( *pDeletedIter ); + + (*pDeletedIter)->m_aName = (*pDeletedIter)->m_aOriginalName; + (*pDeletedIter)->m_bIsRemoved = sal_False; + } + m_aDeletedList.clear(); + + m_bControlMediaType = sal_False; + m_bControlVersion = sal_False; + + GetStorageProperties(); + + if ( m_nStorageType == OFOPXML_STORAGE ) + { + // currently the relations storage is changed only on commit + m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_aRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_nRelInfoStatus = RELINFO_NO_INIT; + } +} + +//----------------------------------------------- +::rtl::OUString OStorage_Impl::GetCommonRootPass() + throw ( packages::NoEncryptionException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ) ; + + if ( m_nStorageType != PACKAGE_STORAGE ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_bIsRoot ) + { + if ( !m_bHasCommonPassword ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_aCommonPassword; + } + else + { + if ( !m_pParent ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_pParent->GetCommonRootPass(); + } +} + +//----------------------------------------------- +SotElement_Impl* OStorage_Impl::FindElement( const ::rtl::OUString& rName ) +{ + OSL_ENSURE( rName.getLength(), "Name is empty!" ); + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + ReadContents(); + + for ( SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + pElementIter != m_aChildrenList.end(); pElementIter++ ) + { + if ( (*pElementIter)->m_aName == rName && !(*pElementIter)->m_bIsRemoved ) + return *pElementIter; + } + + return NULL; +} + +//----------------------------------------------- +SotElement_Impl* OStorage_Impl::InsertStream( ::rtl::OUString aName, sal_Bool bEncr ) +{ + OSL_ENSURE( m_xPackage.is(), "Not possible to refer to package as to factory!\n" ); + if ( !m_xPackage.is() ) + throw embed::InvalidStorageException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< uno::Any > aSeq( 1 ); + aSeq[0] <<= sal_False; + uno::Reference< lang::XUnoTunnel > xNewElement( m_xPackage->createInstanceWithArguments( aSeq ), + uno::UNO_QUERY ); + + OSL_ENSURE( xNewElement.is(), "Not possible to create a new stream!\n" ); + if ( !xNewElement.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< packages::XDataSinkEncrSupport > xPackageSubStream( xNewElement, uno::UNO_QUERY ); + if ( !xPackageSubStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + OSL_ENSURE( m_nStorageType == PACKAGE_STORAGE || !bEncr, "Only package storage supports encryption!\n" ); + if ( m_nStorageType != PACKAGE_STORAGE && bEncr ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // the mode is not needed for storage stream internal implementation + SotElement_Impl* pNewElement = InsertElement( aName, sal_False ); + pNewElement->m_pStream = new OWriteStream_Impl( this, xPackageSubStream, m_xPackage, m_xFactory, bEncr, m_nStorageType, sal_True ); + + m_aChildrenList.push_back( pNewElement ); + m_bIsModified = sal_True; + m_bBroadcastModified = sal_True; + + return pNewElement; +} + +//----------------------------------------------- +SotElement_Impl* OStorage_Impl::InsertRawStream( ::rtl::OUString aName, const uno::Reference< io::XInputStream >& xInStream ) +{ + // insert of raw stream means insert and commit + OSL_ENSURE( m_xPackage.is(), "Not possible to refer to package as to factory!\n" ); + if ( !m_xPackage.is() ) + throw embed::InvalidStorageException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_nStorageType != PACKAGE_STORAGE ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY ); + uno::Reference< io::XInputStream > xInStrToInsert = xSeek.is() ? xInStream : + GetSeekableTempCopy( xInStream, GetServiceFactory() ); + + uno::Sequence< uno::Any > aSeq( 1 ); + aSeq[0] <<= sal_False; + uno::Reference< lang::XUnoTunnel > xNewElement( m_xPackage->createInstanceWithArguments( aSeq ), + uno::UNO_QUERY ); + + OSL_ENSURE( xNewElement.is(), "Not possible to create a new stream!\n" ); + if ( !xNewElement.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< packages::XDataSinkEncrSupport > xPackageSubStream( xNewElement, uno::UNO_QUERY ); + if ( !xPackageSubStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + xPackageSubStream->setRawStream( xInStrToInsert ); + + // the mode is not needed for storage stream internal implementation + SotElement_Impl* pNewElement = InsertElement( aName, sal_False ); + pNewElement->m_pStream = new OWriteStream_Impl( this, xPackageSubStream, m_xPackage, m_xFactory, sal_True, m_nStorageType, sal_False ); + // the stream is inserted and must be treated as a commited one + pNewElement->m_pStream->SetToBeCommited(); + + m_aChildrenList.push_back( pNewElement ); + m_bIsModified = sal_True; + m_bBroadcastModified = sal_True; + + return pNewElement; +} + +//----------------------------------------------- +OStorage_Impl* OStorage_Impl::CreateNewStorageImpl( sal_Int32 nStorageMode ) +{ + OSL_ENSURE( m_xPackage.is(), "Not possible to refer to package as to factory!\n" ); + if ( !m_xPackage.is() ) + throw embed::InvalidStorageException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< uno::Any > aSeq( 1 ); + aSeq[0] <<= sal_True; + uno::Reference< lang::XUnoTunnel > xNewElement( m_xPackage->createInstanceWithArguments( aSeq ), + uno::UNO_QUERY ); + + OSL_ENSURE( xNewElement.is(), "Not possible to create a new storage!\n" ); + if ( !xNewElement.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< container::XNameContainer > xPackageSubFolder( xNewElement, uno::UNO_QUERY ); + if ( !xPackageSubFolder.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + OStorage_Impl* pResult = + new OStorage_Impl( this, nStorageMode, xPackageSubFolder, m_xPackage, m_xFactory, m_nStorageType ); + pResult->m_bIsModified = sal_True; + + return pResult; +} + +//----------------------------------------------- +SotElement_Impl* OStorage_Impl::InsertStorage( ::rtl::OUString aName, sal_Int32 nStorageMode ) +{ + SotElement_Impl* pNewElement = InsertElement( aName, sal_True ); + + pNewElement->m_pStorage = CreateNewStorageImpl( nStorageMode ); + + m_aChildrenList.push_back( pNewElement ); + + return pNewElement; +} + +//----------------------------------------------- +SotElement_Impl* OStorage_Impl::InsertElement( ::rtl::OUString aName, sal_Bool bIsStorage ) +{ + OSL_ENSURE( FindElement( aName ) == NULL, "Should not try to insert existing element" ); + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + SotElement_Impl* pDeletedElm = NULL; + + for ( SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + pElementIter != m_aChildrenList.end(); pElementIter++ ) + { + if ( (*pElementIter)->m_aName == aName ) + { + OSL_ENSURE( (*pElementIter)->m_bIsRemoved, "Try to insert an element instead of existing one!\n" ); + if ( (*pElementIter)->m_bIsRemoved ) + { + OSL_ENSURE( !(*pElementIter)->m_bIsInserted, "Inserted elements must be deleted immediatelly!\n" ); + pDeletedElm = *pElementIter; + break; + } + } + } + + if ( pDeletedElm ) + { + if ( pDeletedElm->m_bIsStorage ) + OpenSubStorage( pDeletedElm, embed::ElementModes::READWRITE ); + else + OpenSubStream( pDeletedElm ); + + m_aChildrenList.remove( pDeletedElm ); // correct usage of list ??? + m_aDeletedList.push_back( pDeletedElm ); + } + + // create new element + return new SotElement_Impl( aName, bIsStorage, sal_True ); +} + +//----------------------------------------------- +void OStorage_Impl::OpenSubStorage( SotElement_Impl* pElement, sal_Int32 nStorageMode ) +{ + OSL_ENSURE( pElement, "pElement is not set!\n" ); + OSL_ENSURE( pElement->m_bIsStorage, "Storage flag is not set!\n" ); + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !pElement->m_pStorage ) + { + OSL_ENSURE( !pElement->m_bIsInserted, "Inserted element must be created already!\n" ); + + uno::Reference< lang::XUnoTunnel > xTunnel; + m_xPackageFolder->getByName( pElement->m_aOriginalName ) >>= xTunnel; + if ( !xTunnel.is() ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< container::XNameContainer > xPackageSubFolder( xTunnel, uno::UNO_QUERY ); + + OSL_ENSURE( xPackageSubFolder.is(), "Can not get XNameContainer interface from folder!\n" ); + + if ( !xPackageSubFolder.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + pElement->m_pStorage = new OStorage_Impl( this, nStorageMode, xPackageSubFolder, m_xPackage, m_xFactory, m_nStorageType ); + } +} + +//----------------------------------------------- +void OStorage_Impl::OpenSubStream( SotElement_Impl* pElement ) +{ + OSL_ENSURE( pElement, "pElement is not set!\n" ); + OSL_ENSURE( !pElement->m_bIsStorage, "Storage flag is set!\n" ); + + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !pElement->m_pStream ) + { + OSL_ENSURE( !pElement->m_bIsInserted, "Inserted element must be created already!\n" ); + + uno::Reference< lang::XUnoTunnel > xTunnel; + m_xPackageFolder->getByName( pElement->m_aOriginalName ) >>= xTunnel; + if ( !xTunnel.is() ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< packages::XDataSinkEncrSupport > xPackageSubStream( xTunnel, uno::UNO_QUERY ); + if ( !xPackageSubStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // the stream can never be inserted here, because inserted stream element holds the stream till commit or destruction + pElement->m_pStream = new OWriteStream_Impl( this, xPackageSubStream, m_xPackage, m_xFactory, sal_False, m_nStorageType, sal_False, GetRelInfoStreamForName( pElement->m_aOriginalName ) ); + } +} + +//----------------------------------------------- +uno::Sequence< ::rtl::OUString > OStorage_Impl::GetElementNames() +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + ReadContents(); + + sal_uInt32 nSize = m_aChildrenList.size(); + uno::Sequence< ::rtl::OUString > aElementNames( nSize ); + + sal_uInt32 nInd = 0; + for ( SotElementList_Impl::iterator pElementIter = m_aChildrenList.begin(); + pElementIter != m_aChildrenList.end(); pElementIter++ ) + { + if ( !(*pElementIter)->m_bIsRemoved ) + aElementNames[nInd++] = (*pElementIter)->m_aName; + } + + aElementNames.realloc( nInd ); + return aElementNames; +} + +//----------------------------------------------- +void OStorage_Impl::RemoveElement( SotElement_Impl* pElement ) +{ + OSL_ENSURE( pElement, "Element must be provided!" ); + + if ( !pElement ) + return; + + if ( (pElement->m_pStorage && ( pElement->m_pStorage->m_pAntiImpl || !pElement->m_pStorage->m_aReadOnlyWrapList.empty() )) + || (pElement->m_pStream && ( pElement->m_pStream->m_pAntiImpl || !pElement->m_pStream->m_aInputStreamsList.empty() )) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: Access denied + + if ( pElement->m_bIsInserted ) + { + m_aChildrenList.remove( pElement ); + delete pElement; // ??? + } + else + { + pElement->m_bIsRemoved = sal_True; + ClearElement( pElement ); + } + + // TODO/OFOPXML: the rel stream should be removed as well +} + +//----------------------------------------------- +void OStorage_Impl::ClearElement( SotElement_Impl* pElement ) +{ + if ( pElement->m_pStorage ) + { + delete pElement->m_pStorage; + pElement->m_pStorage = NULL; + } + + if ( pElement->m_pStream ) + { + delete pElement->m_pStream; + pElement->m_pStream = NULL; + } +} + +//----------------------------------------------- +void OStorage_Impl::CloneStreamElement( const ::rtl::OUString& aStreamName, + sal_Bool bPassProvided, + const ::rtl::OUString& aPass, + uno::Reference< io::XStream >& xTargetStream ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + SotElement_Impl *pElement = FindElement( aStreamName ); + if ( !pElement ) + { + // element does not exist, throw exception + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + } + else if ( pElement->m_bIsStorage ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !pElement->m_pStream ) + OpenSubStream( pElement ); + + if ( pElement->m_pStream && pElement->m_pStream->m_xPackageStream.is() ) + { + // the existence of m_pAntiImpl of the child is not interesting, + // the copy will be created internally + + // usual copying is not applicable here, only last flushed version of the + // child stream should be used for copiing. Probably the childs m_xPackageStream + // can be used as a base of a new stream, that would be copied to result + // storage. The only problem is that some package streams can be accessed from outside + // at the same time ( now solwed by wrappers that remember own position ). + + if ( bPassProvided ) + pElement->m_pStream->GetCopyOfLastCommit( xTargetStream, aPass ); + else + pElement->m_pStream->GetCopyOfLastCommit( xTargetStream ); + } + else + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: general_error +} + +//----------------------------------------------- +void OStorage_Impl::RemoveStreamRelInfo( const ::rtl::OUString& aOriginalName ) +{ + // this method should be used only in OStorage_Impl::Commit() method + // the aOriginalName can be empty, in this case the storage relation info should be removed + + if ( m_nStorageType == OFOPXML_STORAGE && m_xRelStorage.is() ) + { + ::rtl::OUString aRelStreamName = aOriginalName; + aRelStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".rels" ) ); + + if ( m_xRelStorage->hasByName( aRelStreamName ) ) + m_xRelStorage->removeElement( aRelStreamName ); + } +} + +//----------------------------------------------- +void OStorage_Impl::CreateRelStorage() +{ + if ( m_nStorageType != OFOPXML_STORAGE ) + return; + + if ( !m_xRelStorage.is() ) + { + if ( !m_pRelStorElement ) + { + m_pRelStorElement = new SotElement_Impl( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ), sal_True, sal_True ); + m_pRelStorElement->m_pStorage = CreateNewStorageImpl( embed::ElementModes::WRITE ); + if ( m_pRelStorElement->m_pStorage ) + m_pRelStorElement->m_pStorage->m_pParent = NULL; // the relation storage is completely controlled by parent + } + + if ( !m_pRelStorElement->m_pStorage ) + OpenSubStorage( m_pRelStorElement, embed::ElementModes::WRITE ); + + if ( !m_pRelStorElement->m_pStorage ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + OStorage* pResultStorage = new OStorage( m_pRelStorElement->m_pStorage, sal_False ); + m_xRelStorage = uno::Reference< embed::XStorage >( (embed::XStorage*) pResultStorage ); + } +} + +//----------------------------------------------- +void OStorage_Impl::CommitStreamRelInfo( SotElement_Impl* pStreamElement ) +{ + // this method should be used only in OStorage_Impl::Commit() method + + // the stream element must be provided + if ( !pStreamElement ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_nStorageType == OFOPXML_STORAGE && pStreamElement->m_pStream ) + { + OSL_ENSURE( pStreamElement->m_aName.getLength(), "The name must not be empty!\n" ); + + if ( !m_xRelStorage.is() ) + { + // Create new rels storage, this is commit scenario so it must be possible + CreateRelStorage(); + } + + pStreamElement->m_pStream->CommitStreamRelInfo( m_xRelStorage, pStreamElement->m_aOriginalName, pStreamElement->m_aName ); + } +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > OStorage_Impl::GetRelInfoStreamForName( const ::rtl::OUString& aName ) +{ + if ( m_nStorageType == OFOPXML_STORAGE ) + { + ReadContents(); + if ( m_xRelStorage.is() ) + { + ::rtl::OUString aRelStreamName = aName; + aRelStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".rels" ) ); + if ( m_xRelStorage->hasByName( aRelStreamName ) ) + { + uno::Reference< io::XStream > xStream = m_xRelStorage->openStreamElement( aRelStreamName, embed::ElementModes::READ ); + if ( xStream.is() ) + return xStream->getInputStream(); + } + } + } + + return uno::Reference< io::XInputStream >(); +} + +//----------------------------------------------- +void OStorage_Impl::CommitRelInfo( const uno::Reference< container::XNameContainer >& xNewPackageFolder ) +{ + // this method should be used only in OStorage_Impl::Commit() method + ::rtl::OUString aRelsStorName( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ); + + if ( !xNewPackageFolder.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_nStorageType == OFOPXML_STORAGE ) + { + if ( m_nRelInfoStatus == RELINFO_BROKEN || m_nRelInfoStatus == RELINFO_CHANGED_BROKEN ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_nRelInfoStatus == RELINFO_CHANGED + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + if ( m_nRelInfoStatus == RELINFO_CHANGED ) + { + if ( m_aRelInfo.getLength() ) + { + CreateRelStorage(); + + uno::Reference< io::XStream > xRelsStream = + m_xRelStorage->openStreamElement( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".rels" ) ), + embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE ); + + uno::Reference< io::XOutputStream > xOutStream = xRelsStream->getOutputStream(); + if ( !xOutStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + ::comphelper::OFOPXMLHelper::WriteRelationsInfoSequence( xOutStream, m_aRelInfo, m_xFactory ); + + // set the mediatype + uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW ); + xPropSet->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), + uno::makeAny( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "application/vnd.openxmlformats-package.relationships+xml" ) ) ) ); + + m_nRelInfoStatus = RELINFO_READ; + } + else if ( m_xRelStorage.is() ) + RemoveStreamRelInfo( ::rtl::OUString() ); // remove own rel info + } + else if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM_READ + || m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + CreateRelStorage(); + + uno::Reference< io::XStream > xRelsStream = + m_xRelStorage->openStreamElement( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".rels" ) ), + embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE ); + + uno::Reference< io::XOutputStream > xOutputStream = xRelsStream->getOutputStream(); + if ( !xOutputStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XSeekable > xSeek( m_xNewRelInfoStream, uno::UNO_QUERY_THROW ); + xSeek->seek( 0 ); + ::comphelper::OStorageHelper::CopyInputToOutput( m_xNewRelInfoStream, xOutputStream ); + + // set the mediatype + uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW ); + xPropSet->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), + uno::makeAny( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "application/vnd.openxmlformats-package.relationships+xml" ) ) ) ); + + m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + if ( m_nRelInfoStatus == RELINFO_CHANGED_STREAM ) + { + m_aRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_nRelInfoStatus = RELINFO_NO_INIT; + } + else + m_nRelInfoStatus = RELINFO_READ; + } + } + + if ( m_xRelStorage.is() ) + { + if ( m_xRelStorage->hasElements() ) + { + uno::Reference< embed::XTransactedObject > xTrans( m_xRelStorage, uno::UNO_QUERY_THROW ); + if ( xTrans.is() ) + xTrans->commit(); + } + + if ( xNewPackageFolder.is() && xNewPackageFolder->hasByName( aRelsStorName ) ) + xNewPackageFolder->removeByName( aRelsStorName ); + + if ( !m_xRelStorage->hasElements() ) + { + // the empty relations storage should not be created + delete m_pRelStorElement; + m_pRelStorElement = NULL; + m_xRelStorage = uno::Reference< embed::XStorage >(); + } + else if ( m_pRelStorElement && m_pRelStorElement->m_pStorage && xNewPackageFolder.is() ) + m_pRelStorElement->m_pStorage->InsertIntoPackageFolder( aRelsStorName, xNewPackageFolder ); + } + } +} + +//===================================================== +// OStorage implementation +//===================================================== + +//----------------------------------------------- +OStorage::OStorage( uno::Reference< io::XInputStream > xInputStream, + sal_Int32 nMode, + uno::Sequence< beans::PropertyValue > xProperties, + uno::Reference< lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ) +: m_pImpl( new OStorage_Impl( xInputStream, nMode, xProperties, xFactory, nStorageType ) ) +{ + m_pImpl->m_pAntiImpl = this; + m_pData = new StorInternalData_Impl( m_pImpl->m_rMutexRef, m_pImpl->m_bIsRoot, m_pImpl->m_nStorageType, sal_False ); +} + +//----------------------------------------------- +OStorage::OStorage( uno::Reference< io::XStream > xStream, + sal_Int32 nMode, + uno::Sequence< beans::PropertyValue > xProperties, + uno::Reference< lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ) +: m_pImpl( new OStorage_Impl( xStream, nMode, xProperties, xFactory, nStorageType ) ) +{ + m_pImpl->m_pAntiImpl = this; + m_pData = new StorInternalData_Impl( m_pImpl->m_rMutexRef, m_pImpl->m_bIsRoot, m_pImpl->m_nStorageType, sal_False ); +} + +//----------------------------------------------- +OStorage::OStorage( OStorage_Impl* pImpl, sal_Bool bReadOnlyWrap ) +: m_pImpl( pImpl ) +{ + // this call can be done only from OStorage_Impl implementation to create child storage + OSL_ENSURE( m_pImpl && m_pImpl->m_rMutexRef.Is(), "The provided pointer & mutex MUST NOT be empty!\n" ); + + m_pData = new StorInternalData_Impl( m_pImpl->m_rMutexRef, m_pImpl->m_bIsRoot, m_pImpl->m_nStorageType, bReadOnlyWrap ); + + OSL_ENSURE( ( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) == embed::ElementModes::WRITE || + m_pData->m_bReadOnlyWrap, + "The wrapper can not allow writing in case implementation does not!\n" ); + + if ( !bReadOnlyWrap ) + m_pImpl->m_pAntiImpl = this; +} + +//----------------------------------------------- +OStorage::~OStorage() +{ + { + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + if ( m_pImpl ) + { + m_refCount++; // to call dispose + try { + dispose(); + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Handled exception" ) ) ); + } + } + } + + if ( m_pData ) + { + if ( m_pData->m_pSubElDispListener ) + { + m_pData->m_pSubElDispListener->release(); + m_pData->m_pSubElDispListener = NULL; + } + + if ( m_pData->m_pTypeCollection ) + { + delete m_pData->m_pTypeCollection; + m_pData->m_pTypeCollection = NULL; + } + + delete m_pData; + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::InternalDispose( sal_Bool bNotifyImpl ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::InternalDispose" ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + // the source object is also a kind of locker for the current object + // since the listeners could dispose the object while being notified + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + m_pData->m_aListenersContainer.disposeAndClear( aSource ); + + if ( m_pData->m_bReadOnlyWrap ) + { + OSL_ENSURE( !m_pData->m_aOpenSubComponentsList.size() || m_pData->m_pSubElDispListener, + "If any subelements are open the listener must exist!\n" ); + + if ( m_pData->m_pSubElDispListener ) + { + m_pData->m_pSubElDispListener->OwnerIsDisposed(); + + // iterate through m_pData->m_aOpenSubComponentsList + // deregister m_pData->m_pSubElDispListener and dispose all of them + if ( !m_pData->m_aOpenSubComponentsList.empty() ) + { + for ( WeakComponentList::iterator pCompIter = m_pData->m_aOpenSubComponentsList.begin(); + pCompIter != m_pData->m_aOpenSubComponentsList.end(); pCompIter++ ) + { + uno::Reference< lang::XComponent > xTmp = (*pCompIter); + if ( xTmp.is() ) + { + xTmp->removeEventListener( uno::Reference< lang::XEventListener >( + static_cast< lang::XEventListener* >( m_pData->m_pSubElDispListener ) ) ); + + try { + xTmp->dispose(); + } catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + } + } + + m_pData->m_aOpenSubComponentsList.clear(); + } + } + + if ( bNotifyImpl ) + m_pImpl->RemoveReadOnlyWrap( *this ); + } + else + { + m_pImpl->m_pAntiImpl = NULL; + + if ( bNotifyImpl ) + { + if ( m_pData->m_bIsRoot ) + delete m_pImpl; + else + { + // the noncommited changes for the storage must be removed + m_pImpl->Revert(); + } + } + } + + m_pImpl = NULL; +} + +//----------------------------------------------- +void OStorage::ChildIsDisposed( const uno::Reference< uno::XInterface >& xChild ) +{ + // this method can only be called by child disposing listener + + // this method must not contain any locking + // the locking is done in the listener + + if ( !m_pData->m_aOpenSubComponentsList.empty() ) + { + for ( WeakComponentList::iterator pCompIter = m_pData->m_aOpenSubComponentsList.begin(); + pCompIter != m_pData->m_aOpenSubComponentsList.end(); ) + { + uno::Reference< lang::XComponent > xTmp = (*pCompIter); + if ( !xTmp.is() || xTmp == xChild ) + { + WeakComponentList::iterator pIterToRemove = pCompIter; + pCompIter++; + m_pData->m_aOpenSubComponentsList.erase( pIterToRemove ); + } + else + pCompIter++; + } + } +} + +//----------------------------------------------- +void OStorage::BroadcastModifiedIfNecessary() +{ + // no need to lock mutex here for the checking of m_pImpl, and m_pData is alive until the object is destructed + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !m_pImpl->m_bBroadcastModified ) + return; + + m_pImpl->m_bBroadcastModified = sal_False; + + OSL_ENSURE( !m_pData->m_bReadOnlyWrap, "The storage can not be modified at all!\n" ); + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + + ::cppu::OInterfaceContainerHelper* pContainer = + m_pData->m_aListenersContainer.getContainer( + ::getCppuType( ( const uno::Reference< util::XModifyListener >*) NULL ) ); + if ( pContainer ) + { + ::cppu::OInterfaceIteratorHelper pIterator( *pContainer ); + while ( pIterator.hasMoreElements( ) ) + { + ( ( util::XModifyListener* )pIterator.next( ) )->modified( aSource ); + } + } +} + +//----------------------------------------------- +void OStorage::BroadcastTransaction( sal_Int8 nMessage ) +/* + 1 - preCommit + 2 - commited + 3 - preRevert + 4 - reverted +*/ +{ + // no need to lock mutex here for the checking of m_pImpl, and m_pData is alive until the object is destructed + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + OSL_ENSURE( !m_pData->m_bReadOnlyWrap, "The storage can not be modified at all!\n" ); + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + + ::cppu::OInterfaceContainerHelper* pContainer = + m_pData->m_aListenersContainer.getContainer( + ::getCppuType( ( const uno::Reference< embed::XTransactionListener >*) NULL ) ); + if ( pContainer ) + { + ::cppu::OInterfaceIteratorHelper pIterator( *pContainer ); + while ( pIterator.hasMoreElements( ) ) + { + OSL_ENSURE( nMessage >= 1 && nMessage <= 4, "Wrong internal notification code is used!\n" ); + + switch( nMessage ) + { + case STOR_MESS_PRECOMMIT: + ( ( embed::XTransactionListener* )pIterator.next( ) )->preCommit( aSource ); + break; + case STOR_MESS_COMMITED: + ( ( embed::XTransactionListener* )pIterator.next( ) )->commited( aSource ); + break; + case STOR_MESS_PREREVERT: + ( ( embed::XTransactionListener* )pIterator.next( ) )->preRevert( aSource ); + break; + case STOR_MESS_REVERTED: + ( ( embed::XTransactionListener* )pIterator.next( ) )->reverted( aSource ); + break; + } + } + } +} + +//----------------------------------------------- +SotElement_Impl* OStorage::OpenStreamElement_Impl( const ::rtl::OUString& aStreamName, sal_Int32 nOpenMode, sal_Bool bEncr ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + OSL_ENSURE( !m_pData->m_bReadOnlyWrap || ( nOpenMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE, + "An element can not be opened for writing in readonly storage!\n" ); + + SotElement_Impl *pElement = m_pImpl->FindElement( aStreamName ); + if ( !pElement ) + { + // element does not exist, check if creation is allowed + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) + || (( nOpenMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE ) + || ( nOpenMode & embed::ElementModes::NOCREATE ) == embed::ElementModes::NOCREATE ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + + // create a new StreamElement and insert it into the list + pElement = m_pImpl->InsertStream( aStreamName, bEncr ); + } + else if ( pElement->m_bIsStorage ) + { + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + OSL_ENSURE( pElement, "In case element can not be created an exception must be thrown!" ); + + if ( !pElement->m_pStream ) + m_pImpl->OpenSubStream( pElement ); + + if ( !pElement->m_pStream ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return pElement; +} + +//----------------------------------------------- +void OStorage::MakeLinkToSubComponent_Impl( const uno::Reference< lang::XComponent >& xComponent ) +{ + if ( !xComponent.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pData->m_pSubElDispListener ) + { + m_pData->m_pSubElDispListener = new OChildDispListener_Impl( *this ); + m_pData->m_pSubElDispListener->acquire(); + } + + xComponent->addEventListener( uno::Reference< lang::XEventListener >( + static_cast< ::cppu::OWeakObject* >( m_pData->m_pSubElDispListener ), uno::UNO_QUERY ) ); + + m_pData->m_aOpenSubComponentsList.push_back( xComponent ); +} + +//____________________________________________________________________________________________________ +// XInterface +//____________________________________________________________________________________________________ + +//----------------------------------------------- +uno::Any SAL_CALL OStorage::queryInterface( const uno::Type& rType ) + throw( uno::RuntimeException ) +{ + uno::Any aReturn; + + // common interfaces + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<lang::XTypeProvider*> ( this ) + , static_cast<embed::XStorage*> ( this ) + , static_cast<embed::XTransactedObject*> ( this ) + , static_cast<embed::XTransactionBroadcaster*> ( this ) + , static_cast<util::XModifiable*> ( this ) + , static_cast<container::XNameAccess*> ( this ) + , static_cast<container::XElementAccess*> ( this ) + , static_cast<lang::XComponent*> ( this ) + , static_cast<beans::XPropertySet*> ( this ) + , static_cast<embed::XOptimizedStorage*> ( this ) + , static_cast<embed::XHierarchicalStorageAccess*> ( this ) ); + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + + if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + if ( m_pData->m_bIsRoot ) + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XStorageRawAccess*> ( this ) + , static_cast<embed::XEncryptionProtectedSource*> ( this ) ); + } + else + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XStorageRawAccess*> ( this ) ); + } + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + aReturn <<= ::cppu::queryInterface + ( rType + , static_cast<embed::XRelationshipAccess*> ( this ) ); + } + + if ( aReturn.hasValue() == sal_True ) + return aReturn ; + + return OWeakObject::queryInterface( rType ); +} + +//----------------------------------------------- +void SAL_CALL OStorage::acquire() throw() +{ + OWeakObject::acquire(); +} + +//----------------------------------------------- +void SAL_CALL OStorage::release() throw() +{ + OWeakObject::release(); +} + +//____________________________________________________________________________________________________ +// XTypeProvider +//____________________________________________________________________________________________________ + +//----------------------------------------------- +uno::Sequence< uno::Type > SAL_CALL OStorage::getTypes() + throw( uno::RuntimeException ) +{ + if ( m_pData->m_pTypeCollection == NULL ) + { + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( m_pData->m_pTypeCollection == NULL ) + { + if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + if ( m_pData->m_bIsRoot ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XStorage >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XStorageRawAccess >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< util::XModifiable >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XEncryptionProtectedSource >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + else + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XStorage >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XStorageRawAccess >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< util::XModifiable >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XStorage >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< util::XModifiable >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XRelationshipAccess >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + else + { + m_pData->m_pTypeCollection = new ::cppu::OTypeCollection + ( ::getCppuType( ( const uno::Reference< lang::XTypeProvider >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XStorage >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactedObject >* )NULL ) + , ::getCppuType( ( const uno::Reference< embed::XTransactionBroadcaster >* )NULL ) + , ::getCppuType( ( const uno::Reference< util::XModifiable >* )NULL ) + , ::getCppuType( ( const uno::Reference< beans::XPropertySet >* )NULL ) ); + } + } + } + + return m_pData->m_pTypeCollection->getTypes() ; +} + +//----------------------------------------------- +uno::Sequence< sal_Int8 > SAL_CALL OStorage::getImplementationId() + throw( uno::RuntimeException ) +{ + static ::cppu::OImplementationId* pID = NULL ; + + if ( pID == NULL ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ; + + if ( pID == NULL ) + { + static ::cppu::OImplementationId aID( sal_False ) ; + pID = &aID ; + } + } + + return pID->getImplementationId() ; + +} + +//____________________________________________________________________________________________________ +// XStorage +//____________________________________________________________________________________________________ + + +//----------------------------------------------- +void SAL_CALL OStorage::copyToStorage( const uno::Reference< embed::XStorage >& xDest ) + throw ( embed::InvalidStorageException, + io::IOException, + lang::IllegalArgumentException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::copyToStorage" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !xDest.is() || xDest == uno::Reference< uno::XInterface >( static_cast< OWeakObject*> ( this ), uno::UNO_QUERY ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + try { + m_pImpl->CopyToStorage( xDest, sal_False ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't copy storage!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +uno::Reference< io::XStream > SAL_CALL OStorage::openStreamElement( + const ::rtl::OUString& aStreamName, sal_Int32 nOpenMode ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::openStreamElement" ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aStreamName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable element name + + if ( ( nOpenMode & embed::ElementModes::WRITE ) && m_pData->m_bReadOnlyWrap ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + uno::Reference< io::XStream > xResult; + try + { + SotElement_Impl *pElement = OpenStreamElement_Impl( aStreamName, nOpenMode, sal_False ); + OSL_ENSURE( pElement && pElement->m_pStream, "In case element can not be created an exception must be thrown!" ); + + xResult = pElement->m_pStream->GetStream( nOpenMode, sal_False ); + OSL_ENSURE( xResult.is(), "The method must throw exception instead of removing empty result!\n" ); + + if ( m_pData->m_bReadOnlyWrap ) + { + // before the storage disposes the stream it must deregister itself as listener + uno::Reference< lang::XComponent > xStreamComponent( xResult, uno::UNO_QUERY ); + if ( !xStreamComponent.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + MakeLinkToSubComponent_Impl( xStreamComponent ); + } + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + m_pImpl->AddLog( aWrongPasswordException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't open stream element!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + aGuard.clear(); + + BroadcastModifiedIfNecessary(); + + return xResult; +} + +//----------------------------------------------- +uno::Reference< io::XStream > SAL_CALL OStorage::openEncryptedStreamElement( + const ::rtl::OUString& aStreamName, sal_Int32 nOpenMode, const ::rtl::OUString& aPass ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::NoEncryptionException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::openEncryptedStreamElement" ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + packages::NoEncryptionException(); + + if ( ( nOpenMode & embed::ElementModes::WRITE ) && m_pData->m_bReadOnlyWrap ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + if ( !aPass.getLength() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 3 ); + + uno::Reference< io::XStream > xResult; + try + { + SotElement_Impl *pElement = OpenStreamElement_Impl( aStreamName, nOpenMode, sal_True ); + OSL_ENSURE( pElement && pElement->m_pStream, "In case element can not be created an exception must be thrown!" ); + + xResult = pElement->m_pStream->GetStream( nOpenMode, aPass, sal_False ); + OSL_ENSURE( xResult.is(), "The method must throw exception instead of removing empty result!\n" ); + + if ( m_pData->m_bReadOnlyWrap ) + { + // before the storage disposes the stream it must deregister itself as listener + uno::Reference< lang::XComponent > xStreamComponent( xResult, uno::UNO_QUERY ); + if ( !xStreamComponent.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + MakeLinkToSubComponent_Impl( xStreamComponent ); + } + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + m_pImpl->AddLog( aNoEncryptionException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + m_pImpl->AddLog( aWrongPasswordException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't open encrypted stream stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + aGuard.clear(); + + BroadcastModifiedIfNecessary(); + + return xResult; +} + +//----------------------------------------------- +uno::Reference< embed::XStorage > SAL_CALL OStorage::openStorageElement( + const ::rtl::OUString& aStorName, sal_Int32 nStorageMode ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::openStorageElement" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStorName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStorName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aStorName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable storage name + + if ( ( nStorageMode & embed::ElementModes::WRITE ) && m_pData->m_bReadOnlyWrap ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + if ( ( nStorageMode & embed::ElementModes::TRUNCATE ) + && !( nStorageMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + // it's allways possible to read written storage in this implementation + nStorageMode |= embed::ElementModes::READ; + + uno::Reference< embed::XStorage > xResult; + try + { + SotElement_Impl *pElement = m_pImpl->FindElement( aStorName ); + if ( !pElement ) + { + // element does not exist, check if creation is allowed + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) + || (( nStorageMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE ) + || ( nStorageMode & embed::ElementModes::NOCREATE ) == embed::ElementModes::NOCREATE ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + + // create a new StorageElement and insert it into the list + pElement = m_pImpl->InsertStorage( aStorName, nStorageMode ); + } + else if ( !pElement->m_bIsStorage ) + { + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + else if ( pElement->m_pStorage ) + { + // storage has already been opened; it may be opened another time, if it the mode allows to do so + if ( pElement->m_pStorage->m_pAntiImpl ) + { + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + } + else if ( !pElement->m_pStorage->m_aReadOnlyWrapList.empty() + && ( nStorageMode & embed::ElementModes::WRITE ) ) + { + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + } + else + { + // in case parent storage allows writing the readonly mode of the child storage is + // virtual, that means that it is just enough to change the flag to let it be writable + // and since there is no AntiImpl nobody should be notified about it + pElement->m_pStorage->m_nStorageMode = nStorageMode | embed::ElementModes::READ; + + if ( ( nStorageMode & embed::ElementModes::TRUNCATE ) ) + { + for ( SotElementList_Impl::iterator pElementIter = pElement->m_pStorage->m_aChildrenList.begin(); + pElementIter != pElement->m_pStorage->m_aChildrenList.end(); ) + { + SotElement_Impl* pElementToDel = (*pElementIter); + pElementIter++; + + m_pImpl->RemoveElement( pElementToDel ); + } + } + } + } + + if ( !pElement->m_pStorage ) + m_pImpl->OpenSubStorage( pElement, nStorageMode ); + + if ( !pElement->m_pStorage ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: general_error + + sal_Bool bReadOnlyWrap = ( ( nStorageMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE ); + OStorage* pResultStorage = new OStorage( pElement->m_pStorage, bReadOnlyWrap ); + xResult = uno::Reference< embed::XStorage >( (embed::XStorage*) pResultStorage ); + + if ( bReadOnlyWrap ) + { + // Before this call is done the object must be refcounted already + pElement->m_pStorage->SetReadOnlyWrap( *pResultStorage ); + + // before the storage disposes the stream it must deregister itself as listener + uno::Reference< lang::XComponent > xStorageComponent( xResult, uno::UNO_QUERY ); + if ( !xStorageComponent.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + MakeLinkToSubComponent_Impl( xStorageComponent ); + } + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't open storage!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + return xResult; +} + +//----------------------------------------------- +uno::Reference< io::XStream > SAL_CALL OStorage::cloneStreamElement( const ::rtl::OUString& aStreamName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::cloneStreamElement" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aStreamName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable storage name + + try + { + uno::Reference< io::XStream > xResult; + m_pImpl->CloneStreamElement( aStreamName, sal_False, ::rtl::OUString(), xResult ); + if ( !xResult.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + return xResult; + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + m_pImpl->AddLog( aWrongPasswordException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't clone stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +uno::Reference< io::XStream > SAL_CALL OStorage::cloneEncryptedStreamElement( + const ::rtl::OUString& aStreamName, + const ::rtl::OUString& aPass ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::NoEncryptionException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::cloneEncryptedStreamElement" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + packages::NoEncryptionException(); + + if ( !aPass.getLength() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + + try + { + uno::Reference< io::XStream > xResult; + m_pImpl->CloneStreamElement( aStreamName, sal_True, aPass, xResult ); + if ( !xResult.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + return xResult; + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + m_pImpl->AddLog( aNoEncryptionException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + m_pImpl->AddLog( aWrongPasswordException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't clone encrypted stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::copyLastCommitTo( + const uno::Reference< embed::XStorage >& xTargetStorage ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::copyLastCommitTo" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + try + { + m_pImpl->CopyLastCommitTo( xTargetStorage ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't copy last commit version!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + +} + +//----------------------------------------------- +void SAL_CALL OStorage::copyStorageElementLastCommitTo( + const ::rtl::OUString& aStorName, + const uno::Reference< embed::XStorage >& xTargetStorage ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::copyStorageElementLastCommitTo" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStorName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStorName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aStorName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable storage name + + // it's allways possible to read written storage in this implementation + sal_Int32 nStorageMode = embed::ElementModes::READ; + + try + { + SotElement_Impl *pElement = m_pImpl->FindElement( aStorName ); + if ( !pElement ) + { + // element does not exist, throw exception + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + } + else if ( !pElement->m_bIsStorage ) + { + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !pElement->m_pStorage ) + m_pImpl->OpenSubStorage( pElement, nStorageMode ); + + uno::Reference< embed::XStorage > xResult; + if ( pElement->m_pStorage ) + { + // the existence of m_pAntiImpl of the child is not interesting, + // the copy will be created internally + + pElement->m_pStorage->CopyLastCommitTo( xTargetStorage ); + } + else + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: general_error + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't copy last commit element version!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +sal_Bool SAL_CALL OStorage::isStreamElement( const ::rtl::OUString& aElementName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable name + + SotElement_Impl* pElement = NULL; + + try + { + pElement = m_pImpl->FindElement( aElementName ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't detect whether it is a stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); //??? + + return !pElement->m_bIsStorage; +} + +//----------------------------------------------- +sal_Bool SAL_CALL OStorage::isStorageElement( const ::rtl::OUString& aElementName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + SotElement_Impl* pElement = NULL; + + try + { + pElement = m_pImpl->FindElement( aElementName ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "can't detect whether it is a storage" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); //??? + + return pElement->m_bIsStorage; +} + +//----------------------------------------------- +void SAL_CALL OStorage::removeElement( const ::rtl::OUString& aElementName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::removeElement" ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // TODO: unacceptable name + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aElementName ); + + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); //??? + + m_pImpl->RemoveElement( pElement ); + + m_pImpl->m_bIsModified = sal_True; + m_pImpl->m_bBroadcastModified = sal_True; + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't remove element!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + aGuard.clear(); + + BroadcastModifiedIfNecessary(); +} + +//----------------------------------------------- +void SAL_CALL OStorage::renameElement( const ::rtl::OUString& aElementName, const ::rtl::OUString& aNewName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::renameElement" ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) + || !aNewName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aNewName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && ( aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) + || aNewName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); // TODO: unacceptable element name + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + try + { + SotElement_Impl* pRefElement = m_pImpl->FindElement( aNewName ); + if ( pRefElement ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); //??? + + SotElement_Impl* pElement = m_pImpl->FindElement( aElementName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); //??? + + pElement->m_aName = aNewName; + + m_pImpl->m_bIsModified = sal_True; + m_pImpl->m_bBroadcastModified = sal_True; + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::ElementExistException& aElementExistException ) + { + m_pImpl->AddLog( aElementExistException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't rename element!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + aGuard.clear(); + + BroadcastModifiedIfNecessary(); +} + +//----------------------------------------------- +void SAL_CALL OStorage::copyElementTo( const ::rtl::OUString& aElementName, + const uno::Reference< embed::XStorage >& xDest, + const ::rtl::OUString& aNewName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::copyElementTo" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) + || !aNewName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aNewName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !xDest.is() ) + // || xDest == uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), uno::UNO_QUERY ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && ( aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) + || aNewName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); // unacceptable element name + + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aElementName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< XNameAccess > xNameAccess( xDest, uno::UNO_QUERY ); + if ( !xNameAccess.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( xNameAccess->hasByName( aNewName ) ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_pImpl->CopyStorageElement( pElement, xDest, aNewName, sal_False ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::ElementExistException& aElementExistException ) + { + m_pImpl->AddLog( aElementExistException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't copy element!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + + +//----------------------------------------------- +void SAL_CALL OStorage::moveElementTo( const ::rtl::OUString& aElementName, + const uno::Reference< embed::XStorage >& xDest, + const ::rtl::OUString& aNewName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::moveElementTo" ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) + || !aNewName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aNewName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !xDest.is() || xDest == uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), uno::UNO_QUERY ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && ( aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) + || aNewName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); // unacceptable element name + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aElementName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); //??? + + uno::Reference< XNameAccess > xNameAccess( xDest, uno::UNO_QUERY ); + if ( !xNameAccess.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( xNameAccess->hasByName( aNewName ) ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_pImpl->CopyStorageElement( pElement, xDest, aNewName, sal_False ); + + m_pImpl->RemoveElement( pElement ); + + m_pImpl->m_bIsModified = sal_True; + m_pImpl->m_bBroadcastModified = sal_True; + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::ElementExistException& aElementExistException ) + { + m_pImpl->AddLog( aElementExistException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't move element!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + aGuard.clear(); + + BroadcastModifiedIfNecessary(); +} + +//____________________________________________________________________________________________________ +// XStorageRawAccess +//____________________________________________________________________________________________________ + +//----------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL OStorage::getPlainRawStreamElement( + const ::rtl::OUString& sStreamName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::getPlainRawStreamElement" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // the interface is not supported and must not be accessible + + if ( !sStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( sStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + uno::Reference < io::XInputStream > xTempIn; + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( sStreamName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !pElement->m_pStream ) + { + m_pImpl->OpenSubStream( pElement ); + if ( !pElement->m_pStream ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + uno::Reference< io::XInputStream > xRawInStream = pElement->m_pStream->GetPlainRawInStream(); + if ( !xRawInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference < io::XOutputStream > xTempOut( + m_pImpl->GetServiceFactory()->createInstance ( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + xTempIn = uno::Reference < io::XInputStream >( xTempOut, uno::UNO_QUERY ); + uno::Reference < io::XSeekable > xSeek( xTempOut, uno::UNO_QUERY ); + + if ( !xTempOut.is() || !xTempIn.is() || !xSeek.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // Copy temporary file to a new one + ::comphelper::OStorageHelper::CopyInputToOutput( xRawInStream, xTempOut ); + xTempOut->closeOutput(); + xSeek->seek( 0 ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't get plain raw stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + return xTempIn; +} + +//----------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL OStorage::getRawEncrStreamElement( + const ::rtl::OUString& sStreamName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::NoEncryptionException, + container::NoSuchElementException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::getRawEncrStreamElement" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !sStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( sStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + uno::Reference < io::XInputStream > xTempIn; + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( sStreamName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !pElement->m_pStream ) + { + m_pImpl->OpenSubStream( pElement ); + if ( !pElement->m_pStream ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !pElement->m_pStream->IsEncrypted() ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XInputStream > xRawInStream = pElement->m_pStream->GetRawInStream(); + if ( !xRawInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference < io::XOutputStream > xTempOut( + m_pImpl->GetServiceFactory()->createInstance ( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + xTempIn = uno::Reference < io::XInputStream >( xTempOut, uno::UNO_QUERY ); + uno::Reference < io::XSeekable > xSeek( xTempOut, uno::UNO_QUERY ); + + if ( !xTempOut.is() || !xTempIn.is() || !xSeek.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // Copy temporary file to a new one + ::comphelper::OStorageHelper::CopyInputToOutput( xRawInStream, xTempOut ); + xTempOut->closeOutput(); + xSeek->seek( 0 ); + + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::NoEncryptionException& aNoEncryptionException ) + { + m_pImpl->AddLog( aNoEncryptionException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't get raw stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + return xTempIn; +} + +//----------------------------------------------- +void SAL_CALL OStorage::insertRawEncrStreamElement( const ::rtl::OUString& aStreamName, + const uno::Reference< io::XInputStream >& xInStream ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::NoRawFormatException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::insertRawEncrStreamElement" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !aStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !xInStream.is() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aStreamName ); + if ( pElement ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_pImpl->InsertRawStream( aStreamName, xInStream ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::NoRawFormatException& aNoRawFormatException ) + { + m_pImpl->AddLog( aNoRawFormatException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::ElementExistException& aElementExistException ) + { + m_pImpl->AddLog( aElementExistException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't insert raw stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//____________________________________________________________________________________________________ +// XTransactedObject +//____________________________________________________________________________________________________ + +//----------------------------------------------- +void SAL_CALL OStorage::commit() + throw ( io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::commit" ); + + uno::Reference< util::XModifiable > xParentModif; + + try { + BroadcastTransaction( STOR_MESS_PRECOMMIT ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_bReadOnlyWrap ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access_denied + + m_pImpl->Commit(); // the root storage initiates the storing to source + + // when the storage is commited the parent is modified + if ( m_pImpl->m_pParent && m_pImpl->m_pParent->m_pAntiImpl ) + xParentModif = (util::XModifiable*)m_pImpl->m_pParent->m_pAntiImpl; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Problems on commit!" ) ), + uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >( this ) ), + aCaught ); + } + + setModified( sal_False ); + if ( xParentModif.is() ) + xParentModif->setModified( sal_True ); + + BroadcastTransaction( STOR_MESS_COMMITED ); +} + +//----------------------------------------------- +void SAL_CALL OStorage::revert() + throw ( io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::revert" ); + + // the method removes all the changes done after last commit + + BroadcastTransaction( STOR_MESS_PREREVERT ); + + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + for ( SotElementList_Impl::iterator pElementIter = m_pImpl->m_aChildrenList.begin(); + pElementIter != m_pImpl->m_aChildrenList.end(); pElementIter++ ) + { + if ( ((*pElementIter)->m_pStorage + && ( (*pElementIter)->m_pStorage->m_pAntiImpl || !(*pElementIter)->m_pStorage->m_aReadOnlyWrapList.empty() )) + || ((*pElementIter)->m_pStream + && ( (*pElementIter)->m_pStream->m_pAntiImpl || !(*pElementIter)->m_pStream->m_aInputStreamsList.empty()) ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + } + + if ( m_pData->m_bReadOnlyWrap || !m_pImpl->m_bListCreated ) + return; // nothing to do + + try { + m_pImpl->Revert(); + m_pImpl->m_bIsModified = sal_False; + m_pImpl->m_bBroadcastModified = sal_True; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Problems on revert!" ) ), + uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >( this ) ), + aCaught ); + } + + aGuard.clear(); + + setModified( sal_False ); + BroadcastTransaction( STOR_MESS_REVERTED ); +} + +//____________________________________________________________________________________________________ +// XTransactionBroadcaster +//____________________________________________________________________________________________________ + +//----------------------------------------------- +void SAL_CALL OStorage::addTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + m_pData->m_aListenersContainer.addInterface( ::getCppuType((const uno::Reference< embed::XTransactionListener >*)0), + aListener ); +} + +//----------------------------------------------- +void SAL_CALL OStorage::removeTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + m_pData->m_aListenersContainer.removeInterface( ::getCppuType((const uno::Reference< embed::XTransactionListener >*)0), + aListener ); +} + +//____________________________________________________________________________________________________ +// XModifiable +// TODO: if there will be no demand on this interface it will be removed from implementation, +// I do not want to remove it now since it is still possible that it will be inserted +// to the service back. +//____________________________________________________________________________________________________ + +//----------------------------------------------- +sal_Bool SAL_CALL OStorage::isModified() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + return m_pImpl->m_bIsModified; +} + + +//----------------------------------------------- +void SAL_CALL OStorage::setModified( sal_Bool bModified ) + throw ( beans::PropertyVetoException, + uno::RuntimeException ) +{ + ::osl::ResettableMutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_bReadOnlyWrap ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + if ( m_pImpl->m_bIsModified != bModified ) + m_pImpl->m_bIsModified = bModified; + + aGuard.clear(); + if ( bModified ) + { + m_pImpl->m_bBroadcastModified = sal_True; + BroadcastModifiedIfNecessary(); + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::addModifyListener( + const uno::Reference< util::XModifyListener >& aListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + m_pData->m_aListenersContainer.addInterface( + ::getCppuType( ( const uno::Reference< util::XModifyListener >* )0 ), aListener ); +} + + +//----------------------------------------------- +void SAL_CALL OStorage::removeModifyListener( + const uno::Reference< util::XModifyListener >& aListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + m_pData->m_aListenersContainer.removeInterface( + ::getCppuType( ( const uno::Reference< util::XModifyListener >* )0 ), aListener ); +} + +//____________________________________________________________________________________________________ +// XNameAccess +//____________________________________________________________________________________________________ + +//----------------------------------------------- +uno::Any SAL_CALL OStorage::getByName( const ::rtl::OUString& aName ) + throw ( container::NoSuchElementException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::getByName" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable element name + + uno::Any aResult; + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( pElement->m_bIsStorage ) + aResult <<= openStorageElement( aName, embed::ElementModes::READ ); + else + aResult <<= openStreamElement( aName, embed::ElementModes::READ ); + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::WrappedTargetException& aWrappedTargetException ) + { + m_pImpl->AddLog( aWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open storage!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } + + return aResult; +} + + +//----------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OStorage::getElementNames() + throw ( uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::getElementNames" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + try + { + return m_pImpl->GetElementNames(); + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open storage!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } +} + + +//----------------------------------------------- +sal_Bool SAL_CALL OStorage::hasByName( const ::rtl::OUString& aName ) + throw ( uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::hasByName" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aName.getLength() ) + return sal_False; + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + return sal_False; + + SotElement_Impl* pElement = NULL; + try + { + pElement = m_pImpl->FindElement( aName ); + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open storage!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } + + return ( pElement != NULL ); +} + + +//----------------------------------------------- +uno::Type SAL_CALL OStorage::getElementType() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + // it is a multitype container + return uno::Type(); +} + + +//----------------------------------------------- +sal_Bool SAL_CALL OStorage::hasElements() + throw ( uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::hasElements" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + try + { + return ( m_pImpl->GetChildrenList().size() != 0 ); + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open storage!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } +} + + +//____________________________________________________________________________________________________ +// XComponent +//____________________________________________________________________________________________________ + +//----------------------------------------------- +void SAL_CALL OStorage::dispose() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + try + { + InternalDispose( sal_True ); + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open storage!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::addEventListener( + const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + m_pData->m_aListenersContainer.addInterface( + ::getCppuType( ( const uno::Reference< lang::XEventListener >* )0 ), xListener ); +} + +//----------------------------------------------- +void SAL_CALL OStorage::removeEventListener( + const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + m_pData->m_aListenersContainer.removeInterface( + ::getCppuType( ( const uno::Reference< lang::XEventListener >* )0 ), xListener ); +} + +//____________________________________________________________________________________________________ +// XEncryptionProtectedSource +//____________________________________________________________________________________________________ + +void SAL_CALL OStorage::setEncryptionPassword( const ::rtl::OUString& aPass ) + throw ( uno::RuntimeException, + io::IOException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::setEncryptionPassword" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // the interface must be visible only for package storage + + OSL_ENSURE( m_pData->m_bIsRoot, "setEncryptionPassword() method is not available for nonroot storages!\n" ); + + if ( m_pData->m_bIsRoot ) + { + try { + m_pImpl->ReadContents(); + } + catch ( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open package!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } + + uno::Reference< beans::XPropertySet > xPackPropSet( m_pImpl->m_xPackage, uno::UNO_QUERY ); + if ( !xPackPropSet.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + try + { + xPackPropSet->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionKey" ) ), + uno::makeAny( ::package::MakeKeyFromPass( aPass, sal_True ) ) ); + + m_pImpl->m_bHasCommonPassword = sal_True; + m_pImpl->m_aCommonPassword = aPass; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + OSL_ENSURE( sal_False, "The call must not fail, it is pretty simple!" ); + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::removeEncryption() + throw ( uno::RuntimeException, + io::IOException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::removeEncryption" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // the interface must be visible only for package storage + + OSL_ENSURE( m_pData->m_bIsRoot, "removeEncryption() method is not available for nonroot storages!\n" ); + + if ( m_pData->m_bIsRoot ) + { + try { + m_pImpl->ReadContents(); + } + catch ( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open package!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } + + // TODO: check if the password is valid + // update all streams that was encrypted with old password + + uno::Reference< beans::XPropertySet > xPackPropSet( m_pImpl->m_xPackage, uno::UNO_QUERY ); + if ( !xPackPropSet.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + try + { + xPackPropSet->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionKey" ) ), + uno::makeAny( uno::Sequence< sal_Int8 >() ) ); + + m_pImpl->m_bHasCommonPassword = sal_False; + m_pImpl->m_aCommonPassword = ::rtl::OUString(); + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + OSL_ENSURE( sal_False, "The call must not fail, it is pretty simple!" ); + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + } +} + +//____________________________________________________________________________________________________ +// XPropertySet +//____________________________________________________________________________________________________ + +//----------------------------------------------- +uno::Reference< beans::XPropertySetInfo > SAL_CALL OStorage::getPropertySetInfo() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + //TODO: + return uno::Reference< beans::XPropertySetInfo >(); +} + + +//----------------------------------------------- +void SAL_CALL OStorage::setPropertyValue( const ::rtl::OUString& aPropertyName, const uno::Any& aValue ) + throw ( beans::UnknownPropertyException, + beans::PropertyVetoException, + lang::IllegalArgumentException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::setPropertyValue" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + //TODO: think about interaction handler + + // WORKAROUND: + // The old document might have no version in the manifest.xml, so we have to allow to set the version + // even for readonly storages, so that the version from content.xml can be used. + if ( m_pData->m_bReadOnlyWrap && !aPropertyName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: Access denied + + if ( m_pData->m_nStorageType == ZIP_STORAGE ) + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else if ( m_pData->m_nStorageType == PACKAGE_STORAGE ) + { + if ( aPropertyName.equalsAscii( "MediaType" ) ) + { + aValue >>= m_pImpl->m_aMediaType; + m_pImpl->m_bControlMediaType = sal_True; + + m_pImpl->m_bBroadcastModified = sal_True; + m_pImpl->m_bIsModified = sal_True; + } + else if ( aPropertyName.equalsAscii( "Version" ) ) + { + aValue >>= m_pImpl->m_aVersion; + m_pImpl->m_bControlVersion = sal_True; + + // this property can be set even for readonly storage + if ( !m_pData->m_bReadOnlyWrap ) + { + m_pImpl->m_bBroadcastModified = sal_True; + m_pImpl->m_bIsModified = sal_True; + } + } + else if ( m_pData->m_bIsRoot && ( aPropertyName.equalsAscii( "HasEncryptedEntries" ) + || aPropertyName.equalsAscii( "HasNonEncryptedEntries" ) + || aPropertyName.equalsAscii( "IsInconsistent" ) + || aPropertyName.equalsAscii( "URL" ) + || aPropertyName.equalsAscii( "RepairPackage" ) ) + || aPropertyName.equalsAscii( "IsRoot" ) + || aPropertyName.equalsAscii( "MediaTypeFallbackUsed" ) ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + else if ( m_pData->m_nStorageType == OFOPXML_STORAGE ) + { + if ( aPropertyName.equalsAscii( "RelationsInfoStream" ) ) + { + uno::Reference< io::XInputStream > xInRelStream; + if ( ( aValue >>= xInRelStream ) && xInRelStream.is() ) + { + uno::Reference< io::XSeekable > xSeek( xInRelStream, uno::UNO_QUERY ); + if ( !xSeek.is() ) + { + // currently this is an internal property that is used for optimization + // and the stream must support XSeekable interface + // TODO/LATER: in future it can be changed if property is used from outside + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + } + + m_pImpl->m_xNewRelInfoStream = xInRelStream; + m_pImpl->m_aRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED_STREAM; + m_pImpl->m_bBroadcastModified = sal_True; + m_pImpl->m_bIsModified = sal_True; + } + else + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + } + else if ( aPropertyName.equalsAscii( "RelationsInfo" ) ) + { + if ( aValue >>= m_pImpl->m_aRelInfo ) + { + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; + m_pImpl->m_bBroadcastModified = sal_True; + m_pImpl->m_bIsModified = sal_True; + } + else + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + } + else if ( m_pData->m_bIsRoot && ( aPropertyName.equalsAscii( "URL" ) + || aPropertyName.equalsAscii( "RepairPackage" ) ) + || aPropertyName.equalsAscii( "IsRoot" ) ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + BroadcastModifiedIfNecessary(); +} + + +//----------------------------------------------- +uno::Any SAL_CALL OStorage::getPropertyValue( const ::rtl::OUString& aPropertyName ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::getPropertyValue" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType == PACKAGE_STORAGE + && ( aPropertyName.equalsAscii( "MediaType" ) + || aPropertyName.equalsAscii( "MediaTypeFallbackUsed" ) + || aPropertyName.equalsAscii( "Version" ) ) ) + { + try + { + m_pImpl->ReadContents(); + } + catch ( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Can't read contents!" ) ), + uno::Reference< XInterface >( static_cast< OWeakObject* >( this ), uno::UNO_QUERY ), + aCaught ); + } + + if ( aPropertyName.equalsAscii( "MediaType" ) ) + return uno::makeAny( m_pImpl->m_aMediaType ); + else if ( aPropertyName.equalsAscii( "Version" ) ) + return uno::makeAny( m_pImpl->m_aVersion ); + else + return uno::makeAny( m_pImpl->m_bMTFallbackUsed ); + } + else if ( aPropertyName.equalsAscii( "IsRoot" ) ) + { + return uno::makeAny( m_pData->m_bIsRoot ); + } + else if ( aPropertyName.equalsAscii( "OpenMode" ) ) + { + return uno::makeAny( m_pImpl->m_nStorageMode ); + } + else if ( m_pData->m_bIsRoot ) + { + if ( aPropertyName.equalsAscii( "URL" ) + || aPropertyName.equalsAscii( "RepairPackage" ) ) + { + for ( sal_Int32 aInd = 0; aInd < m_pImpl->m_xProperties.getLength(); aInd++ ) + { + if ( m_pImpl->m_xProperties[aInd].Name.equals( aPropertyName ) ) + return m_pImpl->m_xProperties[aInd].Value; + } + + if ( aPropertyName.equalsAscii( "URL" ) ) + return uno::makeAny( ::rtl::OUString() ); + + return uno::makeAny( sal_False ); // RepairPackage + } + else if ( m_pData->m_nStorageType == PACKAGE_STORAGE + && ( aPropertyName.equalsAscii( "HasEncryptedEntries" ) + || aPropertyName.equalsAscii( "HasNonEncryptedEntries" ) + || aPropertyName.equalsAscii( "IsInconsistent" ) ) ) + { + try { + m_pImpl->ReadContents(); + uno::Reference< beans::XPropertySet > xPackPropSet( m_pImpl->m_xPackage, uno::UNO_QUERY ); + if ( !xPackPropSet.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return xPackPropSet->getPropertyValue( aPropertyName ); + } + catch ( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch ( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can not open package!\n" ) ), + uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), + uno::UNO_QUERY ), + aCaught ); + } + } + } + + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + + +//----------------------------------------------- +void SAL_CALL OStorage::addPropertyChangeListener( + const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OStorage::removePropertyChangeListener( + const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OStorage::addVetoableChangeListener( + const ::rtl::OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + //TODO: +} + + +//----------------------------------------------- +void SAL_CALL OStorage::removeVetoableChangeListener( + const ::rtl::OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw ( beans::UnknownPropertyException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + //TODO: +} + +//____________________________________________________________________________________________________ +// XRelationshipAccess +//____________________________________________________________________________________________________ + +// TODO/LATER: the storage and stream implementations of this interface are very similar, they could use a helper class + +//----------------------------------------------- +sal_Bool SAL_CALL OStorage::hasByID( const ::rtl::OUString& sID ) + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + try + { + getRelationshipByID( sID ); + return sal_True; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Quiet exception" ) ) ); + } + + return sal_False; +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL OStorage::getTargetByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID ); + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( aSeq[nInd].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Target" ) ) ) + return aSeq[nInd].Second; + + return ::rtl::OUString(); +} + +//----------------------------------------------- +::rtl::OUString SAL_CALL OStorage::getTypeByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID ); + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( aSeq[nInd].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Type" ) ) ) + return aSeq[nInd].Second; + + return ::rtl::OUString(); +} + +//----------------------------------------------- +uno::Sequence< beans::StringPair > SAL_CALL OStorage::getRelationshipByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Id" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + return aSeq[nInd1]; + break; + } + + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OStorage::getRelationshipsByType( const ::rtl::OUString& sType ) + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< uno::Sequence< beans::StringPair > > aResult; + sal_Int32 nEntriesNum = 0; + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Type" ) ) ) + { + // the type is usually an URL, so the check should be case insensitive + if ( aSeq[nInd1][nInd2].Second.equalsIgnoreAsciiCase( sType ) ) + { + aResult.realloc( ++nEntriesNum ); + aResult[nEntriesNum-1] = aSeq[nInd1]; + } + break; + } + + return aResult; +} + +//----------------------------------------------- +uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OStorage::getAllRelationships() + throw (io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_pImpl->GetAllRelationshipsIfAny(); +} + +//----------------------------------------------- +void SAL_CALL OStorage::insertRelationshipByID( const ::rtl::OUString& sID, const uno::Sequence< beans::StringPair >& aEntry, ::sal_Bool bReplace ) + throw ( container::ElementExistException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + ::rtl::OUString aIDTag( RTL_CONSTASCII_USTRINGPARAM( "Id" ) ); + + sal_Int32 nIDInd = -1; + + // TODO/LATER: in future the unification of the ID could be checked + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equals( aIDTag ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + nIDInd = nInd1; + + break; + } + + if ( nIDInd == -1 || bReplace ) + { + if ( nIDInd == -1 ) + { + nIDInd = aSeq.getLength(); + aSeq.realloc( nIDInd + 1 ); + } + + aSeq[nIDInd].realloc( aEntry.getLength() + 1 ); + + aSeq[nIDInd][0].First = aIDTag; + aSeq[nIDInd][0].Second = sID; + sal_Int32 nIndTarget = 1; + for ( sal_Int32 nIndOrig = 0; + nIndOrig < aEntry.getLength(); + nIndOrig++ ) + { + if ( !aEntry[nIndOrig].First.equals( aIDTag ) ) + aSeq[nIDInd][nIndTarget++] = aEntry[nIndOrig]; + } + + aSeq[nIDInd].realloc( nIndTarget ); + } + else + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + + m_pImpl->m_aRelInfo = aSeq; + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; +} + +//----------------------------------------------- +void SAL_CALL OStorage::removeRelationshipByID( const ::rtl::OUString& sID ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ ) + for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ ) + if ( aSeq[nInd1][nInd2].First.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Id" ) ) ) + { + if ( aSeq[nInd1][nInd2].Second.equals( sID ) ) + { + sal_Int32 nLength = aSeq.getLength(); + aSeq[nInd1] = aSeq[nLength-1]; + aSeq.realloc( nLength - 1 ); + + m_pImpl->m_aRelInfo = aSeq; + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; + + // TODO/LATER: in future the unification of the ID could be checked + return; + } + + break; + } + + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//----------------------------------------------- +void SAL_CALL OStorage::insertRelationships( const uno::Sequence< uno::Sequence< beans::StringPair > >& aEntries, ::sal_Bool bReplace ) + throw ( container::ElementExistException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + ::rtl::OUString aIDTag( RTL_CONSTASCII_USTRINGPARAM( "Id" ) ); + uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships(); + uno::Sequence< uno::Sequence< beans::StringPair > > aResultSeq( aSeq.getLength() + aEntries.getLength() ); + sal_Int32 nResultInd = 0; + + for ( sal_Int32 nIndTarget1 = 0; nIndTarget1 < aSeq.getLength(); nIndTarget1++ ) + for ( sal_Int32 nIndTarget2 = 0; nIndTarget2 < aSeq[nIndTarget1].getLength(); nIndTarget2++ ) + if ( aSeq[nIndTarget1][nIndTarget2].First.equals( aIDTag ) ) + { + sal_Int32 nIndSourceSame = -1; + + for ( sal_Int32 nIndSource1 = 0; nIndSource1 < aEntries.getLength(); nIndSource1++ ) + for ( sal_Int32 nIndSource2 = 0; nIndSource2 < aEntries[nIndSource1].getLength(); nIndSource2++ ) + { + if ( aEntries[nIndSource1][nIndSource2].First.equals( aIDTag ) ) + { + if ( aEntries[nIndSource1][nIndSource2].Second.equals( aSeq[nIndTarget1][nIndTarget2].Second ) ) + { + if ( !bReplace ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + nIndSourceSame = nIndSource1; + } + + break; + } + } + + if ( nIndSourceSame == -1 ) + { + // no such element in the provided sequence + aResultSeq[nResultInd++] = aSeq[nIndTarget1]; + } + + break; + } + + for ( sal_Int32 nIndSource1 = 0; nIndSource1 < aEntries.getLength(); nIndSource1++ ) + { + aResultSeq[nResultInd].realloc( aEntries[nIndSource1].getLength() ); + sal_Bool bHasID = sal_False; + sal_Int32 nResInd2 = 1; + + for ( sal_Int32 nIndSource2 = 0; nIndSource2 < aEntries[nIndSource1].getLength(); nIndSource2++ ) + if ( aEntries[nIndSource1][nIndSource2].First.equals( aIDTag ) ) + { + aResultSeq[nResultInd][0] = aEntries[nIndSource1][nIndSource2]; + bHasID = sal_True; + } + else if ( nResInd2 < aResultSeq[nResultInd].getLength() ) + aResultSeq[nResultInd][nResInd2++] = aEntries[nIndSource1][nIndSource2]; + else + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: illegal relation ( no ID ) + + if ( !bHasID ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: illegal relations + + nResultInd++; + } + + aResultSeq.realloc( nResultInd ); + m_pImpl->m_aRelInfo = aResultSeq; + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; +} + +//----------------------------------------------- +void SAL_CALL OStorage::clearRelationships() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != OFOPXML_STORAGE ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_pImpl->m_aRelInfo.realloc( 0 ); + m_pImpl->m_xNewRelInfoStream = uno::Reference< io::XInputStream >(); + m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED; +} + +//____________________________________________________________________________________________________ +// XOptimizedStorage +//____________________________________________________________________________________________________ +//----------------------------------------------- +void SAL_CALL OStorage::insertRawNonEncrStreamElementDirect( + const ::rtl::OUString& /*sStreamName*/, + const uno::Reference< io::XInputStream >& /*xInStream*/ ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::NoRawFormatException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + // not implemented currently because there is still no demand + // might need to be implemented if direct copying of compressed streams is used + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//----------------------------------------------- +void SAL_CALL OStorage::insertStreamElementDirect( + const ::rtl::OUString& aStreamName, + const uno::Reference< io::XInputStream >& xInStream, + const uno::Sequence< beans::PropertyValue >& aProps ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::insertStreamElementDirect" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aStreamName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable storage name + + if ( m_pData->m_bReadOnlyWrap ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: access denied + + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aStreamName ); + + if ( pElement ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + pElement = OpenStreamElement_Impl( aStreamName, embed::ElementModes::READWRITE, sal_False ); + OSL_ENSURE( pElement && pElement->m_pStream, "In case element can not be created an exception must be thrown!" ); + + pElement->m_pStream->InsertStreamDirectly( xInStream, aProps ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::ElementExistException& aElementExistException ) + { + m_pImpl->AddLog( aElementExistException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't insert stream directly!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::copyElementDirectlyTo( + const ::rtl::OUString& aElementName, + const uno::Reference< embed::XOptimizedStorage >& xDest, + const ::rtl::OUString& aNewName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + container::ElementExistException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::copyElementDirectlyTo" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) + || !aNewName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aNewName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !xDest.is() || xDest == uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ), uno::UNO_QUERY ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && ( aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) + || aNewName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); // unacceptable name + + try + { + SotElement_Impl* pElement = m_pImpl->FindElement( aElementName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< XNameAccess > xNameAccess( xDest, uno::UNO_QUERY ); + if ( !xNameAccess.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( xNameAccess->hasByName( aNewName ) ) + throw container::ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // let the element be copied directly + uno::Reference< embed::XStorage > xStorDest( xDest, uno::UNO_QUERY_THROW ); + m_pImpl->CopyStorageElement( pElement, xStorDest, aNewName, sal_True ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::ElementExistException& aElementExistException ) + { + m_pImpl->AddLog( aElementExistException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't copy element direcly!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::writeAndAttachToStream( const uno::Reference< io::XStream >& xStream ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::writeAndAttachToStream" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !m_pData->m_bIsRoot ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + + if ( !m_pImpl->m_pSwitchStream ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + try + { + m_pImpl->m_pSwitchStream->CopyAndSwitchPersistenceTo( xStream ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't write and attach to stream!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + +} + +//----------------------------------------------- +void SAL_CALL OStorage::attachToURL( const ::rtl::OUString& sURL, + sal_Bool bReadOnly ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::attachToURL" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !m_pData->m_bIsRoot ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + + if ( !m_pImpl->m_pSwitchStream ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference < ucb::XSimpleFileAccess > xAccess( + m_pImpl->m_xFactory->createInstance ( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.SimpleFileAccess" ) ) ), + uno::UNO_QUERY_THROW ); + + try + { + if ( bReadOnly ) + { + uno::Reference< io::XInputStream > xInputStream = xAccess->openFileRead( sURL ); + m_pImpl->m_pSwitchStream->SwitchPersistenceTo( xInputStream ); + } + else + { + uno::Reference< io::XStream > xStream = xAccess->openFileReadWrite( sURL ); + m_pImpl->m_pSwitchStream->SwitchPersistenceTo( xStream ); + } + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't attach to URL!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +uno::Any SAL_CALL OStorage::getElementPropertyValue( const ::rtl::OUString& aElementName, const ::rtl::OUString& aPropertyName ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + io::IOException, + beans::UnknownPropertyException, + beans::PropertyVetoException, + embed::StorageWrappedTargetException, + uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT( aLog, "package (mv76033) OStorage::getElementPropertyValue" ); + + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aElementName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aElementName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aElementName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // TODO: unacceptable name + + try + { + SotElement_Impl *pElement = m_pImpl->FindElement( aElementName ); + if ( !pElement ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // TODO/LATER: Currently it is only implemented for MediaType property of substorages, might be changed in future + if ( !pElement->m_bIsStorage || m_pData->m_nStorageType != PACKAGE_STORAGE || !aPropertyName.equalsAscii( "MediaType" ) ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !pElement->m_pStorage ) + m_pImpl->OpenSubStorage( pElement, embed::ElementModes::READ ); + + if ( !pElement->m_pStorage ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // TODO: general_error + + pElement->m_pStorage->ReadContents(); + return uno::makeAny( pElement->m_pStorage->m_aMediaType ); + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( container::NoSuchElementException& aNoSuchElementException ) + { + m_pImpl->AddLog( aNoSuchElementException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( beans::UnknownPropertyException& aUnknownPropertyException ) + { + m_pImpl->AddLog( aUnknownPropertyException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( beans::PropertyVetoException& aPropertyVetoException ) + { + m_pImpl->AddLog( aPropertyVetoException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't get element property!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } +} + +//----------------------------------------------- +void SAL_CALL OStorage::copyStreamElementData( const ::rtl::OUString& aStreamName, const uno::Reference< io::XStream >& xTargetStream ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStreamName.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamName, sal_False ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( m_pData->m_nStorageType == OFOPXML_STORAGE + && aStreamName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_rels" ) ) ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); // unacceptable name + + if ( !xTargetStream.is() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + + try + { + uno::Reference< io::XStream > xNonconstRef = xTargetStream; + m_pImpl->CloneStreamElement( aStreamName, sal_False, ::rtl::OUString(), xNonconstRef ); + + OSL_ENSURE( xNonconstRef == xTargetStream, "The provided stream reference seems not be filled in correctly!\n" ); + if ( xNonconstRef != xTargetStream ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // if the stream reference is set it must not be changed! + } + catch( embed::InvalidStorageException& aInvalidStorageException ) + { + m_pImpl->AddLog( aInvalidStorageException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( lang::IllegalArgumentException& aIllegalArgumentException ) + { + m_pImpl->AddLog( aIllegalArgumentException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( packages::WrongPasswordException& aWrongPasswordException ) + { + m_pImpl->AddLog( aWrongPasswordException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( io::IOException& aIOException ) + { + m_pImpl->AddLog( aIOException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( embed::StorageWrappedTargetException& aStorageWrappedTargetException ) + { + m_pImpl->AddLog( aStorageWrappedTargetException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::RuntimeException& aRuntimeException ) + { + m_pImpl->AddLog( aRuntimeException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + throw; + } + catch( uno::Exception& aException ) + { + m_pImpl->AddLog( aException.Message ); + m_pImpl->AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Rethrow" ) ) ); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw embed::StorageWrappedTargetException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Can't copy stream data!" ) ), + uno::Reference< io::XInputStream >(), + aCaught ); + } + + +} + +//____________________________________________________________________________________________________ +// XHierarchicalStorageAccess +//____________________________________________________________________________________________________ + +//----------------------------------------------- +uno::Reference< embed::XExtendedStorageStream > SAL_CALL OStorage::openStreamElementByHierarchicalName( const ::rtl::OUString& aStreamPath, ::sal_Int32 nOpenMode ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStreamPath.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamPath, sal_True ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) + && ( nOpenMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // Access denied + + OStringList_Impl aListPath = OHierarchyHolder_Impl::GetListPathFromString( aStreamPath ); + OSL_ENSURE( aListPath.size(), "The result list must not be empty!" ); + + uno::Reference< embed::XExtendedStorageStream > xResult; + if ( aListPath.size() == 1 ) + { + // that must be a direct request for a stream + // the transacted version of the stream should be opened + + SotElement_Impl *pElement = OpenStreamElement_Impl( aStreamPath, nOpenMode, sal_False ); + OSL_ENSURE( pElement && pElement->m_pStream, "In case element can not be created an exception must be thrown!" ); + + xResult = uno::Reference< embed::XExtendedStorageStream >( + pElement->m_pStream->GetStream( nOpenMode, sal_True ), + uno::UNO_QUERY_THROW ); + } + else + { + // there are still storages in between + if ( !m_pData->m_rHierarchyHolder.is() ) + m_pData->m_rHierarchyHolder = new OHierarchyHolder_Impl( + uno::Reference< embed::XStorage >( static_cast< embed::XStorage* >( this ) ) ); + + xResult = m_pData->m_rHierarchyHolder->GetStreamHierarchically( + ( m_pImpl->m_nStorageMode & embed::ElementModes::READWRITE ), + aListPath, + nOpenMode ); + } + + if ( !xResult.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return xResult; +} + +//----------------------------------------------- +uno::Reference< embed::XExtendedStorageStream > SAL_CALL OStorage::openEncryptedStreamElementByHierarchicalName( const ::rtl::OUString& aStreamPath, ::sal_Int32 nOpenMode, const ::rtl::OUString& sPassword ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + packages::NoEncryptionException, + packages::WrongPasswordException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( m_pData->m_nStorageType != PACKAGE_STORAGE ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !aStreamPath.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamPath, sal_True ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !sPassword.getLength() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 3 ); + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) + && ( nOpenMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // Access denied + + OStringList_Impl aListPath = OHierarchyHolder_Impl::GetListPathFromString( aStreamPath ); + OSL_ENSURE( aListPath.size(), "The result list must not be empty!" ); + + uno::Reference< embed::XExtendedStorageStream > xResult; + if ( aListPath.size() == 1 ) + { + // that must be a direct request for a stream + // the transacted version of the stream should be opened + + SotElement_Impl *pElement = OpenStreamElement_Impl( aStreamPath, nOpenMode, sal_True ); + OSL_ENSURE( pElement && pElement->m_pStream, "In case element can not be created an exception must be thrown!" ); + + xResult = uno::Reference< embed::XExtendedStorageStream >( + pElement->m_pStream->GetStream( nOpenMode, sPassword, sal_True ), + uno::UNO_QUERY_THROW ); + } + else + { + // there are still storages in between + if ( !m_pData->m_rHierarchyHolder.is() ) + m_pData->m_rHierarchyHolder = new OHierarchyHolder_Impl( + uno::Reference< embed::XStorage >( static_cast< embed::XStorage* >( this ) ) ); + + xResult = m_pData->m_rHierarchyHolder->GetStreamHierarchically( + ( m_pImpl->m_nStorageMode & embed::ElementModes::READWRITE ), + aListPath, + nOpenMode, + sPassword ); + } + + if ( !xResult.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return xResult; +} + +//----------------------------------------------- +void SAL_CALL OStorage::removeStreamElementByHierarchicalName( const ::rtl::OUString& aStreamPath ) + throw ( embed::InvalidStorageException, + lang::IllegalArgumentException, + container::NoSuchElementException, + io::IOException, + embed::StorageWrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_pData->m_rSharedMutexRef->GetMutex() ); + + if ( !m_pImpl ) + { + ::package::StaticAddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Disposed!" ) ) ); + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + if ( !aStreamPath.getLength() || !::comphelper::OStorageHelper::IsValidZipEntryFileName( aStreamPath, sal_True ) ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected entry name syntax." ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !( m_pImpl->m_nStorageMode & embed::ElementModes::WRITE ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // Access denied + + OStringList_Impl aListPath = OHierarchyHolder_Impl::GetListPathFromString( aStreamPath ); + OSL_ENSURE( aListPath.size(), "The result list must not be empty!" ); + + if ( !m_pData->m_rHierarchyHolder.is() ) + m_pData->m_rHierarchyHolder = new OHierarchyHolder_Impl( + uno::Reference< embed::XStorage >( static_cast< embed::XStorage* >( this ) ) ); + + m_pData->m_rHierarchyHolder->RemoveStreamHierarchically( aListPath ); +} + diff --git a/package/source/xstor/xstorage.hxx b/package/source/xstor/xstorage.hxx new file mode 100644 index 000000000000..91be457b02cb --- /dev/null +++ b/package/source/xstor/xstorage.hxx @@ -0,0 +1,815 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xstorage.hxx,v $ + * $Revision: 1.17 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __XSTORAGE_HXX_ +#define __XSTORAGE_HXX_ + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XOptimizedStorage.hpp> +#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp> +#include <com/sun/star/embed/XStorageRawAccess.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/embed/XClassifiedObject.hpp> +#include <com/sun/star/embed/XEncryptionProtectedSource.hpp> +#include <com/sun/star/embed/XRelationshipAccess.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/StringPair.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/packages/NoEncryptionException.hpp> +#include <com/sun/star/logging/XSimpleLogRing.hpp> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/interfacecontainer.h> + +#include "mutexholder.hxx" + + +#define PACKAGE_STORAGE 0 +#define ZIP_STORAGE 1 +#define OFOPXML_STORAGE 2 + +#define RELINFO_NO_INIT 1 +#define RELINFO_READ 2 +#define RELINFO_CHANGED 3 +#define RELINFO_CHANGED_STREAM 4 +#define RELINFO_CHANGED_STREAM_READ 5 +#define RELINFO_BROKEN 6 +#define RELINFO_CHANGED_BROKEN 7 + +#define STOR_MESS_PRECOMMIT 1 +#define STOR_MESS_COMMITED 2 +#define STOR_MESS_PREREVERT 3 +#define STOR_MESS_REVERTED 4 + +namespace cppu +{ + class OTypeCollection; +} + +//================================================ +// a common implementation for an entry + +struct StorInternalData_Impl; +struct OStorage_Impl; +struct OWriteStream_Impl; + +struct SotElement_Impl +{ + ::rtl::OUString m_aName; + ::rtl::OUString m_aOriginalName; + sal_Bool m_bIsRemoved; + sal_Bool m_bIsInserted; + sal_Bool m_bIsStorage; + + OStorage_Impl* m_pStorage; + OWriteStream_Impl* m_pStream; + +public: + SotElement_Impl( const ::rtl::OUString& rName, sal_Bool bStor, sal_Bool bNew ); + ~SotElement_Impl(); +}; + +#include <list> +typedef ::std::list< SotElement_Impl* > SotElementList_Impl; + +//========================================================================= +// Main storage implementation + +class OStorage; + +struct StorageHolder_Impl +{ + OStorage* m_pPointer; + ::com::sun::star::uno::WeakReference< ::com::sun::star::embed::XStorage > m_xWeakRef; + + StorageHolder_Impl( OStorage* pStorage ) + : m_pPointer( pStorage ) + , m_xWeakRef( ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >( + (::com::sun::star::embed::XStorage*)pStorage ) ) + { + } + + StorageHolder_Impl( const StorageHolder_Impl& aSH ) + : m_pPointer( aSH.m_pPointer ) + , m_xWeakRef( aSH.m_xWeakRef ) + { + } +}; + +typedef ::std::list< StorageHolder_Impl > OStorageList_Impl; + +class SwitchablePersistenceStream; +struct OStorage_Impl +{ + SotMutexHolderRef m_rMutexRef; + + OStorage* m_pAntiImpl; // only valid if external references exists + OStorageList_Impl m_aReadOnlyWrapList; // only valid if readonly external reference exists + + sal_Int32 m_nStorageMode; // open mode ( read/write/trunc/nocreate ) + sal_Bool m_bIsModified; // only modified elements will be sent to the original content + sal_Bool m_bBroadcastModified; // will be set if notification is required + sal_Bool m_bCommited; // sending the streams is coordinated by the root storage of the package + + sal_Bool m_bIsRoot; // marks this storage as root storages that manages all commits and reverts + sal_Bool m_bListCreated; + + + SotElementList_Impl m_aChildrenList; + SotElementList_Impl m_aDeletedList; + + ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > m_xPackageFolder; + ::com::sun::star::uno::Reference< ::com::sun::star::logging::XSimpleLogRing > m_xLogRing; + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > m_xPackage; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory; + + // valid only for root storage + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xInputStream; // ??? may be stored in properties + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > m_xStream; // ??? may be stored in properties + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_xProperties; + sal_Bool m_bHasCommonPassword; + ::rtl::OUString m_aCommonPassword; + + // must be empty in case of root storage + OStorage_Impl* m_pParent; + + sal_Bool m_bControlMediaType; + ::rtl::OUString m_aMediaType; + sal_Bool m_bMTFallbackUsed; + + sal_Bool m_bControlVersion; + ::rtl::OUString m_aVersion; + + SwitchablePersistenceStream* m_pSwitchStream; + + sal_Int16 m_nStorageType; // the mode in wich the storage is used + + // the _rels substorage that is handled in a special way in OFOPXML_STORAGE + SotElement_Impl* m_pRelStorElement; + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > m_xRelStorage; + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > m_aRelInfo; + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xNewRelInfoStream; + sal_Int16 m_nRelInfoStatus; + + ////////////////////////////////////////// + // Constructors + + OStorage_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > xInputStream, + sal_Int32 nMode, + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > xProperties, + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ); + + OStorage_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xStream, + sal_Int32 nMode, + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > xProperties, + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ); + + // constructor for a substorage + OStorage_Impl( OStorage_Impl* pParent, + sal_Int32 nMode, + ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > xPackageFolder, + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > xPackage, + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ); + + ~OStorage_Impl(); + + void AddLog( const ::rtl::OUString& aMessage ); + + void SetReadOnlyWrap( OStorage& aStorage ); + void RemoveReadOnlyWrap( OStorage& aStorage ); + + void OpenOwnPackage(); + void ReadContents(); + void ReadRelInfoIfNecessary(); + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > GetServiceFactory(); + SotElementList_Impl& GetChildrenList(); + void GetStorageProperties(); + + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > GetAllRelationshipsIfAny(); + void CopyLastCommitTo( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xNewStor ); + void CopyLastCommitTo( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xNewStor, + const ::rtl::OUString& aPass ); + + void InsertIntoPackageFolder( + const ::rtl::OUString& aName, + const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& xParentPackageFolder ); + + void Commit(); + void Revert(); + + ::rtl::OUString GetCommonRootPass() throw ( ::com::sun::star::packages::NoEncryptionException ); + + void CopyToStorage( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xDest, + sal_Bool bDirect ); + void CopyStorageElement( SotElement_Impl* pElement, + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > xDest, + ::rtl::OUString aName, + sal_Bool bDirect ); + + void SetModified( sal_Bool bModified ); + + SotElement_Impl* FindElement( const ::rtl::OUString& rName ); + + + SotElement_Impl* InsertStream( ::rtl::OUString aName, sal_Bool bEncr ); + SotElement_Impl* InsertRawStream( ::rtl::OUString aName, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream ); + + OStorage_Impl* CreateNewStorageImpl( sal_Int32 nStorageMode ); + SotElement_Impl* InsertStorage( ::rtl::OUString aName, sal_Int32 nStorageMode ); + SotElement_Impl* InsertElement( ::rtl::OUString aName, sal_Bool bIsStorage ); + + void OpenSubStorage( SotElement_Impl* pElement, sal_Int32 nStorageMode ); + void OpenSubStream( SotElement_Impl* pElement ); + + ::com::sun::star::uno::Sequence< ::rtl::OUString > GetElementNames(); + + void RemoveElement( SotElement_Impl* pElement ); + void ClearElement( SotElement_Impl* pElement ); + void DisposeChildren(); + + void CloneStreamElement( + const ::rtl::OUString& aStreamName, + sal_Bool bPassProvided, + const ::rtl::OUString& aPass, + ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xTargetStream ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + void RemoveStreamRelInfo( const ::rtl::OUString& aOriginalName ); + void CreateRelStorage(); + void CommitStreamRelInfo( SotElement_Impl* pStreamElement ); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetRelInfoStreamForName( const ::rtl::OUString& aName ); + void CommitRelInfo( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& xNewPackageFolder ); + + static void completeStorageStreamCopy_Impl( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xSource, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xDest, + sal_Int16 nStorageType, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > >& aRelInfo ); + +}; + + +class OStorage : public ::com::sun::star::lang::XTypeProvider + , public ::com::sun::star::embed::XStorage + , public ::com::sun::star::embed::XStorageRawAccess + , public ::com::sun::star::embed::XTransactedObject + , public ::com::sun::star::embed::XTransactionBroadcaster + , public ::com::sun::star::util::XModifiable + // , public ::com::sun::star::container::XNameAccess + // , public ::com::sun::star::lang::XComponent + , public ::com::sun::star::embed::XEncryptionProtectedSource + , public ::com::sun::star::beans::XPropertySet + , public ::com::sun::star::embed::XOptimizedStorage + , public ::com::sun::star::embed::XRelationshipAccess + , public ::com::sun::star::embed::XHierarchicalStorageAccess + , public ::cppu::OWeakObject +{ + OStorage_Impl* m_pImpl; + StorInternalData_Impl* m_pData; + +protected: + + void Commit_Impl(); + + SotElement_Impl* OpenStreamElement_Impl( const ::rtl::OUString& aStreamName, sal_Int32 nOpenMode, sal_Bool bEncr ); + + void BroadcastModifiedIfNecessary(); + + void BroadcastTransaction( sal_Int8 nMessage ); + + void MakeLinkToSubComponent_Impl( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xComponent ); + +public: + + OStorage( ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > xInputStream, + sal_Int32 nMode, + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > xProperties, + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ); + + OStorage( ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xStream, + sal_Int32 nMode, + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > xProperties, + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory, + sal_Int16 nStorageType ); + + OStorage( OStorage_Impl* pImpl, sal_Bool bReadOnlyWrap ); + + virtual ~OStorage(); + + void SAL_CALL InternalDispose( sal_Bool bNotifyImpl ); + + void ChildIsDisposed( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xChild ); + + sal_Int32 GetRefCount_Impl() { return m_refCount; } + + //____________________________________________________________________________________________________ + // XInterface + //____________________________________________________________________________________________________ + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& rType ) + throw( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL acquire() throw(); + + virtual void SAL_CALL release() throw(); + + //____________________________________________________________________________________________________ + // XTypeProvider + //____________________________________________________________________________________________________ + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes() + throw( ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() + throw( ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XStorage + //____________________________________________________________________________________________________ + + virtual void SAL_CALL copyToStorage( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xDest ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > SAL_CALL openStreamElement( + const ::rtl::OUString& aStreamName, sal_Int32 nOpenMode ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > SAL_CALL openEncryptedStreamElement( + const ::rtl::OUString& aStreamName, sal_Int32 nOpenMode, const ::rtl::OUString& aPass ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > SAL_CALL openStorageElement( + const ::rtl::OUString& aStorName, sal_Int32 nStorageMode ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > SAL_CALL cloneStreamElement( + const ::rtl::OUString& aStreamName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > SAL_CALL cloneEncryptedStreamElement( + const ::rtl::OUString& aStreamName, const ::rtl::OUString& aPass ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL copyLastCommitTo( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xTargetStorage ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL copyStorageElementLastCommitTo( + const ::rtl::OUString& aStorName, + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xTargetStorage ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL isStreamElement( const ::rtl::OUString& aElementName ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL isStorageElement( const ::rtl::OUString& aElementName ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removeElement( const ::rtl::OUString& aElementName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL renameElement( const ::rtl::OUString& rEleName, const ::rtl::OUString& rNewName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL copyElementTo( const ::rtl::OUString& aElementName, + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xDest, + const ::rtl::OUString& aNewName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL moveElementTo( const ::rtl::OUString& aElementName, + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xDest, + const ::rtl::OUString& rNewName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XStorageRawAccess + //____________________________________________________________________________________________________ + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getPlainRawStreamElement( + const ::rtl::OUString& sStreamName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawEncrStreamElement( + const ::rtl::OUString& sStreamName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL insertRawEncrStreamElement( const ::rtl::OUString& aStreamName, + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::NoRawFormatException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + //____________________________________________________________________________________________________ + // XTransactedObject + //____________________________________________________________________________________________________ + + virtual void SAL_CALL commit() + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL revert() + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XTransactionBroadcaster + //____________________________________________________________________________________________________ + + virtual void SAL_CALL addTransactionListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XTransactionListener >& aListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removeTransactionListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XTransactionListener >& aListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XModifiable + //____________________________________________________________________________________________________ + + virtual sal_Bool SAL_CALL isModified() + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL setModified( sal_Bool bModified ) + throw ( ::com::sun::star::beans::PropertyVetoException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL addModifyListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removeModifyListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XNameAccess + //____________________________________________________________________________________________________ + + virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames() + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Type SAL_CALL getElementType() + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL hasElements() + throw ( ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XComponent + //____________________________________________________________________________________________________ + + virtual void SAL_CALL dispose() + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL addEventListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removeEventListener( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) + throw ( ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XEncryptionProtectedSource + //____________________________________________________________________________________________________ + + virtual void SAL_CALL setEncryptionPassword( const ::rtl::OUString& aPass ) + throw ( ::com::sun::star::uno::RuntimeException, + ::com::sun::star::io::IOException ); + + virtual void SAL_CALL removeEncryption() + throw ( ::com::sun::star::uno::RuntimeException, + ::com::sun::star::io::IOException ); + + //____________________________________________________________________________________________________ + // XPropertySet + //____________________________________________________________________________________________________ + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw ( ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::beans::PropertyVetoException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw ( ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL addPropertyChangeListener( + const ::rtl::OUString& aPropertyName, + const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) + throw ( ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removePropertyChangeListener( + const ::rtl::OUString& aPropertyName, + const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) + throw ( ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL addVetoableChangeListener( + const ::rtl::OUString& PropertyName, + const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw ( ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw ( ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::lang::WrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XOptimizedStorage + //____________________________________________________________________________________________________ + virtual void SAL_CALL insertRawNonEncrStreamElementDirect( const ::rtl::OUString& sStreamName, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::NoRawFormatException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL insertStreamElementDirect( const ::rtl::OUString& sStreamName, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL copyElementDirectlyTo( const ::rtl::OUString& sSourceName, const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XOptimizedStorage >& xTargetStorage, const ::rtl::OUString& sTargetName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL writeAndAttachToStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xStream ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL attachToURL( const ::rtl::OUString& sURL, sal_Bool bReadOnly ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Any SAL_CALL getElementPropertyValue( const ::rtl::OUString& sElementName, const ::rtl::OUString& sPropertyName ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::beans::PropertyVetoException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL copyStreamElementData( const ::rtl::OUString& sStreamName, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream >& xTargetStream ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException ); + + //____________________________________________________________________________________________________ + // XRelationshipAccess + //____________________________________________________________________________________________________ + + virtual ::sal_Bool SAL_CALL hasByID( const ::rtl::OUString& sID ) + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual ::rtl::OUString SAL_CALL getTargetByID( const ::rtl::OUString& sID ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual ::rtl::OUString SAL_CALL getTypeByID( const ::rtl::OUString& sID ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > SAL_CALL getRelationshipByID( const ::rtl::OUString& sID ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > SAL_CALL getRelationshipsByType( const ::rtl::OUString& sType ) + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > > SAL_CALL getAllRelationships( ) + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL insertRelationshipByID( const ::rtl::OUString& sID, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair >& aEntry, ::sal_Bool bReplace ) + throw ( ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL removeRelationshipByID( const ::rtl::OUString& sID ) + throw ( ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL insertRelationships( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::beans::StringPair > >& aEntries, ::sal_Bool bReplace ) + throw ( ::com::sun::star::container::ElementExistException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL clearRelationships( ) + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException); + + //____________________________________________________________________________________________________ + // XHierarchicalStorageAccess + //____________________________________________________________________________________________________ + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::embed::XExtendedStorageStream > SAL_CALL openStreamElementByHierarchicalName( const ::rtl::OUString& sStreamPath, ::sal_Int32 nOpenMode ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::embed::XExtendedStorageStream > SAL_CALL openEncryptedStreamElementByHierarchicalName( const ::rtl::OUString& sStreamName, ::sal_Int32 nOpenMode, const ::rtl::OUString& sPassword ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL removeStreamElementByHierarchicalName( const ::rtl::OUString& sElementPath ) + throw ( ::com::sun::star::embed::InvalidStorageException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException, + ::com::sun::star::io::IOException, + ::com::sun::star::embed::StorageWrappedTargetException, + ::com::sun::star::uno::RuntimeException); + +}; + + +#endif + diff --git a/package/source/zipapi/ByteChucker.cxx b/package/source/zipapi/ByteChucker.cxx new file mode 100644 index 000000000000..f7a5f8c123f9 --- /dev/null +++ b/package/source/zipapi/ByteChucker.cxx @@ -0,0 +1,115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ByteChucker.cxx,v $ + * $Revision: 1.22 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ByteChucker.hxx> +#include <PackageConstants.hxx> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XOutputStream.hpp> + +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +ByteChucker::ByteChucker(Reference<XOutputStream> xOstream) +: xStream(xOstream) +, xSeek (xOstream, UNO_QUERY ) +, a1Sequence ( 1 ) +, a2Sequence ( 2 ) +, a4Sequence ( 4 ) +, p1Sequence ( a1Sequence.getArray() ) +, p2Sequence ( a2Sequence.getArray() ) +, p4Sequence ( a4Sequence.getArray() ) +{ +} + +ByteChucker::~ByteChucker() +{ +} + +void ByteChucker::WriteBytes( const Sequence< sal_Int8 >& aData ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + xStream->writeBytes(aData); +} + +sal_Int64 ByteChucker::GetPosition( ) + throw(IOException, RuntimeException) +{ + return xSeek->getPosition(); +} + +ByteChucker& ByteChucker::operator << (sal_Int8 nInt8) +{ + p1Sequence[0] = nInt8 & 0xFF; + WriteBytes( a1Sequence ); + return *this; +} + +ByteChucker& ByteChucker::operator << (sal_Int16 nInt16) +{ + p2Sequence[0] = static_cast< sal_Int8 >((nInt16 >> 0 ) & 0xFF); + p2Sequence[1] = static_cast< sal_Int8 >((nInt16 >> 8 ) & 0xFF); + WriteBytes( a2Sequence ); + return *this; +} +ByteChucker& ByteChucker::operator << (sal_Int32 nInt32) +{ + p4Sequence[0] = static_cast< sal_Int8 >((nInt32 >> 0 ) & 0xFF); + p4Sequence[1] = static_cast< sal_Int8 >((nInt32 >> 8 ) & 0xFF); + p4Sequence[2] = static_cast< sal_Int8 >((nInt32 >> 16 ) & 0xFF); + p4Sequence[3] = static_cast< sal_Int8 >((nInt32 >> 24 ) & 0xFF); + WriteBytes( a4Sequence ); + return *this; +} + +ByteChucker& ByteChucker::operator << (sal_uInt8 nuInt8) +{ + p1Sequence[0] = nuInt8 & 0xFF; + WriteBytes( a1Sequence ); + return *this; +} +ByteChucker& ByteChucker::operator << (sal_uInt16 nuInt16) +{ + p2Sequence[0] = static_cast< sal_Int8 >((nuInt16 >> 0 ) & 0xFF); + p2Sequence[1] = static_cast< sal_Int8 >((nuInt16 >> 8 ) & 0xFF); + WriteBytes( a2Sequence ); + return *this; +} +ByteChucker& ByteChucker::operator << (sal_uInt32 nuInt32) +{ + p4Sequence[0] = static_cast < sal_Int8 > ((nuInt32 >> 0 ) & 0xFF); + p4Sequence[1] = static_cast < sal_Int8 > ((nuInt32 >> 8 ) & 0xFF); + p4Sequence[2] = static_cast < sal_Int8 > ((nuInt32 >> 16 ) & 0xFF); + p4Sequence[3] = static_cast < sal_Int8 > ((nuInt32 >> 24 ) & 0xFF); + WriteBytes( a4Sequence ); + return *this; +} diff --git a/package/source/zipapi/ByteGrabber.cxx b/package/source/zipapi/ByteGrabber.cxx new file mode 100644 index 000000000000..84cd6465f7bf --- /dev/null +++ b/package/source/zipapi/ByteGrabber.cxx @@ -0,0 +1,194 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ByteGrabber.cxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ByteGrabber.hxx> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XInputStream.hpp> + +using namespace ::com::sun::star; + +/** ByteGrabber implements the >> operators on an XOutputStream. This is + * potentially quite slow and may need to be optimised + */ + +ByteGrabber::ByteGrabber(uno::Reference < io::XInputStream > xIstream) +: xStream(xIstream) +, xSeek (xIstream, uno::UNO_QUERY ) +, aSequence ( 4 ) +{ + pSequence = aSequence.getArray(); +} + +ByteGrabber::~ByteGrabber() +{ +} + +void ByteGrabber::setInputStream (uno::Reference < io::XInputStream > xNewStream) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + xStream = xNewStream; + xSeek = uno::Reference < io::XSeekable > (xNewStream, uno::UNO_QUERY); +} + +// XInputStream chained +sal_Int32 SAL_CALL ByteGrabber::readBytes( uno::Sequence< sal_Int8 >& aData, + sal_Int32 nBytesToRead ) + throw(io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return xStream->readBytes(aData, nBytesToRead ); +} + +// XSeekable chained... +sal_Int64 SAL_CALL ByteGrabber::seek( sal_Int64 location ) + throw(lang::IllegalArgumentException, io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (xSeek.is() ) + { + sal_Int64 nLen = xSeek->getLength(); + if ( location < 0 || location > nLen ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + if (location > nLen ) + location = nLen; + xSeek->seek( location ); + return location; + } + else + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +sal_Int64 SAL_CALL ByteGrabber::getPosition( ) + throw(io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (xSeek.is() ) + return xSeek->getPosition(); + else + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +sal_Int64 SAL_CALL ByteGrabber::getLength( ) + throw(io::IOException, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (xSeek.is() ) + return xSeek->getLength(); + else + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +ByteGrabber& ByteGrabber::operator >> (sal_Int8& rInt8) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (xStream->readBytes(aSequence,1) != 1) + rInt8 = 0; + else + rInt8 = aSequence[0] & 0xFF; + return *this; +} + +ByteGrabber& ByteGrabber::operator >> (sal_Int16& rInt16) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (xStream->readBytes ( aSequence, 2) != 2) + rInt16 = 0; + else + { + pSequence = aSequence.getConstArray(); + rInt16 = static_cast <sal_Int16> + ( (pSequence[0] & 0xFF) + | (pSequence[1] & 0xFF) << 8); + } + return *this; +} + +ByteGrabber& ByteGrabber::operator >> (sal_Int32& rInt32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if (xStream->readBytes(aSequence, 4) != 4) + rInt32 = 0; + else + { + pSequence = aSequence.getConstArray(); + rInt32 = static_cast < sal_Int32 > + ( (pSequence[0] & 0xFF) + | ( pSequence[1] & 0xFF ) << 8 + | ( pSequence[2] & 0xFF ) << 16 + | ( pSequence[3] & 0xFF ) << 24 ); + } + return *this; +} + +ByteGrabber& ByteGrabber::operator >> (sal_uInt8& rInt8) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if (xStream->readBytes(aSequence,1) != 1) + rInt8 = 0; + else + rInt8 = static_cast < sal_uInt8 > (aSequence[0] & 0xFF ); + return *this; +} +ByteGrabber& ByteGrabber::operator >> (sal_uInt16& rInt16) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if (xStream->readBytes(aSequence, 2) != 2) + rInt16 = 0; + else + { + pSequence = aSequence.getConstArray(); + rInt16 = static_cast <sal_uInt16> + ( (pSequence[0] & 0xFF) + | (pSequence[1] & 0xFF) << 8); + } + return *this; +} +ByteGrabber& ByteGrabber::operator >> (sal_uInt32& ruInt32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if (xStream->readBytes(aSequence, 4) != 4) + ruInt32 = 0; + else + { + pSequence = aSequence.getConstArray(); + ruInt32 = static_cast < sal_uInt32 > + ( (pSequence[0] & 0xFF) + | ( pSequence[1] & 0xFF ) << 8 + | ( pSequence[2] & 0xFF ) << 16 + | ( pSequence[3] & 0xFF ) << 24 ); + } + return *this; +} diff --git a/package/source/zipapi/CRC32.cxx b/package/source/zipapi/CRC32.cxx new file mode 100644 index 000000000000..080f90b9db50 --- /dev/null +++ b/package/source/zipapi/CRC32.cxx @@ -0,0 +1,99 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: CRC32.cxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <CRC32.hxx> +#ifndef _ZLIB_H +#ifdef SYSTEM_ZLIB +#include <zlib.h> +#else +#include <external/zlib/zlib.h> +#endif +#endif +#include <PackageConstants.hxx> +#include <com/sun/star/io/XInputStream.hpp> + +using namespace rtl; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; + +/** A class to compute the CRC32 value of a data stream + */ + +CRC32::CRC32() +: nCRC(0) +{ +} +CRC32::~CRC32() +{ +} +void SAL_CALL CRC32::reset() + throw(RuntimeException) +{ + nCRC=0; +} +sal_Int32 SAL_CALL CRC32::getValue() + throw(RuntimeException) +{ + return nCRC & 0xFFFFFFFFL; +} +/** Update CRC32 with specified sequence of bytes + */ +void SAL_CALL CRC32::updateSegment(const Sequence< sal_Int8 > &b, + sal_Int32 off, + sal_Int32 len) + throw(RuntimeException) +{ + nCRC = crc32(nCRC, (const unsigned char*)b.getConstArray()+off, len ); +} +/** Update CRC32 with specified sequence of bytes + */ +void SAL_CALL CRC32::update(const Sequence< sal_Int8 > &b) + throw(RuntimeException) +{ + nCRC = crc32(nCRC, (const unsigned char*)b.getConstArray(),b.getLength()); +} + +sal_Int32 SAL_CALL CRC32::updateStream( Reference < XInputStream > & xStream ) + throw ( RuntimeException ) +{ + sal_Int32 nLength, nTotal = 0; + Sequence < sal_Int8 > aSeq ( n_ConstBufferSize ); + do + { + nLength = xStream->readBytes ( aSeq, n_ConstBufferSize ); + updateSegment ( aSeq, 0, nLength ); + nTotal += nLength; + } + while ( nLength == n_ConstBufferSize ); + + return nTotal; +} diff --git a/package/source/zipapi/Deflater.cxx b/package/source/zipapi/Deflater.cxx new file mode 100644 index 000000000000..338f4e4364a0 --- /dev/null +++ b/package/source/zipapi/Deflater.cxx @@ -0,0 +1,215 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Deflater.cxx,v $ + * $Revision: 1.17 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <Deflater.hxx> +#ifndef _ZLIB_H +#ifdef SYSTEM_ZLIB +#include <zlib.h> +#else +#include <external/zlib/zlib.h> +#endif +#endif +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <string.h> // for memset + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star; + +/** Provides general purpose compression using the ZLIB compression + * library. + */ + +Deflater::~Deflater(void) +{ + end(); +} +void Deflater::init (sal_Int32 nLevelArg, sal_Int32 nStrategyArg, sal_Bool bNowrap) +{ + pStream = new z_stream; + /* Memset it to 0...sets zalloc/zfree/opaque to NULL */ + memset (pStream, 0, sizeof(*pStream)); + + switch (deflateInit2(pStream, nLevelArg, Z_DEFLATED, bNowrap? -MAX_WBITS : MAX_WBITS, + DEF_MEM_LEVEL, nStrategyArg)) + { + case Z_OK: + break; + case Z_MEM_ERROR: + delete pStream; + break; + case Z_STREAM_ERROR: + delete pStream; + break; + default: + break; + } +} + +Deflater::Deflater(sal_Int32 nSetLevel, sal_Bool bNowrap) +: bFinish(sal_False) +, bFinished(sal_False) +, bSetParams(sal_False) +, nLevel(nSetLevel) +, nStrategy(DEFAULT_STRATEGY) +, nOffset(0) +, nLength(0) +{ + init(nSetLevel, DEFAULT_STRATEGY, bNowrap); +} + +sal_Int32 Deflater::doDeflateBytes (uno::Sequence < sal_Int8 > &rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength) +{ + sal_Int32 nResult; + if (bSetParams) + { + pStream->next_in = (unsigned char*) sInBuffer.getConstArray() + nOffset; + pStream->next_out = (unsigned char*) rBuffer.getArray()+nNewOffset; + pStream->avail_in = nLength; + pStream->avail_out = nNewLength; + +#ifdef SYSTEM_ZLIB + nResult = deflateParams(pStream, nLevel, nStrategy); +#else + nResult = z_deflateParams(pStream, nLevel, nStrategy); +#endif + switch (nResult) + { + case Z_OK: + bSetParams = sal_False; + nOffset += nLength - pStream->avail_in; + nLength = pStream->avail_in; + return nNewLength - pStream->avail_out; + case Z_BUF_ERROR: + bSetParams = sal_False; + return 0; + default: + return 0; + } + } + else + { + pStream->next_in = (unsigned char*) sInBuffer.getConstArray() + nOffset; + pStream->next_out = (unsigned char*) rBuffer.getArray()+nNewOffset; + pStream->avail_in = nLength; + pStream->avail_out = nNewLength; + +#ifdef SYSTEM_ZLIB + nResult = deflate(pStream, bFinish ? Z_FINISH : Z_NO_FLUSH); +#else + nResult = z_deflate(pStream, bFinish ? Z_FINISH : Z_NO_FLUSH); +#endif + switch (nResult) + { + case Z_STREAM_END: + bFinished = sal_True; + case Z_OK: + nOffset += nLength - pStream->avail_in; + nLength = pStream->avail_in; + return nNewLength - pStream->avail_out; + case Z_BUF_ERROR: + bSetParams = sal_False; + return 0; + default: + return 0; + } + } +} + +void SAL_CALL Deflater::setInputSegment( const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) +{ + OSL_ASSERT( !(nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())); + + sInBuffer = rBuffer; + nOffset = nNewOffset; + nLength = nNewLength; +} +void SAL_CALL Deflater::setLevel( sal_Int32 nNewLevel ) +{ + if ((nNewLevel < 0 || nNewLevel > 9) && nNewLevel != DEFAULT_COMPRESSION) + { + // do error handling + } + if (nNewLevel != nLevel) + { + nLevel = nNewLevel; + bSetParams = sal_True; + } +} +sal_Bool SAL_CALL Deflater::needsInput( ) +{ + return nLength <=0; +} +void SAL_CALL Deflater::finish( ) +{ + bFinish = sal_True; +} +sal_Bool SAL_CALL Deflater::finished( ) +{ + return bFinished; +} +sal_Int32 SAL_CALL Deflater::doDeflateSegment( uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) +{ + OSL_ASSERT( !(nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())); + return doDeflateBytes(rBuffer, nNewOffset, nNewLength); +} +sal_Int32 SAL_CALL Deflater::getTotalIn( ) +{ + return pStream->total_in; +} +sal_Int32 SAL_CALL Deflater::getTotalOut( ) +{ + return pStream->total_out; +} +void SAL_CALL Deflater::reset( ) +{ +#ifdef SYSTEM_ZLIB + deflateReset(pStream); +#else + z_deflateReset(pStream); +#endif + bFinish = sal_False; + bFinished = sal_False; + nOffset = nLength = 0; +} +void SAL_CALL Deflater::end( ) +{ + if (pStream != NULL) + { +#ifdef SYSTEM_ZLIB + deflateEnd(pStream); +#else + z_deflateEnd(pStream); +#endif + delete pStream; + } + pStream = NULL; +} diff --git a/package/source/zipapi/EntryInputStream.cxx b/package/source/zipapi/EntryInputStream.cxx new file mode 100644 index 000000000000..46e218ec3229 --- /dev/null +++ b/package/source/zipapi/EntryInputStream.cxx @@ -0,0 +1,204 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: EntryInputStream.cxx,v $ + * $Revision: 1.22 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <EntryInputStream.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <rtl/cipher.h> +#include <rtl/digest.h> +#include <memory.h> // for memcpy + +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::packages::zip::ZipConstants; + +/** Provides access to the compressed data in a zipfile. + * + * 04/12/00 - uncompresses the stream into memory and seeks on it 'in memory' + * This and the ZipPackageBuffer used in the ZipOutputStream are memory hogs + * and will hopefully be replaced eventually + * + * Acts on the same underlying XInputStream as both the full Zip File and other + * EntryInputStreams, and thus must maintain its current position in the stream and + * seek to it before performing any reads. + */ + +EntryInputStream::EntryInputStream( Reference < io::XInputStream > xNewInput, + const ZipEntry & rNewEntry, + const vos::ORef < EncryptionData > &xEncryptData, + sal_Bool bGetRawStream) +: xStream( xNewInput ) +, xSeek( xNewInput, UNO_QUERY ) +, aEntry (rNewEntry ) +, nCurrent( 0 ) +, bHaveInMemory ( sal_False ) +, aInflater( sal_True ) +, aBuffer( 0 ) +, xEncryptionData (xEncryptData) +, bRawStream (bGetRawStream) +{ + if (bGetRawStream) + { + nUncompressedSize = aEntry.nMethod == DEFLATED ? aEntry.nCompressedSize : aEntry.nSize; + nEnd = aEntry.nOffset + nUncompressedSize; + } + else + { + nEnd = aEntry.nMethod == DEFLATED ? aEntry.nOffset + aEntry.nCompressedSize : aEntry.nOffset + aEntry.nSize; + nUncompressedSize = aEntry.nSize; + } +} +void EntryInputStream::readIntoMemory() + throw(io::NotConnectedException, io::BufferSizeExceededException, io::IOException, RuntimeException) +{ + if (!bHaveInMemory) + { + Sequence < sal_Int8 > aReadBuffer; + xSeek->seek(aEntry.nOffset); + sal_Int32 nSize = aEntry.nMethod == DEFLATED ? aEntry.nCompressedSize : aEntry.nSize; + + if (nSize <0) + throw io::BufferSizeExceededException(::rtl::OUString(), *this); + + xStream->readBytes( aReadBuffer, nSize ); // Now it holds the raw stuff from disk + + if (xEncryptionData->aSalt.getLength()) + { + // Have salt, will travel + Sequence < sal_uInt8 > aDerivedKey (16); + rtlCipherError aResult; + Sequence < sal_Int8 > aDecryptBuffer; + + // Get the key + rtl_digest_PBKDF2 ( aDerivedKey.getArray(), 16, + reinterpret_cast < const sal_uInt8 * > (xEncryptionData->aKey.getConstArray()), + xEncryptionData->aKey.getLength(), + xEncryptionData->aSalt.getConstArray(), + xEncryptionData->aSalt.getLength(), + xEncryptionData->nIterationCount ); + + rtlCipher aCipher = rtl_cipher_create (rtl_Cipher_AlgorithmBF, rtl_Cipher_ModeStream); + aResult = rtl_cipher_init( aCipher, rtl_Cipher_DirectionDecode, + aDerivedKey.getConstArray(), + aDerivedKey.getLength(), + xEncryptionData->aInitVector.getConstArray(), + xEncryptionData->aInitVector.getLength()); + OSL_ASSERT (aResult == rtl_Cipher_E_None); + aDecryptBuffer.realloc ( nSize ); + aResult = rtl_cipher_decode ( aCipher, + aReadBuffer.getConstArray(), + nSize, + reinterpret_cast < sal_uInt8 * > (aDecryptBuffer.getArray()), + nSize); + OSL_ASSERT (aResult == rtl_Cipher_E_None); + aReadBuffer = aDecryptBuffer; // Now it holds the decrypted data + } + if (bRawStream || aEntry.nMethod == STORED) + aBuffer = aReadBuffer; // bRawStream means the caller doesn't want it decompressed + else + { + aInflater.setInputSegment(aReadBuffer, 0, nSize ); + aBuffer.realloc( aEntry.nSize ); + aInflater.doInflate(aBuffer); + aInflater.end(); + } + bHaveInMemory = sal_True; + } +} +EntryInputStream::~EntryInputStream( void ) +{ +} + +sal_Int32 SAL_CALL EntryInputStream::readBytes( Sequence< sal_Int8 >& aData, + sal_Int32 nBytesToRead ) + throw(io::NotConnectedException, io::BufferSizeExceededException, io::IOException, RuntimeException) +{ + if (nBytesToRead <0) + throw io::BufferSizeExceededException(::rtl::OUString(), *this); + if (!bHaveInMemory) + readIntoMemory(); + if (nBytesToRead + nCurrent > nUncompressedSize) + nBytesToRead = static_cast < sal_Int32> ( nUncompressedSize - nCurrent ); + + aData.realloc( nBytesToRead ); + memcpy(aData.getArray(), aBuffer.getConstArray() + nCurrent, nBytesToRead); + nCurrent+=nBytesToRead; + + return nBytesToRead; +} +sal_Int32 SAL_CALL EntryInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, + sal_Int32 nMaxBytesToRead ) + throw(io::NotConnectedException, io::BufferSizeExceededException, io::IOException, RuntimeException) +{ + return readBytes( aData, nMaxBytesToRead ); +} +void SAL_CALL EntryInputStream::skipBytes( sal_Int32 nBytesToSkip ) + throw(io::NotConnectedException, io::BufferSizeExceededException, io::IOException, RuntimeException) +{ + if (nBytesToSkip < 0) + throw io::BufferSizeExceededException(::rtl::OUString(), *this); + + if (nBytesToSkip + nCurrent > nUncompressedSize) + nBytesToSkip = static_cast < sal_Int32 > (nUncompressedSize- nCurrent); + + nCurrent+=nBytesToSkip; +} +sal_Int32 SAL_CALL EntryInputStream::available( ) + throw(io::NotConnectedException, io::IOException, RuntimeException) +{ + return static_cast < sal_Int32 > (nUncompressedSize - nCurrent); +} +void SAL_CALL EntryInputStream::closeInput( ) + throw(io::NotConnectedException, io::IOException, RuntimeException) +{ +} + +void SAL_CALL EntryInputStream::seek( sal_Int64 location ) + throw(lang::IllegalArgumentException, io::IOException, RuntimeException) +{ + if (location > nUncompressedSize) + location = nUncompressedSize; + if (location <0) + location = 0; + nCurrent = location; +} +sal_Int64 SAL_CALL EntryInputStream::getPosition( ) + throw(io::IOException, RuntimeException) +{ + return nCurrent; +} +sal_Int64 SAL_CALL EntryInputStream::getLength( ) + throw(io::IOException, RuntimeException) +{ + return nUncompressedSize; +} diff --git a/package/source/zipapi/EntryInputStream.hxx b/package/source/zipapi/EntryInputStream.hxx new file mode 100644 index 000000000000..4e614dd321be --- /dev/null +++ b/package/source/zipapi/EntryInputStream.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: EntryInputStream.hxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ENTRY_INPUT_STREAM_HXX +#define _ENTRY_INPUT_STREAM_HXX + +#include <cppuhelper/implbase2.hxx> // helper for implementations +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <Inflater.hxx> +#include <com/sun/star/packages/zip/ZipEntry.hpp> +#ifndef _VOS_REF_H_ +#include <vos/ref.hxx> +#endif +#ifndef _ENCRYPTION_DATA_HXX +#include <EncryptionData.hxx> +#endif +class EntryInputStream : public cppu::WeakImplHelper2< com::sun::star::io::XInputStream, + com::sun::star::io::XSeekable > +{ +protected: + com::sun::star::uno::Reference< com::sun::star::io::XInputStream > xStream; + com::sun::star::uno::Reference< com::sun::star::io::XSeekable > xSeek; + sal_Int64 nEnd, nCurrent, nUncompressedSize; + sal_Bool bRawStream, bHaveInMemory, bEncrypted; + com::sun::star::uno::Sequence < sal_Int8 > aBuffer; + const vos::ORef < EncryptionData > xEncryptionData; + const com::sun::star::packages::zip::ZipEntry aEntry; + Inflater aInflater; + void readIntoMemory() + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); +public: + EntryInputStream( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xInput, + const com::sun::star::packages::zip::ZipEntry &rNewEntry, + const vos::ORef < EncryptionData > &xEncryptData, + sal_Bool bGetRawStream = sal_False); + virtual ~EntryInputStream(); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + /* +private: + void fill( void ); + */ +}; + +#endif diff --git a/package/source/zipapi/Inflater.cxx b/package/source/zipapi/Inflater.cxx new file mode 100644 index 000000000000..62228bf22c8e --- /dev/null +++ b/package/source/zipapi/Inflater.cxx @@ -0,0 +1,165 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Inflater.cxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <Inflater.hxx> +#ifndef _ZLIB_H +#ifdef SYSTEM_ZLIB +#include <zlib.h> +#else +#include <external/zlib/zlib.h> +#endif +#endif +#include <string.h> // for memset + +using namespace com::sun::star::uno; + +/** Provides general purpose decompression using the ZLIB library */ + +Inflater::Inflater(sal_Bool bNoWrap) +: bFinished(sal_False), + bSetParams(sal_False), + bNeedDict(sal_False), + nOffset(0), + nLength(0), + nLastInflateError(0), + pStream(NULL) +{ + pStream = new z_stream; + /* memset to 0 to set zalloc/opaque etc */ + memset (pStream, 0, sizeof(*pStream)); + sal_Int32 nRes; + nRes = inflateInit2(pStream, bNoWrap ? -MAX_WBITS : MAX_WBITS); + switch (nRes) + { + case Z_OK: + break; + case Z_MEM_ERROR: + delete pStream; + break; + case Z_STREAM_ERROR: + delete pStream; + break; + default: + break; + } +} + +Inflater::~Inflater() +{ + end(); +} + +void SAL_CALL Inflater::setInput( const Sequence< sal_Int8 >& rBuffer ) +{ + sInBuffer = rBuffer; + nOffset = 0; + nLength = rBuffer.getLength(); +} + +sal_Bool SAL_CALL Inflater::needsDictionary( ) +{ + return bNeedDict; +} + +sal_Bool SAL_CALL Inflater::finished( ) +{ + return bFinished; +} + +sal_Int32 SAL_CALL Inflater::doInflateSegment( Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) +{ + if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength()) + { + // do error handling + } + return doInflateBytes(rBuffer, nNewOffset, nNewLength); +} + +void SAL_CALL Inflater::end( ) +{ + if (pStream != NULL) + { +#ifdef SYSTEM_ZLIB + inflateEnd(pStream); +#else + z_inflateEnd(pStream); +#endif + delete pStream; + } + pStream = NULL; +} + +sal_Int32 Inflater::doInflateBytes (Sequence < sal_Int8 > &rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength) +{ + if ( !pStream ) + { + nLastInflateError = Z_STREAM_ERROR; + return 0; + } + + nLastInflateError = 0; + + pStream->next_in = ( unsigned char* ) ( sInBuffer.getConstArray() + nOffset ); + pStream->avail_in = nLength; + pStream->next_out = reinterpret_cast < unsigned char* > ( rBuffer.getArray() + nNewOffset ); + pStream->avail_out = nNewLength; + +#ifdef SYSTEM_ZLIB + sal_Int32 nResult = ::inflate(pStream, Z_PARTIAL_FLUSH); +#else + sal_Int32 nResult = ::z_inflate(pStream, Z_PARTIAL_FLUSH); +#endif + + switch (nResult) + { + case Z_STREAM_END: + bFinished = sal_True; + case Z_OK: + nOffset += nLength - pStream->avail_in; + nLength = pStream->avail_in; + return nNewLength - pStream->avail_out; + + case Z_NEED_DICT: + bNeedDict = sal_True; + nOffset += nLength - pStream->avail_in; + nLength = pStream->avail_in; + return 0; + + default: + // it is no error, if there is no input or no output + if ( nLength && nNewLength ) + nLastInflateError = nResult; + } + + return 0; +} + diff --git a/package/source/zipapi/MemoryByteGrabber.hxx b/package/source/zipapi/MemoryByteGrabber.hxx new file mode 100644 index 000000000000..f15cc8d2d59b --- /dev/null +++ b/package/source/zipapi/MemoryByteGrabber.hxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: MemoryByteGrabber.hxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _MEMORY_BYTE_GRABBER_HXX_ +#define _MEMORY_BYTE_GRABBER_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <string.h> + +class MemoryByteGrabber +{ +protected: + const com::sun::star::uno::Sequence < sal_Int8 > maBuffer; + const sal_Int8 *mpBuffer; + sal_Int32 mnCurrent, mnEnd; +public: + MemoryByteGrabber ( const com::sun::star::uno::Sequence < sal_Int8 > & rBuffer ) + : maBuffer ( rBuffer ) + , mpBuffer ( rBuffer.getConstArray() ) + , mnCurrent ( 0 ) + , mnEnd ( rBuffer.getLength() ) + { + } + MemoryByteGrabber() + { + } + const sal_Int8 * getCurrentPos () { return mpBuffer + mnCurrent; } + + // XInputStream chained + sal_Int32 SAL_CALL readBytes( com::sun::star::uno::Sequence< sal_Int8 >& aData, + sal_Int32 nBytesToRead ) + throw(com::sun::star::io::NotConnectedException, com::sun::star::io::BufferSizeExceededException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + if ( nBytesToRead < 0) + throw com::sun::star::io::BufferSizeExceededException(); + + if (nBytesToRead + mnCurrent > mnEnd) + nBytesToRead = mnEnd - mnCurrent; + + aData.realloc ( nBytesToRead ); + memcpy ( aData.getArray(), mpBuffer + mnCurrent, nBytesToRead ); + mnCurrent += nBytesToRead; + return nBytesToRead; + } + + sal_Int32 SAL_CALL readSomeBytes( com::sun::star::uno::Sequence< sal_Int8 >& aData, + sal_Int32 nMaxBytesToRead ) + throw(com::sun::star::io::NotConnectedException, com::sun::star::io::BufferSizeExceededException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + return readBytes( aData, nMaxBytesToRead ); + } + void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(com::sun::star::io::NotConnectedException, com::sun::star::io::BufferSizeExceededException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + mnCurrent += nBytesToSkip; + } + sal_Int32 SAL_CALL available( ) + throw(com::sun::star::io::NotConnectedException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + return mnEnd - mnCurrent; + } + void SAL_CALL closeInput( ) + throw(com::sun::star::io::NotConnectedException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + } + + // XSeekable chained... + sal_Int64 SAL_CALL seek( sal_Int64 location ) + throw(com::sun::star::lang::IllegalArgumentException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + if ( location < 0 || location > mnEnd ) + throw com::sun::star::lang::IllegalArgumentException (); + mnCurrent = static_cast < sal_Int32 > ( location ); + return mnCurrent; + } + sal_Int64 SAL_CALL getPosition( ) + throw(com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + return mnCurrent; + } + sal_Int64 SAL_CALL getLength( ) + throw(com::sun::star::io::IOException, com::sun::star::uno::RuntimeException) + { + return mnEnd; + } + MemoryByteGrabber& operator >> (sal_Int8& rInt8) + { + if (mnCurrent + 1 > mnEnd ) + rInt8 = 0; + else + rInt8 = mpBuffer [mnCurrent++] & 0xFF; + return *this; + } + MemoryByteGrabber& operator >> (sal_Int16& rInt16) + { + if (mnCurrent + 2 > mnEnd ) + rInt16 = 0; + else + { + rInt16 = mpBuffer[mnCurrent++] & 0xFF; + rInt16 |= ( mpBuffer[mnCurrent++] & 0xFF ) << 8; + } + return *this; + } + MemoryByteGrabber& operator >> (sal_Int32& rInt32) + { + if (mnCurrent + 4 > mnEnd ) + rInt32 = 0; + else + { + rInt32 = mpBuffer[mnCurrent++] & 0xFF; + rInt32 |= ( mpBuffer[mnCurrent++] & 0xFF ) << 8; + rInt32 |= ( mpBuffer[mnCurrent++] & 0xFF ) << 16; + rInt32 |= ( mpBuffer[mnCurrent++] & 0xFF ) << 24; + } + return *this; + } + + MemoryByteGrabber& operator >> (sal_uInt8& rInt8) + { + if (mnCurrent + 1 > mnEnd ) + rInt8 = 0; + else + rInt8 = mpBuffer [mnCurrent++] & 0xFF; + return *this; + } + MemoryByteGrabber& operator >> (sal_uInt16& rInt16) + { + if (mnCurrent + 2 > mnEnd ) + rInt16 = 0; + else + { + rInt16 = mpBuffer [mnCurrent++] & 0xFF; + rInt16 |= ( mpBuffer [mnCurrent++] & 0xFF ) << 8; + } + return *this; + } + MemoryByteGrabber& operator >> (sal_uInt32& rInt32) + { + if (mnCurrent + 4 > mnEnd ) + rInt32 = 0; + else + { + rInt32 = mpBuffer [mnCurrent++] & 0xFF; + rInt32 |= ( mpBuffer [mnCurrent++] & 0xFF ) << 8; + rInt32 |= ( mpBuffer [mnCurrent++] & 0xFF ) << 16; + rInt32 |= ( mpBuffer [mnCurrent++] & 0xFF ) << 24; + } + return *this; + } +}; + +#endif diff --git a/package/source/zipapi/XFileStream.cxx b/package/source/zipapi/XFileStream.cxx new file mode 100644 index 000000000000..7549c3873169 --- /dev/null +++ b/package/source/zipapi/XFileStream.cxx @@ -0,0 +1,230 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XFileStream.cxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <XFileStream.hxx> +#include <EncryptionData.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <PackageConstants.hxx> +#include <rtl/cipher.h> +#include <ZipFile.hxx> +#include <EncryptedDataHeader.hxx> +#include <com/sun/star/io/XOutputStream.hpp> + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using com::sun::star::lang::IllegalArgumentException; +using ::rtl::OUString; + +XFileStream::XFileStream( ZipEntry & rEntry, + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewZipStream, + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewTempStream, + const vos::ORef < EncryptionData > &rData, + sal_Bool bNewRawStream, + sal_Bool bIsEncrypted ) +: maEntry ( rEntry ) +, mxData ( rData ) +, mbRawStream ( bNewRawStream ) +, mbFinished ( sal_False ) +, mxTempIn ( xNewTempStream ) +, mxTempSeek ( xNewTempStream, UNO_QUERY ) +, mxTempOut ( xNewTempStream, UNO_QUERY ) +, mxZipStream ( xNewZipStream ) +, mxZipSeek ( xNewZipStream, UNO_QUERY ) +, maInflater ( sal_True ) +, maCipher ( NULL ) +{ + mnZipCurrent = maEntry.nOffset; + if (mbRawStream) + { + mnZipSize = maEntry.nMethod == DEFLATED ? maEntry.nCompressedSize : maEntry.nSize; + mnZipEnd = maEntry.nOffset + mnZipSize; + } + else + { + mnZipSize = maEntry.nSize; + mnZipEnd = maEntry.nMethod == DEFLATED ? maEntry.nOffset + maEntry.nCompressedSize : maEntry.nOffset + maEntry.nSize; + } + + if ( bIsEncrypted ) + { + sal_Bool bHaveEncryptData = ( !rData.isEmpty() && rData->aSalt.getLength() && rData->aInitVector.getLength() && rData->nIterationCount != 0 ) ? sal_True : sal_False; + + // if we have all the encrypted data, and want a raw stream, then prepend it to the stream, otherwise + // make a cipher so we can decrypt it + if ( bHaveEncryptData ) + { + if ( !bNewRawStream ) + ZipFile::StaticGetCipher ( rData, maCipher, sal_True ); + else + { + // Put in the EncryptedDataHeader + Sequence < sal_Int8 > aEncryptedDataHeader ( n_ConstHeaderSize + + rData->aInitVector.getLength() + + rData->aSalt.getLength() + + rData->aDigest.getLength() ); + sal_Int8 * pHeader = aEncryptedDataHeader.getArray(); + ZipFile::StaticFillHeader ( rData, rEntry.nSize, pHeader ); + mxTempOut->writeBytes ( aEncryptedDataHeader ); + mnZipSize += mxTempSeek->getPosition(); + mxTempSeek->seek ( 0 ); + } + } + } +} + +XFileStream::~XFileStream() +{ + if ( maCipher ) + rtl_cipher_destroy ( maCipher ); +} + +void XFileStream::fill( sal_Int64 nUntil) +{ + sal_Int32 nRead; + sal_Int64 nPosition = mxTempSeek->getPosition(); + mxTempSeek->seek ( mxTempSeek->getLength() ); + maBuffer.realloc ( n_ConstBufferSize ); + + while ( mxTempSeek->getLength() < nUntil ) + { + if ( !mbRawStream ) + { + while ( 0 == ( nRead = maInflater.doInflate( maBuffer ) ) ) + { + if ( maInflater.finished() || maInflater.needsDictionary() ) + { + // some error handling ? + return; + } + + sal_Int64 nDiff = mnZipEnd - mnZipCurrent; + if ( nDiff > 0 ) + { + mxZipSeek->seek ( mnZipCurrent ); + nRead = mxZipStream->readBytes ( maCompBuffer, static_cast < sal_Int32 > ( nDiff < n_ConstBufferSize ? nDiff : n_ConstBufferSize ) ); + mnZipCurrent += nRead; + // maCompBuffer now has the uncompressed data, check if we need to decrypt + // before passing to the Inflater + if ( maCipher ) + { + Sequence < sal_Int8 > aCryptBuffer ( nRead ); + rtlCipherError aResult = rtl_cipher_decode ( maCipher, + maCompBuffer.getConstArray(), + nRead, + reinterpret_cast < sal_uInt8 * > (aCryptBuffer.getArray()), + nRead); + OSL_ASSERT (aResult == rtl_Cipher_E_None); + maCompBuffer = aCryptBuffer; // Now it holds the decrypted data + + } + maInflater.setInput ( maCompBuffer ); + } + else + { + // some error handling ? + return; + } + } + } + else + { + sal_Int64 nDiff = mnZipEnd - mnZipCurrent; + mxZipSeek->seek ( mnZipCurrent ); + nRead = mxZipStream->readBytes ( maBuffer, static_cast < sal_Int32 > ( nDiff < n_ConstBufferSize ? nDiff : n_ConstBufferSize ) ); + mnZipCurrent += nRead; + } + Sequence < sal_Int8 > aTmpBuffer ( maBuffer.getConstArray(), nRead ); + mxTempOut->writeBytes ( aTmpBuffer ); + } + mxTempSeek->seek ( nPosition ); +} + +sal_Int32 SAL_CALL XFileStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + sal_Int64 nPosition = mxTempSeek->getPosition(); + if ( nPosition + nBytesToRead > mnZipSize ) + nBytesToRead = static_cast < sal_Int32 > ( mnZipSize - nPosition ); + + sal_Int64 nUntil = nBytesToRead + nPosition + n_ConstBufferSize; + if (nUntil > mnZipSize ) + nUntil = mnZipSize; + if ( nUntil > mxTempSeek->getLength() ) + fill ( nUntil ); + sal_Int32 nRead = mxTempIn->readBytes ( aData, nBytesToRead ); + return nRead; +} + +sal_Int32 SAL_CALL XFileStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + return readBytes ( aData, nMaxBytesToRead ); +} +void SAL_CALL XFileStream::skipBytes( sal_Int32 nBytesToSkip ) + throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + seek ( mxTempSeek->getPosition() + nBytesToSkip ); +} + +sal_Int32 SAL_CALL XFileStream::available( ) + throw( NotConnectedException, IOException, RuntimeException) +{ + return static_cast < sal_Int32 > ( mnZipSize - mxTempSeek->getPosition() ); +} + +void SAL_CALL XFileStream::closeInput( ) + throw( NotConnectedException, IOException, RuntimeException) +{ +} +void SAL_CALL XFileStream::seek( sal_Int64 location ) + throw( IllegalArgumentException, IOException, RuntimeException) +{ + if ( location > mnZipSize || location < 0 ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + if ( location > mxTempSeek->getLength() ) + { + sal_Int64 nUntil = location + n_ConstBufferSize > mnZipSize ? mnZipSize : location + n_ConstBufferSize; + fill ( nUntil ); + } + mxTempSeek->seek ( location ); +} +sal_Int64 SAL_CALL XFileStream::getPosition( ) + throw(IOException, RuntimeException) +{ + return mxTempSeek->getPosition(); +} +sal_Int64 SAL_CALL XFileStream::getLength( ) + throw(IOException, RuntimeException) +{ + return mnZipSize; +} diff --git a/package/source/zipapi/XFileStream.hxx b/package/source/zipapi/XFileStream.hxx new file mode 100644 index 000000000000..d2c8bb045613 --- /dev/null +++ b/package/source/zipapi/XFileStream.hxx @@ -0,0 +1,99 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XFileStream.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _XFILE_STREAM_HXX +#define _XFILE_STREAM_HXX + +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <cppuhelper/implbase2.hxx> +#ifndef _VOS_REF_H_ +#include <vos/ref.hxx> +#endif +#ifndef _INFLATER_HXX +#include <Inflater.hxx> +#endif +#include <ZipEntry.hxx> + +namespace com { namespace sun { namespace star { + namespace io { class XOutputStream; } +} } } +class EncryptionData; +typedef void* rtlCipher; +class XFileStream : public cppu::WeakImplHelper2 +< + com::sun::star::io::XInputStream, + com::sun::star::io::XSeekable +> +{ +protected: + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > mxZipStream; + com::sun::star::uno::Reference < com::sun::star::io::XSeekable > mxZipSeek; + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > mxTempIn; + com::sun::star::uno::Reference < com::sun::star::io::XSeekable > mxTempSeek; + com::sun::star::uno::Reference < com::sun::star::io::XOutputStream > mxTempOut; + com::sun::star::uno::Sequence < sal_Int8 > maBuffer, maCompBuffer; + ZipEntry maEntry; + vos::ORef < EncryptionData > mxData; + rtlCipher maCipher; + Inflater maInflater; + sal_Bool mbRawStream, mbFinished; + sal_Int64 mnZipCurrent, mnZipEnd, mnZipSize; + void fill( sal_Int64 nUntil ); + +public: + XFileStream( ZipEntry & rEntry, + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewZipStream, + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewTempStream, + const vos::ORef < EncryptionData > &rData, + sal_Bool bRawStream, + sal_Bool bIsEncrypted ); + virtual ~XFileStream(); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zipapi/XMemoryStream.cxx b/package/source/zipapi/XMemoryStream.cxx new file mode 100644 index 000000000000..30976424c46f --- /dev/null +++ b/package/source/zipapi/XMemoryStream.cxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XMemoryStream.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <XMemoryStream.hxx> + +using namespace com::sun::star::io; +using namespace com::sun::star::uno; + +XMemoryStream::XMemoryStream ( com::sun::star::uno::Sequence < sal_Int8 > & rNewBuffer ) +: ZipPackageBuffer ( rNewBuffer ) +{ +} +XMemoryStream::~XMemoryStream(void) +{ +} +::com::sun::star::uno::Any SAL_CALL XMemoryStream::queryInterface( const com::sun::star::uno::Type& rType ) + throw(com::sun::star::uno::RuntimeException) +{ + return ::cppu::queryInterface ( rType , + // OWeakObject interfaces + reinterpret_cast< XInterface* > ( this ) , + static_cast< XWeak* > ( this ) , + // my interfaces + static_cast< XInputStream* > ( this ) , + static_cast< XSeekable* > ( this ) ); +} diff --git a/package/source/zipapi/XMemoryStream.hxx b/package/source/zipapi/XMemoryStream.hxx new file mode 100644 index 000000000000..819feb03a426 --- /dev/null +++ b/package/source/zipapi/XMemoryStream.hxx @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XMemoryStream.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _XMEMORY_STREAM_HXX +#define _XMEMORY_STREAM_HXX + +#include <ZipPackageBuffer.hxx> + +class ZipPackage; + +class XMemoryStream: public ZipPackageBuffer +{ +public: + XMemoryStream ( com::sun::star::uno::Sequence < sal_Int8 > & rNewBuffer ); + virtual ~XMemoryStream(void); + virtual com::sun::star::uno::Any SAL_CALL queryInterface( const com::sun::star::uno::Type& rType ) + throw(com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zipapi/XUnbufferedStream.cxx b/package/source/zipapi/XUnbufferedStream.cxx new file mode 100644 index 000000000000..53e4301844c9 --- /dev/null +++ b/package/source/zipapi/XUnbufferedStream.cxx @@ -0,0 +1,363 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XUnbufferedStream.cxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <XUnbufferedStream.hxx> +#include <EncryptionData.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <com/sun/star/packages/zip/ZipIOException.hpp> +#include <PackageConstants.hxx> +#include <rtl/cipher.h> +#include <ZipFile.hxx> +#include <EncryptedDataHeader.hxx> +#include <algorithm> +#include <string.h> + +#include <osl/mutex.hxx> + +#if 0 +// for debugging purposes here +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <comphelper/processfactory.hxx> +using namespace ::com::sun::star; +#endif + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::packages::zip::ZipIOException; +using ::rtl::OUString; + +XUnbufferedStream::XUnbufferedStream( SotMutexHolderRef aMutexHolder, + ZipEntry & rEntry, + Reference < XInputStream > xNewZipStream, + const vos::ORef < EncryptionData > &rData, + sal_Int8 nStreamMode, + sal_Bool bIsEncrypted, + const ::rtl::OUString& aMediaType, + sal_Bool bRecoveryMode ) +: maMutexHolder( aMutexHolder.Is() ? aMutexHolder : SotMutexHolderRef( new SotMutexHolder ) ) +, mxZipStream ( xNewZipStream ) +, mxZipSeek ( xNewZipStream, UNO_QUERY ) +, maEntry ( rEntry ) +, mxData ( rData ) +, maCipher ( NULL ) +, maInflater ( sal_True ) +, mbRawStream ( nStreamMode == UNBUFF_STREAM_RAW || nStreamMode == UNBUFF_STREAM_WRAPPEDRAW ) +, mbWrappedRaw ( nStreamMode == UNBUFF_STREAM_WRAPPEDRAW ) +, mbFinished ( sal_False ) +, mnHeaderToRead ( 0 ) +, mnZipCurrent ( 0 ) +, mnZipEnd ( 0 ) +, mnZipSize ( 0 ) +, mnMyCurrent ( 0 ) +, mbCheckCRC( !bRecoveryMode ) +{ + mnZipCurrent = maEntry.nOffset; + if ( mbRawStream ) + { + mnZipSize = maEntry.nMethod == DEFLATED ? maEntry.nCompressedSize : maEntry.nSize; + mnZipEnd = maEntry.nOffset + mnZipSize; + } + else + { + mnZipSize = maEntry.nSize; + mnZipEnd = maEntry.nMethod == DEFLATED ? maEntry.nOffset + maEntry.nCompressedSize : maEntry.nOffset + maEntry.nSize; + } + sal_Bool bHaveEncryptData = ( !rData.isEmpty() && rData->aSalt.getLength() && rData->aInitVector.getLength() && rData->nIterationCount != 0 ) ? sal_True : sal_False; + sal_Bool bMustDecrypt = ( nStreamMode == UNBUFF_STREAM_DATA && bHaveEncryptData && bIsEncrypted ) ? sal_True : sal_False; + + if ( bMustDecrypt ) + ZipFile::StaticGetCipher ( rData, maCipher, sal_True ); + if ( bHaveEncryptData && mbWrappedRaw && bIsEncrypted ) + { + // if we have the data needed to decrypt it, but didn't want it decrypted (or + // we couldn't decrypt it due to wrong password), then we prepend this + // data to the stream + + // Make a buffer big enough to hold both the header and the data itself + maHeader.realloc ( n_ConstHeaderSize + + rData->aInitVector.getLength() + + rData->aSalt.getLength() + + rData->aDigest.getLength() + + aMediaType.getLength() * sizeof( sal_Unicode ) ); + sal_Int8 * pHeader = maHeader.getArray(); + ZipFile::StaticFillHeader ( rData, rEntry.nSize, aMediaType, pHeader ); + mnHeaderToRead = static_cast < sal_Int16 > ( maHeader.getLength() ); + } +} + +// allows to read package raw stream +XUnbufferedStream::XUnbufferedStream( const Reference < XInputStream >& xRawStream, + const vos::ORef < EncryptionData > &rData ) +: maMutexHolder( new SotMutexHolder ) +, mxZipStream ( xRawStream ) +, mxZipSeek ( xRawStream, UNO_QUERY ) +, mxData ( rData ) +, maCipher ( NULL ) +, maInflater ( sal_True ) +, mbRawStream ( sal_False ) +, mbWrappedRaw ( sal_False ) +, mbFinished ( sal_False ) +, mnHeaderToRead ( 0 ) +, mnZipCurrent ( 0 ) +, mnZipEnd ( 0 ) +, mnZipSize ( 0 ) +, mnMyCurrent ( 0 ) +, mbCheckCRC( sal_False ) +{ + // for this scenario maEntry is not set !!! + OSL_ENSURE( mxZipSeek.is(), "The stream must be seekable!\n" ); + + // skip raw header, it must be already parsed to rData + mnZipCurrent = n_ConstHeaderSize + rData->aInitVector.getLength() + + rData->aSalt.getLength() + rData->aDigest.getLength(); + + try { + if ( mxZipSeek.is() ) + mnZipSize = mxZipSeek->getLength(); + } catch( Exception& ) + { + // in case of problem the size will stay set to 0 + } + + mnZipEnd = mnZipCurrent + mnZipSize; + + ZipFile::StaticGetCipher ( rData, maCipher, sal_True ); +} + +XUnbufferedStream::~XUnbufferedStream() +{ + if ( maCipher ) + rtl_cipher_destroy ( maCipher ); +} + +sal_Int32 SAL_CALL XUnbufferedStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( maMutexHolder->GetMutex() ); + + sal_Int32 nRequestedBytes = nBytesToRead; + OSL_ENSURE( !mnHeaderToRead || mbWrappedRaw, "Only encrypted raw stream can be provided with header!" ); + if ( mnMyCurrent + nRequestedBytes > mnZipSize + maHeader.getLength() ) + nRequestedBytes = static_cast < sal_Int32 > ( mnZipSize + maHeader.getLength() - mnMyCurrent ); + + sal_Int32 nRead = 0, nLastRead = 0, nTotal = 0; + aData.realloc ( nRequestedBytes ); + if ( nRequestedBytes ) + { + if ( mbRawStream ) + { + sal_Int64 nDiff = mnZipEnd - mnZipCurrent; + + if ( mbWrappedRaw && mnHeaderToRead ) + { + sal_Int16 nHeadRead = static_cast< sal_Int16 >(( nRequestedBytes > mnHeaderToRead ? + mnHeaderToRead : nRequestedBytes )); + memcpy ( aData.getArray(), maHeader.getConstArray() + maHeader.getLength() - mnHeaderToRead, nHeadRead ); + mnHeaderToRead = mnHeaderToRead - nHeadRead; + + if ( nHeadRead < nRequestedBytes ) + { + sal_Int32 nToRead = nRequestedBytes - nHeadRead; + nToRead = ( nDiff < nToRead ) ? sal::static_int_cast< sal_Int32 >( nDiff ) : nToRead; + + Sequence< sal_Int8 > aPureData( nToRead ); + mxZipSeek->seek ( mnZipCurrent ); + nRead = mxZipStream->readBytes ( aPureData, nToRead ); + mnZipCurrent += nRead; + + aPureData.realloc( nRead ); + if ( mbCheckCRC ) + maCRC.update( aPureData ); + + aData.realloc( nHeadRead + nRead ); + + sal_Int8* pPureBuffer = aPureData.getArray(); + sal_Int8* pBuffer = aData.getArray(); + for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ ) + pBuffer[ nHeadRead + nInd ] = pPureBuffer[ nInd ]; + } + + nRead += nHeadRead; + } + else + { + mxZipSeek->seek ( mnZipCurrent ); + + nRead = mxZipStream->readBytes ( + aData, + static_cast < sal_Int32 > ( nDiff < nRequestedBytes ? nDiff : nRequestedBytes ) ); + + mnZipCurrent += nRead; + + aData.realloc( nRead ); + if ( mbWrappedRaw && mbCheckCRC ) + maCRC.update( aData ); + } + } + else + { + while ( 0 == ( nLastRead = maInflater.doInflateSegment( aData, nRead, aData.getLength() - nRead ) ) || + ( nRead + nLastRead != nRequestedBytes && mnZipCurrent < mnZipEnd ) ) + { + nRead += nLastRead; + + if ( nRead > nRequestedBytes ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Should not be possible to read more then requested!" ) ), + Reference< XInterface >() ); + + if ( maInflater.finished() || maInflater.getLastInflateError() ) + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), + Reference< XInterface >() ); + + if ( maInflater.needsDictionary() ) + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "Dictionaries are not supported!" ) ), + Reference< XInterface >() ); + + sal_Int32 nDiff = static_cast < sal_Int32 > ( mnZipEnd - mnZipCurrent ); + if ( nDiff > 0 ) + { + mxZipSeek->seek ( mnZipCurrent ); + sal_Int32 nToRead = std::min ( nDiff, std::max ( nRequestedBytes, static_cast< sal_Int32 >( 8192 ) ) ); + sal_Int32 nZipRead = mxZipStream->readBytes ( maCompBuffer, nToRead ); + if ( nZipRead < nToRead ) + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "No expected data!" ) ), + Reference< XInterface >() ); + + mnZipCurrent += nZipRead; + // maCompBuffer now has the data, check if we need to decrypt + // before passing to the Inflater + if ( maCipher ) + { + if ( mbCheckCRC ) + maCRC.update( maCompBuffer ); + + Sequence < sal_Int8 > aCryptBuffer ( nZipRead ); + rtlCipherError aResult = + rtl_cipher_decode ( maCipher, + maCompBuffer.getConstArray(), + nZipRead, + reinterpret_cast < sal_uInt8 * > (aCryptBuffer.getArray()), + nZipRead); + if( aResult != rtl_Cipher_E_None ) { + OSL_ASSERT (aResult == rtl_Cipher_E_None); + } + maCompBuffer = aCryptBuffer; // Now it holds the decrypted data + + } + maInflater.setInput ( maCompBuffer ); + } + else + { + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), + Reference< XInterface >() ); + } + } + } + + mnMyCurrent += nRead + nLastRead; + nTotal = nRead + nLastRead; + if ( nTotal < nRequestedBytes) + aData.realloc ( nTotal ); + + if ( mbCheckCRC && ( !mbRawStream || mbWrappedRaw ) ) + { + if ( !maCipher && !mbWrappedRaw ) + maCRC.update( aData ); + +#if 0 + // for debugging purposes here + if ( mbWrappedRaw ) + { + if ( 0 ) + { + uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); + uno::Reference< ucb::XSimpleFileAccess > xAccess( xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY ); + uno::Reference< io::XOutputStream > xOut = xAccess->openFileWrite( ::rtl::OUString::createFromAscii( "file:///d:/777/Encrypted/picture" ) ); + xOut->writeBytes( aData ); + xOut->closeOutput(); + } + } +#endif + + if ( mnZipSize + maHeader.getLength() == mnMyCurrent && maCRC.getValue() != maEntry.nCrc ) + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), + Reference< XInterface >() ); + } + } + + return nTotal; +} + +sal_Int32 SAL_CALL XUnbufferedStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + return readBytes ( aData, nMaxBytesToRead ); +} +void SAL_CALL XUnbufferedStream::skipBytes( sal_Int32 nBytesToSkip ) + throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if ( nBytesToSkip ) + { + Sequence < sal_Int8 > aSequence ( nBytesToSkip ); + readBytes ( aSequence, nBytesToSkip ); + } +} + +sal_Int32 SAL_CALL XUnbufferedStream::available( ) + throw( NotConnectedException, IOException, RuntimeException) +{ + return static_cast < sal_Int32 > ( mnZipSize - mnMyCurrent ); +} + +void SAL_CALL XUnbufferedStream::closeInput( ) + throw( NotConnectedException, IOException, RuntimeException) +{ +} +/* +void SAL_CALL XUnbufferedStream::seek( sal_Int64 location ) + throw( IllegalArgumentException, IOException, RuntimeException) +{ +} +sal_Int64 SAL_CALL XUnbufferedStream::getPosition( ) + throw(IOException, RuntimeException) +{ + return mnMyCurrent; +} +sal_Int64 SAL_CALL XUnbufferedStream::getLength( ) + throw(IOException, RuntimeException) +{ + return mnZipSize; +} +*/ diff --git a/package/source/zipapi/XUnbufferedStream.hxx b/package/source/zipapi/XUnbufferedStream.hxx new file mode 100644 index 000000000000..db688761726e --- /dev/null +++ b/package/source/zipapi/XUnbufferedStream.hxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XUnbufferedStream.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _XUNBUFFERED_STREAM_HXX +#define _XUNBUFFERED_STREAM_HXX + +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <cppuhelper/implbase1.hxx> +#include <vos/ref.hxx> +#include <Inflater.hxx> +#include <ZipEntry.hxx> +#include <CRC32.hxx> +#include <mutexholder.hxx> + +#define UNBUFF_STREAM_DATA 0 +#define UNBUFF_STREAM_RAW 1 +#define UNBUFF_STREAM_WRAPPEDRAW 2 + +class EncryptionData; +typedef void* rtlCipher; +class XUnbufferedStream : public cppu::WeakImplHelper1 +< + com::sun::star::io::XInputStream +> +{ +protected: + SotMutexHolderRef maMutexHolder; + + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > mxZipStream; + com::sun::star::uno::Reference < com::sun::star::io::XSeekable > mxZipSeek; + com::sun::star::uno::Sequence < sal_Int8 > maCompBuffer, maHeader; + ZipEntry maEntry; + vos::ORef < EncryptionData > mxData; + rtlCipher maCipher; + Inflater maInflater; + sal_Bool mbRawStream, mbWrappedRaw, mbFinished; + sal_Int16 mnHeaderToRead; + sal_Int64 mnZipCurrent, mnZipEnd, mnZipSize, mnMyCurrent; + CRC32 maCRC; + sal_Bool mbCheckCRC; + +public: + XUnbufferedStream( + SotMutexHolderRef aMutexHolder, + ZipEntry & rEntry, + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xNewZipStream, + const vos::ORef < EncryptionData > &rData, + sal_Int8 nStreamMode, + sal_Bool bIsEncrypted, + const ::rtl::OUString& aMediaType, + sal_Bool bRecoveryMode ); + + // allows to read package raw stream + XUnbufferedStream( const com::sun::star::uno::Reference < com::sun::star::io::XInputStream >& xRawStream, + const vos::ORef < EncryptionData > &rData ); + + + virtual ~XUnbufferedStream(); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + /* + virtual void SAL_CALL seek( sal_Int64 location ) + throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength( ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + */ +}; +#endif diff --git a/package/source/zipapi/ZipEnumeration.cxx b/package/source/zipapi/ZipEnumeration.cxx new file mode 100644 index 000000000000..7df79df00dc1 --- /dev/null +++ b/package/source/zipapi/ZipEnumeration.cxx @@ -0,0 +1,56 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipEnumeration.cxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipEnumeration.hxx> + +/** Provides an Enumeration over the contents of a Zip file */ + +ZipEnumeration::ZipEnumeration( EntryHash & rNewEntryHash) +: rEntryHash(rNewEntryHash) +, aIterator(rEntryHash.begin()) +{ +} +ZipEnumeration::~ZipEnumeration( void ) +{ +} +sal_Bool SAL_CALL ZipEnumeration::hasMoreElements() +{ + return (aIterator != rEntryHash.end()); +} + +const ZipEntry* SAL_CALL ZipEnumeration::nextElement() +{ + if (aIterator != rEntryHash.end()) + return &((*aIterator++).second); + else + return NULL; +} diff --git a/package/source/zipapi/ZipFile.cxx b/package/source/zipapi/ZipFile.cxx new file mode 100644 index 000000000000..9934caa0c066 --- /dev/null +++ b/package/source/zipapi/ZipFile.cxx @@ -0,0 +1,1064 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipFile.cxx,v $ + * $Revision: 1.50 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipFile.hxx> +#include <ZipEnumeration.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <rtl/cipher.h> +#include <rtl/digest.h> +/* +#include <XMemoryStream.hxx> +#include <XFileStream.hxx> +*/ +#include <XUnbufferedStream.hxx> +#include <PackageConstants.hxx> +#include <EncryptedDataHeader.hxx> +#include <EncryptionData.hxx> +#include <MemoryByteGrabber.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> + +#ifndef _CRC32_HXX_ +#include <CRC32.hxx> +#endif + +#include <string.h> // for memcpy +#include <vector> + +#include <comphelper/storagehelper.hxx> + +using namespace vos; +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace com::sun::star::lang; +using namespace com::sun::star::packages; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::packages::zip::ZipConstants; + + +/** This class is used to read entries from a zip file + */ +ZipFile::ZipFile( Reference < XInputStream > &xInput, const Reference < XMultiServiceFactory > &xNewFactory, sal_Bool bInitialise ) + throw(IOException, ZipException, RuntimeException) +: aGrabber(xInput) +, aInflater (sal_True) +, xStream(xInput) +, xSeek(xInput, UNO_QUERY) +, xFactory ( xNewFactory ) +, bRecoveryMode( sal_False ) +{ + if (bInitialise) + { + if ( readCEN() == -1 ) + { + aEntries.clear(); + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "stream data looks to be broken" ) ), Reference < XInterface > () ); + } + } +} + + + +ZipFile::ZipFile( Reference < XInputStream > &xInput, const Reference < XMultiServiceFactory > &xNewFactory, sal_Bool bInitialise, sal_Bool bForceRecovery, Reference < XProgressHandler > xProgress ) + throw(IOException, ZipException, RuntimeException) +: aGrabber(xInput) +, aInflater (sal_True) +, xStream(xInput) +, xSeek(xInput, UNO_QUERY) +, xFactory ( xNewFactory ) +, xProgressHandler( xProgress ) +, bRecoveryMode( bForceRecovery ) +{ + if (bInitialise) + { + if ( bForceRecovery ) + { + recover(); + } + else if ( readCEN() == -1 ) + { + aEntries.clear(); + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "stream data looks to be broken" ) ), Reference < XInterface > () ); + } + } +} + +ZipFile::~ZipFile() +{ + aEntries.clear(); +} + +void ZipFile::setInputStream ( Reference < XInputStream > xNewStream ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + xStream = xNewStream; + xSeek = Reference < XSeekable > ( xStream, UNO_QUERY ); + aGrabber.setInputStream ( xStream ); +} + +sal_Bool ZipFile::StaticGetCipher ( const ORef < EncryptionData > & xEncryptionData, rtlCipher &rCipher, sal_Bool bDecode ) +{ + sal_Bool bResult = sal_False; + if ( ! xEncryptionData.isEmpty() ) + { + Sequence < sal_uInt8 > aDerivedKey (16); + rtlCipherError aResult; + Sequence < sal_Int8 > aDecryptBuffer; + + // Get the key + rtl_digest_PBKDF2 ( aDerivedKey.getArray(), 16, + reinterpret_cast < const sal_uInt8 * > (xEncryptionData->aKey.getConstArray() ), + xEncryptionData->aKey.getLength(), + reinterpret_cast < const sal_uInt8 * > ( xEncryptionData->aSalt.getConstArray() ), + xEncryptionData->aSalt.getLength(), + xEncryptionData->nIterationCount ); + + rCipher = rtl_cipher_create (rtl_Cipher_AlgorithmBF, rtl_Cipher_ModeStream); + aResult = rtl_cipher_init( rCipher, bDecode ? rtl_Cipher_DirectionDecode : rtl_Cipher_DirectionEncode, + aDerivedKey.getConstArray(), + aDerivedKey.getLength(), + reinterpret_cast < const sal_uInt8 * > ( xEncryptionData->aInitVector.getConstArray() ), + xEncryptionData->aInitVector.getLength()); + OSL_ASSERT (aResult == rtl_Cipher_E_None); + + bResult = ( aResult == rtl_Cipher_E_None ); + } + + return bResult; +} + +void ZipFile::StaticFillHeader ( const ORef < EncryptionData > & rData, + sal_Int32 nSize, + const ::rtl::OUString& aMediaType, + sal_Int8 * & pHeader ) +{ + // I think it's safe to restrict vector and salt length to 2 bytes ! + sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->aInitVector.getLength() ); + sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->aSalt.getLength() ); + sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->aDigest.getLength() ); + sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) ); + + // First the header + *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF; + *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF; + *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF; + *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF; + + // Then the version + *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF; + *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF; + + // Then the iteration Count + sal_Int32 nIterationCount = rData->nIterationCount; + *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF); + + // Then the size + *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF); + + // Then the salt length + *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF); + + // Then the IV length + *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF); + + // Then the digest length + *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF); + + // Then the mediatype length + *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF); + *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF); + + // Then the salt content + memcpy ( pHeader, rData->aSalt.getConstArray(), nSaltLength ); + pHeader += nSaltLength; + + // Then the IV content + memcpy ( pHeader, rData->aInitVector.getConstArray(), nIVLength ); + pHeader += nIVLength; + + // Then the digest content + memcpy ( pHeader, rData->aDigest.getConstArray(), nDigestLength ); + pHeader += nDigestLength; + + // Then the mediatype itself + memcpy ( pHeader, aMediaType.getStr(), nMediaTypeLength ); + pHeader += nMediaTypeLength; +} + +sal_Bool ZipFile::StaticFillData ( ORef < EncryptionData > & rData, + sal_Int32 &rSize, + ::rtl::OUString& aMediaType, + Reference < XInputStream > &rStream ) +{ + sal_Bool bOk = sal_False; + const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4; + Sequence < sal_Int8 > aBuffer ( nHeaderSize ); + if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) ) + { + sal_Int16 nPos = 0; + sal_Int8 *pBuffer = aBuffer.getArray(); + sal_Int16 nVersion = pBuffer[nPos++] & 0xFF; + nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8; + if ( nVersion == n_ConstCurrentVersion ) + { + sal_Int32 nCount = pBuffer[nPos++] & 0xFF; + nCount |= ( pBuffer[nPos++] & 0xFF ) << 8; + nCount |= ( pBuffer[nPos++] & 0xFF ) << 16; + nCount |= ( pBuffer[nPos++] & 0xFF ) << 24; + rData->nIterationCount = nCount; + + rSize = pBuffer[nPos++] & 0xFF; + rSize |= ( pBuffer[nPos++] & 0xFF ) << 8; + rSize |= ( pBuffer[nPos++] & 0xFF ) << 16; + rSize |= ( pBuffer[nPos++] & 0xFF ) << 24; + + sal_Int16 nSaltLength = pBuffer[nPos++] & 0xFF; + nSaltLength |= ( pBuffer[nPos++] & 0xFF ) << 8; + sal_Int16 nIVLength = ( pBuffer[nPos++] & 0xFF ); + nIVLength |= ( pBuffer[nPos++] & 0xFF ) << 8; + sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF; + nDigestLength |= ( pBuffer[nPos++] & 0xFF ) << 8; + + sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF; + nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8; + + if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) ) + { + rData->aSalt.realloc ( nSaltLength ); + memcpy ( rData->aSalt.getArray(), aBuffer.getConstArray(), nSaltLength ); + if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) ) + { + rData->aInitVector.realloc ( nIVLength ); + memcpy ( rData->aInitVector.getArray(), aBuffer.getConstArray(), nIVLength ); + if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) ) + { + rData->aDigest.realloc ( nDigestLength ); + memcpy ( rData->aDigest.getArray(), aBuffer.getConstArray(), nDigestLength ); + + if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) ) + { + aMediaType = ::rtl::OUString( (sal_Unicode*)aBuffer.getConstArray(), + nMediaTypeLength / sizeof( sal_Unicode ) ); + bOk = sal_True; + } + } + } + } + } + } + return bOk; +} + +Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const Reference< XInputStream >& xStream, + const ORef < EncryptionData > &rData ) + throw ( packages::WrongPasswordException, ZipIOException, RuntimeException ) +{ + if ( rData.isEmpty() ) + throw ZipIOException( OUString::createFromAscii( "Encrypted stream without encryption data!\n" ), + Reference< XInterface >() ); + + if ( !rData->aKey.getLength() ) + throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Reference< XSeekable > xSeek( xStream, UNO_QUERY ); + if ( !xSeek.is() ) + throw ZipIOException( OUString::createFromAscii( "The stream must be seekable!\n" ), + Reference< XInterface >() ); + + + // if we have a digest, then this file is an encrypted one and we should + // check if we can decrypt it or not + OSL_ENSURE( rData->aDigest.getLength(), "Can't detect password correctness without digest!\n" ); + if ( rData->aDigest.getLength() ) + { + sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() ); + nSize = nSize > n_ConstDigestLength ? n_ConstDigestLength : nSize; + + // skip header + xSeek->seek( n_ConstHeaderSize + rData->aInitVector.getLength() + + rData->aSalt.getLength() + rData->aDigest.getLength() ); + + // Only want to read enough to verify the digest + Sequence < sal_Int8 > aReadBuffer ( nSize ); + + xStream->readBytes( aReadBuffer, nSize ); + + if ( !StaticHasValidPassword( aReadBuffer, rData ) ) + throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + return new XUnbufferedStream ( xStream, rData ); +} + +sal_Bool ZipFile::StaticHasValidPassword( const Sequence< sal_Int8 > &aReadBuffer, const ORef < EncryptionData > &rData ) +{ + if ( !rData.isValid() || !rData->aKey.getLength() ) + return sal_False; + + sal_Bool bRet = sal_False; + sal_Int32 nSize = aReadBuffer.getLength(); + + // make a temporary cipher + rtlCipher aCipher; + StaticGetCipher ( rData, aCipher, sal_True ); + + Sequence < sal_Int8 > aDecryptBuffer ( nSize ); + rtlDigest aDigest = rtl_digest_createSHA1(); + rtlDigestError aDigestResult; + Sequence < sal_uInt8 > aDigestSeq ( RTL_DIGEST_LENGTH_SHA1 ); + rtlCipherError aResult = rtl_cipher_decode ( aCipher, + aReadBuffer.getConstArray(), + nSize, + reinterpret_cast < sal_uInt8 * > (aDecryptBuffer.getArray()), + nSize); + if(aResult != rtl_Cipher_E_None ) { + OSL_ASSERT ( aResult == rtl_Cipher_E_None); + } + + aDigestResult = rtl_digest_updateSHA1 ( aDigest, + static_cast < const void * > ( aDecryptBuffer.getConstArray() ), nSize ); + OSL_ASSERT ( aDigestResult == rtl_Digest_E_None ); + + aDigestResult = rtl_digest_getSHA1 ( aDigest, aDigestSeq.getArray(), RTL_DIGEST_LENGTH_SHA1 ); + OSL_ASSERT ( aDigestResult == rtl_Digest_E_None ); + + // If we don't have a digest, then we have to assume that the password is correct + if ( rData->aDigest.getLength() != 0 && + ( aDigestSeq.getLength() != rData->aDigest.getLength() || + 0 != rtl_compareMemory ( aDigestSeq.getConstArray(), + rData->aDigest.getConstArray(), + aDigestSeq.getLength() ) ) ) + { + // We should probably tell the user that the password they entered was wrong + } + else + bRet = sal_True; + + rtl_digest_destroySHA1 ( aDigest ); + + return bRet; +} + +sal_Bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ORef < EncryptionData > &rData ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Bool bRet = sal_False; + if ( rData->aKey.getLength() ) + { + xSeek->seek( rEntry.nOffset ); + sal_Int32 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize; + + // Only want to read enough to verify the digest + nSize = nSize > n_ConstDigestLength ? n_ConstDigestLength : nSize; + Sequence < sal_Int8 > aReadBuffer ( nSize ); + + xStream->readBytes( aReadBuffer, nSize ); + + bRet = StaticHasValidPassword( aReadBuffer, rData ); + } + return bRet; +} + +#if 0 +Reference < XInputStream > ZipFile::createFileStream( + ZipEntry & rEntry, + const ORef < EncryptionData > &rData, + sal_Bool bRawStream, + sal_Bool bIsEncrypted ) +{ + static OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); + Reference < XInputStream > xTempStream = Reference < XInputStream > ( xFactory->createInstance ( sServiceName ), UNO_QUERY ); + return new XFileStream ( rEntry, xStream, xTempStream, rData, bRawStream, bIsEncrypted ); +} +Reference < XInputStream > ZipFile::createMemoryStream( + ZipEntry & rEntry, + const ORef < EncryptionData > &rData, + sal_Bool bRawStream, + sal_Bool bIsEncrypted ) +{ + sal_Int32 nUncompressedSize, nEnd; + if (bRawStream) + { + nUncompressedSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize; + nEnd = rEntry.nOffset + nUncompressedSize; + } + else + { + nUncompressedSize = rEntry.nSize; + nEnd = rEntry.nMethod == DEFLATED ? rEntry.nOffset + rEntry.nCompressedSize : rEntry.nOffset + rEntry.nSize; + } + sal_Int32 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize; + Sequence < sal_Int8 > aReadBuffer ( nSize ), aDecryptBuffer, aWriteBuffer; + rtlCipher aCipher; + + // If the encryption key is zero, we need to return the raw stream. First check if + // we have the salt. If we have the salt, then check if we have the encryption key + // if not, return rawStream instead. + + sal_Bool bHaveEncryptData = ( !rData.isEmpty() && rData->aSalt.getLength() && rData->aInitVector.getLength() && rData->nIterationCount != 0 ) ? sal_True : sal_False; + sal_Bool bMustDecrypt = ( !bRawStream && bHaveEncryptData && bIsEncrypted ) ? sal_True : sal_False; + + if ( bMustDecrypt ) + { + StaticGetCipher ( rData, aCipher, sal_True ); + aDecryptBuffer.realloc ( nSize ); + } + + if ( nSize <0 ) + throw IOException ( ); + + xSeek->seek( rEntry.nOffset ); + xStream->readBytes( aReadBuffer, nSize ); // Now it holds the raw stuff from disk + + if ( bMustDecrypt ) + { + rtlCipherError aResult = rtl_cipher_decode ( aCipher, + aReadBuffer.getConstArray(), + nSize, + reinterpret_cast < sal_uInt8 * > (aDecryptBuffer.getArray()), + nSize); + OSL_ASSERT (aResult == rtl_Cipher_E_None); + aReadBuffer = aDecryptBuffer; // Now it holds the decrypted data + } + if (bRawStream || rEntry.nMethod == STORED) + aWriteBuffer = aReadBuffer; // bRawStream means the caller doesn't want it decompressed + else + { + aInflater.setInputSegment( aReadBuffer, 0, nSize ); + aWriteBuffer.realloc( nUncompressedSize ); + aInflater.doInflate( aWriteBuffer ); + aInflater.reset(); + } + + if ( bHaveEncryptData && !bMustDecrypt && bIsEncrypted ) + { + // if we have the data needed to decrypt it, but didn't want it decrypted (or + // we couldn't decrypt it due to wrong password), then we prepend this + // data to the stream + + // Make a buffer big enough to hold both the header and the data itself + Sequence < sal_Int8 > aEncryptedDataHeader ( n_ConstHeaderSize + + rData->aInitVector.getLength() + + rData->aSalt.getLength() + + rData->aDigest.getLength() + + aWriteBuffer.getLength() ); + sal_Int8 * pHeader = aEncryptedDataHeader.getArray(); + StaticFillHeader ( rData, rEntry.nSize, pHeader ); + memcpy ( pHeader, aWriteBuffer.getConstArray(), aWriteBuffer.getLength() ); + + // dump old buffer and point aWriteBuffer to the new one with the header + aWriteBuffer = aEncryptedDataHeader; + } + return Reference < XInputStream > ( new XMemoryStream ( aWriteBuffer ) ); +} +#endif +Reference < XInputStream > ZipFile::createUnbufferedStream( + SotMutexHolderRef aMutexHolder, + ZipEntry & rEntry, + const ORef < EncryptionData > &rData, + sal_Int8 nStreamMode, + sal_Bool bIsEncrypted, + ::rtl::OUString aMediaType ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return new XUnbufferedStream ( aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode ); +} + + +ZipEnumeration * SAL_CALL ZipFile::entries( ) +{ + return new ZipEnumeration ( aEntries ); +} + +Reference< XInputStream > SAL_CALL ZipFile::getInputStream( ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bIsEncrypted, + SotMutexHolderRef aMutexHolder ) + throw(IOException, ZipException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( rEntry.nOffset <= 0 ) + readLOC( rEntry ); + + // We want to return a rawStream if we either don't have a key or if the + // key is wrong + + sal_Bool bNeedRawStream = rEntry.nMethod == STORED; + + // if we have a digest, then this file is an encrypted one and we should + // check if we can decrypt it or not + if ( bIsEncrypted && !rData.isEmpty() && rData->aDigest.getLength() ) + bNeedRawStream = !hasValidPassword ( rEntry, rData ); + + return createUnbufferedStream ( aMutexHolder, + rEntry, + rData, + bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA, + bIsEncrypted ); +} + +Reference< XInputStream > SAL_CALL ZipFile::getDataStream( ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bIsEncrypted, + SotMutexHolderRef aMutexHolder ) + throw ( packages::WrongPasswordException, + IOException, + ZipException, + RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( rEntry.nOffset <= 0 ) + readLOC( rEntry ); + + // An exception must be thrown in case stream is encrypted and + // there is no key or the key is wrong + sal_Bool bNeedRawStream = sal_False; + if ( bIsEncrypted ) + { + // in case no digest is provided there is no way + // to detect password correctness + if ( rData.isEmpty() ) + throw ZipException( OUString::createFromAscii( "Encrypted stream without encryption data!\n" ), + Reference< XInterface >() ); + + // if we have a digest, then this file is an encrypted one and we should + // check if we can decrypt it or not + OSL_ENSURE( rData->aDigest.getLength(), "Can't detect password correctness without digest!\n" ); + if ( rData->aDigest.getLength() && !hasValidPassword ( rEntry, rData ) ) + throw packages::WrongPasswordException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + else + bNeedRawStream = ( rEntry.nMethod == STORED ); + + return createUnbufferedStream ( aMutexHolder, + rEntry, + rData, + bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA, + bIsEncrypted ); +} + +Reference< XInputStream > SAL_CALL ZipFile::getRawData( ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + sal_Bool bIsEncrypted, + SotMutexHolderRef aMutexHolder ) + throw(IOException, ZipException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( rEntry.nOffset <= 0 ) + readLOC( rEntry ); + + return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted ); +} + +Reference< XInputStream > SAL_CALL ZipFile::getWrappedRawStream( + ZipEntry& rEntry, + const vos::ORef < EncryptionData > &rData, + const ::rtl::OUString& aMediaType, + SotMutexHolderRef aMutexHolder ) + throw ( packages::NoEncryptionException, + IOException, + ZipException, + RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( rData.isEmpty() ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( rEntry.nOffset <= 0 ) + readLOC( rEntry ); + + return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, sal_True, aMediaType ); +} + +sal_Bool ZipFile::readLOC( ZipEntry &rEntry ) + throw(IOException, ZipException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nTestSig, nTime, nCRC, nSize, nCompressedSize; + sal_Int16 nVersion, nFlag, nHow, nPathLen, nExtraLen; + sal_Int32 nPos = -rEntry.nOffset; + + aGrabber.seek(nPos); + aGrabber >> nTestSig; + + if (nTestSig != LOCSIG) + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid LOC header (bad signature") ), Reference < XInterface > () ); + aGrabber >> nVersion; + aGrabber >> nFlag; + aGrabber >> nHow; + aGrabber >> nTime; + aGrabber >> nCRC; + aGrabber >> nCompressedSize; + aGrabber >> nSize; + aGrabber >> nPathLen; + aGrabber >> nExtraLen; + rEntry.nOffset = static_cast < sal_Int32 > (aGrabber.getPosition()) + nPathLen + nExtraLen; + + // read always in UTF8, some tools seem not to set UTF8 bit + uno::Sequence < sal_Int8 > aNameBuffer( nPathLen ); + sal_Int32 nRead = aGrabber.readBytes( aNameBuffer, nPathLen ); + if ( nRead < aNameBuffer.getLength() ) + aNameBuffer.realloc( nRead ); + + ::rtl::OUString sLOCPath = rtl::OUString::intern( (sal_Char *) aNameBuffer.getArray(), + aNameBuffer.getLength(), + RTL_TEXTENCODING_UTF8 ); + + if ( rEntry.nPathLen == -1 ) // the file was created + { + rEntry.nPathLen = nPathLen; + rEntry.sPath = sLOCPath; + } + + // the method can be reset for internal use so it is not checked + sal_Bool bBroken = rEntry.nVersion != nVersion + || rEntry.nFlag != nFlag + || rEntry.nTime != nTime + || rEntry.nPathLen != nPathLen + || !rEntry.sPath.equals( sLOCPath ); + + if ( bBroken && !bRecoveryMode ) + throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ), + Reference< XInterface >() ); + + return sal_True; +} + +sal_Int32 ZipFile::findEND( ) + throw(IOException, ZipException, RuntimeException) +{ + // this method is called in constructor only, no need for mutex + sal_Int32 nLength, nPos, nEnd; + Sequence < sal_Int8 > aBuffer; + try + { + nLength = static_cast <sal_Int32 > (aGrabber.getLength()); + if (nLength == 0 || nLength < ENDHDR) + return -1; + nPos = nLength - ENDHDR - ZIP_MAXNAMELEN; + nEnd = nPos >= 0 ? nPos : 0 ; + + aGrabber.seek( nEnd ); + aGrabber.readBytes ( aBuffer, nLength - nEnd ); + + const sal_Int8 *pBuffer = aBuffer.getConstArray(); + + nPos = nLength - nEnd - ENDHDR; + while ( nPos >= 0 ) + { + if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 ) + return nPos + nEnd; + nPos--; + } + } + catch ( IllegalArgumentException& ) + { + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); + } + catch ( NotConnectedException& ) + { + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); + } + catch ( BufferSizeExceededException& ) + { + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); + } + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); +} + +sal_Int32 ZipFile::readCEN() + throw(IOException, ZipException, RuntimeException) +{ + // this method is called in constructor only, no need for mutex + sal_Int32 nCenLen, nCenPos = -1, nCenOff, nEndPos, nLocPos; + sal_uInt16 nCount, nTotal; + + try + { + nEndPos = findEND(); + if (nEndPos == -1) + return -1; + aGrabber.seek(nEndPos + ENDTOT); + aGrabber >> nTotal; + aGrabber >> nCenLen; + aGrabber >> nCenOff; + + if ( nTotal * CENHDR > nCenLen ) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "invalid END header (bad entry count)") ), Reference < XInterface > () ); + + if ( nTotal > ZIP_MAXENTRIES ) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "too many entries in ZIP File") ), Reference < XInterface > () ); + + if ( nCenLen < 0 || nCenLen > nEndPos ) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid END header (bad central directory size)") ), Reference < XInterface > () ); + + nCenPos = nEndPos - nCenLen; + + if ( nCenOff < 0 || nCenOff > nCenPos ) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid END header (bad central directory size)") ), Reference < XInterface > () ); + + nLocPos = nCenPos - nCenOff; + aGrabber.seek( nCenPos ); + Sequence < sal_Int8 > aCENBuffer ( nCenLen ); + sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen ); + if ( static_cast < sal_Int64 > ( nCenLen ) != nRead ) + throw ZipException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Error reading CEN into memory buffer!") ), Reference < XInterface > () ); + + MemoryByteGrabber aMemGrabber ( aCENBuffer ); + + ZipEntry aEntry; + sal_Int32 nTestSig; + sal_Int16 nCommentLen; + + for (nCount = 0 ; nCount < nTotal; nCount++) + { + aMemGrabber >> nTestSig; + if ( nTestSig != CENSIG ) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (bad signature)") ), Reference < XInterface > () ); + + aMemGrabber.skipBytes ( 2 ); + aMemGrabber >> aEntry.nVersion; + + if ( ( aEntry.nVersion & 1 ) == 1 ) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (encrypted entry)") ), Reference < XInterface > () ); + + aMemGrabber >> aEntry.nFlag; + aMemGrabber >> aEntry.nMethod; + + if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Invalid CEN header (bad compression method)") ), Reference < XInterface > () ); + + aMemGrabber >> aEntry.nTime; + aMemGrabber >> aEntry.nCrc; + aMemGrabber >> aEntry.nCompressedSize; + aMemGrabber >> aEntry.nSize; + aMemGrabber >> aEntry.nPathLen; + aMemGrabber >> aEntry.nExtraLen; + aMemGrabber >> nCommentLen; + aMemGrabber.skipBytes ( 8 ); + aMemGrabber >> aEntry.nOffset; + + aEntry.nOffset += nLocPos; + aEntry.nOffset *= -1; + + if ( aEntry.nPathLen < 0 || aEntry.nPathLen > ZIP_MAXNAMELEN ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "name length exceeds ZIP_MAXNAMELEN bytes" ) ), Reference < XInterface > () ); + + if ( nCommentLen < 0 || nCommentLen > ZIP_MAXNAMELEN ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "comment length exceeds ZIP_MAXNAMELEN bytes" ) ), Reference < XInterface > () ); + + if ( aEntry.nExtraLen < 0 || aEntry.nExtraLen > ZIP_MAXEXTRA ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "extra header info exceeds ZIP_MAXEXTRA bytes") ), Reference < XInterface > () ); + + // read always in UTF8, some tools seem not to set UTF8 bit + aEntry.sPath = rtl::OUString::intern ( (sal_Char *) aMemGrabber.getCurrentPos(), + aEntry.nPathLen, + RTL_TEXTENCODING_UTF8 ); + + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, sal_True ) ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip entry has an invalid name.") ), Reference < XInterface > () ); + + aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + nCommentLen ); + aEntries[aEntry.sPath] = aEntry; + } + + if (nCount != nTotal) + throw ZipException(OUString( RTL_CONSTASCII_USTRINGPARAM ( "Count != Total") ), Reference < XInterface > () ); + } + catch ( IllegalArgumentException & ) + { + // seek can throw this... + nCenPos = -1; // make sure we return -1 to indicate an error + } + return nCenPos; +} + +sal_Int32 ZipFile::recover() + throw(IOException, ZipException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nLength; + Sequence < sal_Int8 > aBuffer; + Sequence < sal_Int32 > aHeaderOffsets; + + try + { + nLength = static_cast <sal_Int32 > (aGrabber.getLength()); + if (nLength == 0 || nLength < ENDHDR) + return -1; + + aGrabber.seek( 0 ); + + for( sal_Int32 nGenPos = 0; aGrabber.readBytes( aBuffer, 32000 ) && aBuffer.getLength() > 30; ) + { + const sal_Int8 *pBuffer = aBuffer.getConstArray(); + sal_Int32 nBufSize = aBuffer.getLength(); + + sal_Int32 nPos = 0; + while( nPos < nBufSize - 16 ) + { + if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 ) + { + ZipEntry aEntry; + MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 26 ) ); + + aMemGrabber >> aEntry.nVersion; + if ( ( aEntry.nVersion & 1 ) != 1 ) + { + aMemGrabber >> aEntry.nFlag; + aMemGrabber >> aEntry.nMethod; + + if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED ) + { + aMemGrabber >> aEntry.nTime; + aMemGrabber >> aEntry.nCrc; + aMemGrabber >> aEntry.nCompressedSize; + aMemGrabber >> aEntry.nSize; + aMemGrabber >> aEntry.nPathLen; + aMemGrabber >> aEntry.nExtraLen; + + sal_Int32 nDescrLength = + ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? + 16 : 0; + + + // This is a quick fix for OOo1.1RC + // For OOo2.0 the whole package must be switched to unsigned values + if ( aEntry.nCompressedSize < 0 ) aEntry.nCompressedSize = 0x7FFFFFFF; + if ( aEntry.nSize < 0 ) aEntry.nSize = 0x7FFFFFFF; + if ( aEntry.nPathLen < 0 ) aEntry.nPathLen = 0x7FFF; + if ( aEntry.nExtraLen < 0 ) aEntry.nExtraLen = 0x7FFF; + // End of quick fix + + sal_Int32 nDataSize = ( aEntry.nMethod == DEFLATED ) ? aEntry.nCompressedSize : aEntry.nSize; + sal_Int32 nBlockLength = nDataSize + aEntry.nPathLen + aEntry.nExtraLen + 30 + nDescrLength; + if ( aEntry.nPathLen <= ZIP_MAXNAMELEN && aEntry.nExtraLen < ZIP_MAXEXTRA + && ( nGenPos + nPos + nBlockLength ) <= nLength ) + { + // read always in UTF8, some tools seem not to set UTF8 bit + if( nPos + 30 + aEntry.nPathLen <= nBufSize ) + aEntry.sPath = OUString ( (sal_Char *) &pBuffer[nPos + 30], + aEntry.nPathLen, + RTL_TEXTENCODING_UTF8 ); + else + { + Sequence < sal_Int8 > aFileName; + aGrabber.seek( nGenPos + nPos + 30 ); + aGrabber.readBytes( aFileName, aEntry.nPathLen ); + aEntry.sPath = OUString ( (sal_Char *) aFileName.getArray(), + aFileName.getLength(), + RTL_TEXTENCODING_UTF8 ); + aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength()); + } + + aEntry.nOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen; + + if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) ) + { + aEntry.nCrc = 0; + aEntry.nCompressedSize = 0; + aEntry.nSize = 0; + } + + if ( aEntries.find( aEntry.sPath ) == aEntries.end() ) + aEntries[aEntry.sPath] = aEntry; + } + } + } + + nPos += 4; + } + else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 ) + { + sal_Int32 nCompressedSize, nSize, nCRC32; + MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 12 ) ); + aMemGrabber >> nCRC32; + aMemGrabber >> nCompressedSize; + aMemGrabber >> nSize; + + for( EntryHash::iterator aIter = aEntries.begin(); aIter != aEntries.end(); aIter++ ) + { + ZipEntry aTmp = (*aIter).second; + + // this is a broken package, accept this block not only for DEFLATED streams + if( (*aIter).second.nFlag & 8 ) + { + sal_Int32 nStreamOffset = nGenPos + nPos - nCompressedSize; + if ( nStreamOffset == (*aIter).second.nOffset && nCompressedSize > (*aIter).second.nCompressedSize ) + { + // only DEFLATED blocks need to be checked + sal_Bool bAcceptBlock = ( (*aIter).second.nMethod == STORED && nCompressedSize == nSize ); + + if ( !bAcceptBlock ) + { + sal_Int32 nRealSize = 0, nRealCRC = 0; + getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC ); + bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 ); + } + + if ( bAcceptBlock ) + { + (*aIter).second.nCrc = nCRC32; + (*aIter).second.nCompressedSize = nCompressedSize; + (*aIter).second.nSize = nSize; + } + } +#if 0 +// for now ignore clearly broken streams + else if( !(*aIter).second.nCompressedSize ) + { + (*aIter).second.nCrc = nCRC32; + sal_Int32 nRealStreamSize = nGenPos + nPos - (*aIter).second.nOffset; + (*aIter).second.nCompressedSize = nGenPos + nPos - (*aIter).second.nOffset; + (*aIter).second.nSize = nSize; + } +#endif + } + } + + nPos += 4; + } + else + nPos++; + } + + nGenPos += nPos; + aGrabber.seek( nGenPos ); + } + + return 0; + } + catch ( IllegalArgumentException& ) + { + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); + } + catch ( NotConnectedException& ) + { + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); + } + catch ( BufferSizeExceededException& ) + { + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "Zip END signature not found!") ), Reference < XInterface > () ); + } +} + +sal_Bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nSize = 0, nCRC = 0; + + if( aEntry.nMethod == STORED ) + return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc ); + + getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC ); + return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC ); +} + +sal_Int32 ZipFile::getCRC( sal_Int32 nOffset, sal_Int32 nSize ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Sequence < sal_Int8 > aBuffer; + CRC32 aCRC; + sal_Int32 nBlockSize = ::std::min( nSize, static_cast< sal_Int32 >( 32000 ) ); + + aGrabber.seek( nOffset ); + for ( int ind = 0; + aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize; + ind++ ) + { + aCRC.updateSegment( aBuffer, 0, ::std::min( nBlockSize, nSize - ind * nBlockSize ) ); + } + + return aCRC.getValue(); +} + +void ZipFile::getSizeAndCRC( sal_Int32 nOffset, sal_Int32 nCompressedSize, sal_Int32 *nSize, sal_Int32 *nCRC ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Sequence < sal_Int8 > aBuffer; + CRC32 aCRC; + sal_Int32 nRealSize = 0; + Inflater aInflaterLocal( sal_True ); + sal_Int32 nBlockSize = ::std::min( nCompressedSize, static_cast< sal_Int32 >( 32000 ) ); + + aGrabber.seek( nOffset ); + for ( int ind = 0; + !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize; + ind++ ) + { + Sequence < sal_Int8 > aData( nBlockSize ); + sal_Int32 nLastInflated = 0; + sal_Int32 nInBlock = 0; + + aInflaterLocal.setInput( aBuffer ); + do + { + nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize ); + aCRC.updateSegment( aData, 0, nLastInflated ); + nInBlock += nLastInflated; + } while( !aInflater.finished() && nLastInflated ); + + nRealSize += nInBlock; + } + + if( aInflaterLocal.finished() ) + { + *nSize = nRealSize; + *nCRC = aCRC.getValue(); + } + else + *nSize = *nCRC = 0; +} diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx new file mode 100644 index 000000000000..1faa37176271 --- /dev/null +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -0,0 +1,432 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipOutputStream.cxx,v $ + * $Revision: 1.41 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipOutputStream.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <osl/time.h> +#include <EncryptionData.hxx> +#include <PackageConstants.hxx> +#include <ZipEntry.hxx> +#include <ZipFile.hxx> +#include <vos/ref.hxx> +#include <com/sun/star/io/XOutputStream.hpp> + +#include <comphelper/storagehelper.hxx> + +using namespace rtl; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using namespace com::sun::star::packages; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::packages::zip::ZipConstants; + +/** This class is used to write Zip files + */ +ZipOutputStream::ZipOutputStream( Reference < XOutputStream > &xOStream ) +: xStream(xOStream) +, aBuffer(n_ConstBufferSize) +, aDeflater(DEFAULT_COMPRESSION, sal_True) +, aChucker(xOStream) +, pCurrentEntry(NULL) +, nMethod(DEFLATED) +, bFinished(sal_False) +, bEncryptCurrentEntry(sal_False) + + +{ +} + +ZipOutputStream::~ZipOutputStream( void ) +{ + for (sal_Int32 i = 0, nEnd = aZipList.size(); i < nEnd; i++) + delete aZipList[i]; +} + +void SAL_CALL ZipOutputStream::setMethod( sal_Int32 nNewMethod ) + throw(RuntimeException) +{ + nMethod = static_cast < sal_Int16 > (nNewMethod); +} +void SAL_CALL ZipOutputStream::setLevel( sal_Int32 nNewLevel ) + throw(RuntimeException) +{ + aDeflater.setLevel( nNewLevel); +} + +void SAL_CALL ZipOutputStream::putNextEntry( ZipEntry& rEntry, + vos::ORef < EncryptionData > &xEncryptData, + sal_Bool bEncrypt) + throw(IOException, RuntimeException) +{ + if (pCurrentEntry != NULL) + closeEntry(); + if (rEntry.nTime == -1) + rEntry.nTime = getCurrentDosTime(); + if (rEntry.nMethod == -1) + rEntry.nMethod = nMethod; + rEntry.nVersion = 20; + rEntry.nFlag = 1 << 11; + if (rEntry.nSize == -1 || rEntry.nCompressedSize == -1 || + rEntry.nCrc == -1) + rEntry.nFlag |= 8; + + if (bEncrypt) + { + bEncryptCurrentEntry = sal_True; + + ZipFile::StaticGetCipher( xEncryptData, aCipher, sal_False ); + + aDigest = rtl_digest_createSHA1(); + mnDigested = 0; + rEntry.nFlag |= 1 << 4; + pCurrentEncryptData = xEncryptData.getBodyPtr(); + } + sal_Int32 nLOCLength = writeLOC(rEntry); + rEntry.nOffset = static_cast < sal_Int32 > (aChucker.GetPosition()) - nLOCLength; + aZipList.push_back( &rEntry ); + pCurrentEntry = &rEntry; +} + +void SAL_CALL ZipOutputStream::closeEntry( ) + throw(IOException, RuntimeException) +{ + ZipEntry *pEntry = pCurrentEntry; + if (pEntry) + { + switch (pEntry->nMethod) + { + case DEFLATED: + aDeflater.finish(); + while (!aDeflater.finished()) + doDeflate(); + if ((pEntry->nFlag & 8) == 0) + { + if (pEntry->nSize != aDeflater.getTotalIn()) + { + OSL_ENSURE(false,"Invalid entry size"); + } + if (pEntry->nCompressedSize != aDeflater.getTotalOut()) + { + //VOS_DEBUG_ONLY("Invalid entry compressed size"); + // Different compression strategies make the merit of this + // test somewhat dubious + pEntry->nCompressedSize = aDeflater.getTotalOut(); + } + if (pEntry->nCrc != aCRC.getValue()) + { + OSL_ENSURE(false,"Invalid entry CRC-32"); + } + } + else + { + pEntry->nSize = aDeflater.getTotalIn(); + pEntry->nCompressedSize = aDeflater.getTotalOut(); + pEntry->nCrc = aCRC.getValue(); + if ( bEncryptCurrentEntry ) + pEntry->nSize = pEntry->nCompressedSize; + writeEXT(*pEntry); + } + aDeflater.reset(); + aCRC.reset(); + break; + case STORED: + if (!((pEntry->nFlag & 8) == 0)) + OSL_ENSURE ( false, "Serious error, one of compressed size, size or CRC was -1 in a STORED stream"); + break; + default: + OSL_ENSURE(false,"Invalid compression method"); + break; + } + + if (bEncryptCurrentEntry) + { + rtlDigestError aDigestResult; + aEncryptionBuffer.realloc ( 0 ); + bEncryptCurrentEntry = sal_False; + rtl_cipher_destroy ( aCipher ); + pCurrentEncryptData->aDigest.realloc ( RTL_DIGEST_LENGTH_SHA1 ); + aDigestResult = rtl_digest_getSHA1 ( aDigest, + reinterpret_cast < sal_uInt8 * > ( pCurrentEncryptData->aDigest.getArray() ), + RTL_DIGEST_LENGTH_SHA1 ); + OSL_ASSERT( aDigestResult == rtl_Digest_E_None ); + rtl_digest_destroySHA1 ( aDigest ); + } + pCurrentEntry = NULL; + } +} + +void SAL_CALL ZipOutputStream::write( const Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) + throw(IOException, RuntimeException) +{ + switch (pCurrentEntry->nMethod) + { + case DEFLATED: + if (!aDeflater.finished()) + { + aDeflater.setInputSegment(rBuffer, nNewOffset, nNewLength); + while (!aDeflater.needsInput()) + doDeflate(); + if (!bEncryptCurrentEntry) + aCRC.updateSegment(rBuffer, nNewOffset, nNewLength); + } + break; + case STORED: + { + Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength ); + aChucker.WriteBytes( aTmpBuffer ); + } + break; + } +} + +void SAL_CALL ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) + throw(IOException, RuntimeException) +{ + Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength ); + aChucker.WriteBytes( aTmpBuffer ); +} + +void SAL_CALL ZipOutputStream::rawCloseEntry( ) + throw(IOException, RuntimeException) +{ + if ( pCurrentEntry->nMethod == DEFLATED && ( pCurrentEntry->nFlag & 8 ) ) + writeEXT(*pCurrentEntry); + pCurrentEntry = NULL; +} + +void SAL_CALL ZipOutputStream::finish( ) + throw(IOException, RuntimeException) +{ + if (bFinished) + return; + + if (pCurrentEntry != NULL) + closeEntry(); + + if (aZipList.size() < 1) + OSL_ENSURE(false,"Zip file must have at least one entry!\n"); + + sal_Int32 nOffset= static_cast < sal_Int32 > (aChucker.GetPosition()); + for (sal_Int32 i =0, nEnd = aZipList.size(); i < nEnd; i++) + writeCEN( *aZipList[i] ); + writeEND( nOffset, static_cast < sal_Int32 > (aChucker.GetPosition()) - nOffset); + bFinished = sal_True; + xStream->flush(); +} + +void ZipOutputStream::doDeflate() +{ + sal_Int32 nLength = aDeflater.doDeflateSegment(aBuffer, 0, aBuffer.getLength()); + sal_Int32 nOldLength = aBuffer.getLength(); + + if ( nLength > 0 ) + { + Sequence < sal_Int8 > aTmpBuffer ( aBuffer.getConstArray(), nLength ); + const void *pTmpBuffer = static_cast < const void * > ( aTmpBuffer.getConstArray() ); + if (bEncryptCurrentEntry) + { + // Need to update our digest before encryption... + rtlDigestError aDigestResult = rtl_Digest_E_None; + sal_Int16 nDiff = n_ConstDigestLength - mnDigested; + if ( nDiff ) + { + sal_Int16 nEat = static_cast < sal_Int16 > ( nDiff > nLength ? nLength : nDiff ); + aDigestResult = rtl_digest_updateSHA1 ( aDigest, pTmpBuffer, nEat ); + mnDigested = mnDigested + nEat; + } + OSL_ASSERT( aDigestResult == rtl_Digest_E_None ); + + aEncryptionBuffer.realloc ( nLength ); + + rtlCipherError aCipherResult; + aCipherResult = rtl_cipher_encode ( aCipher, pTmpBuffer, + nLength, reinterpret_cast < sal_uInt8 * > (aEncryptionBuffer.getArray()), nLength ); + OSL_ASSERT( aCipherResult == rtl_Cipher_E_None ); + + aChucker.WriteBytes( aEncryptionBuffer ); + aCRC.update ( aEncryptionBuffer ); + aEncryptionBuffer.realloc ( nOldLength ); + } + else + aChucker.WriteBytes ( aTmpBuffer ); + } +} +void ZipOutputStream::writeEND(sal_uInt32 nOffset, sal_uInt32 nLength) + throw(IOException, RuntimeException) +{ + aChucker << ENDSIG; + aChucker << static_cast < sal_Int16 > ( 0 ); + aChucker << static_cast < sal_Int16 > ( 0 ); + aChucker << static_cast < sal_Int16 > ( aZipList.size() ); + aChucker << static_cast < sal_Int16 > ( aZipList.size() ); + aChucker << nLength; + aChucker << nOffset; + aChucker << static_cast < sal_Int16 > ( 0 ); +} +void ZipOutputStream::writeCEN( const ZipEntry &rEntry ) + throw(IOException, RuntimeException) +{ + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, sal_True ) ) + throw IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected character is used in file name." ) ), Reference< XInterface >() ); + + ::rtl::OString sUTF8Name = ::rtl::OUStringToOString( rEntry.sPath, RTL_TEXTENCODING_UTF8 ); + sal_Int16 nNameLength = static_cast < sal_Int16 > ( sUTF8Name.getLength() ); + + aChucker << CENSIG; + aChucker << rEntry.nVersion; + aChucker << rEntry.nVersion; + if (rEntry.nFlag & (1 << 4) ) + { + // If it's an encrypted entry, we pretend its stored plain text + ZipEntry *pEntry = const_cast < ZipEntry * > ( &rEntry ); + pEntry->nFlag &= ~(1 <<4 ); + aChucker << rEntry.nFlag; + aChucker << static_cast < sal_Int16 > ( STORED ); + } + else + { + aChucker << rEntry.nFlag; + aChucker << rEntry.nMethod; + } + aChucker << static_cast < sal_uInt32> ( rEntry.nTime ); + aChucker << static_cast < sal_uInt32> ( rEntry.nCrc ); + aChucker << rEntry.nCompressedSize; + aChucker << rEntry.nSize; + aChucker << nNameLength; + aChucker << static_cast < sal_Int16> (0); + aChucker << static_cast < sal_Int16> (0); + aChucker << static_cast < sal_Int16> (0); + aChucker << static_cast < sal_Int16> (0); + aChucker << static_cast < sal_Int32> (0); + aChucker << rEntry.nOffset; + + Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() ); + aChucker.WriteBytes( aSequence ); +} +void ZipOutputStream::writeEXT( const ZipEntry &rEntry ) + throw(IOException, RuntimeException) +{ + aChucker << EXTSIG; + aChucker << static_cast < sal_uInt32> ( rEntry.nCrc ); + aChucker << rEntry.nCompressedSize; + aChucker << rEntry.nSize; +} + +sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry ) + throw(IOException, RuntimeException) +{ + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, sal_True ) ) + throw IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected character is used in file name." ) ), Reference< XInterface >() ); + + ::rtl::OString sUTF8Name = ::rtl::OUStringToOString( rEntry.sPath, RTL_TEXTENCODING_UTF8 ); + sal_Int16 nNameLength = static_cast < sal_Int16 > ( sUTF8Name.getLength() ); + + aChucker << LOCSIG; + aChucker << rEntry.nVersion; + + if (rEntry.nFlag & (1 << 4) ) + { + // If it's an encrypted entry, we pretend its stored plain text + sal_Int16 nTmpFlag = rEntry.nFlag; + nTmpFlag &= ~(1 <<4 ); + aChucker << nTmpFlag; + aChucker << static_cast < sal_Int16 > ( STORED ); + } + else + { + aChucker << rEntry.nFlag; + aChucker << rEntry.nMethod; + } + + aChucker << static_cast < sal_uInt32 > (rEntry.nTime); + if ((rEntry.nFlag & 8) == 8 ) + { + aChucker << static_cast < sal_Int32 > (0); + aChucker << static_cast < sal_Int32 > (0); + aChucker << static_cast < sal_Int32 > (0); + } + else + { + aChucker << static_cast < sal_uInt32 > (rEntry.nCrc); + aChucker << rEntry.nCompressedSize; + aChucker << rEntry.nSize; + } + aChucker << nNameLength; + aChucker << static_cast < sal_Int16 > (0); + + Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() ); + aChucker.WriteBytes( aSequence ); + + return LOCHDR + nNameLength; +} +sal_uInt32 ZipOutputStream::getCurrentDosTime( ) +{ + oslDateTime aDateTime; + TimeValue aTimeValue; + osl_getSystemTime ( &aTimeValue ); + osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime); + + sal_uInt32 nYear = static_cast <sal_uInt32> (aDateTime.Year); + + if (nYear>1980) + nYear-=1980; + else if (nYear>80) + nYear-=80; + sal_uInt32 nResult = static_cast < sal_uInt32>( ( ( ( aDateTime.Day) + + ( 32 * (aDateTime.Month)) + + ( 512 * nYear ) ) << 16) | + ( ( aDateTime.Seconds/2) + + ( 32 * aDateTime.Minutes) + + ( 2048 * static_cast <sal_uInt32 > (aDateTime.Hours) ) ) ); + return nResult; +} +/* + + This is actually never used, so I removed it, but thought that the + implementation details may be useful in the future...mtg 20010307 + + I stopped using the time library and used the OSL version instead, but + it might still be useful to have this code here.. + +void ZipOutputStream::dosDateToTMDate ( tm &rTime, sal_uInt32 nDosDate) +{ + sal_uInt32 nDate = static_cast < sal_uInt32 > (nDosDate >> 16); + rTime.tm_mday = static_cast < sal_uInt32 > ( nDate & 0x1F); + rTime.tm_mon = static_cast < sal_uInt32 > ( ( ( (nDate) & 0x1E0)/0x20)-1); + rTime.tm_year = static_cast < sal_uInt32 > ( ( (nDate & 0x0FE00)/0x0200)+1980); + + rTime.tm_hour = static_cast < sal_uInt32 > ( (nDosDate & 0xF800)/0x800); + rTime.tm_min = static_cast < sal_uInt32 > ( (nDosDate & 0x7E0)/0x20); + rTime.tm_sec = static_cast < sal_uInt32 > ( 2 * (nDosDate & 0x1F) ); +} +*/ + diff --git a/package/source/zipapi/makefile.mk b/package/source/zipapi/makefile.mk new file mode 100644 index 000000000000..e0fb43f93180 --- /dev/null +++ b/package/source/zipapi/makefile.mk @@ -0,0 +1,63 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.19 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=package +TARGET=zipapi + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- +.IF "$(L10N_framework)"=="" +#CFLAGS+=/Ob0 /Od +.IF "$(SYSTEM_ZLIB)" == "YES" +CFLAGS+=-DSYSTEM_ZLIB +.ENDIF +SLOFILES= \ + $(SLO)$/CRC32.obj \ + $(SLO)$/ByteChucker.obj \ + $(SLO)$/ByteGrabber.obj \ + $(SLO)$/Inflater.obj \ + $(SLO)$/Deflater.obj \ + $(SLO)$/ZipEnumeration.obj \ + $(SLO)$/ZipFile.obj \ + $(SLO)$/ZipOutputStream.obj \ + $(SLO)$/XUnbufferedStream.obj + +.ENDIF # L10N_framework + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/package/source/zippackage/ContentInfo.hxx b/package/source/zippackage/ContentInfo.hxx new file mode 100644 index 000000000000..7a0efe5ba1fe --- /dev/null +++ b/package/source/zippackage/ContentInfo.hxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ContentInfo.hxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CONTENT_INFO_HXX_ +#define _CONTENT_INFO_HXX_ + +#include <com/sun/star/container/XNameContainer.hpp> +#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEl_HPP_ +#include <com/sun/star/lang/XUnoTunnel.hpp> +#endif +#include <ZipPackageFolder.hxx> +#include <ZipPackageStream.hxx> + +namespace com { namespace sun { namespace star { namespace packages { +class ContentInfo : public cppu::OWeakObject +{ +public: + com::sun::star::uno::Reference < com::sun::star::lang::XUnoTunnel > xTunnel; + bool bFolder; + union + { + ZipPackageFolder *pFolder; + ZipPackageStream *pStream; + }; + ContentInfo ( ZipPackageStream * pNewStream ) + : xTunnel ( pNewStream ) + , bFolder ( false ) + , pStream ( pNewStream ) + { + } + ContentInfo ( ZipPackageFolder * pNewFolder ) + : xTunnel ( pNewFolder ) + , bFolder ( true ) + , pFolder ( pNewFolder ) + { + } + virtual ~ContentInfo () + { + if ( bFolder ) + pFolder->releaseUpwardRef(); + else + pStream->clearParent(); + } +}; +} } } } +#endif diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx new file mode 100644 index 000000000000..a692586681b5 --- /dev/null +++ b/package/source/zippackage/ZipPackage.cxx @@ -0,0 +1,1700 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackage.cxx,v $ + * $Revision: 1.114 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackage.hxx> +#include <ZipPackageSink.hxx> +#include <ZipEnumeration.hxx> +#include <ZipPackageStream.hxx> +#include <ZipPackageFolder.hxx> +#include <ZipOutputStream.hxx> +#include <ZipPackageBuffer.hxx> +#include <ZipFile.hxx> +#include <PackageConstants.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <com/sun/star/packages/manifest/XManifestReader.hpp> +#include <com/sun/star/packages/manifest/XManifestWriter.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <ucbhelper/content.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/UseBackupException.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <cppuhelper/implbase1.hxx> +#include <ContentInfo.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <rtl/uri.hxx> +#include <rtl/random.h> +#include <rtl/logfile.hxx> +#include <osl/time.h> +#include <osl/file.hxx> +#include "com/sun/star/io/XAsyncOutputMonitor.hpp" + +#include <memory> +#include <vector> + +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/fileidentifierconverter.hxx> +#include <comphelper/seekableinput.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/ofopxmlhelper.hxx> +#include <comphelper/documentconstants.hxx> + +using namespace rtl; +using namespace std; +using namespace osl; +using namespace cppu; +using namespace ucbhelper; +using namespace com::sun::star; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace com::sun::star::util; +using namespace com::sun::star::lang; +using namespace com::sun::star::task; +using namespace com::sun::star::beans; +using namespace com::sun::star::packages; +using namespace com::sun::star::container; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::packages::manifest; +using namespace com::sun::star::packages::zip::ZipConstants; + +#define LOGFILE_AUTHOR "mg115289" + + +namespace { + +sal_Bool isLocalFile_Impl( ::rtl::OUString aURL ) +{ + ::rtl::OUString aSystemPath; + ContentBroker* pBroker = ContentBroker::get(); + if ( !pBroker ) + { + ::rtl::OUString aRet; + if ( FileBase::getSystemPathFromFileURL( aURL, aRet ) == FileBase::E_None ) + aSystemPath = aRet; + } + else + { + uno::Reference< XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + aSystemPath = getSystemPathFromFileURL( xManager, aURL ); + } + catch ( Exception& ) + { + } + } + + return ( aSystemPath.getLength() != 0 ); +} + +} + +//=========================================================================== + +class ActiveDataStreamer : public ::cppu::WeakImplHelper1< XActiveDataStreamer > +{ + uno::Reference< XStream > mStream; +public: + + virtual uno::Reference< XStream > SAL_CALL getStream() + throw( RuntimeException ) + { return mStream; } + + virtual void SAL_CALL setStream( const uno::Reference< XStream >& stream ) + throw( RuntimeException ) + { mStream = stream; } +}; + +class DummyInputStream : public ::cppu::WeakImplHelper1< XInputStream > +{ + virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >&, sal_Int32 ) + throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) + { return 0; } + + virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >&, sal_Int32 ) + throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) + { return 0; } + + virtual void SAL_CALL skipBytes( sal_Int32 ) + throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) + {} + + virtual sal_Int32 SAL_CALL available() + throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) + { return 0; } + + virtual void SAL_CALL closeInput() + throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) + {} +}; + +//=========================================================================== + +ZipPackage::ZipPackage (const uno::Reference < XMultiServiceFactory > &xNewFactory) +: m_aMutexHolder( new SotMutexHolder ) +, m_bHasEncryptedEntries ( sal_False ) +, m_bHasNonEncryptedEntries ( sal_False ) +, m_bInconsistent ( sal_False ) +, m_bUseManifest ( sal_True ) +, m_bForceRecovery ( sal_False ) +, m_bMediaTypeFallbackUsed ( sal_False ) +, m_nFormat( PACKAGE_FORMAT ) // package is the default format +, m_bAllowRemoveOnInsert( sal_True ) +, m_eMode ( e_IMode_None ) +, m_xFactory( xNewFactory ) +, m_pRootFolder( NULL ) +, m_pZipFile( NULL ) +{ + m_xRootFolder = m_pRootFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert ); +} + +ZipPackage::~ZipPackage( void ) +{ + delete m_pZipFile; + + // All folders and streams contain pointers to their parents, when a parent diappeares + // it should disconnect all the children from itself during destruction automatically. + // So there is no need in explicit m_pRootFolder->releaseUpwardRef() call here any more + // since m_pRootFolder has no parent and cleaning of it's children will be done automatically + // during m_pRootFolder dieing by refcount. + +#if 0 + // As all folders and streams contain references to their parents, + // we must remove these references so that they will be deleted when + // the hash_map of the root folder is cleared, releasing all subfolders + // and substreams which in turn release theirs, etc. When m_xRootFolder is + // released when this destructor completes, the folder tree should be + // deleted fully (and automagically). + + m_pRootFolder->releaseUpwardRef(); +#endif +} + +void ZipPackage::parseManifest() +{ + if ( m_nFormat == PACKAGE_FORMAT ) + { + sal_Bool bManifestParsed = sal_False; + const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) ); + if ( m_xRootFolder->hasByName( sMeta ) ) + { + const OUString sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") ); + + try { + uno::Reference< XUnoTunnel > xTunnel; + Any aAny = m_xRootFolder->getByName( sMeta ); + aAny >>= xTunnel; + uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY ); + if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) ) + { + aAny = xMetaInfFolder->getByName( sManifest ); + aAny >>= xTunnel; + uno::Reference < XActiveDataSink > xSink (xTunnel, UNO_QUERY); + if (xSink.is()) + { + OUString sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) ); + uno::Reference < XManifestReader > xReader (m_xFactory->createInstance( sManifestReader ), UNO_QUERY ); + if ( xReader.is() ) + { + const OUString sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); + const OUString sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); + const OUString sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); + const OUString sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) ); + const OUString sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) ); + const OUString sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) ); + const OUString sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) ); + const OUString sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) ); + + Sequence < Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() ); + sal_Int32 nLength = aManifestSequence.getLength(); + const Sequence < PropertyValue > *pSequence = aManifestSequence.getConstArray(); + ZipPackageStream *pStream = NULL; + ZipPackageFolder *pFolder = NULL; + + for (sal_Int32 i = 0; i < nLength ; i++, pSequence++) + { + OUString sPath, sMediaType, sVersion; + const PropertyValue *pValue = pSequence->getConstArray(); + const Any *pSalt = NULL, *pVector = NULL, *pCount = NULL, *pSize = NULL, *pDigest = NULL; + for (sal_Int32 j = 0, nNum = pSequence->getLength(); j < nNum; j++ ) + { + if (pValue[j].Name.equals( sPropFullPath ) ) + pValue[j].Value >>= sPath; + else if (pValue[j].Name.equals( sPropVersion ) ) + pValue[j].Value >>= sVersion; + else if (pValue[j].Name.equals( sPropMediaType ) ) + pValue[j].Value >>= sMediaType; + else if (pValue[j].Name.equals( sPropSalt ) ) + pSalt = &(pValue[j].Value); + else if (pValue[j].Name.equals( sPropInitialisationVector ) ) + pVector = &(pValue[j].Value); + else if (pValue[j].Name.equals( sPropIterationCount ) ) + pCount = &(pValue[j].Value); + else if (pValue[j].Name.equals( sPropSize ) ) + pSize = &(pValue[j].Value); + else if (pValue[j].Name.equals( sPropDigest ) ) + pDigest = &(pValue[j].Value); + } + + if (sPath.getLength() && hasByHierarchicalName ( sPath ) ) + { + aAny = getByHierarchicalName( sPath ); + uno::Reference < XUnoTunnel > xUnoTunnel; + aAny >>= xUnoTunnel; + sal_Int64 nTest=0; + if ((nTest = xUnoTunnel->getSomething(ZipPackageFolder::static_getImplementationId())) != 0) + { + pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest ); + pFolder->SetMediaType ( sMediaType ); + pFolder->SetVersion ( sVersion ); + } + else + { + pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething(ZipPackageStream::static_getImplementationId())); + pStream->SetMediaType ( sMediaType ); + pStream->SetFromManifest( sal_True ); + + if (pSalt && pVector && pCount && pSize) + { + Sequence < sal_uInt8 > aSequence; + sal_Int32 nCount = 0, nSize = 0; + pStream->SetToBeEncrypted ( sal_True ); + + *pSalt >>= aSequence; + pStream->setSalt ( aSequence ); + + *pVector >>= aSequence; + pStream->setInitialisationVector ( aSequence ); + + *pCount >>= nCount; + pStream->setIterationCount ( nCount ); + + *pSize >>= nSize; + pStream->setSize ( nSize ); + + if ( pDigest ) + { + *pDigest >>= aSequence; + pStream->setDigest ( aSequence ); + } + + pStream->SetToBeCompressed ( sal_True ); + pStream->SetToBeEncrypted ( sal_True ); + pStream->SetIsEncrypted ( sal_True ); + if ( !m_bHasEncryptedEntries + && pStream->getName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "content.xml" ) ) ) ) + m_bHasEncryptedEntries = sal_True; + } + else + m_bHasNonEncryptedEntries = sal_True; + } + } + } + + bManifestParsed = sal_True; + } + else + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No manifes parser!" ) ), uno::Reference< uno::XInterface >() ); + } + + // now hide the manifest.xml file from user + xMetaInfFolder->removeByName( sManifest ); + } + } + catch( Exception& ) + { + if ( !m_bForceRecovery ) + throw; + } + } + + if ( !bManifestParsed && !m_bForceRecovery ) + throw ZipIOException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Could not parse manifest.xml\n" ) ), + uno::Reference< uno::XInterface >() ); + + const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) ); + if ( m_xRootFolder->hasByName( sMimetype ) ) + { + // get mediatype from the "mimetype" stream + ::rtl::OUString aPackageMediatype; + uno::Reference< lang::XUnoTunnel > xMimeTypeTunnel; + m_xRootFolder->getByName( sMimetype ) >>= xMimeTypeTunnel; + uno::Reference < io::XActiveDataSink > xMimeSink( xMimeTypeTunnel, UNO_QUERY ); + if ( xMimeSink.is() ) + { + uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream(); + if ( xMimeInStream.is() ) + { + // Mediatypes longer than 1024 symbols should not appear here + uno::Sequence< sal_Int8 > aData( 1024 ); + sal_Int32 nRead = xMimeInStream->readBytes( aData, 1024 ); + if ( nRead > aData.getLength() ) + nRead = aData.getLength(); + + if ( nRead ) + aPackageMediatype = ::rtl::OUString( (sal_Char*)aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US ); + } + } + + + if ( !bManifestParsed ) + { + // the manifest.xml could not be successfuly parsed, this is an inconsistent package + if ( aPackageMediatype.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 ) + { + // accept only types that look similar to own mediatypes + m_pRootFolder->SetMediaType( aPackageMediatype ); + m_bMediaTypeFallbackUsed = sal_True; + } + } + else if ( !m_bForceRecovery ) + { + // the mimetype stream should contain the information from manifest.xml + if ( !m_pRootFolder->GetMediaType().equals( aPackageMediatype ) ) + throw ZipIOException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "mimetype conflicts with manifest.xml\n" ) ), + uno::Reference< uno::XInterface >() ); + } + + m_xRootFolder->removeByName( sMimetype ); + } + + m_bInconsistent = m_pRootFolder->LookForUnexpectedODF12Streams( ::rtl::OUString() ); + + sal_Bool bODF12AndOlder = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 ); + if ( !m_bForceRecovery && bODF12AndOlder && m_bInconsistent ) + { + // this is an ODF1.2 document that contains streams not referred in the manifest.xml; + // in case of ODF1.2 documents without version in manifest.xml the property IsInconsistent + // should be checked later + throw ZipIOException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "there are streams not referred in manifest.xml\n" ) ), + uno::Reference< uno::XInterface >() ); + } + + // in case it is a correct ODF1.2 document, the version must be set + // and the META-INF folder is reserved for package format + if ( bODF12AndOlder ) + m_xRootFolder->removeByName( sMeta ); + } +} + +void ZipPackage::parseContentType() +{ + if ( m_nFormat == OFOPXML_FORMAT ) + { + const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) ); + try { + // the content type must exist in OFOPXML format! + if ( !m_xRootFolder->hasByName( aContentTypes ) ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong format!" ) ), + uno::Reference< uno::XInterface >() ); + + uno::Reference< lang::XUnoTunnel > xTunnel; + uno::Any aAny = m_xRootFolder->getByName( aContentTypes ); + aAny >>= xTunnel; + uno::Reference < io::XActiveDataSink > xSink( xTunnel, UNO_QUERY ); + if ( xSink.is() ) + { + uno::Reference< io::XInputStream > xInStream = xSink->getInputStream(); + if ( xInStream.is() ) + { + sal_Int32 nInd = 0; + // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides + uno::Sequence< uno::Sequence< beans::StringPair > > aContentTypeInfo = + ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream, m_xFactory ); + + if ( aContentTypeInfo.getLength() != 2 ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // set the implicit types fist + for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ ) + m_pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] ); + + // now set the explicit types + for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ ) + { + ::rtl::OUString aPath; + if ( aContentTypeInfo[1][nInd].First.toChar() == (sal_Unicode)'/' ) + aPath = aContentTypeInfo[1][nInd].First.copy( 1 ); + else + aPath = aContentTypeInfo[1][nInd].First; + + if ( aPath.getLength() && hasByHierarchicalName( aPath ) ) + { + uno::Any aIterAny = getByHierarchicalName( aPath ); + uno::Reference < lang::XUnoTunnel > xIterTunnel; + aIterAny >>= xIterTunnel; + sal_Int64 nTest = xIterTunnel->getSomething( ZipPackageStream::static_getImplementationId() ); + if ( nTest != 0 ) + { + // this is a package stream, in OFOPXML format only streams can have mediatype + ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream* > ( nTest ); + pStream->SetMediaType( aContentTypeInfo[1][nInd].Second ); + } + } + } + } + } + + m_xRootFolder->removeByName( aContentTypes ); + } + catch( uno::Exception& ) + { + if ( !m_bForceRecovery ) + throw; + } + } +} + +void ZipPackage::getZipFileContents() +{ + auto_ptr < ZipEnumeration > pEnum ( m_pZipFile->entries() ); + ZipPackageStream *pPkgStream; + ZipPackageFolder *pPkgFolder, *pCurrent; + OUString sTemp, sDirName; + sal_Int32 nOldIndex, nIndex, nStreamIndex; + FolderHash::iterator aIter; + + while (pEnum->hasMoreElements()) + { + nIndex = nOldIndex = 0; + pCurrent = m_pRootFolder; + const ZipEntry & rEntry = *pEnum->nextElement(); + const OUString & rName = rEntry.sPath; + + nStreamIndex = rName.lastIndexOf ( '/' ); + if ( nStreamIndex != -1 ) + { + sDirName = rName.copy ( 0, nStreamIndex); + aIter = m_aRecent.find ( sDirName ); + if ( aIter != m_aRecent.end() ) + pCurrent = (*aIter).second; + } + + if ( pCurrent == m_pRootFolder ) + { + while ( (nIndex = rName.indexOf('/', nOldIndex) ) != -1 ) + { + sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex ); + if (nIndex == nOldIndex) + break; + if ( !pCurrent->hasByName( sTemp ) ) + { + pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert ); + pPkgFolder->setName( sTemp ); + pPkgFolder->doSetParent( pCurrent, sal_True ); + pCurrent = pPkgFolder; + } + else + pCurrent = pCurrent->doGetByName(sTemp).pFolder; + nOldIndex = nIndex+1; + } + if ( nStreamIndex != -1 && sDirName.getLength() ) + m_aRecent [ sDirName ] = pCurrent; + } + if ( rName.getLength() -1 != nStreamIndex ) + { + nStreamIndex++; + sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex); + pPkgStream = new ZipPackageStream( *this, m_xFactory, m_bAllowRemoveOnInsert ); + pPkgStream->SetPackageMember( sal_True ); + pPkgStream->setZipEntryOnLoading( rEntry ); + pPkgStream->setName( sTemp ); + pPkgStream->doSetParent( pCurrent, sal_True ); + } + } + + if ( m_nFormat == PACKAGE_FORMAT ) + parseManifest(); + else if ( m_nFormat == OFOPXML_FORMAT ) + parseContentType(); +} + +// XInitialization +void SAL_CALL ZipPackage::initialize( const Sequence< Any >& aArguments ) + throw(Exception, RuntimeException) +{ + RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" ); + sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True; + uno::Reference< XProgressHandler > xProgressHandler; + beans::NamedValue aNamedValue; + + if ( aArguments.getLength() ) + { + for( int ind = 0; ind < aArguments.getLength(); ind++ ) + { + OUString aParamUrl; + if ( (aArguments[ind] >>= aParamUrl)) + { + m_eMode = e_IMode_URL; + try + { + sal_Int32 nParam = aParamUrl.indexOf( '?' ); + if ( nParam >= 0 ) + { + m_aURL = aParamUrl.copy( 0, nParam ); + OUString aParam = aParamUrl.copy( nParam + 1 ); + + sal_Int32 nIndex = 0; + do + { + ::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex ); + if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) ) + { + m_bForceRecovery = sal_True; + break; + } + else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) ) + { + m_nFormat = ZIP_FORMAT; + m_pRootFolder->setPackageFormat_Impl( m_nFormat ); + break; + } + else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) ) + { + m_nFormat = OFOPXML_FORMAT; + m_pRootFolder->setPackageFormat_Impl( m_nFormat ); + break; + } + } + while ( nIndex >= 0 ); + } + else + m_aURL = aParamUrl; + + Content aContent ( m_aURL, uno::Reference < XCommandEnvironment >() ); + Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) ); + sal_uInt64 aSize = 0; + // kind of optimisation: treat empty files as nonexistent files + // and write to such files directly. Note that "Size" property is optional. + bool bHasSizeProperty = aAny >>= aSize; + if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) ) + { + uno::Reference < XActiveDataSink > xSink = new ZipPackageSink; + if (aContent.openStream ( xSink ) ) + m_xContentStream = xSink->getInputStream(); + } + else + bHaveZipFile = sal_False; + } + catch (com::sun::star::uno::Exception&) + { + // Exception derived from uno::Exception thrown. This probably + // means the file doesn't exist...we'll create it at + // commitChanges time + bHaveZipFile = sal_False; + } + } + else if ( (aArguments[ind] >>= m_xStream ) ) + { + // a writable stream can implement both XStream & XInputStream + m_eMode = e_IMode_XStream; + m_xContentStream = m_xStream->getInputStream(); + } + else if ( (aArguments[ind] >>= m_xContentStream) ) + { + m_eMode = e_IMode_XInputStream; + } + else if ( ( aArguments[ind] >>= aNamedValue ) ) + { + if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) ) + aNamedValue.Value >>= m_bForceRecovery; + else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) ) + { + // setting this argument to true means Package format + // setting it to false means plain Zip format + + sal_Bool bPackFormat = sal_True; + aNamedValue.Value >>= bPackFormat; + if ( !bPackFormat ) + m_nFormat = ZIP_FORMAT; + + m_pRootFolder->setPackageFormat_Impl( m_nFormat ); + } + else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) ) + { + ::rtl::OUString aFormatName; + aNamedValue.Value >>= aFormatName; + if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) ) + m_nFormat = PACKAGE_FORMAT; + else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) ) + m_nFormat = ZIP_FORMAT; + else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) ) + m_nFormat = OFOPXML_FORMAT; + else + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + m_pRootFolder->setPackageFormat_Impl( m_nFormat ); + } + else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) ) + { + aNamedValue.Value >>= m_bAllowRemoveOnInsert; + m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert ); + } + + // for now the progress handler is not used, probably it will never be + // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" ) + } + else + { + // The URL is not acceptable + throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ), + static_cast < ::cppu::OWeakObject * > ( this ) ); + } + } + + try + { + if (m_xContentStream.is()) + { + // the stream must be seekable, if it is not it will be wrapped + m_xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream, m_xFactory ); + m_xContentSeek = uno::Reference < XSeekable > ( m_xContentStream, UNO_QUERY ); + if ( ! m_xContentSeek.is() ) + throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ), + static_cast < ::cppu::OWeakObject * > ( this ) ); + + if ( !m_xContentSeek->getLength() ) + bHaveZipFile = sal_False; + } + else + bHaveZipFile = sal_False; + } + catch (com::sun::star::uno::Exception&) + { + // Exception derived from uno::Exception thrown. This probably + // means the file doesn't exist...we'll create it at + // commitChanges time + bHaveZipFile = sal_False; + } + if ( bHaveZipFile ) + { + try + { + m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler ); + getZipFileContents(); + } + catch ( IOException & ) + { + bBadZipFile = sal_True; + } + catch ( ZipException & ) + { + bBadZipFile = sal_True; + } + catch ( Exception & ) + { + if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; } + throw; + } + + if ( bBadZipFile ) + { + // clean up the memory, and tell the UCB about the error + if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; } + + throw com::sun::star::packages::zip::ZipIOException ( + OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ), + static_cast < ::cppu::OWeakObject * > ( this ) ); + } + } + } + + RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" ); +} + +Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName ) + throw(NoSuchElementException, RuntimeException) +{ + OUString sTemp, sDirName; + sal_Int32 nOldIndex, nIndex, nStreamIndex; + FolderHash::iterator aIter; + + if ( (nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' ) + return makeAny ( uno::Reference < XUnoTunnel > (m_pRootFolder) ); + else + { + nStreamIndex = aName.lastIndexOf ( '/' ); + bool bFolder = nStreamIndex == nIndex-1; + if ( nStreamIndex != -1 ) + { + sDirName = aName.copy ( 0, nStreamIndex); + aIter = m_aRecent.find ( sDirName ); + if ( aIter != m_aRecent.end() ) + { + if ( bFolder ) + { + sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex ); + sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 ); + if ( sTemp == (*aIter).second->getName() ) + return makeAny ( uno::Reference < XUnoTunnel > ( (*aIter).second ) ); + else + m_aRecent.erase ( aIter ); + } + else + { + sTemp = aName.copy ( nStreamIndex + 1 ); + if ( (*aIter).second->hasByName( sTemp ) ) + return (*aIter).second->getByName( sTemp ); + else + m_aRecent.erase( aIter ); + } + } + } + else + { + if ( m_pRootFolder->hasByName ( aName ) ) + return m_pRootFolder->getByName ( aName ); + } + nOldIndex = 0; + ZipPackageFolder * pCurrent = m_pRootFolder; + ZipPackageFolder * pPrevious = NULL; + while ( ( nIndex = aName.indexOf('/', nOldIndex)) != -1) + { + sTemp = aName.copy (nOldIndex, nIndex - nOldIndex); + if ( nIndex == nOldIndex ) + break; + if ( pCurrent->hasByName( sTemp ) ) + { + pPrevious = pCurrent; + pCurrent = pCurrent->doGetByName(sTemp).pFolder; + } + else + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + nOldIndex = nIndex+1; + } + if ( bFolder ) + { + if (nStreamIndex != -1 ) + m_aRecent[sDirName] = pPrevious; + return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) ); + } + else + { + sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex); + if ( pCurrent->hasByName ( sTemp ) ) + { + if (nStreamIndex != -1 ) + m_aRecent[sDirName] = pCurrent; + return pCurrent->getByName( sTemp ); + } + else + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + } +} + +sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName ) + throw(RuntimeException) +{ + OUString sTemp, sDirName; + sal_Int32 nOldIndex, nIndex, nStreamIndex; + FolderHash::iterator aIter; + + if ( (nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' ) + return sal_True; + else + { + nStreamIndex = aName.lastIndexOf ( '/' ); + bool bFolder = nStreamIndex == nIndex-1; + if ( nStreamIndex != -1 ) + { + sDirName = aName.copy ( 0, nStreamIndex); + aIter = m_aRecent.find ( sDirName ); + if ( aIter != m_aRecent.end() ) + { + if ( bFolder ) + { + sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex ); + sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 ); + if ( sTemp == (*aIter).second->getName() ) + return sal_True; + else + m_aRecent.erase ( aIter ); + } + else + { + sTemp = aName.copy ( nStreamIndex + 1 ); + if ( (*aIter).second->hasByName( sTemp ) ) + return sal_True; + else + m_aRecent.erase( aIter ); + } + } + } + else + { + if ( m_pRootFolder->hasByName ( aName ) ) + return sal_True; + } + ZipPackageFolder * pCurrent = m_pRootFolder; + ZipPackageFolder * pPrevious = NULL; + nOldIndex = 0; + while ( ( nIndex = aName.indexOf('/', nOldIndex)) != -1) + { + sTemp = aName.copy (nOldIndex, nIndex - nOldIndex); + if ( nIndex == nOldIndex ) + break; + if ( pCurrent->hasByName( sTemp ) ) + { + pPrevious = pCurrent; + pCurrent = pCurrent->doGetByName( sTemp ).pFolder; + } + else + return sal_False; + nOldIndex = nIndex+1; + } + if ( bFolder ) + { + m_aRecent[sDirName] = pPrevious; + return sal_True; + } + else + { + sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex); + + if ( pCurrent->hasByName( sTemp ) ) + { + m_aRecent[sDirName] = pCurrent; + return sal_True; + } + } + return sal_False; + } +} + +// XSingleServiceFactory +uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance( ) + throw(Exception, RuntimeException) +{ + uno::Reference < XInterface > xRef = *(new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert )); + return xRef; +} +uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const Sequence< Any >& aArguments ) + throw(Exception, RuntimeException) +{ + sal_Bool bArg = sal_False; + uno::Reference < XInterface > xRef; + if ( aArguments.getLength() ) + aArguments[0] >>= bArg; + if (bArg) + xRef = *new ZipPackageFolder ( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert ); + else + xRef = *new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ); + + return xRef; +} + +void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) +{ + const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) ); + if (m_xRootFolder->hasByName( sMime ) ) + m_xRootFolder->removeByName( sMime ); + + ZipEntry * pEntry = new ZipEntry; + sal_Int32 nBufferLength = m_pRootFolder->GetMediaType( ).getLength(); + OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US ); + Sequence< sal_Int8 > aType( (sal_Int8*)sMediaType.getStr(), + nBufferLength ); + + + pEntry->sPath = sMime; + pEntry->nMethod = STORED; + pEntry->nSize = pEntry->nCompressedSize = nBufferLength; + pEntry->nTime = ZipOutputStream::getCurrentDosTime(); + + CRC32 aCRC32; + aCRC32.update( aType ); + pEntry->nCrc = aCRC32.getValue(); + + try + { + vos::ORef < EncryptionData > xEmpty; + aZipOut.putNextEntry( *pEntry, xEmpty ); + aZipOut.write( aType, 0, nBufferLength ); + aZipOut.closeEntry(); + } + catch ( ::com::sun::star::io::IOException & r ) + { + VOS_ENSURE( 0, "Error adding mimetype to the ZipOutputStream" ); + throw WrappedTargetException( + OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ), + static_cast < OWeakObject * > ( this ), + makeAny( r ) ); + } +} + +void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< Sequence < PropertyValue > >& aManList ) +{ + // Write the manifest + uno::Reference < XOutputStream > xManOutStream; + OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) ); + uno::Reference < XManifestWriter > xWriter ( m_xFactory->createInstance( sManifestWriter ), UNO_QUERY ); + if ( xWriter.is() ) + { + ZipEntry * pEntry = new ZipEntry; + ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize ); + xManOutStream = uno::Reference < XOutputStream > (*pBuffer, UNO_QUERY); + + pEntry->sPath = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml") ); + pEntry->nMethod = DEFLATED; + pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1; + pEntry->nTime = ZipOutputStream::getCurrentDosTime(); + + // Convert vector into a Sequence + Sequence < Sequence < PropertyValue > > aManifestSequence ( aManList.size() ); + Sequence < PropertyValue > * pSequence = aManifestSequence.getArray(); + for (vector < Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end(); + aIter != aEnd; + aIter++, pSequence++) + *pSequence= (*aIter); + xWriter->writeManifestSequence ( xManOutStream, aManifestSequence ); + + sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() ); + pBuffer->realloc( nBufferLength ); + + // the manifest.xml is never encrypted - so pass an empty reference + vos::ORef < EncryptionData > xEmpty; + aZipOut.putNextEntry( *pEntry, xEmpty ); + aZipOut.write( pBuffer->getSequence(), 0, nBufferLength ); + aZipOut.closeEntry(); + } + else + { + VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" ); + IOException aException; + throw WrappedTargetException( + OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ), + static_cast < OWeakObject * > ( this ), + makeAny( aException ) ); + } +} + +void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< Sequence < PropertyValue > >& aManList ) +{ + const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); + const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); + + ZipEntry* pEntry = new ZipEntry; + ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize ); + uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY ); + + pEntry->sPath = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml") ); + pEntry->nMethod = DEFLATED; + pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1; + pEntry->nTime = ZipOutputStream::getCurrentDosTime(); + + // Convert vector into a Sequence + // TODO/LATER: use Defaulst entries in future + uno::Sequence< beans::StringPair > aDefaultsSequence; + uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() ); + sal_Int32 nSeqLength = 0; + for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(), + aEnd = aManList.end(); + aIter != aEnd; + aIter++) + { + ::rtl::OUString aPath; + ::rtl::OUString aType; + OSL_ENSURE( (*aIter)[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && (*aIter)[PKG_MNFST_FULLPATH].Name.equals( sFullPath ), + "The mediatype sequence format is wrong!\n" ); + (*aIter)[PKG_MNFST_MEDIATYPE].Value >>= aType; + if ( aType.getLength() ) + { + // only nonempty type makes sence here + nSeqLength++; + (*aIter)[PKG_MNFST_FULLPATH].Value >>= aPath; + aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath; + aOverridesSequence[nSeqLength-1].Second = aType; + } + } + aOverridesSequence.realloc( nSeqLength ); + + ::comphelper::OFOPXMLHelper::WriteContentSequence( + xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory ); + + sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() ); + pBuffer->realloc( nBufferLength ); + + // there is no encryption in this format currently + vos::ORef < EncryptionData > xEmpty; + aZipOut.putNextEntry( *pEntry, xEmpty ); + aZipOut.write( pBuffer->getSequence(), 0, nBufferLength ); + aZipOut.closeEntry(); +} + +void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream ) +{ + m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW ); + m_xContentStream = xInStream; + + // seek back to the beginning of the temp file so we can read segments from it + m_xContentSeek->seek( 0 ); + if ( m_pZipFile ) + m_pZipFile->setInputStream( m_xContentStream ); + else + m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_False ); +} + +uno::Reference< io::XInputStream > ZipPackage::writeTempFile() +{ + // In case the target local file does not exist or empty + // write directly to it otherwize create a temporary file to write to. + // If a temporary file is created it is returned back by the method. + // If the data written directly, xComponentStream will be switched here + + sal_Bool bUseTemp = sal_True; + uno::Reference < io::XInputStream > xResult; + uno::Reference < io::XInputStream > xTempIn; + + uno::Reference < io::XOutputStream > xTempOut; + uno::Reference< io::XActiveDataStreamer > xSink; + + if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) ) + { + xSink = openOriginalForOutput(); + if( xSink.is() ) + { + uno::Reference< io::XStream > xStr = xSink->getStream(); + if( xStr.is() ) + { + xTempOut = xStr->getOutputStream(); + if( xTempOut.is() ) + bUseTemp = sal_False; + } + } + } + else if ( m_eMode == e_IMode_XStream && !m_pZipFile ) + { + // write directly to an empty stream + xTempOut = m_xStream->getOutputStream(); + if( xTempOut.is() ) + bUseTemp = sal_False; + } + + if( bUseTemp ) + { + // create temporary file + const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); + uno::Reference < io::XStream > xTempFile( m_xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW ); + xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW ); + xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW ); + } + + // Hand it to the ZipOutputStream: + ZipOutputStream aZipOut ( xTempOut ); + aZipOut.setMethod(DEFLATED); + aZipOut.setLevel(DEFAULT_COMPRESSION); + + try + { + if ( m_nFormat == PACKAGE_FORMAT ) + { + // Remove the old manifest.xml file as the + // manifest will be re-generated and the + // META-INF directory implicitly created if does not exist + const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) ); + + if ( m_xRootFolder->hasByName( sMeta ) ) + { + const OUString sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") ); + + uno::Reference< XUnoTunnel > xTunnel; + Any aAny = m_xRootFolder->getByName( sMeta ); + aAny >>= xTunnel; + uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY ); + if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) ) + xMetaInfFolder->removeByName( sManifest ); + } + + // Write a magic file with mimetype + WriteMimetypeMagicFile( aZipOut ); + } + else if ( m_nFormat == OFOPXML_FORMAT ) + { + // Remove the old [Content_Types].xml file as the + // file will be re-generated + + const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) ); + + if ( m_xRootFolder->hasByName( aContentTypes ) ) + m_xRootFolder->removeByName( aContentTypes ); + } + + // Create a vector to store data for the manifest.xml file + vector < Sequence < PropertyValue > > aManList; + + const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); + const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); + const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); + + if ( m_nFormat == PACKAGE_FORMAT ) + { + Sequence < PropertyValue > aPropSeq ( PKG_SIZE_NOENCR_MNFST ); + aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType; + aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_pRootFolder->GetMediaType( ); + aPropSeq [PKG_MNFST_VERSION].Name = sVersion; + aPropSeq [PKG_MNFST_VERSION].Value <<= m_pRootFolder->GetVersion( ); + aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath; + aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + + aManList.push_back( aPropSeq ); + } + + // Get a random number generator and seed it with current timestamp + // This will be used to generate random salt and initialisation vectors + // for encrypted streams + TimeValue aTime; + osl_getSystemTime( &aTime ); + rtlRandomPool aRandomPool = rtl_random_createPool (); + rtl_random_addBytes ( aRandomPool, &aTime, 8 ); + + + // call saveContents (it will recursively save sub-directories + OUString aEmptyString; + m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, m_aEncryptionKey, aRandomPool ); + + // Clean up random pool memory + rtl_random_destroyPool ( aRandomPool ); + + if( m_bUseManifest && m_nFormat == PACKAGE_FORMAT ) + { + WriteManifest( aZipOut, aManList ); + } + else if( m_nFormat == OFOPXML_FORMAT ) + { + WriteContentTypes( aZipOut, aManList ); + } + + aZipOut.finish(); + + if( bUseTemp ) + xResult = xTempIn; + + // Update our References to point to the new temp file + if( !bUseTemp ) + { + // the case when the original contents were written directly + xTempOut->flush(); + + // in case the stream is based on a file it will implement the following interface + // the call should be used to be sure that the contents are written to the file system + uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY ); + if ( asyncOutputMonitor.is() ) + asyncOutputMonitor->waitForCompletion(); + + // no need to postpone switching to the new stream since the target was written directly + uno::Reference< io::XInputStream > xNewStream; + if ( m_eMode == e_IMode_URL ) + xNewStream = xSink->getStream()->getInputStream(); + else if ( m_eMode == e_IMode_XStream && m_xStream.is() ) + xNewStream = m_xStream->getInputStream(); + + if ( xNewStream.is() ) + ConnectTo( xNewStream ); + } + } + catch ( uno::Exception& ) + { + if( bUseTemp ) + { + // no information loss appeares, thus no special handling is required + uno::Any aCaught( ::cppu::getCaughtException() ); + + // it is allowed to throw WrappedTargetException + WrappedTargetException aException; + if ( aCaught >>= aException ) + throw aException; + + throw WrappedTargetException( + OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ), + static_cast < OWeakObject * > ( this ), + aCaught ); + } + else + { + // the document is written directly, although it was empty it is important to notify that the writing has failed + // TODO/LATER: let the package be able to recover in this situation + ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) ); + embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() ); + throw WrappedTargetException( aErrTxt, + static_cast < OWeakObject * > ( this ), + makeAny ( aException ) ); + } + } + + return xResult; +} + +uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput() +{ + // open and truncate the original file + Content aOriginalContent (m_aURL, uno::Reference < XCommandEnvironment >() ); + uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer; + + if ( m_eMode == e_IMode_URL ) + { + try + { + sal_Bool bTruncSuccess = sal_False; + + try + { + Exception aDetect; + sal_Int64 aSize = 0; + Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) ); + if( !( aAny >>= aDetect ) ) + bTruncSuccess = sal_True; + } + catch( Exception& ) + { + } + + if( !bTruncSuccess ) + { + // the file is not accessible + // just try to write an empty stream to it + + uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY ); + aOriginalContent.writeStream( xTempIn , sal_True ); + } + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = xSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) ); + } + catch( Exception& ) + { + // seems to be nonlocal file + // temporary file mechanics should be used + } + } + + return xSink; +} + +// XChangesBatch +void SAL_CALL ZipPackage::commitChanges() + throw(WrappedTargetException, RuntimeException) +{ + // lock the component for the time of commiting + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_eMode == e_IMode_XInputStream ) + { + IOException aException; + throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ), + static_cast < OWeakObject * > ( this ), makeAny ( aException ) ); + } + + RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" ); + + // first the writeTempFile is called, if it returns a stream the stream should be written to the target + // if no stream was returned, the file was written directly, nothing should be done + + uno::Reference< io::XInputStream > xTempInStream = writeTempFile(); + if ( xTempInStream.is() ) + { + uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW ); + + try + { + xTempSeek->seek( 0 ); + } + catch( uno::Exception& r ) + { + throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Temporary file should be seekable!" ) ), + static_cast < OWeakObject * > ( this ), makeAny ( r ) ); + } + + // connect to the temporary stream + ConnectTo( xTempInStream ); + + if ( m_eMode == e_IMode_XStream ) + { + // First truncate our output stream + uno::Reference < XOutputStream > xOutputStream; + + // preparation for copy step + try + { + xOutputStream = m_xStream->getOutputStream(); + uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY ); + if ( !xTruncate.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // after successful truncation the original file contents are already lost + xTruncate->truncate(); + } + catch( uno::Exception& r ) + { + throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ), + static_cast < OWeakObject * > ( this ), makeAny ( r ) ); + } + + try + { + // then copy the contents of the tempfile to our output stream + ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream ); + xOutputStream->flush(); + uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( + xOutputStream, uno::UNO_QUERY); + if (asyncOutputMonitor.is()) { + asyncOutputMonitor->waitForCompletion(); + } + } + catch( uno::Exception& ) + { + // if anything goes wrong in this block the target file becomes corrupted + // so an exception should be thrown as a notification about it + // and the package must disconnect from the stream + DisconnectFromTargetAndThrowException_Impl( xTempInStream ); + } + } + else if ( m_eMode == e_IMode_URL ) + { + uno::Reference< XOutputStream > aOrigFileStream; + sal_Bool bCanBeCorrupted = sal_False; + + if( isLocalFile_Impl( m_aURL ) ) + { + // write directly in case of local file + uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess( + m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), + uno::UNO_QUERY ); + OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" ); + uno::Reference< io::XTruncate > xOrigTruncate; + if ( xSimpleAccess.is() ) + { + try + { + aOrigFileStream = xSimpleAccess->openFileWrite( m_aURL ); + xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW ); + // after successful truncation the file is already corrupted + xOrigTruncate->truncate(); + } + catch( uno::Exception& ) + {} + } + + if( xOrigTruncate.is() ) + { + try + { + ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream ); + aOrigFileStream->closeOutput(); + } + catch( uno::Exception& ) + { + try { + aOrigFileStream->closeOutput(); + } catch ( uno::Exception& ) {} + + aOrigFileStream = uno::Reference< XOutputStream >(); + // the original file can already be corrupted + bCanBeCorrupted = sal_True; + } + } + } + + if( !aOrigFileStream.is() ) + { + try + { + uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY ); + OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" ); + if ( !xPropSet.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ); + Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () ); + + OUString sTempURL; + Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) ); + aAny >>= sTempURL; + + TransferInfo aInfo; + aInfo.NameClash = NameClash::OVERWRITE; + aInfo.MoveData = sal_False; + aInfo.SourceURL = sTempURL; + aInfo.NewTitle = rtl::Uri::decode ( m_aURL.copy ( 1 + m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8 ); + aAny <<= aInfo; + + // if the file is still not corrupted, it can become after the next step + aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny ); + } + catch (::com::sun::star::uno::Exception& r) + { + if ( bCanBeCorrupted ) + DisconnectFromTargetAndThrowException_Impl( xTempInStream ); + + throw WrappedTargetException( + OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ), + static_cast < OWeakObject * > ( this ), + makeAny ( r ) ); + } + } + } + } + + // after successful storing it can be set to false + m_bMediaTypeFallbackUsed = sal_False; + + RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" ); +} + +void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream ) +{ + m_xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY ); + if ( m_xStream.is() ) + m_eMode = e_IMode_XStream; + else + m_eMode = e_IMode_XInputStream; + + ::rtl::OUString aTempURL; + try { + uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW ); + uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) ); + aUrl >>= aTempURL; + xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ), + uno::makeAny( sal_False ) ); + } + catch ( uno::Exception& ) + { + OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" ); + } + + ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ); + embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL ); + throw WrappedTargetException( aErrTxt, + static_cast < OWeakObject * > ( this ), + makeAny ( aException ) ); +} + +sal_Bool SAL_CALL ZipPackage::hasPendingChanges( ) + throw(RuntimeException) +{ + return sal_False; +} +Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges( ) + throw(RuntimeException) +{ + return Sequence < ElementChange > (); +} + +/** + * Function to create a new component instance; is needed by factory helper implementation. + * @param xMgr service manager to if the components needs other component instances + */ +uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance( + const uno::Reference< XMultiServiceFactory > & xMgr ) +{ + return uno::Reference< XInterface >( *new ZipPackage(xMgr) ); +} + +OUString ZipPackage::static_getImplementationName() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) ); +} + +Sequence< OUString > ZipPackage::static_getSupportedServiceNames() +{ + Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) ); + return aNames; +} +sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName ) +{ + return rServiceName == getSupportedServiceNames()[0]; +} + +OUString ZipPackage::getImplementationName() + throw (RuntimeException) +{ + return static_getImplementationName(); +} + +Sequence< OUString > ZipPackage::getSupportedServiceNames() + throw (RuntimeException) +{ + return static_getSupportedServiceNames(); +} +sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName ) + throw (RuntimeException) +{ + return static_supportsService ( rServiceName ); +} +uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory ) +{ + return cppu::createSingleFactory (rServiceFactory, + static_getImplementationName(), + ZipPackage_createInstance, + static_getSupportedServiceNames()); +} + +// XUnoTunnel +Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void ) + throw (RuntimeException) +{ + static ::cppu::OImplementationId * pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +sal_Int64 SAL_CALL ZipPackage::getSomething( const Sequence< sal_Int8 >& aIdentifier ) + throw(RuntimeException) +{ + if (aIdentifier.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) + return reinterpret_cast < sal_Int64 > ( this ); + return 0; +} + +uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo( ) + throw(RuntimeException) +{ + return uno::Reference < XPropertySetInfo > (); +} +void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) + throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + if ( m_nFormat != PACKAGE_FORMAT ) + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasEncryptedEntries") ) + ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasNonEncryptedEntries") ) + ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("IsInconsistent") ) + ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaTypeFallbackUsed") ) ) + throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) ) + { + if (!( aValue >>= m_aEncryptionKey ) ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("UseManifest") ) ) + { + if (!( aValue >>= m_bUseManifest ) ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + } + else + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} +Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // TODO/LATER: Activate the check when zip-ucp is ready + // if ( m_nFormat != PACKAGE_FORMAT ) + // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Any aAny; + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "EncryptionKey" ) ) ) + { + aAny <<= m_aEncryptionKey; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasEncryptedEntries" ) ) ) + { + aAny <<= m_bHasEncryptedEntries; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasNonEncryptedEntries" ) ) ) + { + aAny <<= m_bHasNonEncryptedEntries; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "IsInconsistent" ) ) ) + { + aAny <<= m_bInconsistent; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "UseManifest" ) ) ) + { + aAny <<= m_bUseManifest; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "MediaTypeFallbackUsed" ) ) ) + { + aAny <<= m_bMediaTypeFallbackUsed; + return aAny; + } + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} +void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} diff --git a/package/source/zippackage/ZipPackageBuffer.cxx b/package/source/zippackage/ZipPackageBuffer.cxx new file mode 100644 index 000000000000..114c04adbcbe --- /dev/null +++ b/package/source/zippackage/ZipPackageBuffer.cxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageBuffer.cxx,v $ + * $Revision: 1.18 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageBuffer.hxx> +#include <string.h> // for memcpy + +using namespace ::com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using com::sun::star::lang::IllegalArgumentException; + +ZipPackageBuffer::ZipPackageBuffer(sal_Int64 nNewBufferSize ) +: m_nBufferSize (nNewBufferSize) +, m_nEnd(0) +, m_nCurrent(0) +, m_bMustInitBuffer ( sal_True ) +{ +} +ZipPackageBuffer::~ZipPackageBuffer(void) +{ +} + +sal_Int32 SAL_CALL ZipPackageBuffer::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if (nBytesToRead < 0) + throw BufferSizeExceededException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), *this ); + + if (nBytesToRead + m_nCurrent > m_nEnd) + nBytesToRead = static_cast < sal_Int32 > (m_nEnd - m_nCurrent); + + aData.realloc ( nBytesToRead ); + memcpy(aData.getArray(), m_aBuffer.getConstArray() + m_nCurrent, nBytesToRead); + m_nCurrent +=nBytesToRead; + return nBytesToRead; +} + +sal_Int32 SAL_CALL ZipPackageBuffer::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + return readBytes(aData, nMaxBytesToRead); +} +void SAL_CALL ZipPackageBuffer::skipBytes( sal_Int32 nBytesToSkip ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if (nBytesToSkip < 0) + throw BufferSizeExceededException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), *this ); + + if (nBytesToSkip + m_nCurrent > m_nEnd) + nBytesToSkip = static_cast < sal_Int32 > (m_nEnd - m_nCurrent); + + m_nCurrent+=nBytesToSkip; +} +sal_Int32 SAL_CALL ZipPackageBuffer::available( ) + throw(NotConnectedException, IOException, RuntimeException) +{ + return static_cast < sal_Int32 > (m_nEnd - m_nCurrent); +} +void SAL_CALL ZipPackageBuffer::closeInput( ) + throw(NotConnectedException, IOException, RuntimeException) +{ +} +void SAL_CALL ZipPackageBuffer::writeBytes( const Sequence< sal_Int8 >& aData ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + sal_Int64 nDataLen = aData.getLength(), nCombined = m_nEnd + nDataLen; + + if ( nCombined > m_nBufferSize) + { + do + m_nBufferSize *=2; + while (nCombined > m_nBufferSize); + m_aBuffer.realloc(static_cast < sal_Int32 > (m_nBufferSize)); + m_bMustInitBuffer = sal_False; + } + else if (m_bMustInitBuffer) + { + m_aBuffer.realloc ( static_cast < sal_Int32 > ( m_nBufferSize ) ); + m_bMustInitBuffer = sal_False; + } + memcpy( m_aBuffer.getArray() + m_nCurrent, aData.getConstArray(), static_cast < sal_Int32 > (nDataLen)); + m_nCurrent+=nDataLen; + if (m_nCurrent>m_nEnd) + m_nEnd = m_nCurrent; +} +void SAL_CALL ZipPackageBuffer::flush( ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ +} +void SAL_CALL ZipPackageBuffer::closeOutput( ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ +} +void SAL_CALL ZipPackageBuffer::seek( sal_Int64 location ) + throw( IllegalArgumentException, IOException, RuntimeException) +{ + if ( location > m_nEnd || location < 0 ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + m_nCurrent = location; +} +sal_Int64 SAL_CALL ZipPackageBuffer::getPosition( ) + throw(IOException, RuntimeException) +{ + return m_nCurrent; +} +sal_Int64 SAL_CALL ZipPackageBuffer::getLength( ) + throw(IOException, RuntimeException) +{ + return m_nEnd; +} diff --git a/package/source/zippackage/ZipPackageEntry.cxx b/package/source/zippackage/ZipPackageEntry.cxx new file mode 100644 index 000000000000..b233e34c2a28 --- /dev/null +++ b/package/source/zippackage/ZipPackageEntry.cxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageEntry.cxx,v $ + * $Revision: 1.30 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageEntry.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <osl/diagnose.h> + +#include <ZipPackageFolder.hxx> +#include <ZipPackageStream.hxx> +#include <ContentInfo.hxx> + +#include <comphelper/storagehelper.hxx> + +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::packages::zip::ZipConstants; + +ZipPackageEntry::ZipPackageEntry ( bool bNewFolder ) +: mbIsFolder ( bNewFolder ) +, mbAllowRemoveOnInsert( sal_True ) +, pParent ( NULL ) +{ +} + +ZipPackageEntry::~ZipPackageEntry() +{ + // When the entry is destroyed it must be already disconnected from the parent + OSL_ENSURE( !pParent, "The parent must be disconnected already! Memory corruption is possible!\n" ); +} + +// XChild +OUString SAL_CALL ZipPackageEntry::getName( ) + throw(RuntimeException) +{ + return msName; +} +void SAL_CALL ZipPackageEntry::setName( const OUString& aName ) + throw(RuntimeException) +{ + if ( pParent && msName.getLength() && pParent->hasByName ( msName ) ) + pParent->removeByName ( msName ); + + // unfortunately no other exception than RuntimeException can be thrown here + // usually the package is used through storage implementation, the problem should be detected there + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aName, sal_True ) ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected character is used in file name." ) ), Reference< XInterface >() ); + + msName = aName; + + if ( pParent ) + pParent->doInsertByName ( this, sal_False ); +} +Reference< XInterface > SAL_CALL ZipPackageEntry::getParent( ) + throw(RuntimeException) +{ + // return Reference< XInterface >( xParent, UNO_QUERY ); + return Reference< XInterface >( static_cast< ::cppu::OWeakObject* >( pParent ), UNO_QUERY ); +} + +void ZipPackageEntry::doSetParent ( ZipPackageFolder * pNewParent, sal_Bool bInsert ) +{ + // xParent = pParent = pNewParent; + pParent = pNewParent; + if ( bInsert && msName.getLength() && !pNewParent->hasByName ( msName ) ) + pNewParent->doInsertByName ( this, sal_False ); +} + +void SAL_CALL ZipPackageEntry::setParent( const Reference< XInterface >& xNewParent ) + throw(NoSupportException, RuntimeException) +{ + sal_Int64 nTest(0); + Reference < XUnoTunnel > xTunnel ( xNewParent, UNO_QUERY ); + if ( !xNewParent.is() || ( nTest = xTunnel->getSomething ( ZipPackageFolder::static_getImplementationId () ) ) == 0 ) + throw NoSupportException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + ZipPackageFolder *pNewParent = reinterpret_cast < ZipPackageFolder * > ( nTest ); + + if ( pNewParent != pParent ) + { + if ( pParent && msName.getLength() && pParent->hasByName ( msName ) && mbAllowRemoveOnInsert ) + pParent->removeByName( msName ); + doSetParent ( pNewParent, sal_True ); + } +} + //XPropertySet +Reference< beans::XPropertySetInfo > SAL_CALL ZipPackageEntry::getPropertySetInfo( ) + throw(RuntimeException) +{ + return Reference < beans::XPropertySetInfo > (); +} +void SAL_CALL ZipPackageEntry::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackageEntry::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< beans::XPropertyChangeListener >& /*aListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackageEntry::addVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackageEntry::removeVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} diff --git a/package/source/zippackage/ZipPackageEntry.hxx b/package/source/zippackage/ZipPackageEntry.hxx new file mode 100644 index 000000000000..01b47d71f728 --- /dev/null +++ b/package/source/zippackage/ZipPackageEntry.hxx @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageEntry.hxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_ENTRY_HXX +#define _ZIP_PACKAGE_ENTRY_HXX + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif +#include <ZipEntry.hxx> +#include <cppuhelper/implbase5.hxx> + +class ZipPackageFolder; + +class ZipPackageEntry : public cppu::WeakImplHelper5 +< + com::sun::star::container::XNamed, + com::sun::star::container::XChild, + com::sun::star::lang::XUnoTunnel, + com::sun::star::beans::XPropertySet, + com::sun::star::lang::XServiceInfo +> +{ +protected: + ::rtl::OUString msName; + bool mbIsFolder:1; + bool mbAllowRemoveOnInsert:1; + // com::sun::star::uno::Reference < com::sun::star::container::XNameContainer > xParent; + ::rtl::OUString sMediaType; + ZipPackageFolder * pParent; +public: + ZipEntry aEntry; + ZipPackageEntry ( bool bNewFolder = sal_False ); + virtual ~ZipPackageEntry( void ); + + ::rtl::OUString & GetMediaType () { return sMediaType; } + void SetMediaType ( const ::rtl::OUString & sNewType) { sMediaType = sNewType; } + void doSetParent ( ZipPackageFolder * pNewParent, sal_Bool bInsert ); + bool IsFolder ( ) { return mbIsFolder; } + ZipPackageFolder* GetParent ( ) { return pParent; } + void SetFolder ( bool bSetFolder ) { mbIsFolder = bSetFolder; } + + void clearParent ( void ) + { + // xParent.clear(); + pParent = NULL; + } + // XNamed + virtual ::rtl::OUString SAL_CALL getName( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + // XChild + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getParent( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setParent( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Parent ) + throw(::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw(::com::sun::star::uno::RuntimeException) = 0; + // XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) = 0; + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zippackage/ZipPackageFolder.cxx b/package/source/zippackage/ZipPackageFolder.cxx new file mode 100644 index 000000000000..5215c07579d2 --- /dev/null +++ b/package/source/zippackage/ZipPackageFolder.cxx @@ -0,0 +1,806 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageFolder.cxx,v $ + * $Revision: 1.85 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageFolder.hxx> +#include <ZipFile.hxx> +#include <ZipOutputStream.hxx> +#include <ZipPackageStream.hxx> +#include <PackageConstants.hxx> +#include <ZipPackageFolderEnumeration.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <vos/diagnose.hxx> +#include <osl/time.h> +#include <rtl/digest.h> +#include <ContentInfo.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <EncryptedDataHeader.hxx> +#include <rtl/random.h> +#include <memory> + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::container; +using namespace com::sun::star::packages; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace cppu; +using namespace rtl; +using namespace std; +using namespace ::com::sun::star; +using vos::ORef; + +Sequence < sal_Int8 > ZipPackageFolder::aImplementationId = Sequence < sal_Int8 > (); + +ZipPackageFolder::ZipPackageFolder ( const Reference< XMultiServiceFactory >& xFactory, + sal_Int16 nFormat, + sal_Bool bAllowRemoveOnInsert ) +: m_xFactory( xFactory ) +, m_nFormat( nFormat ) +{ + OSL_ENSURE( m_xFactory.is(), "No factory is provided to the package folder!" ); + + this->mbAllowRemoveOnInsert = bAllowRemoveOnInsert; + + SetFolder ( sal_True ); + aEntry.nVersion = -1; + aEntry.nFlag = 0; + aEntry.nMethod = STORED; + aEntry.nTime = -1; + aEntry.nCrc = 0; + aEntry.nCompressedSize = 0; + aEntry.nSize = 0; + aEntry.nOffset = -1; + if ( !aImplementationId.getLength() ) + { + aImplementationId = getImplementationId(); + } +} + + +ZipPackageFolder::~ZipPackageFolder() +{ +} + +sal_Bool ZipPackageFolder::LookForUnexpectedODF12Streams( const ::rtl::OUString& aPath ) +{ + sal_Bool bHasUnexpected = sal_False; + + for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end(); + !bHasUnexpected && aCI != aEnd; + aCI++) + { + const OUString &rShortName = (*aCI).first; + const ContentInfo &rInfo = *(*aCI).second; + + if ( rInfo.bFolder ) + { + if ( aPath.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) ) + { + // META-INF is not allowed to contain subfolders + bHasUnexpected = sal_True; + } + else + { + OUString sOwnPath = aPath + rShortName + OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath ); + } + } + else + { + if ( aPath.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) ) + { + if ( !rShortName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) ) ) + && rShortName.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "signatures" ) ) ) == -1 ) + { + // a stream from META-INF with unexpected name + bHasUnexpected = sal_True; + } + + // streams from META-INF with expected names are allowed not to be registered in manifest.xml + } + else if ( !rInfo.pStream->IsFromManifest() ) + { + // the stream is not in META-INF and ist notregistered in manifest.xml, + // check whether it is an internal part of the package format + if ( aPath.getLength() + || !rShortName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "mimetype" ) ) ) ) + { + // if it is not "mimetype" from the root it is not a part of the package + bHasUnexpected = sal_True; + } + } + } + } + + return bHasUnexpected; +} + +void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair ) +{ + ::rtl::OUString aExt; + if ( aPair.First.toChar() == (sal_Unicode)'.' ) + aExt = aPair.First; + else + aExt = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ) + aPair.First; + + for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end(); + aCI != aEnd; + aCI++) + { + const OUString &rShortName = (*aCI).first; + const ContentInfo &rInfo = *(*aCI).second; + + if ( rInfo.bFolder ) + rInfo.pFolder->setChildStreamsTypeByExtension( aPair ); + else + { + sal_Int32 nPathLength = rShortName.getLength(); + sal_Int32 nExtLength = aExt.getLength(); + if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) ) + rInfo.pStream->SetMediaType( aPair.Second ); + } + } +} + +void ZipPackageFolder::copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource) +{ + rDest.nVersion = rSource.nVersion; + rDest.nFlag = rSource.nFlag; + rDest.nMethod = rSource.nMethod; + rDest.nTime = rSource.nTime; + rDest.nCrc = rSource.nCrc; + rDest.nCompressedSize = rSource.nCompressedSize; + rDest.nSize = rSource.nSize; + rDest.nOffset = rSource.nOffset; + rDest.sPath = rSource.sPath; + rDest.nPathLen = rSource.nPathLen; + rDest.nExtraLen = rSource.nExtraLen; +} + + // XNameContainer +void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const Any& aElement ) + throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + if (hasByName(aName)) + throw ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else + { + Reference < XUnoTunnel > xRef; + aElement >>= xRef; + if ( ( aElement >>= xRef ) ) + { + sal_Int64 nTest; + ZipPackageEntry *pEntry; + if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 ) + { + ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest ); + pEntry = static_cast < ZipPackageEntry * > ( pFolder ); + } + else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 ) + { + ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest ); + pEntry = static_cast < ZipPackageEntry * > ( pStream ); + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + + if (pEntry->getName() != aName ) + pEntry->setName (aName); + doInsertByName ( pEntry, sal_True ); + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + } +} +void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name ) + throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ContentHash::iterator aIter = maContents.find ( Name ); + if ( aIter == maContents.end() ) + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + maContents.erase( aIter ); +} + // XEnumerationAccess +Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( ) + throw(RuntimeException) +{ + return Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents)); +} + // XElementAccess +Type SAL_CALL ZipPackageFolder::getElementType( ) + throw(RuntimeException) +{ + return ::getCppuType ((const Reference< XUnoTunnel > *) 0); +} +sal_Bool SAL_CALL ZipPackageFolder::hasElements( ) + throw(RuntimeException) +{ + return maContents.size() > 0; +} + // XNameAccess +ContentInfo& ZipPackageFolder::doGetByName( const OUString& aName ) + throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ContentHash::iterator aIter = maContents.find ( aName ); + if ( aIter == maContents.end()) + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + return *(*aIter).second; +} +Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName ) + throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + return makeAny ( doGetByName ( aName ).xTunnel ); +} +Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( ) + throw(RuntimeException) +{ + sal_uInt32 i=0, nSize = maContents.size(); + Sequence < OUString > aSequence ( nSize ); + OUString *pNames = aSequence.getArray(); + for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end(); + aIterator != aEnd; + ++i, ++aIterator) + pNames[i] = (*aIterator).first; + return aSequence; +} +sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName ) + throw(RuntimeException) +{ + return maContents.find ( aName ) != maContents.end (); +} + // XNameReplace +void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const Any& aElement ) + throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + if ( hasByName( aName ) ) + removeByName( aName ); + else + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + insertByName(aName, aElement); +} + +static void ImplSetStoredData( ZipEntry & rEntry, Reference < XInputStream> & rStream ) +{ + // It's very annoying that we have to do this, but lots of zip packages + // don't allow data descriptors for STORED streams, meaning we have to + // know the size and CRC32 of uncompressed streams before we actually + // write them ! + CRC32 aCRC32; + rEntry.nMethod = STORED; + rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream ); + rEntry.nCrc = aCRC32.getValue(); +} + +void ZipPackageFolder::saveContents(OUString &rPath, std::vector < Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, Sequence < sal_Int8 > &rEncryptionKey, rtlRandomPool &rRandomPool) + throw(RuntimeException) +{ + sal_Bool bWritingFailed = sal_False; + ZipPackageFolder *pFolder = NULL; + ZipPackageStream *pStream = NULL; + const OUString sMediaTypeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); + const OUString sVersionProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); + const OUString sFullPathProperty ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); + const OUString sInitialisationVectorProperty ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) ); + const OUString sSaltProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) ); + const OUString sIterationCountProperty ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) ); + const OUString sSizeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) ); + const OUString sDigestProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) ); + + sal_Bool bHaveEncryptionKey = rEncryptionKey.getLength() ? sal_True : sal_False; + + if ( maContents.begin() == maContents.end() && rPath.getLength() && m_nFormat != OFOPXML_FORMAT ) + { + // it is an empty subfolder, use workaround to store it + ZipEntry* pTempEntry = new ZipEntry(); + ZipPackageFolder::copyZipEntry ( *pTempEntry, aEntry ); + pTempEntry->nPathLen = (sal_Int16)( ::rtl::OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() ); + pTempEntry->nExtraLen = -1; + pTempEntry->sPath = rPath; + + try + { + vos::ORef < EncryptionData > aEmptyEncr; + rZipOut.putNextEntry ( *pTempEntry, aEmptyEncr, sal_False ); + rZipOut.rawCloseEntry(); + } + catch ( ZipException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + catch ( IOException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + } + + for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end(); + aCI != aEnd; + aCI++) + { + const OUString &rShortName = (*aCI).first; + const ContentInfo &rInfo = *(*aCI).second; + + Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST); + PropertyValue *pValue = aPropSet.getArray(); + + if ( rInfo.bFolder ) + pFolder = rInfo.pFolder; + else + pStream = rInfo.pStream; + + if ( rInfo.bFolder ) + { + OUString sTempName = rPath + rShortName + OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + + pValue[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; + pValue[PKG_MNFST_MEDIATYPE].Value <<= pFolder->GetMediaType(); + pValue[PKG_MNFST_VERSION].Name = sVersionProperty; + pValue[PKG_MNFST_VERSION].Value <<= pFolder->GetVersion(); + pValue[PKG_MNFST_FULLPATH].Name = sFullPathProperty; + pValue[PKG_MNFST_FULLPATH].Value <<= sTempName; + + pFolder->saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool); + } + else + { + // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream + // and be deleted in the ZipOutputStream destructor + auto_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry ); + ZipEntry* pTempEntry = pAutoTempEntry.get(); + + // In case the entry we are reading is also the entry we are writing, we will + // store the ZipEntry data in pTempEntry + + ZipPackageFolder::copyZipEntry ( *pTempEntry, pStream->aEntry ); + pTempEntry->sPath = rPath + rShortName; + pTempEntry->nPathLen = (sal_Int16)( ::rtl::OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() ); + + sal_Bool bToBeEncrypted = pStream->IsToBeEncrypted() && (bHaveEncryptionKey || pStream->HasOwnKey()); + sal_Bool bToBeCompressed = bToBeEncrypted ? sal_True : pStream->IsToBeCompressed(); + + pValue[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; + pValue[PKG_MNFST_MEDIATYPE].Value <<= pStream->GetMediaType( ); + pValue[PKG_MNFST_VERSION].Name = sVersionProperty; + pValue[PKG_MNFST_VERSION].Value <<= ::rtl::OUString(); // no version is stored for streams currently + pValue[PKG_MNFST_FULLPATH].Name = sFullPathProperty; + pValue[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath; + + + OSL_ENSURE( pStream->GetStreamMode() != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" ); + + sal_Bool bRawStream = sal_False; + if ( pStream->GetStreamMode() == PACKAGE_STREAM_DETECT ) + bRawStream = pStream->ParsePackageRawStream(); + else if ( pStream->GetStreamMode() == PACKAGE_STREAM_RAW ) + bRawStream = sal_True; + + sal_Bool bTransportOwnEncrStreamAsRaw = sal_False; + // During the storing the original size of the stream can be changed + // TODO/LATER: get rid of this hack + sal_Int32 nOwnStreamOrigSize = bRawStream ? pStream->GetMagicalHackSize() : pStream->getSize(); + + sal_Bool bUseNonSeekableAccess = sal_False; + Reference < XInputStream > xStream; + if ( !pStream->IsPackageMember() && !bRawStream && !bToBeEncrypted && bToBeCompressed ) + { + // the stream is not a package member, not a raw stream, + // it should not be encrypted and it should be compressed, + // in this case nonseekable access can be used + + xStream = pStream->GetOwnStreamNoWrap(); + Reference < XSeekable > xSeek ( xStream, UNO_QUERY ); + + bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() ); + } + + if ( !bUseNonSeekableAccess ) + { + xStream = pStream->getRawData(); + + if ( !xStream.is() ) + { + VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" ); + bWritingFailed = sal_True; + continue; + } + + Reference < XSeekable > xSeek ( xStream, UNO_QUERY ); + try + { + if ( xSeek.is() ) + { + // If the stream is a raw one, then we should be positioned + // at the beginning of the actual data + if ( !bToBeCompressed || bRawStream ) + { + // The raw stream can neither be encrypted nor connected + OSL_ENSURE( !bRawStream || !bToBeCompressed && !bToBeEncrypted, "The stream is already encrypted!\n" ); + xSeek->seek ( bRawStream ? pStream->GetMagicalHackPos() : 0 ); + ImplSetStoredData ( *pTempEntry, xStream ); + + // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties! + } + else if ( bToBeEncrypted ) + { + // this is the correct original size + pTempEntry->nSize = static_cast < sal_Int32 > ( xSeek->getLength() ); + nOwnStreamOrigSize = pTempEntry->nSize; + } + + xSeek->seek ( 0 ); + } + else + { + // Okay, we don't have an xSeekable stream. This is possibly bad. + // check if it's one of our own streams, if it is then we know that + // each time we ask for it we'll get a new stream that will be + // at position zero...otherwise, assert and skip this stream... + if ( pStream->IsPackageMember() ) + { + // if the password has been changed than the stream should not be package member any more + if ( pStream->IsEncrypted() && pStream->IsToBeEncrypted() ) + { + // Should be handled close to the raw stream handling + bTransportOwnEncrStreamAsRaw = sal_True; + pTempEntry->nMethod = STORED; + + // TODO/LATER: get rid of this situation + // this size should be different from the one that will be stored in manifest.xml + // it is used in storing algorithms and after storing the correct size will be set + pTempEntry->nSize = pTempEntry->nCompressedSize; + } + } + else + { + VOS_ENSURE( 0, "The package component requires that every stream either be FROM a package or it must support XSeekable!" ); + continue; + } + } + } + catch ( Exception& ) + { + VOS_ENSURE( 0, "The stream provided to the package component has problems!" ); + bWritingFailed = sal_True; + continue; + } + + if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw ) + { + if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw ) + { + Sequence < sal_uInt8 > aSalt ( 16 ), aVector ( 8 ); + rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 ); + rtl_random_getBytes ( rRandomPool, aVector.getArray(), 8 ); + sal_Int32 nIterationCount = 1024; + + if ( !pStream->HasOwnKey() ) + pStream->setKey ( rEncryptionKey ); + + pStream->setInitialisationVector ( aVector ); + pStream->setSalt ( aSalt ); + pStream->setIterationCount ( nIterationCount ); + } + + // last property is digest, which is inserted later if we didn't have + // a magic header + aPropSet.realloc(PKG_SIZE_ENCR_MNFST); + + pValue = aPropSet.getArray(); + pValue[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty; + pValue[PKG_MNFST_INIVECTOR].Value <<= pStream->getInitialisationVector(); + pValue[PKG_MNFST_SALT].Name = sSaltProperty; + pValue[PKG_MNFST_SALT].Value <<= pStream->getSalt(); + pValue[PKG_MNFST_ITERATION].Name = sIterationCountProperty; + pValue[PKG_MNFST_ITERATION].Value <<= pStream->getIterationCount (); + + // Need to store the uncompressed size in the manifest + OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" ); + pValue[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty; + pValue[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize; + + if ( bRawStream || bTransportOwnEncrStreamAsRaw ) + { + pValue[PKG_MNFST_DIGEST].Name = sDigestProperty; + pValue[PKG_MNFST_DIGEST].Value <<= pStream->getDigest(); + } + } + } + + // If the entry is already stored in the zip file in the format we + // want for this write...copy it raw + if ( !bUseNonSeekableAccess && + ( bRawStream || bTransportOwnEncrStreamAsRaw || + ( pStream->IsPackageMember() && !bToBeEncrypted && + ( pStream->aEntry.nMethod == DEFLATED && bToBeCompressed ) || + ( pStream->aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) + { + // If it's a PackageMember, then it's an unbuffered stream and we need + // to get a new version of it as we can't seek backwards. + if ( pStream->IsPackageMember() ) + { + xStream = pStream->getRawData(); + if ( !xStream.is() ) + { + // Make sure that we actually _got_ a new one ! + VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" ); + continue; + } + } + + try + { + if ( bRawStream ) + xStream->skipBytes( pStream->GetMagicalHackPos() ); + + rZipOut.putNextEntry ( *pTempEntry, pStream->getEncryptionData(), sal_False ); + // the entry is provided to the ZipOutputStream that will delete it + pAutoTempEntry.release(); + + Sequence < sal_Int8 > aSeq ( n_ConstBufferSize ); + sal_Int32 nLength; + + do + { + nLength = xStream->readBytes( aSeq, n_ConstBufferSize ); + rZipOut.rawWrite(aSeq, 0, nLength); + } + while ( nLength == n_ConstBufferSize ); + + rZipOut.rawCloseEntry(); + } + catch ( ZipException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + catch ( IOException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + } + else + { + // This stream is defenitly not a raw stream + + // If nonseekable access is used the stream should be at the beginning and + // is useless after the storing. Thus if the storing fails the package should + // be thrown away ( as actually it is done currently )! + // To allow to reuse the package after the error, the optimization must be removed! + + // If it's a PackageMember, then our previous reference held a 'raw' stream + // so we need to re-get it, unencrypted, uncompressed and positioned at the + // beginning of the stream + if ( pStream->IsPackageMember() ) + { + xStream = pStream->getInputStream(); + if ( !xStream.is() ) + { + // Make sure that we actually _got_ a new one ! + VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" ); + continue; + } + } + + if ( bToBeCompressed ) + { + pTempEntry->nMethod = DEFLATED; + pTempEntry->nCrc = pTempEntry->nCompressedSize = pTempEntry->nSize = -1; + } + + try + { + rZipOut.putNextEntry ( *pTempEntry, pStream->getEncryptionData(), bToBeEncrypted); + // the entry is provided to the ZipOutputStream that will delete it + pAutoTempEntry.release(); + + sal_Int32 nLength; + Sequence < sal_Int8 > aSeq (n_ConstBufferSize); + do + { + nLength = xStream->readBytes(aSeq, n_ConstBufferSize); + rZipOut.write(aSeq, 0, nLength); + } + while ( nLength == n_ConstBufferSize ); + + rZipOut.closeEntry(); + } + catch ( ZipException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + catch ( IOException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + + if ( bToBeEncrypted ) + { + pValue[PKG_MNFST_DIGEST].Name = sDigestProperty; + pValue[PKG_MNFST_DIGEST].Value <<= pStream->getDigest(); + pStream->SetIsEncrypted ( sal_True ); + } + } + + if( !bWritingFailed ) + { + if ( !pStream->IsPackageMember() ) + { + pStream->CloseOwnStreamIfAny(); + pStream->SetPackageMember ( sal_True ); + } + + if ( bRawStream ) + { + // the raw stream was integrated and now behaves + // as usual encrypted stream + pStream->SetToBeEncrypted( sal_True ); + } + + // Remove hacky bit from entry flags + if ( pTempEntry->nFlag & ( 1 << 4 ) ) + { + pTempEntry->nFlag &= ~( 1 << 4 ); + pTempEntry->nMethod = STORED; + } + + // Then copy it back afterwards... + ZipPackageFolder::copyZipEntry ( pStream->aEntry, *pTempEntry ); + + // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) + if ( pStream->IsEncrypted() ) + pStream->setSize( nOwnStreamOrigSize ); + + pStream->aEntry.nOffset *= -1; + } + } + + // folder can have a mediatype only in package format + if ( m_nFormat == PACKAGE_FORMAT || ( m_nFormat == OFOPXML_FORMAT && !rInfo.bFolder ) ) + rManList.push_back( aPropSet ); + } + + if( bWritingFailed ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +void ZipPackageFolder::releaseUpwardRef( void ) +{ + // Now it is possible that a package folder is disconnected from the package before removing of the folder. + // Such a scenario is used in storage implementation. When a new version of a folder is provided the old + // one is retrieved, removed from the package but preserved for the error handling. + // In this scenario the referencing to the parent is not really useful, since it requires disposing. + + // Actually there is no need in having a reference to the parent, it even make things more complicated and + // requires disposing mechanics. Using of a simple pointer seems to be easier solution and also a safe enough. + + clearParent(); + +#if 0 + for ( ContentHash::const_iterator aCI = maContents.begin(); + aCI!=maContents.end(); + aCI++) + { + ContentInfo &rInfo = * (*aCI).second; + if ( rInfo.bFolder )// && ! rInfo.pFolder->HasReleased () ) + rInfo.pFolder->releaseUpwardRef(); + else //if ( !rInfo.bFolder && !rInfo.pStream->HasReleased() ) + rInfo.pStream->clearParent(); + } + clearParent(); + + VOS_ENSURE ( m_refCount == 1, "Ref-count is not 1!" ); +#endif +} + +sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const Sequence< sal_Int8 >& aIdentifier ) + throw(RuntimeException) +{ + sal_Int64 nMe = 0; + if ( aIdentifier.getLength() == 16 && + 0 == rtl_compareMemory(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) + nMe = reinterpret_cast < sal_Int64 > ( this ); + return nMe; +} +void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) + throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaType"))) + { + // TODO/LATER: activate when zip ucp is ready + // if ( m_nFormat != PACKAGE_FORMAT ) + // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + aValue >>= sMediaType; + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Version"))) + aValue >>= m_sVersion; + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Size") ) ) + aValue >>= aEntry.nSize; + else + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} +Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + // TODO/LATER: activate when zip ucp is ready + // if ( m_nFormat != PACKAGE_FORMAT ) + // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return makeAny ( sMediaType ); + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Version" ) ) ) + return makeAny( m_sVersion ); + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Size" ) ) ) + return makeAny ( aEntry.nSize ); + else + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, sal_Bool bSetParent ) + throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + if ( pEntry->IsFolder() ) + maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageFolder *> ( pEntry ) ); + else + maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) ); + + if ( bSetParent ) + pEntry->setParent ( *this ); +} +OUString ZipPackageFolder::getImplementationName() + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageFolder" ) ); +} + +Sequence< OUString > ZipPackageFolder::getSupportedServiceNames() + throw (RuntimeException) +{ + Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageFolder" ) ); + return aNames; +} +sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName ) + throw (RuntimeException) +{ + return rServiceName == getSupportedServiceNames()[0]; +} diff --git a/package/source/zippackage/ZipPackageFolderEnumeration.cxx b/package/source/zippackage/ZipPackageFolderEnumeration.cxx new file mode 100644 index 000000000000..8f4a2204fbdc --- /dev/null +++ b/package/source/zippackage/ZipPackageFolderEnumeration.cxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageFolderEnumeration.cxx,v $ + * $Revision: 1.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageFolderEnumeration.hxx> +#include <ContentInfo.hxx> + +using namespace com::sun::star; +using rtl::OUString; + +ZipPackageFolderEnumeration::ZipPackageFolderEnumeration ( ContentHash &rInput) +: rContents (rInput) +, aIterator (rContents.begin()) +{ +} + +ZipPackageFolderEnumeration::~ZipPackageFolderEnumeration( void ) +{ +} + +sal_Bool SAL_CALL ZipPackageFolderEnumeration::hasMoreElements( ) + throw(uno::RuntimeException) +{ + return (aIterator != rContents.end() ); +} +uno::Any SAL_CALL ZipPackageFolderEnumeration::nextElement( ) + throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) +{ + uno::Any aAny; + if (aIterator == rContents.end() ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + aAny <<= (*aIterator).second->xTunnel; + aIterator++; + return aAny; +} + +OUString ZipPackageFolderEnumeration::getImplementationName() + throw (uno::RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageFolderEnumeration" ) ); +} + +uno::Sequence< OUString > ZipPackageFolderEnumeration::getSupportedServiceNames() + throw (uno::RuntimeException) +{ + uno::Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageFolderEnumeration" ) ); + return aNames; +} +sal_Bool SAL_CALL ZipPackageFolderEnumeration::supportsService( OUString const & rServiceName ) + throw (uno::RuntimeException) +{ + return rServiceName == getSupportedServiceNames()[0]; +} diff --git a/package/source/zippackage/ZipPackageFolderEnumeration.hxx b/package/source/zippackage/ZipPackageFolderEnumeration.hxx new file mode 100644 index 000000000000..df311a2e5d6d --- /dev/null +++ b/package/source/zippackage/ZipPackageFolderEnumeration.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageFolderEnumeration.hxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_FOLDER_ENUMERATION_HXX +#define _ZIP_PACKAGE_FOLDER_ENUMERATION_HXX + +#include <cppuhelper/implbase2.hxx> // helper for implementations +#include <com/sun/star/container/XEnumeration.hpp> +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif +#ifndef _HASH_MAPS_HXX +#include <HashMaps.hxx> +#endif + +class ZipPackageFolderEnumeration : public cppu::WeakImplHelper2 +< + com::sun::star::container::XEnumeration, + com::sun::star::lang::XServiceInfo +> +{ +protected: + ContentHash& rContents; + ContentHash::const_iterator aIterator; +public: + //ZipPackageFolderEnumeration (std::hash_map < rtl::OUString, com::sun::star::uno::Reference < com::sun::star::container::XNamed >, hashFunc, eqFunc > &rInput); + ZipPackageFolderEnumeration (ContentHash &rInput); + virtual ~ZipPackageFolderEnumeration( void ); + + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL nextElement( ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); + +}; +#endif diff --git a/package/source/zippackage/ZipPackageSink.cxx b/package/source/zippackage/ZipPackageSink.cxx new file mode 100644 index 000000000000..d1784ccebeff --- /dev/null +++ b/package/source/zippackage/ZipPackageSink.cxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageSink.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageSink.hxx> + +ZipPackageSink::ZipPackageSink(void) +: xStream ( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > (NULL)) +{ +} +ZipPackageSink::~ZipPackageSink(void) +{ +} +void SAL_CALL ZipPackageSink::setInputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw(::com::sun::star::uno::RuntimeException) +{ + xStream = aStream; +} +::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL ZipPackageSink::getInputStream( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return xStream; +} diff --git a/package/source/zippackage/ZipPackageSink.hxx b/package/source/zippackage/ZipPackageSink.hxx new file mode 100644 index 000000000000..8895dc6b3ba7 --- /dev/null +++ b/package/source/zippackage/ZipPackageSink.hxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageSink.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_SINK_HXX +#define _ZIP_PACKAGE_SINK_HXX + +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <cppuhelper/implbase1.hxx> + +class ZipPackageSink : public ::cppu::WeakImplHelper1 +< + com::sun::star::io::XActiveDataSink +> +{ +protected: + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream; +public: + ZipPackageSink(); + virtual ~ZipPackageSink(); + virtual void SAL_CALL setInputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) + throw(::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx new file mode 100644 index 000000000000..242e37bfb764 --- /dev/null +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -0,0 +1,799 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageStream.cxx,v $ + * $Revision: 1.51 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <com/sun/star/packages/zip/ZipIOException.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> + + +#include <ZipPackageStream.hxx> +#include <ZipPackage.hxx> +#include <ZipFile.hxx> +#include <EncryptedDataHeader.hxx> +#include <vos/diagnose.hxx> +#include "wrapstreamforshare.hxx" + +#include <comphelper/seekableinput.hxx> +#include <comphelper/storagehelper.hxx> + +#include <PackageConstants.hxx> + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star; +using namespace cppu; +using namespace rtl; + +Sequence < sal_Int8 > ZipPackageStream::aImplementationId = Sequence < sal_Int8 > (); + + +ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage, + const Reference< XMultiServiceFactory >& xFactory, + sal_Bool bAllowRemoveOnInsert ) +: m_xFactory( xFactory ) +, rZipPackage(rNewPackage) +, bToBeCompressed ( sal_True ) +, bToBeEncrypted ( sal_False ) +, bHaveOwnKey ( sal_False ) +, bIsEncrypted ( sal_False ) +, xEncryptionData ( ) +, m_nStreamMode( PACKAGE_STREAM_NOTSET ) +, m_nMagicalHackPos( 0 ) +, m_nMagicalHackSize( 0 ) +, m_bHasSeekable( sal_False ) +, m_bCompressedIsSetFromOutside( sal_False ) +, m_bFromManifest( sal_False ) +{ + OSL_ENSURE( m_xFactory.is(), "No factory is provided to ZipPackageStream!\n" ); + + this->mbAllowRemoveOnInsert = bAllowRemoveOnInsert; + + SetFolder ( sal_False ); + aEntry.nVersion = -1; + aEntry.nFlag = 0; + aEntry.nMethod = -1; + aEntry.nTime = -1; + aEntry.nCrc = -1; + aEntry.nCompressedSize = -1; + aEntry.nSize = -1; + aEntry.nOffset = -1; + aEntry.nPathLen = -1; + aEntry.nExtraLen = -1; + + if ( !aImplementationId.getLength() ) + { + aImplementationId = getImplementationId(); + } +} + +ZipPackageStream::~ZipPackageStream( void ) +{ +} + +void ZipPackageStream::setZipEntryOnLoading( const ZipEntry &rInEntry) +{ + aEntry.nVersion = rInEntry.nVersion; + aEntry.nFlag = rInEntry.nFlag; + aEntry.nMethod = rInEntry.nMethod; + aEntry.nTime = rInEntry.nTime; + aEntry.nCrc = rInEntry.nCrc; + aEntry.nCompressedSize = rInEntry.nCompressedSize; + aEntry.nSize = rInEntry.nSize; + aEntry.nOffset = rInEntry.nOffset; + aEntry.sPath = rInEntry.sPath; + aEntry.nPathLen = rInEntry.nPathLen; + aEntry.nExtraLen = rInEntry.nExtraLen; + + if ( aEntry.nMethod == STORED ) + bToBeCompressed = sal_False; +} + +//-------------------------------------------------------------------------- +void ZipPackageStream::CloseOwnStreamIfAny() +{ + if ( xStream.is() ) + { + xStream->closeInput(); + xStream = uno::Reference< io::XInputStream >(); + m_bHasSeekable = sal_False; + } +} + +//-------------------------------------------------------------------------- +uno::Reference< io::XInputStream >& ZipPackageStream::GetOwnSeekStream() +{ + if ( !m_bHasSeekable && xStream.is() ) + { + // The package component requires that every stream either be FROM a package or it must support XSeekable! + // The only exception is a nonseekable stream that is provided only for storing, if such a stream + // is accessed before commit it MUST be wrapped. + // Wrap the stream in case it is not seekable + xStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( xStream, m_xFactory ); + Reference< io::XSeekable > xSeek( xStream, UNO_QUERY ); + if ( !xSeek.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "The stream must support XSeekable!" ) ), + Reference< XInterface >() ); + + m_bHasSeekable = sal_True; + } + + return xStream; +} + +//-------------------------------------------------------------------------- +uno::Reference< io::XInputStream > ZipPackageStream::GetRawEncrStreamNoHeaderCopy() +{ + if ( m_nStreamMode != PACKAGE_STREAM_RAW || !GetOwnSeekStream().is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( xEncryptionData.isEmpty() ) + throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Encrypted stream without encryption data!\n" ) ), + Reference< XInterface >() ); + + uno::Reference< io::XSeekable > xSeek( GetOwnSeekStream(), UNO_QUERY ); + if ( !xSeek.is() ) + throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "The stream must be seekable!\n" ) ), + Reference< XInterface >() ); + + // skip header + xSeek->seek( n_ConstHeaderSize + xEncryptionData->aInitVector.getLength() + + xEncryptionData->aSalt.getLength() + xEncryptionData->aDigest.getLength() ); + + // create temporary stream + uno::Reference < io::XOutputStream > xTempOut( + m_xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY ); + uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY ); + if ( !xTempOut.is() || !xTempIn.is() || !xTempSeek.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // copy the raw stream to the temporary file starting from the current position + ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempOut ); + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + return xTempIn; +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > ZipPackageStream::TryToGetRawFromDataStream( sal_Bool bAddHeaderForEncr ) +{ + if ( m_nStreamMode != PACKAGE_STREAM_DATA || !GetOwnSeekStream().is() || (bAddHeaderForEncr && !bToBeEncrypted) ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Sequence< sal_Int8 > aKey; + + if ( bToBeEncrypted ) + { + aKey = ( xEncryptionData.isEmpty() || !bHaveOwnKey ) ? rZipPackage.getEncryptionKey() : + xEncryptionData->aKey; + if ( !aKey.getLength() ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + try + { + // create temporary file + uno::Reference < io::XStream > xTempStream( + m_xFactory->createInstance ( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + if ( !xTempStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // create a package based on it + ZipPackage* pPackage = new ZipPackage( m_xFactory ); + Reference< XSingleServiceFactory > xPackageAsFactory( static_cast< XSingleServiceFactory* >( pPackage ) ); + if ( !xPackageAsFactory.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Sequence< Any > aArgs( 1 ); + aArgs[0] <<= xTempStream; + pPackage->initialize( aArgs ); + + // create a new package stream + Reference< XDataSinkEncrSupport > xNewPackStream( xPackageAsFactory->createInstance(), UNO_QUERY ); + if ( !xNewPackStream.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + xNewPackStream->setDataStream( static_cast< io::XInputStream* >( + new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ) ) ); + + Reference< XPropertySet > xNewPSProps( xNewPackStream, UNO_QUERY ); + if ( !xNewPSProps.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // copy all the properties of this stream to the new stream + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), makeAny( sMediaType ) ); + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ), makeAny( bToBeCompressed ) ); + if ( bToBeEncrypted ) + { + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionKey" ) ), makeAny( aKey ) ); + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Encrypted" ) ), makeAny( sal_True ) ); + } + + // insert a new stream in the package + Reference< XUnoTunnel > xTunnel; + Any aRoot = pPackage->getByHierarchicalName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) ); + aRoot >>= xTunnel; + Reference< container::XNameContainer > xRootNameContainer( xTunnel, UNO_QUERY ); + if ( !xRootNameContainer.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Reference< XUnoTunnel > xNPSTunnel( xNewPackStream, UNO_QUERY ); + xRootNameContainer->insertByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "dummy" ) ), makeAny( xNPSTunnel ) ); + + // commit the temporary package + pPackage->commitChanges(); + + // get raw stream from the temporary package + Reference< io::XInputStream > xInRaw; + if ( bAddHeaderForEncr ) + xInRaw = xNewPackStream->getRawStream(); + else + xInRaw = xNewPackStream->getPlainRawStream(); + + // create another temporary file + uno::Reference < io::XOutputStream > xTempOut( + m_xFactory->createInstance ( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY ); + uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY ); + if ( !xTempOut.is() || !xTempIn.is() || !xTempSeek.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // copy the raw stream to the temporary file + ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut ); + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + // close raw stream, package stream and folder + xInRaw = Reference< io::XInputStream >(); + xNewPSProps = Reference< XPropertySet >(); + xNPSTunnel = Reference< XUnoTunnel >(); + xNewPackStream = Reference< XDataSinkEncrSupport >(); + xTunnel = Reference< XUnoTunnel >(); + xRootNameContainer = Reference< container::XNameContainer >(); + + // return the stream representing the first temporary file + return xTempIn; + } + catch ( RuntimeException& ) + { + throw; + } + catch ( Exception& ) + { + } + + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//-------------------------------------------------------------------------- +sal_Bool ZipPackageStream::ParsePackageRawStream() +{ + OSL_ENSURE( GetOwnSeekStream().is(), "A stream must be provided!\n" ); + + if ( !GetOwnSeekStream().is() ) + return sal_False; + + sal_Bool bOk = sal_False; + + vos::ORef < EncryptionData > xTempEncrData; + sal_Int32 nMagHackSize = 0; + Sequence < sal_Int8 > aHeader ( 4 ); + + try + { + if ( GetOwnSeekStream()->readBytes ( aHeader, 4 ) == 4 ) + { + const sal_Int8 *pHeader = aHeader.getConstArray(); + sal_uInt32 nHeader = ( pHeader [0] & 0xFF ) | + ( pHeader [1] & 0xFF ) << 8 | + ( pHeader [2] & 0xFF ) << 16 | + ( pHeader [3] & 0xFF ) << 24; + if ( nHeader == n_ConstHeader ) + { + // this is one of our god-awful, but extremely devious hacks, everyone cheer + xTempEncrData = new EncryptionData; + + ::rtl::OUString aMediaType; + if ( ZipFile::StaticFillData ( xTempEncrData, nMagHackSize, aMediaType, GetOwnSeekStream() ) ) + { + // We'll want to skip the data we've just read, so calculate how much we just read + // and remember it + m_nMagicalHackPos = n_ConstHeaderSize + xTempEncrData->aSalt.getLength() + + xTempEncrData->aInitVector.getLength() + + xTempEncrData->aDigest.getLength() + + aMediaType.getLength() * sizeof( sal_Unicode ); + m_nMagicalHackSize = nMagHackSize; + sMediaType = aMediaType; + + bOk = sal_True; + } + } + } + } + catch( Exception& ) + { + } + + if ( !bOk ) + { + // the provided stream is not a raw stream + return sal_False; + } + + xEncryptionData = xTempEncrData; + SetIsEncrypted ( sal_True ); + // it's already compressed and encrypted + bToBeEncrypted = bToBeCompressed = sal_False; + + return sal_True; +} + +void ZipPackageStream::SetPackageMember( sal_Bool bNewValue ) +{ + if ( bNewValue ) + { + m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER; + m_nMagicalHackPos = 0; + m_nMagicalHackSize = 0; + } + else if ( m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER ) + m_nStreamMode = PACKAGE_STREAM_NOTSET; // must be reset +} + +// XActiveDataSink +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setInputStream( const Reference< io::XInputStream >& aStream ) + throw(RuntimeException) +{ + // if seekable access is required the wrapping will be done on demand + xStream = aStream; + m_bHasSeekable = sal_False; + SetPackageMember ( sal_False ); + aEntry.nTime = -1; + m_nStreamMode = PACKAGE_STREAM_DETECT; +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawData() + throw(RuntimeException) +{ + try + { + if (IsPackageMember()) + { + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + return rZipPackage.getZipFile().getRawData( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else + return Reference < io::XInputStream > (); + } + catch (ZipException &)//rException) + { + VOS_ENSURE( 0, "ZipException thrown");//rException.Message); + return Reference < io::XInputStream > (); + } + catch (Exception &) + { + VOS_ENSURE( 0, "Exception is thrown during stream wrapping!\n"); + return Reference < io::XInputStream > (); + } +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream( ) + throw(RuntimeException) +{ + try + { + if (IsPackageMember()) + { + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + return rZipPackage.getZipFile().getInputStream( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else + return Reference < io::XInputStream > (); + } + catch (ZipException &)//rException) + { + VOS_ENSURE( 0,"ZipException thrown");//rException.Message); + return Reference < io::XInputStream > (); + } + catch (Exception &) + { + VOS_ENSURE( 0, "Exception is thrown during stream wrapping!\n"); + return Reference < io::XInputStream > (); + } +} + +// XDataSinkEncrSupport +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getDataStream() + throw ( packages::WrongPasswordException, + io::IOException, + RuntimeException ) +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + + if (IsPackageMember()) + { + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + + return rZipPackage.getZipFile().getDataStream( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + return ZipFile::StaticGetDataFromRawStream( GetOwnSeekStream(), xEncryptionData ); + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else + return uno::Reference< io::XInputStream >(); +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawStream() + throw ( packages::NoEncryptionException, + io::IOException, + uno::RuntimeException ) +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if (IsPackageMember()) + { + if ( !bIsEncrypted || xEncryptionData.isEmpty() ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return rZipPackage.getZipFile().getWrappedRawStream( aEntry, xEncryptionData, sMediaType, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else if ( m_nStreamMode == PACKAGE_STREAM_DATA && bToBeEncrypted ) + return TryToGetRawFromDataStream( sal_True ); + } + + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + + +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setDataStream( const Reference< io::XInputStream >& aStream ) + throw ( io::IOException, + RuntimeException ) +{ + setInputStream( aStream ); + m_nStreamMode = PACKAGE_STREAM_DATA; +} + +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setRawStream( const Reference< io::XInputStream >& aStream ) + throw ( packages::EncryptionNotAllowedException, + packages::NoRawFormatException, + io::IOException, + RuntimeException) +{ + // wrap the stream in case it is not seekable + Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xFactory ); + Reference< io::XSeekable > xSeek( xNewStream, UNO_QUERY ); + if ( !xSeek.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "The stream must support XSeekable!" ) ), + Reference< XInterface >() ); + + xSeek->seek( 0 ); + Reference< io::XInputStream > xOldStream = xStream; + xStream = xNewStream; + if ( !ParsePackageRawStream() ) + { + xStream = xOldStream; + throw packages::NoRawFormatException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + // the raw stream MUST have seekable access + m_bHasSeekable = sal_True; + + SetPackageMember ( sal_False ); + aEntry.nTime = -1; + m_nStreamMode = PACKAGE_STREAM_RAW; +} + +//-------------------------------------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getPlainRawStream() + throw ( io::IOException, + uno::RuntimeException ) +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if (IsPackageMember()) + { + return rZipPackage.getZipFile().getRawData( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + { + // the header should not be returned here + return GetRawEncrStreamNoHeaderCopy(); + } + else if ( m_nStreamMode == PACKAGE_STREAM_DATA ) + return TryToGetRawFromDataStream( sal_False ); + } + + return Reference< io::XInputStream >(); +} + +// XUnoTunnel + +//-------------------------------------------------------------------------- +sal_Int64 SAL_CALL ZipPackageStream::getSomething( const Sequence< sal_Int8 >& aIdentifier ) + throw(RuntimeException) +{ + sal_Int64 nMe = 0; + if ( aIdentifier.getLength() == 16 && + 0 == rtl_compareMemory( static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) + nMe = reinterpret_cast < sal_Int64 > ( this ); + return nMe; +} + +// XPropertySet +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaType"))) + { + if ( rZipPackage.getFormat() != PACKAGE_FORMAT && rZipPackage.getFormat() != OFOPXML_FORMAT ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( aValue >>= sMediaType ) + { + if (sMediaType.getLength() > 0) + { + if ( sMediaType.indexOf (OUString( RTL_CONSTASCII_USTRINGPARAM ( "text" ) ) ) != -1 + || sMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM ( "application/vnd.sun.star.oleobject" ) ) ) ) + bToBeCompressed = sal_True; + else if ( !m_bCompressedIsSetFromOutside ) + bToBeCompressed = sal_False; + } + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "MediaType must be a string!\n" ) ), + Reference< XInterface >(), + 2 ); + + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Size") ) ) + { + if ( !( aValue >>= aEntry.nSize ) ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Size property!\n" ) ), + Reference< XInterface >(), + 2 ); + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Encrypted") ) ) + { + if ( rZipPackage.getFormat() != PACKAGE_FORMAT ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + sal_Bool bEnc = sal_False; + if ( aValue >>= bEnc ) + { + // In case of new raw stream, the stream must not be encrypted on storing + if ( bEnc && m_nStreamMode == PACKAGE_STREAM_RAW ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Raw stream can not be encrypted on storing" ) ), + Reference< XInterface >(), + 2 ); + + bToBeEncrypted = bEnc; + if ( bToBeEncrypted && xEncryptionData.isEmpty()) + xEncryptionData = new EncryptionData; + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Encrypted property!\n" ) ), + Reference< XInterface >(), + 2 ); + + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) ) + { + if ( rZipPackage.getFormat() != PACKAGE_FORMAT ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Sequence < sal_Int8 > aNewKey; + + if ( !( aValue >>= aNewKey ) ) + { + OUString sTempString; + if ( ( aValue >>= sTempString ) ) + { + sal_Int32 nPathLength = sTempString.getLength(); + Sequence < sal_Int8 > aSequence ( nPathLength ); + sal_Int8 *pArray = aSequence.getArray(); + const sal_Unicode *pChar = sTempString.getStr(); + for ( sal_Int16 i = 0; i < nPathLength; i++) + pArray[i] = static_cast < const sal_Int8 > (pChar[i]); + aNewKey = aSequence; + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for EncryptionKey property!\n" ) ), + Reference< XInterface >(), + 2 ); + } + + if ( aNewKey.getLength() ) + { + if ( xEncryptionData.isEmpty()) + xEncryptionData = new EncryptionData; + + xEncryptionData->aKey = aNewKey; + // In case of new raw stream, the stream must not be encrypted on storing + bHaveOwnKey = sal_True; + if ( m_nStreamMode != PACKAGE_STREAM_RAW ) + bToBeEncrypted = sal_True; + } + else + bHaveOwnKey = sal_False; + } + else if (aPropertyName.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "Compressed" ) ) ) + { + sal_Bool bCompr = sal_False; + + if ( aValue >>= bCompr ) + { + // In case of new raw stream, the stream must not be encrypted on storing + if ( bCompr && m_nStreamMode == PACKAGE_STREAM_RAW ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Raw stream can not be encrypted on storing" ) ), + Reference< XInterface >(), + 2 ); + + bToBeCompressed = bCompr; + m_bCompressedIsSetFromOutside = sal_True; + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Compressed property!\n" ) ), + Reference< XInterface >(), + 2 ); + } + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//-------------------------------------------------------------------------- +Any SAL_CALL ZipPackageStream::getPropertyValue( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + Any aAny; + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + aAny <<= sMediaType; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Size" ) ) ) + { + aAny <<= aEntry.nSize; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Encrypted" ) ) ) + { + aAny <<= ( m_nStreamMode == PACKAGE_STREAM_RAW ) ? sal_True : bToBeEncrypted; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "WasEncrypted" ) ) ) + { + aAny <<= bIsEncrypted; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Compressed" ) ) ) + { + aAny <<= bToBeCompressed; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionKey" ) ) ) + { + aAny <<= xEncryptionData.isEmpty () ? Sequence < sal_Int8 > () : xEncryptionData->aKey; + return aAny; + } + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//-------------------------------------------------------------------------- +void ZipPackageStream::setSize (const sal_Int32 nNewSize) +{ + if (aEntry.nCompressedSize != nNewSize ) + aEntry.nMethod = DEFLATED; + aEntry.nSize = nNewSize; +} +//-------------------------------------------------------------------------- +OUString ZipPackageStream::getImplementationName() + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageStream" ) ); +} + +//-------------------------------------------------------------------------- +Sequence< OUString > ZipPackageStream::getSupportedServiceNames() + throw (RuntimeException) +{ + Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageStream" ) ); + return aNames; +} +//-------------------------------------------------------------------------- +sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName ) + throw (RuntimeException) +{ + return rServiceName == getSupportedServiceNames()[0]; +} + diff --git a/package/source/zippackage/ZipPackageStream.hxx b/package/source/zippackage/ZipPackageStream.hxx new file mode 100644 index 000000000000..e5aa1d24fcca --- /dev/null +++ b/package/source/zippackage/ZipPackageStream.hxx @@ -0,0 +1,204 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ZipPackageStream.hxx,v $ + * $Revision: 1.23.20.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_STREAM_HXX +#define _ZIP_PACKAGE_STREAM_HXX + +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/packages/XDataSinkEncrSupport.hpp> +#include <ZipPackageEntry.hxx> +#ifndef _VOS_REF_H_ +#include <vos/ref.hxx> +#endif +#include <EncryptionData.hxx> +#ifndef _CPPUHELPER_IMPLBASE2_HXX +#include <cppuhelper/implbase2.hxx> +#endif +#include <mutexholder.hxx> + +#define PACKAGE_STREAM_NOTSET 0 +#define PACKAGE_STREAM_PACKAGEMEMBER 1 +#define PACKAGE_STREAM_DETECT 2 +#define PACKAGE_STREAM_DATA 3 +#define PACKAGE_STREAM_RAW 4 + +class ZipPackage; +struct ZipEntry; +class ZipPackageStream : public cppu::ImplInheritanceHelper2 +< + ZipPackageEntry, + ::com::sun::star::io::XActiveDataSink, + ::com::sun::star::packages::XDataSinkEncrSupport +> +{ + static com::sun::star::uno::Sequence < sal_Int8 > aImplementationId; +protected: + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream; + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > m_xFactory; + ZipPackage &rZipPackage; + sal_Bool bToBeCompressed, bToBeEncrypted, bHaveOwnKey, bIsEncrypted; + vos::ORef < EncryptionData > xEncryptionData; + + sal_uInt8 m_nStreamMode; + sal_uInt32 m_nMagicalHackPos; + sal_uInt32 m_nMagicalHackSize; + + sal_Bool m_bHasSeekable; + + sal_Bool m_bCompressedIsSetFromOutside; + + sal_Bool m_bFromManifest; + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& GetOwnSeekStream(); + +public: + sal_Bool HasOwnKey () const { return bHaveOwnKey;} + sal_Bool IsToBeCompressed () const { return bToBeCompressed;} + sal_Bool IsToBeEncrypted () const { return bToBeEncrypted;} + sal_Bool IsEncrypted () const { return bIsEncrypted;} + sal_Bool IsPackageMember () const { return m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER;} + + sal_Bool IsFromManifest() const { return m_bFromManifest; } + void SetFromManifest( sal_Bool bValue ) { m_bFromManifest = bValue; } + + vos::ORef < EncryptionData > & getEncryptionData () + { return xEncryptionData;} + const com::sun::star::uno::Sequence < sal_Int8 >& getKey () const + { return xEncryptionData->aKey;} + const com::sun::star::uno::Sequence < sal_uInt8 >& getInitialisationVector () const + { return xEncryptionData->aInitVector;} + const com::sun::star::uno::Sequence < sal_uInt8 >& getDigest () const + { return xEncryptionData->aDigest;} + const com::sun::star::uno::Sequence < sal_uInt8 >& getSalt () const + { return xEncryptionData->aSalt;} + sal_Int32 getIterationCount () const + { return xEncryptionData->nIterationCount;} + sal_Int32 getSize () const + { return aEntry.nSize;} + + sal_uInt8 GetStreamMode() const { return m_nStreamMode; } + sal_uInt32 GetMagicalHackPos() const { return m_nMagicalHackPos; } + sal_uInt32 GetMagicalHackSize() const { return m_nMagicalHackSize; } + + void SetToBeCompressed (sal_Bool bNewValue) { bToBeCompressed = bNewValue;} + void SetIsEncrypted (sal_Bool bNewValue) { bIsEncrypted = bNewValue;} + void SetToBeEncrypted (sal_Bool bNewValue) + { + bToBeEncrypted = bNewValue; + if ( bToBeEncrypted && xEncryptionData.isEmpty()) + xEncryptionData = new EncryptionData; + else if ( !bToBeEncrypted && !xEncryptionData.isEmpty() ) + xEncryptionData.unbind(); + } + void SetPackageMember (sal_Bool bNewValue); + void setKey (const com::sun::star::uno::Sequence < sal_Int8 >& rNewKey ) + { xEncryptionData->aKey = rNewKey;} + void setInitialisationVector (const com::sun::star::uno::Sequence < sal_uInt8 >& rNewVector ) + { xEncryptionData->aInitVector = rNewVector;} + void setSalt (const com::sun::star::uno::Sequence < sal_uInt8 >& rNewSalt ) + { xEncryptionData->aSalt = rNewSalt;} + void setDigest (const com::sun::star::uno::Sequence < sal_uInt8 >& rNewDigest ) + { xEncryptionData->aDigest = rNewDigest;} + void setIterationCount (const sal_Int32 nNewCount) + { xEncryptionData->nIterationCount = nNewCount;} + void setSize (const sal_Int32 nNewSize); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetOwnStreamNoWrap() { return xStream; } + + void CloseOwnStreamIfAny(); + + ZipPackageStream ( ZipPackage & rNewPackage, + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory >& xFactory, + sal_Bool bAllowRemoveOnInsert ); + virtual ~ZipPackageStream( void ); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetRawEncrStreamNoHeaderCopy(); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > TryToGetRawFromDataStream( + sal_Bool bAddHeaderForEncr ); + + sal_Bool ParsePackageRawStream(); + + void setZipEntryOnLoading( const ZipEntry &rInEntry); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawData() + throw(::com::sun::star::uno::RuntimeException); + + static ::com::sun::star::uno::Sequence < sal_Int8 >& static_getImplementationId() + { + return aImplementationId; + } + + // XActiveDataSink + virtual void SAL_CALL setInputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) + throw(::com::sun::star::uno::RuntimeException); + + // XDataSinkEncrSupport + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getDataStream() + throw ( ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawStream() + throw ( ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL setDataStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL setRawStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw ( ::com::sun::star::packages::EncryptionNotAllowedException, + ::com::sun::star::packages::NoRawFormatException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getPlainRawStream() + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw(::com::sun::star::uno::RuntimeException); + + // XPropertySet + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zippackage/makefile.mk b/package/source/zippackage/makefile.mk new file mode 100644 index 000000000000..64ddf157571f --- /dev/null +++ b/package/source/zippackage/makefile.mk @@ -0,0 +1,67 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.25 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=package +TARGET=zippackage +AUTOSEG=true + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(L10N_framework)"=="" + +# --- Files -------------------------------------------------------- +# the following flag un-inlines function calls and disables optimisations +#CFLAGS+=/Ob0 /Od + +SLOFILES= \ + $(SLO)$/ZipPackage.obj \ + $(SLO)$/ZipPackageBuffer.obj \ + $(SLO)$/ZipPackageEntry.obj \ + $(SLO)$/ZipPackageFolder.obj \ + $(SLO)$/ZipPackageFolderEnumeration.obj \ + $(SLO)$/ZipPackageSink.obj \ + $(SLO)$/ZipPackageStream.obj \ + $(SLO)$/wrapstreamforshare.obj \ + $(SLO)$/zipfileaccess.obj + +# $(SLO)$/InteractionRequest.obj \ +# $(SLO)$/InteractionContinuation.obj + +.ENDIF # L10N_framework + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/package/source/zippackage/wrapstreamforshare.cxx b/package/source/zippackage/wrapstreamforshare.cxx new file mode 100644 index 000000000000..71a778e19f57 --- /dev/null +++ b/package/source/zippackage/wrapstreamforshare.cxx @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: wrapstreamforshare.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <osl/diagnose.h> + +#include "wrapstreamforshare.hxx" + +using namespace ::com::sun::star; + + +WrapStreamForShare::WrapStreamForShare( const uno::Reference< io::XInputStream >& xInStream, + const SotMutexHolderRef& rMutexRef ) +: m_rMutexRef( rMutexRef ) +, m_xInStream( xInStream ) +, m_nCurPos( 0 ) +{ + m_xSeekable = uno::Reference< io::XSeekable >( m_xInStream, uno::UNO_QUERY ); + if ( !m_rMutexRef.Is() || !m_xInStream.is() || !m_xSeekable.is() ) + { + OSL_ENSURE( sal_False, "Wrong initialization of wrapping stream!\n" ); + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } +} + +WrapStreamForShare::~WrapStreamForShare() +{ +} + +// XInputStream +sal_Int32 SAL_CALL WrapStreamForShare::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_xSeekable->seek( m_nCurPos ); + + sal_Int32 nRead = m_xInStream->readBytes( aData, nBytesToRead ); + m_nCurPos += nRead; + + return nRead; +} + +sal_Int32 SAL_CALL WrapStreamForShare::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_xSeekable->seek( m_nCurPos ); + + sal_Int32 nRead = m_xInStream->readSomeBytes( aData, nMaxBytesToRead ); + m_nCurPos += nRead; + + return nRead; +} + +void SAL_CALL WrapStreamForShare::skipBytes( sal_Int32 nBytesToSkip ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_xSeekable->seek( m_nCurPos ); + + m_xInStream->skipBytes( nBytesToSkip ); + m_nCurPos = m_xSeekable->getPosition(); +} + +sal_Int32 SAL_CALL WrapStreamForShare::available() + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_xInStream->available(); +} + +void SAL_CALL WrapStreamForShare::closeInput() + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // the package is the owner so it will close the stream + // m_xInStream->closeInput(); + m_xInStream = uno::Reference< io::XInputStream >(); + m_xSeekable = uno::Reference< io::XSeekable >(); +} + +// XSeekable +void SAL_CALL WrapStreamForShare::seek( sal_Int64 location ) + throw ( lang::IllegalArgumentException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // let stream implementation do all the checking + m_xSeekable->seek( location ); + + m_nCurPos = m_xSeekable->getPosition(); +} + +sal_Int64 SAL_CALL WrapStreamForShare::getPosition() + throw ( io::IOException, + uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_nCurPos; +} + +sal_Int64 SAL_CALL WrapStreamForShare::getLength() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_xSeekable->getLength(); +} + diff --git a/package/source/zippackage/wrapstreamforshare.hxx b/package/source/zippackage/wrapstreamforshare.hxx new file mode 100644 index 000000000000..19cb78baba02 --- /dev/null +++ b/package/source/zippackage/wrapstreamforshare.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: wrapstreamforshare.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WRAPSTREAMFORSHARE_HXX_ +#define _WRAPSTREAMFORSHARE_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <cppuhelper/implbase2.hxx> + +#include <mutexholder.hxx> + +class WrapStreamForShare : public cppu::WeakImplHelper2 < ::com::sun::star::io::XInputStream + , ::com::sun::star::io::XSeekable > +{ +protected: + SotMutexHolderRef m_rMutexRef; + ::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > m_xInStream; + ::com::sun::star::uno::Reference < ::com::sun::star::io::XSeekable > m_xSeekable; + + sal_Int64 m_nCurPos; + +public: + WrapStreamForShare( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream, + const SotMutexHolderRef& rMutexRef ); + virtual ~WrapStreamForShare(); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + + //XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/package/source/zippackage/zipfileaccess.cxx b/package/source/zippackage/zipfileaccess.cxx new file mode 100644 index 000000000000..42f95d3a268f --- /dev/null +++ b/package/source/zippackage/zipfileaccess.cxx @@ -0,0 +1,495 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: zipfileaccess.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#ifndef _COM_SUN_STAR_LANG_INVALIDARGUMENTEXCEPTION_HPP_ +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#endif +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> + +#include <zipfileaccess.hxx> +#include <ZipEnumeration.hxx> +#include <ZipPackageSink.hxx> +#include <EncryptionData.hxx> + +#include <ucbhelper/content.hxx> + +#include <memory> + + +using namespace ::com::sun::star; + +// ---------------------------------------------------------------- +OZipFileAccess::OZipFileAccess( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_aMutexHolder( new SotMutexHolder ) +, m_xFactory( xFactory ) +, m_pZipFile( NULL ) +, m_pListenersContainer( NULL ) +, m_bDisposed( sal_False ) +{ + if ( !xFactory.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +// ---------------------------------------------------------------- +OZipFileAccess::~OZipFileAccess() +{ + { + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + if ( !m_bDisposed ) + { + try { + m_refCount++; // dispose will use refcounting so the further distruction must be avoided + dispose(); + } catch( uno::Exception& ) + {} + } + } +} + +// ---------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > OZipFileAccess::GetPatternsFromString_Impl( const ::rtl::OUString& aString ) +{ + if ( !aString.getLength() ) + return uno::Sequence< ::rtl::OUString >(); + + uno::Sequence< ::rtl::OUString > aPattern( 1 ); + sal_Int32 nInd = 0; + + const sal_Unicode* pString = aString.getStr(); + while( *pString ) + { + if ( *pString == (sal_Unicode)'\\' ) + { + pString++; + + if ( *pString == (sal_Unicode)'\\' ) + { + aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'\\' ); + pString++; + } + else if ( *pString == (sal_Unicode)'*' ) + { + aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'*' ); + pString++; + } + else + { + OSL_ENSURE( sal_False, "The backslash is not guarded!\n" ); + aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'\\' ); + } + } + else if ( *pString == (sal_Unicode)'*' ) + { + aPattern.realloc( ( ++nInd ) + 1 ); + pString++; + } + else + { + aPattern[nInd] += ::rtl::OUString::valueOf( *pString ); + pString++; + } + } + + return aPattern; +} + +// ---------------------------------------------------------------- +sal_Bool OZipFileAccess::StringGoodForPattern_Impl( const ::rtl::OUString& aString, + const uno::Sequence< ::rtl::OUString >& aPattern ) +{ + sal_Int32 nInd = aPattern.getLength() - 1; + if ( nInd < 0 ) + return sal_False; + + if ( nInd == 0 ) + { + if ( !aPattern[0].getLength() ) + return sal_True; + + return aString.equals( aPattern[0] ); + } + + sal_Int32 nBeginInd = aPattern[0].getLength(); + sal_Int32 nEndInd = aString.getLength() - aPattern[nInd].getLength(); + if ( nEndInd >= nBeginInd + && ( nEndInd == aString.getLength() || aString.copy( nEndInd ).equals( aPattern[nInd] ) ) + && ( nBeginInd == 0 || aString.copy( 0, nBeginInd ).equals( aPattern[0] ) ) ) + { + for ( sal_Int32 nCurInd = aPattern.getLength() - 2; nCurInd > 0; nCurInd-- ) + { + if ( !aPattern[nCurInd].getLength() ) + continue; + + if ( nEndInd == nBeginInd ) + return sal_False; + + // check that search does not use nEndInd position + sal_Int32 nLastInd = aString.lastIndexOf( aPattern[nCurInd], nEndInd - 1 ); + + if ( nLastInd == -1 ) + return sal_False; + + if ( nLastInd < nBeginInd ) + return sal_False; + + nEndInd = nLastInd; + } + + return sal_True; + } + + return sal_False; +} + +// XInitialization +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw ( uno::Exception, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_pZipFile ) + throw uno::Exception( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // initialization is allowed only one time + + if ( !aArguments.getLength() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + OSL_ENSURE( aArguments.getLength() == 1, "Too meny arguments are provided, only the first one will be used!\n" ); + + ::rtl::OUString aParamURL; + uno::Reference< io::XStream > xStream; + uno::Reference< io::XSeekable > xSeekable; + + if ( ( aArguments[0] >>= aParamURL ) ) + { + ::ucbhelper::Content aContent ( aParamURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + uno::Reference < io::XActiveDataSink > xSink = new ZipPackageSink; + if ( aContent.openStream ( xSink ) ) + { + m_xContentStream = xSink->getInputStream(); + xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY ); + } + } + else if ( (aArguments[0] >>= xStream ) ) + { + // a writable stream can implement both XStream & XInputStream + m_xContentStream = xStream->getInputStream(); + xSeekable = uno::Reference< io::XSeekable >( xStream, uno::UNO_QUERY ); + } + else if ( !( aArguments[0] >>= m_xContentStream ) ) + { + xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY ); + } + else + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !m_xContentStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !xSeekable.is() ) + { + // TODO: after fwkbugfix02 is integrated a helper class can be used to make the stream seekable + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + // TODO: in case xSeekable is implemented on separated XStream implementation a wrapper is required + m_pZipFile = new ZipFile( + m_xContentStream, + m_xFactory, + sal_True ); +} + +// XNameAccess +// ---------------------------------------------------------------- +uno::Any SAL_CALL OZipFileAccess::getByName( const ::rtl::OUString& aName ) + throw ( container::NoSuchElementException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName ); + if ( aIter == m_pZipFile->GetEntryHash().end() ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second, + new EncryptionData(), + sal_False, + m_aMutexHolder ) ); + + if ( !xEntryStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return uno::makeAny ( xEntryStream ); +} + +// ---------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getElementNames() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< ::rtl::OUString > aNames( m_pZipFile->GetEntryHash().size() ); + sal_Int32 nLen = 0; + + for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ ) + { + if ( aNames.getLength() < ++nLen ) + { + OSL_ENSURE( sal_False, "The size must be the same!\n" ); + aNames.realloc( nLen ); + } + + aNames[nLen-1] = (*aIter).second.sPath; + } + + if ( aNames.getLength() != nLen ) + { + OSL_ENSURE( sal_False, "The size must be the same!\n" ); + aNames.realloc( nLen ); + } + + return aNames; +} + +// ---------------------------------------------------------------- +sal_Bool SAL_CALL OZipFileAccess::hasByName( const ::rtl::OUString& aName ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName ); + + return ( aIter != m_pZipFile->GetEntryHash().end() ); +} + +// ---------------------------------------------------------------- +uno::Type SAL_CALL OZipFileAccess::getElementType() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ); +} + +// ---------------------------------------------------------------- +sal_Bool SAL_CALL OZipFileAccess::hasElements() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return ( m_pZipFile->GetEntryHash().size() != 0 ); +} + +// XZipFileAccess +// ---------------------------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL OZipFileAccess::getStreamByPattern( const ::rtl::OUString& aPatternString ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // Code to compare strings by patterns + uno::Sequence< ::rtl::OUString > aPattern = GetPatternsFromString_Impl( aPatternString ); + + for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ ) + { + if ( StringGoodForPattern_Impl( (*aIter).second.sPath, aPattern ) ) + { + uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second, + new EncryptionData(), + sal_False, + m_aMutexHolder ) ); + + if ( !xEntryStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + return xEntryStream; + } + } + + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +// XComponent +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::dispose() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_pListenersContainer ) + { + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + m_pListenersContainer->disposeAndClear( aSource ); + delete m_pListenersContainer; + m_pListenersContainer = NULL; + } + + if ( m_pZipFile ) + { + delete m_pZipFile; + m_pZipFile = NULL; + } + + if ( m_xContentStream.is() ) + try { + m_xContentStream->closeInput(); + } catch( uno::Exception& ) + {} + + m_bDisposed = sal_True; +} + +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pListenersContainer ) + m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutexHolder->GetMutex() ); + m_pListenersContainer->addInterface( xListener ); +} + +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_pListenersContainer ) + m_pListenersContainer->removeInterface( xListener ); +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::impl_staticGetSupportedServiceNames() +{ + uno::Sequence< ::rtl::OUString > aRet(2); + aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.packages.zip.ZipFileAccess"); + aRet[1] = ::rtl::OUString::createFromAscii("com.sun.star.comp.packages.zip.ZipFileAccess"); + return aRet; +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OZipFileAccess::impl_staticGetImplementationName() +{ + return ::rtl::OUString::createFromAscii("com.sun.star.comp.package.zip.ZipFileAccess"); +} + +//------------------------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OZipFileAccess::impl_staticCreateSelfInstance( + const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) +{ + return uno::Reference< uno::XInterface >( *new OZipFileAccess( xServiceManager ) ); +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OZipFileAccess::getImplementationName() + throw ( uno::RuntimeException ) +{ + return impl_staticGetImplementationName(); +} + +//------------------------------------------------------------------------- +sal_Bool SAL_CALL OZipFileAccess::supportsService( const ::rtl::OUString& ServiceName ) + throw ( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getSupportedServiceNames() + throw ( uno::RuntimeException ) +{ + return impl_staticGetSupportedServiceNames(); +} + diff --git a/package/util/exports.dxp b/package/util/exports.dxp new file mode 100644 index 000000000000..9630d7e06768 --- /dev/null +++ b/package/util/exports.dxp @@ -0,0 +1,3 @@ +component_getImplementationEnvironment +component_writeInfo +component_getFactory diff --git a/package/util/exports.map b/package/util/exports.map new file mode 100644 index 000000000000..7e12f34d1b86 --- /dev/null +++ b/package/util/exports.map @@ -0,0 +1,8 @@ +PKG_1_0 { + global: + component_getImplementationEnvironment; + component_writeInfo; + component_getFactory; + local: + *; +}; diff --git a/package/util/makefile.mk b/package/util/makefile.mk new file mode 100644 index 000000000000..99573c19ffb0 --- /dev/null +++ b/package/util/makefile.mk @@ -0,0 +1,81 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.13 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +# 2 == Unicode +MAJOR_VERSION=2 + +PRJ=.. +PRJNAME=package +TARGET=package + +ENABLE_EXCEPTIONS=TRUE +USE_DEFFILE=TRUE +NO_BSYMBOLIC=TRUE + + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(L10N_framework)"=="" + +# --- General ---------------------------------------------------- + +LIB1TARGET= $(SLB)$/$(TARGET).lib +LIB1FILES= \ + $(SLB)$/zipapi.lib \ + $(SLB)$/zippackage.lib \ + $(SLB)$/manifest.lib + +# --- Shared-Library ----------------------------------------------- + +SHL1TARGET=$(TARGET)$(MAJOR_VERSION) +SHL1IMPLIB=i$(TARGET) +SHL1VERSIONMAP=$(SOLARENV)$/src$/component.map + +SHL1STDLIBS=\ + $(CPPULIB) \ + $(UCBHELPERLIB) \ + $(CPPUHELPERLIB) \ + $(COMPHELPERLIB) \ + $(SALLIB) \ + $(ZLIB3RDLIB) + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +SHL1LIBS=$(LIB1TARGET) +DEF1NAME=$(SHL1TARGET) + +.ENDIF # L10N_framework + +# --- Targets ---------------------------------------------------------- + +.INCLUDE : target.mk + |