diff options
Diffstat (limited to 'package/source/zipapi')
-rw-r--r-- | package/source/zipapi/ByteChucker.cxx | 112 | ||||
-rw-r--r-- | package/source/zipapi/ByteGrabber.cxx | 191 | ||||
-rw-r--r-- | package/source/zipapi/CRC32.cxx | 96 | ||||
-rw-r--r-- | package/source/zipapi/Deflater.cxx | 212 | ||||
-rw-r--r-- | package/source/zipapi/EntryInputStream.cxx | 201 | ||||
-rw-r--r-- | package/source/zipapi/EntryInputStream.hxx | 86 | ||||
-rw-r--r-- | package/source/zipapi/Inflater.cxx | 162 | ||||
-rw-r--r-- | package/source/zipapi/MemoryByteGrabber.hxx | 177 | ||||
-rw-r--r-- | package/source/zipapi/XFileStream.cxx | 227 | ||||
-rw-r--r-- | package/source/zipapi/XFileStream.hxx | 96 | ||||
-rw-r--r-- | package/source/zipapi/XMemoryStream.cxx | 52 | ||||
-rw-r--r-- | package/source/zipapi/XMemoryStream.hxx | 42 | ||||
-rw-r--r-- | package/source/zipapi/XUnbufferedStream.cxx | 360 | ||||
-rw-r--r-- | package/source/zipapi/XUnbufferedStream.hxx | 108 | ||||
-rw-r--r-- | package/source/zipapi/ZipEnumeration.cxx | 53 | ||||
-rw-r--r-- | package/source/zipapi/ZipFile.cxx | 1057 | ||||
-rw-r--r-- | package/source/zipapi/ZipOutputStream.cxx | 429 | ||||
-rw-r--r-- | package/source/zipapi/makefile.mk | 59 |
18 files changed, 3720 insertions, 0 deletions
diff --git a/package/source/zipapi/ByteChucker.cxx b/package/source/zipapi/ByteChucker.cxx new file mode 100644 index 000000000000..3b93c4696148 --- /dev/null +++ b/package/source/zipapi/ByteChucker.cxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..40998c3de70d --- /dev/null +++ b/package/source/zipapi/ByteGrabber.cxx @@ -0,0 +1,191 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..2ee6b1feea1a --- /dev/null +++ b/package/source/zipapi/CRC32.cxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..ac12a8cb5831 --- /dev/null +++ b/package/source/zipapi/Deflater.cxx @@ -0,0 +1,212 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..671ef7381f9d --- /dev/null +++ b/package/source/zipapi/EntryInputStream.cxx @@ -0,0 +1,201 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..c04a5dc2d33b --- /dev/null +++ b/package/source/zipapi/EntryInputStream.hxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..e95809a35dad --- /dev/null +++ b/package/source/zipapi/Inflater.cxx @@ -0,0 +1,162 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..8a8d96556bae --- /dev/null +++ b/package/source/zipapi/MemoryByteGrabber.hxx @@ -0,0 +1,177 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..9e7156ee82b3 --- /dev/null +++ b/package/source/zipapi/XFileStream.cxx @@ -0,0 +1,227 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..0cf82c5f35cd --- /dev/null +++ b/package/source/zipapi/XFileStream.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..c5ffe9ac874c --- /dev/null +++ b/package/source/zipapi/XMemoryStream.cxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..89db08a6c4ed --- /dev/null +++ b/package/source/zipapi/XMemoryStream.hxx @@ -0,0 +1,42 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..a75af35914a1 --- /dev/null +++ b/package/source/zipapi/XUnbufferedStream.cxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..321ec10b8032 --- /dev/null +++ b/package/source/zipapi/XUnbufferedStream.hxx @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..367c29f6d4a7 --- /dev/null +++ b/package/source/zipapi/ZipEnumeration.cxx @@ -0,0 +1,53 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..f01b7ce06f4b --- /dev/null +++ b/package/source/zipapi/ZipFile.cxx @@ -0,0 +1,1057 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected name length" ) ), Reference < XInterface > () ); + + if ( nCommentLen < 0 ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected comment length" ) ), Reference < XInterface > () ); + + if ( aEntry.nExtraLen < 0 ) + throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "unexpected extra header info length") ), 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 >= 0 && aEntry.nExtraLen >= 0 + && ( 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; + } + + *nSize = nRealSize; + *nCRC = aCRC.getValue(); +} + diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx new file mode 100644 index 000000000000..16457ec12493 --- /dev/null +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -0,0 +1,429 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..a9548ace659b --- /dev/null +++ b/package/source/zipapi/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# 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 |