diff options
Diffstat (limited to 'oox')
-rw-r--r-- | oox/inc/oox/core/binarycodec.hxx | 50 | ||||
-rw-r--r-- | oox/inc/oox/core/filterbase.hxx | 7 | ||||
-rw-r--r-- | oox/inc/oox/dump/dumperbase.hxx | 4 | ||||
-rw-r--r--[-rwxr-xr-x] | oox/inc/oox/ole/vbamodule.hxx | 19 | ||||
-rw-r--r-- | oox/inc/oox/ole/vbaproject.hxx | 21 | ||||
-rw-r--r-- | oox/inc/oox/xls/biffcodec.hxx | 21 | ||||
-rwxr-xr-x | oox/inc/oox/xls/excelvbaproject.hxx | 68 | ||||
-rw-r--r-- | oox/prj/build.lst | 2 | ||||
-rw-r--r-- | oox/prj/d.lst | 1 | ||||
-rw-r--r-- | oox/source/core/binarycodec.cxx | 111 | ||||
-rw-r--r-- | oox/source/core/filterbase.cxx | 4 | ||||
-rw-r--r-- | oox/source/core/filterdetect.cxx | 109 | ||||
-rw-r--r-- | oox/source/drawingml/textcharacterproperties.cxx | 2 | ||||
-rw-r--r-- | oox/source/drawingml/textrun.cxx | 50 | ||||
-rw-r--r-- | oox/source/dump/biffdumper.cxx | 2 | ||||
-rw-r--r-- | oox/source/dump/dumperbase.cxx | 16 | ||||
-rw-r--r-- | oox/source/ole/vbamodule.cxx | 79 | ||||
-rw-r--r-- | oox/source/ole/vbaproject.cxx | 107 | ||||
-rw-r--r-- | oox/source/xls/biffcodec.cxx | 92 | ||||
-rwxr-xr-x | oox/source/xls/excelvbaproject.cxx | 161 | ||||
-rw-r--r-- | oox/source/xls/makefile.mk | 1 | ||||
-rw-r--r-- | oox/source/xls/workbookhelper.cxx | 4 | ||||
-rw-r--r-- | oox/source/xls/worksheethelper.cxx | 134 |
23 files changed, 867 insertions, 198 deletions
diff --git a/oox/inc/oox/core/binarycodec.hxx b/oox/inc/oox/core/binarycodec.hxx index 8abafffa2481..ce57e190f088 100644 --- a/oox/inc/oox/core/binarycodec.hxx +++ b/oox/inc/oox/core/binarycodec.hxx @@ -28,6 +28,9 @@ #ifndef OOX_CORE_BINARYCODEC_HXX #define OOX_CORE_BINARYCODEC_HXX +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/NamedValue.hpp> + #include <rtl/cipher.h> #include <rtl/digest.h> @@ -85,6 +88,22 @@ public: */ void initKey( const sal_uInt8 pnPassData[ 16 ] ); + /** Initializes the algorithm with the encryption data. + + @param aData + The sequence contains the necessary data to initialize + the codec. + */ + bool initCodec( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& aData ); + + /** Retrieves the encryption data + + @return + The sequence contains the necessary data to initialize + the codec. + */ + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > getEncryptionData(); + /** Verifies the validity of the password using the passed key and hash. @precond @@ -150,16 +169,6 @@ public: */ bool skip( sal_Int32 nBytes ); - // static ----------------------------------------------------------------- - - /** Calculates the 16-bit hash value for the given password. - - The password data may be longer than 16 bytes. The array does not need - to be terminated with a null byte (but it can without invalidating the - result). - */ - static sal_uInt16 getHash( const sal_uInt8* pnPassData, sal_Int32 nSize ); - private: CodecType meCodecType; /// Codec type. sal_uInt8 mpnKey[ 16 ]; /// Encryption key. @@ -189,6 +198,22 @@ public: ~BinaryCodec_RCF(); + /** Initializes the algorithm with the encryption data. + + @param aData + The sequence contains the necessary data to initialize + the codec. + */ + bool initCodec( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& aData ); + + /** Retrieves the encryption data + + @return + The sequence contains the necessary data to initialize + the codec. + */ + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > getEncryptionData(); + /** Initializes the algorithm with the specified password and document ID. @param pnPassData @@ -278,9 +303,14 @@ public: bool skip( sal_Int32 nBytes ); private: + void InitKeyImpl( + const sal_uInt8 pKeyData[64], + const sal_uInt8 pUnique[16] ); + rtlCipher mhCipher; rtlDigest mhDigest; sal_uInt8 mpnDigestValue[ RTL_DIGEST_LENGTH_MD5 ]; + sal_uInt8 mpnUnique[16]; }; // ============================================================================ diff --git a/oox/inc/oox/core/filterbase.hxx b/oox/inc/oox/core/filterbase.hxx index 1757b2be4334..9d9b8dcca515 100644 --- a/oox/inc/oox/core/filterbase.hxx +++ b/oox/inc/oox/core/filterbase.hxx @@ -31,6 +31,7 @@ #include <memory> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/document/XImporter.hpp> #include <com/sun/star/document/XExporter.hpp> #include <com/sun/star/document/XFilter.hpp> @@ -194,9 +195,9 @@ public: /** Returns a helper for the handling of OLE obejcts. */ ::oox::ole::OleObjectHelper& getOleObjectHelper() const; - /** Requests a password from the media descriptor or from the user. On - success, the password will be inserted into the media descriptor. */ - ::rtl::OUString requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) const; + /** Requests the encryption data from the media descriptor or from the user. On + success, the encryption data will be inserted into the media descriptor. */ + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) const; /** Imports the raw binary data from the specified stream. @return True, if the data could be imported from the stream. */ diff --git a/oox/inc/oox/dump/dumperbase.hxx b/oox/inc/oox/dump/dumperbase.hxx index ed1a3e1fc938..d9acaa1f1011 100644 --- a/oox/inc/oox/dump/dumperbase.hxx +++ b/oox/inc/oox/dump/dumperbase.hxx @@ -910,7 +910,7 @@ public: void eraseNameList( const ::rtl::OUString& rListName ); NameListRef getNameList( const ::rtl::OUString& rListName ) const; - ::rtl::OUString requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ); + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ); inline bool isPasswordCancelled() const { return mbPwCancelled; } protected: @@ -1011,7 +1011,7 @@ public: template< typename Type > bool hasName( const NameListWrapper& rListWrp, Type nKey ) const; - ::rtl::OUString requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ); + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ); bool isPasswordCancelled() const; protected: diff --git a/oox/inc/oox/ole/vbamodule.hxx b/oox/inc/oox/ole/vbamodule.hxx index 3b529ceee129..377c7abc335a 100755..100644 --- a/oox/inc/oox/ole/vbamodule.hxx +++ b/oox/inc/oox/ole/vbamodule.hxx @@ -68,11 +68,26 @@ public: /** Imports all records for this module until the MODULEEND record. */ void importDirRecords( BinaryInputStream& rDirStrm ); - /** Imports the Basic source code into the passed Basic library. */ - void importSourceCode( + + /** Imports the VBA source code into the passed Basic library. */ + void createAndImportModule( StorageBase& rVbaStrg, const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& rxBasicLib, const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& rxDocObjectNA ) const; + /** Creates an empty Basic module in the passed Basic library. */ + void createEmptyModule( + const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& rxBasicLib, + const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& rxDocObjectNA ) const; + +private: + /** Reads and returns the VBA source code from the passed storage. */ + ::rtl::OUString readSourceCode( StorageBase& rVbaStrg ) const; + + /** Creates a new Basic module and inserts it into the passed Basic library. */ + void createModule( + const ::rtl::OUString& rVBASourceCode, + const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& rxBasicLib, + const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& rxDocObjectNA ) const; private: ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > diff --git a/oox/inc/oox/ole/vbaproject.hxx b/oox/inc/oox/ole/vbaproject.hxx index 1d2fca29dbab..e8d9aa7c0f5d 100644 --- a/oox/inc/oox/ole/vbaproject.hxx +++ b/oox/inc/oox/ole/vbaproject.hxx @@ -97,6 +97,18 @@ public: /** Returns true, if the document contains the specified dialog. */ bool hasDialog( const ::rtl::OUString& rDialogName ) const; +protected: + /** Registers a dummy module that will be created when the VBA project is + imported. */ + void addDummyModule( const ::rtl::OUString& rName, sal_Int32 nType ); + /** Creates all dummy modules in the document. */ + void createDummyModules(); + + /** Called when the import process of the VBA project has been started. */ + virtual void prepareImport(); + /** Called when the import process of the VBA project is finished. */ + virtual void finalizeImport(); + private: VbaProject( const VbaProject& ); VbaProject& operator=( const VbaProject& ); @@ -113,12 +125,18 @@ private: /** Creates and returns the dialog library of the document used for import. */ ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > createDialogLibrary(); + /** Imports the VBA code modules and forms. */ - void importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ); + void importVba( + StorageBase& rVbaPrjStrg, + const GraphicHelper& rGraphicHelper, + bool bDefaultColorBgr ); /** Copies the entire VBA project storage to the passed document model. */ void copyStorage( StorageBase& rVbaPrjStrg ); private: + typedef ::std::map< ::rtl::OUString, sal_Int32 > DummyModuleMap; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxGlobalFactory; /// Global service factory. ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > @@ -127,6 +145,7 @@ private: mxBasicLib; /// The Basic library of the document used for import. ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > mxDialogLib; /// The dialog library of the document used for import. + DummyModuleMap maDummyModules; /// Additional empty modules created on import. const ::rtl::OUString maLibName; /// Name for Basic and dialog library used for import. }; diff --git a/oox/inc/oox/xls/biffcodec.hxx b/oox/inc/oox/xls/biffcodec.hxx index 21b3e82006fd..c1c040de095b 100644 --- a/oox/inc/oox/xls/biffcodec.hxx +++ b/oox/inc/oox/xls/biffcodec.hxx @@ -52,10 +52,9 @@ public: /** Derived classes return a clone of the decoder for usage in new streams. */ inline BiffDecoderBase* clone() { return implClone(); } - /** Implementation of the ::comphelper::IDocPasswordVerifier interface, - calls the new virtual function implVerify(). */ - virtual ::comphelper::DocPasswordVerifierResult - verifyPassword( const ::rtl::OUString& rPassword ); + /** Implementation of the ::comphelper::IDocPasswordVerifier interface. */ + virtual ::comphelper::DocPasswordVerifierResult verifyPassword( const ::rtl::OUString& rPassword, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ); + virtual ::comphelper::DocPasswordVerifierResult verifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ); /** Returns true, if the decoder has been initialized correctly. */ inline bool isValid() const { return mbValid; } @@ -73,7 +72,8 @@ private: /** Derived classes implement password verification and initialization of the decoder. */ - virtual bool implVerify( const ::rtl::OUString& rPassword ) = 0; + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > implVerifyPassword( const ::rtl::OUString& rPassword ) = 0; + virtual bool implVerifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ) = 0; /** Implementation of decryption of a memory block. */ virtual void implDecode( @@ -104,7 +104,9 @@ private: virtual BiffDecoder_XOR* implClone(); /** Implements password verification and initialization of the decoder. */ - virtual bool implVerify( const ::rtl::OUString& rPassword ); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > implVerifyPassword( const ::rtl::OUString& rPassword ); + virtual bool implVerifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ); + /** Implementation of decryption of a memory block. */ virtual void implDecode( @@ -115,7 +117,7 @@ private: private: ::oox::core::BinaryCodec_XOR maCodec; /// Cipher algorithm implementation. - ::std::vector< sal_uInt8 > maPassword; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > maEncryptionData; sal_uInt16 mnKey; sal_uInt16 mnHash; }; @@ -139,7 +141,8 @@ private: virtual BiffDecoder_RCF* implClone(); /** Implements password verification and initialization of the decoder. */ - virtual bool implVerify( const ::rtl::OUString& rPassword ); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > implVerifyPassword( const ::rtl::OUString& rPassword ); + virtual bool implVerifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ); /** Implementation of decryption of a memory block. */ virtual void implDecode( @@ -150,7 +153,7 @@ private: private: ::oox::core::BinaryCodec_RCF maCodec; /// Cipher algorithm implementation. - ::std::vector< sal_uInt16 > maPassword; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > maEncryptionData; ::std::vector< sal_uInt8 > maSalt; ::std::vector< sal_uInt8 > maVerifier; ::std::vector< sal_uInt8 > maVerifierHash; diff --git a/oox/inc/oox/xls/excelvbaproject.hxx b/oox/inc/oox/xls/excelvbaproject.hxx new file mode 100755 index 000000000000..121e6a1667cd --- /dev/null +++ b/oox/inc/oox/xls/excelvbaproject.hxx @@ -0,0 +1,68 @@ +/************************************************************************* + * + * 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 OOX_XLS_EXCELVBAPROJECT_HXX +#define OOX_XLS_EXCELVBAPROJECT_HXX + +#include "oox/ole/vbaproject.hxx" +#include "oox/dllapi.h" + +namespace com { namespace sun { namespace star { + namespace sheet { class XSpreadsheetDocument; } +} } } + +namespace oox { +namespace xls { + +// ============================================================================ + +/** Special implementation of the VBA project for the Excel filters. */ +class OOX_DLLPUBLIC ExcelVbaProject : public ::oox::ole::VbaProject +{ +public: + explicit ExcelVbaProject( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxGlobalFactory, + const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument >& rxDocument ); + + /** Generates VBA modules for sheets that do not specify a codename. */ + void createMissingModules(); + +protected: + /** Adds dummy modules for sheets without imported code name. */ + virtual void prepareImport(); + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheetDocument > + mxDocument; +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif diff --git a/oox/prj/build.lst b/oox/prj/build.lst index 345c72e00558..03735c73dd11 100644 --- a/oox/prj/build.lst +++ b/oox/prj/build.lst @@ -1,4 +1,4 @@ -oox oox : vos cppu cppuhelper comphelper sal offapi sax basegfx xmlscript tools vcl BOOST:boost OPENSSL:openssl NULL +oox oox : vos cppu cppuhelper comphelper sal offapi sax basegfx xmlscript tools vcl BOOST:boost OPENSSL:openssl LIBXSLT:libxslt NULL oox oox usr1 - all oox_mkout NULL oox oox\prj get - all oox_prj NULL oox oox\source\token nmake - all oox_token NULL diff --git a/oox/prj/d.lst b/oox/prj/d.lst index ff13b324d65c..f656056b119e 100644 --- a/oox/prj/d.lst +++ b/oox/prj/d.lst @@ -36,6 +36,7 @@ mkdir: %_DEST%\inc%_EXT%\oox\xls ..\inc\oox\ole\vbaproject.hxx %_DEST%\inc%_EXT%\oox\ole\vbaproject.hxx ..\inc\oox\vml\vmldrawing.hxx %_DEST%\inc%_EXT%\oox\vml\vmldrawing.hxx ..\inc\oox\vml\vmlshape.hxx %_DEST%\inc%_EXT%\oox\vml\vmlshape.hxx +..\inc\oox\xls\excelvbaproject.hxx %_DEST%\inc%_EXT%\oox\xls\excelvbaproject.hxx dos: sh -c "if test %OS% = MACOSX; then create-bundle %_DEST%\lib%_EXT%\*.dylib; fi" diff --git a/oox/source/core/binarycodec.cxx b/oox/source/core/binarycodec.cxx index 6127524c2aae..954f623f1f91 100644 --- a/oox/source/core/binarycodec.cxx +++ b/oox/source/core/binarycodec.cxx @@ -30,6 +30,11 @@ #include <string.h> #include "oox/helper/attributelist.hxx" +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/docpasswordhelper.hxx> + +using namespace ::com::sun::star; + namespace oox { namespace core { @@ -176,6 +181,37 @@ void BinaryCodec_XOR::initKey( const sal_uInt8 pnPassData[ 16 ] ) } } +bool BinaryCodec_XOR::initCodec( const uno::Sequence< beans::NamedValue >& aData ) +{ + bool bResult = sal_False; + + ::comphelper::SequenceAsHashMap aHashData( aData ); + uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95EncryptionKey" ) ), uno::Sequence< sal_Int8 >() ); + + if ( aKey.getLength() == 16 ) + { + (void)memcpy( mpnKey, aKey.getConstArray(), 16 ); + bResult = sal_True; + + mnBaseKey = (sal_uInt16)aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95BaseKey" ) ), (sal_Int16)0 ); + mnHash = (sal_uInt16)aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95PasswordHash" ) ), (sal_Int16)0 ); + } + else + OSL_ENSURE( sal_False, "Unexpected key size!\n" ); + + return bResult; +} + +uno::Sequence< beans::NamedValue > BinaryCodec_XOR::getEncryptionData() +{ + ::comphelper::SequenceAsHashMap aHashData; + aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95EncryptionKey" ) ) ] <<= uno::Sequence<sal_Int8>( (sal_Int8*)mpnKey, 16 ); + aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95BaseKey" ) ) ] <<= (sal_Int16)mnBaseKey; + aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XOR95PasswordHash" ) ) ] <<= (sal_Int16)mnHash; + + return aHashData.getAsConstNamedValueList(); +} + bool BinaryCodec_XOR::verifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const { return (nKey == mnBaseKey) && (nHash == mnHash); @@ -230,11 +266,6 @@ bool BinaryCodec_XOR::skip( sal_Int32 nBytes ) return true; } -sal_uInt16 BinaryCodec_XOR::getHash( const sal_uInt8* pnPassData, sal_Int32 nSize ) -{ - return lclGetHash( pnPassData, nSize ); -} - // ============================================================================ BinaryCodec_RCF::BinaryCodec_RCF() @@ -246,56 +277,62 @@ BinaryCodec_RCF::BinaryCodec_RCF() OSL_ENSURE( mhDigest != 0, "BinaryCodec_RCF::BinaryCodec_RCF - cannot create digest" ); (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) ); + (void)memset (mpnUnique, 0, sizeof(mpnUnique)); } BinaryCodec_RCF::~BinaryCodec_RCF() { (void)memset( mpnDigestValue, 0, sizeof( mpnDigestValue ) ); + (void)memset (mpnUnique, 0, sizeof(mpnUnique)); rtl_digest_destroy( mhDigest ); rtl_cipher_destroy( mhCipher ); } -void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData[ 16 ], const sal_uInt8 pnSalt[ 16 ] ) +bool BinaryCodec_RCF::initCodec( const uno::Sequence< beans::NamedValue >& aData ) { - // create little-endian key data array from password data - sal_uInt8 pnKeyData[ 64 ]; - (void)memset( pnKeyData, 0, sizeof( pnKeyData ) ); + bool bResult = sal_False; - const sal_uInt16* pnCurrPass = pnPassData; - const sal_uInt16* pnPassEnd = pnPassData + 16; - sal_uInt8* pnCurrKey = pnKeyData; - size_t nPassSize = 0; - for( ; (pnCurrPass < pnPassEnd) && (*pnCurrPass != 0); ++pnCurrPass, ++nPassSize ) + ::comphelper::SequenceAsHashMap aHashData( aData ); + uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97EncryptionKey" ) ), uno::Sequence< sal_Int8 >() ); + + if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 ) { - *pnCurrKey++ = static_cast< sal_uInt8 >( *pnCurrPass ); - *pnCurrKey++ = static_cast< sal_uInt8 >( *pnCurrPass >> 8 ); + (void)memcpy( mpnDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 ); + uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97UniqueID" ) ), uno::Sequence< sal_Int8 >() ); + if ( aUniqueID.getLength() == 16 ) + { + (void)memcpy( mpnUnique, aUniqueID.getConstArray(), 16 ); + bResult = sal_False; + } + else + OSL_ENSURE( sal_False, "Unexpected document ID!\n" ); } - pnKeyData[ 2 * nPassSize ] = 0x80; - pnKeyData[ 56 ] = static_cast< sal_uInt8 >( nPassSize << 4 ); + else + OSL_ENSURE( sal_False, "Unexpected key size!\n" ); - // fill raw digest of key data into key data - (void)rtl_digest_updateMD5( mhDigest, pnKeyData, sizeof( pnKeyData ) ); - (void)rtl_digest_rawMD5( mhDigest, pnKeyData, RTL_DIGEST_LENGTH_MD5 ); + return bResult; +} - // update digest with key data and passed salt data - for( size_t nIndex = 0; nIndex < 16; ++nIndex ) - { - rtl_digest_updateMD5( mhDigest, pnKeyData, 5 ); - rtl_digest_updateMD5( mhDigest, pnSalt, 16 ); - } +uno::Sequence< beans::NamedValue > BinaryCodec_RCF::getEncryptionData() +{ + ::comphelper::SequenceAsHashMap aHashData; + aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97EncryptionKey" ) ) ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)mpnDigestValue, RTL_DIGEST_LENGTH_MD5 ); + aHashData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "STD97UniqueID" ) ) ] <<= uno::Sequence< sal_Int8 >( (sal_Int8*)mpnUnique, 16 ); - // update digest with padding - pnKeyData[ 16 ] = 0x80; - (void)memset( pnKeyData + 17, 0, sizeof( pnKeyData ) - 17 ); - pnKeyData[ 56 ] = 0x80; - pnKeyData[ 57 ] = 0x0A; - rtl_digest_updateMD5( mhDigest, pnKeyData + 16, sizeof( pnKeyData ) - 16 ); + return aHashData.getAsConstNamedValueList(); +} - // fill raw digest of above updates into digest value - rtl_digest_rawMD5( mhDigest, mpnDigestValue, sizeof( mpnDigestValue ) ); +void BinaryCodec_RCF::initKey( const sal_uInt16 pnPassData[ 16 ], const sal_uInt8 pnSalt[ 16 ] ) +{ + uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pnPassData, uno::Sequence< sal_Int8 >( (sal_Int8*)pnSalt, 16 ) ); + // Fill raw digest of above updates into DigestValue. - // erase key data array and leave - (void)memset( pnKeyData, 0, sizeof( pnKeyData ) ); + if ( aKey.getLength() == sizeof(mpnDigestValue) ) + (void)memcpy ( mpnDigestValue, (const sal_uInt8*)aKey.getConstArray(), sizeof(mpnDigestValue) ); + else + memset( mpnDigestValue, 0, sizeof(mpnDigestValue) ); + + (void)memcpy( mpnUnique, pnSalt, 16 ); } bool BinaryCodec_RCF::verifyKey( const sal_uInt8 pnVerifier[ 16 ], const sal_uInt8 pnVerifierHash[ 16 ] ) diff --git a/oox/source/core/filterbase.cxx b/oox/source/core/filterbase.cxx index 9b7b00988dd0..6d2b98454444 100644 --- a/oox/source/core/filterbase.cxx +++ b/oox/source/core/filterbase.cxx @@ -67,6 +67,8 @@ using ::comphelper::MediaDescriptor; using ::comphelper::SequenceAsHashMap; using ::oox::ole::OleObjectHelper; +using namespace ::com::sun::star; + namespace oox { namespace core { @@ -399,7 +401,7 @@ OleObjectHelper& FilterBase::getOleObjectHelper() const return *mxImpl->mxOleObjHelper; } -OUString FilterBase::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) const +uno::Sequence< beans::NamedValue > FilterBase::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) const { ::std::vector< OUString > aDefaultPasswords; aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) ); diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx index 00244c224778..53d8809330d9 100644 --- a/oox/source/core/filterdetect.cxx +++ b/oox/source/core/filterdetect.cxx @@ -65,6 +65,8 @@ using ::com::sun::star::xml::sax::XLocator; using ::comphelper::MediaDescriptor; using ::comphelper::SequenceAsHashMap; +using namespace ::com::sun::star; + namespace oox { namespace core { @@ -366,7 +368,49 @@ void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKe // ---------------------------------------------------------------------------- -bool lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen ) +bool lclCheckEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize ) +{ + bool bResult = false; + + // the only currently supported algorithm needs key size 128 + if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 ) + { + // check password + EVP_CIPHER_CTX aes_ctx; + EVP_CIPHER_CTX_init( &aes_ctx ); + EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); + EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 ); + int nOutLen = 0; + sal_uInt8 pnTmpVerifier[ 16 ]; + (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) ); + + /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize ); + EVP_CIPHER_CTX_cleanup( &aes_ctx ); + + EVP_CIPHER_CTX_init( &aes_ctx ); + EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); + EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 ); + sal_uInt8 pnTmpVerifierHash[ 32 ]; + (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) ); + + /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize ); + EVP_CIPHER_CTX_cleanup( &aes_ctx ); + + rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); + rtlDigestError aError = rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) ); + sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ]; + aError = rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 ); + rtl_digest_destroy( aDigest ); + + bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 ); + } + + return bResult; +} + +// ---------------------------------------------------------------------------- + +uno::Sequence< beans::NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen ) { size_t nBufferSize = rEncrInfo.mnSaltSize + 2 * rPassword.getLength(); sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ]; @@ -405,30 +449,19 @@ bool lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUS lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, pnKey, nRequiredKeyLen ); delete[] pnHash; - // check password - EVP_CIPHER_CTX aes_ctx; - EVP_CIPHER_CTX_init( &aes_ctx ); - EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); - EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 ); - int nOutLen = 0; - sal_uInt8 pnVerifier[ 16 ] = { 0 }; - /*int*/ EVP_DecryptUpdate( &aes_ctx, pnVerifier, &nOutLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ) ); - EVP_CIPHER_CTX_cleanup( &aes_ctx ); - - EVP_CIPHER_CTX_init( &aes_ctx ); - EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); - EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 ); - sal_uInt8 pnVerifierHash[ 32 ] = { 0 }; - /*int*/ EVP_DecryptUpdate( &aes_ctx, pnVerifierHash, &nOutLen, rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ); - EVP_CIPHER_CTX_cleanup( &aes_ctx ); + uno::Sequence< beans::NamedValue > aResult; + if ( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) ) + { + ::comphelper::SequenceAsHashMap aEncryptionData; + aEncryptionData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionKey" ) ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen ); + aEncryptionData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionSalt" ) ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize ); + aEncryptionData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionVerifier" ) ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) ); + aEncryptionData[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionVerifierHash" ) ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) ); - aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); - aError = rtl_digest_update( aDigest, pnVerifier, sizeof( pnVerifier ) ); - sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ]; - aError = rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 ); - rtl_digest_destroy( aDigest ); + aResult = aEncryptionData.getAsConstNamedValueList(); + } - return memcmp( pnSha1Hash, pnVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0; + return aResult; } // the password verifier ------------------------------------------------------ @@ -438,8 +471,8 @@ class PasswordVerifier : public ::comphelper::IDocPasswordVerifier public: explicit PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ); - virtual ::comphelper::DocPasswordVerifierResult - verifyPassword( const OUString& rPassword ); + virtual ::comphelper::DocPasswordVerifierResult verifyPassword( const ::rtl::OUString& rPassword, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ); + virtual ::comphelper::DocPasswordVerifierResult verifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ); inline const sal_uInt8* getKey() const { return &maKey.front(); } @@ -454,13 +487,31 @@ PasswordVerifier::PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ) { } -::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword ) +::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const ::rtl::OUString& rPassword, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ) { // verifies the password and writes the related decryption key into maKey - return lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() ) ? + o_rEncryptionData = lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() ); + return ( o_rEncryptionData.getLength() > 0 ) ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; } +::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rEncryptionData ) +{ + ::comphelper::SequenceAsHashMap aHashData( rEncryptionData ); + uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionKey" ) ), uno::Sequence< sal_Int8 >() ); + uno::Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionVerifier" ) ), uno::Sequence< sal_Int8 >() ); + uno::Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AES128EncryptionVerifierHash" ) ), uno::Sequence< sal_Int8 >() ); + + return lclCheckEncryptionData( + reinterpret_cast< const sal_uInt8* >( aKey.getConstArray() ), + aKey.getLength(), + reinterpret_cast< const sal_uInt8* >( aVerifier.getConstArray() ), + aVerifier.getLength(), + reinterpret_cast< const sal_uInt8* >( aVerifierHash.getConstArray() ), + aVerifierHash.getLength() ) + ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; +} + } // namespace // ---------------------------------------------------------------------------- @@ -520,10 +571,10 @@ Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescript (according to the verifier), or with an empty string if user has cancelled the password input dialog. */ PasswordVerifier aVerifier( aEncryptInfo ); - OUString aPassword = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( + uno::Sequence< beans::NamedValue > aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( aVerifier, rMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords ); - if( aPassword.getLength() == 0 ) + if( aEncryptionData.getLength() == 0 ) { rMediaDesc[ MediaDescriptor::PROP_ABORTED() ] <<= true; } diff --git a/oox/source/drawingml/textcharacterproperties.cxx b/oox/source/drawingml/textcharacterproperties.cxx index 3ac5018c1dad..9750375f97dd 100644 --- a/oox/source/drawingml/textcharacterproperties.cxx +++ b/oox/source/drawingml/textcharacterproperties.cxx @@ -96,7 +96,7 @@ void TextCharacterProperties::pushToPropMap( PropertyMap& rPropMap, const XmlFil rPropMap[ PROP_CharFontFamilyComplex ] <<= nFontFamily; } - // symbol font not supported + // symbolfont, will now be ... textrun.cxx ... ausgewertet !!!i#113673 if( maCharColor.isUsed() ) rPropMap[ PROP_CharColor ] <<= maCharColor.getColor( rFilter.getGraphicHelper() ); diff --git a/oox/source/drawingml/textrun.cxx b/oox/source/drawingml/textrun.cxx index aa74d767a7ad..cb8304b76d04 100644 --- a/oox/source/drawingml/textrun.cxx +++ b/oox/source/drawingml/textrun.cxx @@ -78,7 +78,55 @@ void TextRun::insertAt( } else { - xText->insertString( xStart, getText(), sal_False ); + OUString aLatinFontName, aSymbolFontName; + sal_Int16 nLatinFontPitch = 0, nSymbolFontPitch = 0; + sal_Int16 nLatinFontFamily = 0, nSymbolFontFamily = 0; + + if ( !aTextCharacterProps.maSymbolFont.getFontData( aSymbolFontName, nSymbolFontPitch, nSymbolFontFamily, rFilterBase ) ) + xText->insertString( xStart, getText(), sal_False ); + else if ( getText().getLength() ) + { // !!#i113673<<< + aTextCharacterProps.maLatinFont.getFontData( aLatinFontName, nLatinFontPitch, nLatinFontFamily, rFilterBase ); + + sal_Int32 nIndex = 0; + while ( sal_True ) + { + sal_Int32 nCount = 0; + sal_Bool bSymbol = ( getText()[ nIndex ] & 0xff00 ) == 0xf000; + if ( bSymbol ) + { + do + { + nCount++; + } + while( ( ( nCount + nIndex ) < getText().getLength() ) && ( ( getText()[ nCount + nIndex ] & 0xff00 ) == 0xf000 ) ); + aPropSet.setAnyProperty( PROP_CharFontName, Any( aSymbolFontName ) ); + aPropSet.setAnyProperty( PROP_CharFontPitch, Any( nSymbolFontPitch ) ); + aPropSet.setAnyProperty( PROP_CharFontFamily, Any( nSymbolFontFamily ) ); + } + else + { + do + { + nCount++; + } + while( ( ( nCount + nIndex ) < getText().getLength() ) && ( ( getText()[ nCount + nIndex ] & 0xff00 ) != 0xf000 ) ); + aPropSet.setAnyProperty( PROP_CharFontName, Any( aLatinFontName ) ); + aPropSet.setAnyProperty( PROP_CharFontPitch, Any( nLatinFontPitch ) ); + aPropSet.setAnyProperty( PROP_CharFontFamily, Any( nLatinFontFamily ) ); + } + rtl::OUString aSubString( getText().copy( nIndex, nCount ) ); + xText->insertString( xStart, aSubString, sal_False ); + nIndex += nCount; + + if ( nIndex >= getText().getLength() ) + break; + + xStart = Reference< XTextRange >( xAt, UNO_QUERY ); + aPropSet = PropertySet( xStart ); + aTextCharacterProps.pushToPropSet( aPropSet, rFilterBase ); + } + } } } else diff --git a/oox/source/dump/biffdumper.cxx b/oox/source/dump/biffdumper.cxx index 30938f9ebbe6..b78c993a0968 100644 --- a/oox/source/dump/biffdumper.cxx +++ b/oox/source/dump/biffdumper.cxx @@ -2324,7 +2324,7 @@ void WorkbookStreamObject::implDumpRecordBody() rStrm.seekToStart(); BiffDecoderRef xDecoder = BiffCodecHelper::implReadFilePass( rStrm, eBiff ); if( xDecoder.get() ) - cfg().requestPassword( *xDecoder ); + cfg().requestEncryptionData( *xDecoder ); setBinaryOnlyMode( !xDecoder || !xDecoder->isValid() ); } break; diff --git a/oox/source/dump/dumperbase.cxx b/oox/source/dump/dumperbase.cxx index 807a5ec74715..53452765288a 100644 --- a/oox/source/dump/dumperbase.cxx +++ b/oox/source/dump/dumperbase.cxx @@ -65,6 +65,8 @@ using ::com::sun::star::io::XTextOutputStream; using ::comphelper::MediaDescriptor; using ::oox::core::FilterBase; +using namespace ::com::sun::star; + namespace oox { namespace dump { @@ -1581,18 +1583,18 @@ NameListRef SharedConfigData::getNameList( const OUString& rListName ) const return xList; } -OUString SharedConfigData::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) +uno::Sequence< beans::NamedValue > SharedConfigData::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) { - OUString aPassword; + uno::Sequence< beans::NamedValue > aEncryptionData; if( !mbPwCancelled ) { ::std::vector< OUString > aDefaultPasswords; aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) ); - aPassword = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( + aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( rVerifier, mrMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords ); - mbPwCancelled = aPassword.getLength() == 0; + mbPwCancelled = aEncryptionData.getLength() == 0; } - return aPassword; + return aEncryptionData; } bool SharedConfigData::implIsValid() const @@ -1764,9 +1766,9 @@ NameListRef Config::getNameList( const String& rListName ) const return implGetNameList( rListName ); } -OUString Config::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) +uno::Sequence< beans::NamedValue > Config::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) { - return mxCfgData->requestPassword( rVerifier ); + return mxCfgData->requestEncryptionData( rVerifier ); } bool Config::isPasswordCancelled() const diff --git a/oox/source/ole/vbamodule.cxx b/oox/source/ole/vbamodule.cxx index 9886f2cc5968..dbd5c9c02ced 100644 --- a/oox/source/ole/vbamodule.cxx +++ b/oox/source/ole/vbamodule.cxx @@ -128,18 +128,56 @@ void VbaModule::importDirRecords( BinaryInputStream& rDirStrm ) OSL_ENSURE( mnOffset < SAL_MAX_UINT32, "VbaModule::importDirRecords - missing module stream offset" ); } -void VbaModule::importSourceCode( StorageBase& rVbaStrg, - const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const +void VbaModule::createAndImportModule( StorageBase& rVbaStrg, const Reference< XNameContainer >& rxBasicLib, + const Reference< XNameAccess >& rxDocObjectNA ) const { - if( (maName.getLength() == 0) || (maStreamName.getLength() == 0) || (mnOffset == SAL_MAX_UINT32) ) - return; + OUString aVBASourceCode = readSourceCode( rVbaStrg ); + createModule( aVBASourceCode, rxBasicLib, rxDocObjectNA ); +} + +void VbaModule::createEmptyModule( const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const +{ + createModule( OUString(), rxBasicLib, rxDocObjectNA ); +} - BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true ); - OSL_ENSURE( !aInStrm.isEof(), "VbaModule::importSourceCode - cannot open module stream" ); - // skip the 'performance cache' stored before the actual source code - aInStrm.seek( mnOffset ); - // if stream is still valid, load the source code - if( aInStrm.isEof() ) +// private -------------------------------------------------------------------- + +OUString VbaModule::readSourceCode( StorageBase& rVbaStrg ) const +{ + OUStringBuffer aSourceCode; + if( (maStreamName.getLength() > 0) && (mnOffset != SAL_MAX_UINT32) ) + { + BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true ); + OSL_ENSURE( !aInStrm.isEof(), "VbaModule::readSourceCode - cannot open module stream" ); + // skip the 'performance cache' stored before the actual source code + aInStrm.seek( mnOffset ); + // if stream is still valid, load the source code + if( !aInStrm.isEof() ) + { + // decompression starts at current stream position of aInStrm + VbaInputStream aVbaStrm( aInStrm ); + // load the source code line-by-line, with some more processing + TextInputStream aVbaTextStrm( aVbaStrm, meTextEnc ); + while( !aVbaTextStrm.isEof() ) + { + OUString aCodeLine = aVbaTextStrm.readLine(); + if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) ) + { + // normal source code line + if( !mbExecutable ) + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) ); + aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) ); + } + } + } + } + return aSourceCode.makeStringAndClear(); +} + +void VbaModule::createModule( const OUString& rVBASourceCode, + const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const +{ + if( maName.getLength() == 0 ) return; // prepare the Basic module @@ -162,7 +200,7 @@ void VbaModule::importSourceCode( StorageBase& rVbaStrg, break; case ModuleType::DOCUMENT: aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBADocumentModule" ) ); - // get the VBA object associated to the document module + // get the VBA implementation object associated to the document module if( rxDocObjectNA.is() ) try { aModuleInfo.ModuleObject.set( rxDocObjectNA->getByName( maName ), UNO_QUERY ); @@ -188,21 +226,8 @@ void VbaModule::importSourceCode( StorageBase& rVbaStrg, append( maName.replace( ' ', '_' ) ).append( sal_Unicode( '\n' ) ); } - // decompression starts at current stream position of aInStrm - VbaInputStream aVbaStrm( aInStrm ); - // load the source code line-by-line, with some more processing - TextInputStream aVbaTextStrm( aVbaStrm, meTextEnc ); - while( !aVbaTextStrm.isEof() ) - { - OUString aCodeLine = aVbaTextStrm.readLine(); - // skip all 'Attribute' statements - if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) ) - { - if( !mbExecutable ) - aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) ); - aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) ); - } - } + // append passed VBA source code + aSourceCode.append( rVBASourceCode ); // close the subroutine named after the module if( !mbExecutable ) @@ -225,7 +250,7 @@ void VbaModule::importSourceCode( StorageBase& rVbaStrg, } catch( Exception& ) { - OSL_ENSURE( false, "VbaModule::importSourceCode - cannot insert module into library" ); + OSL_ENSURE( false, "VbaModule::createModule - cannot insert module into library" ); } } diff --git a/oox/source/ole/vbaproject.cxx b/oox/source/ole/vbaproject.cxx index deff066a5ed5..0f7e3cb8612a 100644 --- a/oox/source/ole/vbaproject.cxx +++ b/oox/source/ole/vbaproject.cxx @@ -173,6 +173,67 @@ bool VbaProject::hasDialog( const OUString& rDialogName ) const return mxDialogLib.is() && mxDialogLib->hasByName( rDialogName ); } +// protected ------------------------------------------------------------------ + +void VbaProject::addDummyModule( const OUString& rName, sal_Int32 nType ) +{ + OSL_ENSURE( rName.getLength() > 0, "VbaProject::addDummyModule - missing module name" ); + maDummyModules[ rName ] = nType; +} + +void VbaProject::createDummyModules() +{ + /* !! HACK !! This function is called from old XLS filter only, must be + removed when this filter uses the OOX VBA import instead of the old SVX + VBA import. + */ + + // create empty dummy modules + typedef RefMap< OUString, VbaModule > VbaModuleMap; + VbaModuleMap aDummyModules; + for( DummyModuleMap::iterator aIt = maDummyModules.begin(), aEnd = maDummyModules.end(); aIt != aEnd; ++aIt ) + { + OSL_ENSURE( !aDummyModules.has( aIt->first ), "VbaProject::createDummyModules - multiple modules with the same name" ); + VbaModuleMap::mapped_type& rxModule = aDummyModules[ aIt->first ]; + rxModule.reset( new VbaModule( mxDocModel, aIt->first, RTL_TEXTENCODING_MS_1252, isImportVbaExecutable() ) ); + rxModule->setType( aIt->second ); + } + + if( !aDummyModules.empty() ) try + { + // get the model factory and the basic library + Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW ); + Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW ); + + // try to get access to document objects related to code modules + Reference< XNameAccess > xDocObjectNA; + try + { + xDocObjectNA.set( xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAObjectModuleObjectProvider" ) ), UNO_QUERY ); + } + catch( Exception& ) + { + // not all documents support this + } + + // create empty dummy modules + if( xBasicLib.is() ) + aDummyModules.forEachMem( &VbaModule::createEmptyModule, + ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) ); + } + catch( Exception& ) + { + } +} + +void VbaProject::prepareImport() +{ +} + +void VbaProject::finalizeImport() +{ +} + // private -------------------------------------------------------------------- Reference< XLibraryContainer > VbaProject::getLibraryContainer( sal_Int32 nPropId ) @@ -231,6 +292,9 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap if( aDirStrm.isEof() ) return; + // virtual call, derived classes may do some preparations + prepareImport(); + // read all records of the directory rtl_TextEncoding eTextEnc = RTL_TEXTENCODING_MS_1252; sal_uInt16 nModuleCount = 0; @@ -345,17 +409,29 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap } } + // create empty dummy modules + VbaModuleMap aDummyModules; + for( DummyModuleMap::iterator aIt = maDummyModules.begin(), aEnd = maDummyModules.end(); aIt != aEnd; ++aIt ) + { + OSL_ENSURE( !aModules.has( aIt->first ) && !aDummyModules.has( aIt->first ), "VbaProject::importVba - multiple modules with the same name" ); + VbaModuleMap::mapped_type& rxModule = aDummyModules[ aIt->first ]; + rxModule.reset( new VbaModule( mxDocModel, aIt->first, eTextEnc, bExecutable ) ); + rxModule->setType( aIt->second ); + } + /* Now it is time to load the source code. All modules will be inserted into the Basic library of the document specified by the 'maLibName' member. Do not create the Basic library, if there are no modules specified. */ - if( !aModules.empty() ) try + if( !aModules.empty() || !aDummyModules.empty() ) try { // get the model factory and the basic library Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW ); Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW ); - // set library container to VBA compatibility mode + /* Set library container to VBA compatibility mode. This will create + the VBA Globals object and store it in the Basic manager of the + document. */ try { Reference< XVBACompatibility >( getLibraryContainer( PROP_BasicLibraries ), UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True ); @@ -364,15 +440,6 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap { } - // create the VBAGlobals object, the model will store it in the Basic manager - try - { - xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAGlobals" ) ); - } - catch( Exception& ) - { - } - // try to get access to document objects related to code modules Reference< XNameAccess > xDocObjectNA; try @@ -384,10 +451,17 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap // not all documents support this } - // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref if( xBasicLib.is() ) - aModules.forEachMem( &VbaModule::importSourceCode, - ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) ); + { + // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref + aModules.forEachMem( &VbaModule::createAndImportModule, + ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ), + ::boost::cref( xDocObjectNA ) ); + + // create empty dummy modules + aDummyModules.forEachMem( &VbaModule::createEmptyModule, + ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) ); + } } catch( Exception& ) { @@ -402,7 +476,7 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap for( ::std::vector< OUString >::iterator aIt = aElements.begin(), aEnd = aElements.end(); aIt != aEnd; ++aIt ) { // try to open the element as storage - if( !aIt->equals( CREATE_OUSTRING( "VBA" ) ) ) + if( !aIt->equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VBA" ) ) ) { StorageRef xSubStrg = rVbaPrjStrg.openSubStorage( *aIt, false ); if( xSubStrg.get() ) try @@ -425,6 +499,9 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap } } } + + // virtual call, derived classes may do some more processing + finalizeImport(); } void VbaProject::copyStorage( StorageBase& rVbaPrjStrg ) diff --git a/oox/source/xls/biffcodec.cxx b/oox/source/xls/biffcodec.cxx index 2021c21cb08c..0872dcc654df 100644 --- a/oox/source/xls/biffcodec.cxx +++ b/oox/source/xls/biffcodec.cxx @@ -36,6 +36,8 @@ using ::rtl::OUString; using ::rtl::OStringToOUString; using ::oox::core::FilterBase; +using namespace ::com::sun::star; + namespace oox { namespace xls { @@ -50,9 +52,16 @@ BiffDecoderBase::~BiffDecoderBase() { } -::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword ) +::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const ::rtl::OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) +{ + o_rEncryptionData = implVerifyPassword( rPassword ); + mbValid = ( o_rEncryptionData.getLength() > 0 ); + return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; +} + +::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) { - mbValid = implVerify( rPassword ); + mbValid = implVerifyEncryptionData( rEncryptionData ); return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; } @@ -71,7 +80,6 @@ void BiffDecoderBase::decode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, BiffDecoder_XOR::BiffDecoder_XOR( sal_uInt16 nKey, sal_uInt16 nHash ) : maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ), - maPassword( 16 ), mnKey( nKey ), mnHash( nHash ) { @@ -80,12 +88,12 @@ BiffDecoder_XOR::BiffDecoder_XOR( sal_uInt16 nKey, sal_uInt16 nHash ) : BiffDecoder_XOR::BiffDecoder_XOR( const BiffDecoder_XOR& rDecoder ) : BiffDecoderBase(), // must be called to prevent compiler warning maCodec( ::oox::core::BinaryCodec_XOR::CODEC_EXCEL ), - maPassword( rDecoder.maPassword ), + maEncryptionData( rDecoder.maEncryptionData ), mnKey( rDecoder.mnKey ), mnHash( rDecoder.mnHash ) { if( isValid() ) - maCodec.initKey( &maPassword.front() ); + maCodec.initCodec( maEncryptionData ); } BiffDecoder_XOR* BiffDecoder_XOR::implClone() @@ -93,24 +101,40 @@ BiffDecoder_XOR* BiffDecoder_XOR::implClone() return new BiffDecoder_XOR( *this ); } -bool BiffDecoder_XOR::implVerify( const OUString& rPassword ) +uno::Sequence< beans::NamedValue > BiffDecoder_XOR::implVerifyPassword( const ::rtl::OUString& rPassword ) { + maEncryptionData.realloc( 0 ); + /* Convert password to a byte string. TODO: this needs some finetuning according to the spec... */ OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() ); sal_Int32 nLen = aBytePassword.getLength(); if( (0 < nLen) && (nLen < 16) ) { - // copy byte string to sal_uInt8 array - maPassword.clear(); - maPassword.resize( 16, 0 ); - memcpy( &maPassword.front(), aBytePassword.getStr(), static_cast< size_t >( nLen ) ); + // init codec + maCodec.initKey( (sal_uInt8*)aBytePassword.getStr() ); + if ( maCodec.verifyKey( mnKey, mnHash ) ) + maEncryptionData = maCodec.getEncryptionData(); + } + + return maEncryptionData; +} + +bool BiffDecoder_XOR::implVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) +{ + maEncryptionData.realloc( 0 ); + + if( rEncryptionData.getLength() ) + { // init codec - maCodec.initKey( &maPassword.front() ); - return maCodec.verifyKey( mnKey, mnHash ); + maCodec.initCodec( rEncryptionData ); + + if ( maCodec.verifyKey( mnKey, mnHash ) ) + maEncryptionData = rEncryptionData; } - return false; + + return maEncryptionData.getLength(); } void BiffDecoder_XOR::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) @@ -141,7 +165,6 @@ sal_Int32 lclGetRcfOffset( sal_Int64 nStreamPos ) // ---------------------------------------------------------------------------- BiffDecoder_RCF::BiffDecoder_RCF( sal_uInt8 pnSalt[ 16 ], sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) : - maPassword( 16, 0 ), maSalt( pnSalt, pnSalt + 16 ), maVerifier( pnVerifier, pnVerifier + 16 ), maVerifierHash( pnVerifierHash, pnVerifierHash + 16 ) @@ -150,13 +173,13 @@ BiffDecoder_RCF::BiffDecoder_RCF( sal_uInt8 pnSalt[ 16 ], sal_uInt8 pnVerifier[ BiffDecoder_RCF::BiffDecoder_RCF( const BiffDecoder_RCF& rDecoder ) : BiffDecoderBase(), // must be called to prevent compiler warning - maPassword( rDecoder.maPassword ), + maEncryptionData( rDecoder.maEncryptionData ), maSalt( rDecoder.maSalt ), maVerifier( rDecoder.maVerifier ), maVerifierHash( rDecoder.maVerifierHash ) { if( isValid() ) - maCodec.initKey( &maPassword.front(), &maSalt.front() ); + maCodec.initCodec( maEncryptionData ); } BiffDecoder_RCF* BiffDecoder_RCF::implClone() @@ -164,27 +187,48 @@ BiffDecoder_RCF* BiffDecoder_RCF::implClone() return new BiffDecoder_RCF( *this ); } -bool BiffDecoder_RCF::implVerify( const OUString& rPassword ) +uno::Sequence< beans::NamedValue > BiffDecoder_RCF::implVerifyPassword( const ::rtl::OUString& rPassword ) { + maEncryptionData.realloc( 0 ); + sal_Int32 nLen = rPassword.getLength(); if( (0 < nLen) && (nLen < 16) ) { // copy string to sal_uInt16 array - maPassword.clear(); - maPassword.resize( 16, 0 ); + ::std::vector< sal_uInt16 > aPassVect( 16 ); const sal_Unicode* pcChar = rPassword.getStr(); const sal_Unicode* pcCharEnd = pcChar + nLen; - ::std::vector< sal_uInt16 >::iterator aIt = maPassword.begin(); + ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin(); for( ; pcChar < pcCharEnd; ++pcChar, ++aIt ) *aIt = static_cast< sal_uInt16 >( *pcChar ); // init codec - maCodec.initKey( &maPassword.front(), &maSalt.front() ); - return maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ); + maCodec.initKey( &aPassVect.front(), &maSalt.front() ); + if ( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) + maEncryptionData = maCodec.getEncryptionData(); + } + + return maEncryptionData; +} + +bool BiffDecoder_RCF::implVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) +{ + maEncryptionData.realloc( 0 ); + + if( rEncryptionData.getLength() ) + { + // init codec + maCodec.initCodec( rEncryptionData ); + + if ( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) + maEncryptionData = rEncryptionData; } - return false; + + return maEncryptionData.getLength(); } + + void BiffDecoder_RCF::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) { sal_uInt8* pnCurrDest = pnDestData; @@ -316,7 +360,7 @@ bool BiffCodecHelper::importFilePass( BiffInputStream& rStrm ) mxDecoder = implReadFilePass( rStrm, getBiff() ); // request and verify a password (decoder implements IDocPasswordVerifier) if( mxDecoder.get() ) - getBaseFilter().requestPassword( *mxDecoder ); + getBaseFilter().requestEncryptionData( *mxDecoder ); // correct password is indicated by isValid() function of decoder return mxDecoder.get() && mxDecoder->isValid(); } diff --git a/oox/source/xls/excelvbaproject.cxx b/oox/source/xls/excelvbaproject.cxx new file mode 100755 index 000000000000..ee22dc8398ba --- /dev/null +++ b/oox/source/xls/excelvbaproject.cxx @@ -0,0 +1,161 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include "oox/xls/excelvbaproject.hxx" + +#include <list> +#include <set> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <rtl/ustrbuf.hxx> +#include "oox/helper/helper.hxx" +#include "oox/helper/propertyset.hxx" +#include "properties.hxx" + +namespace oox { +namespace xls { + +// ============================================================================ + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::sheet; +using namespace ::com::sun::star::uno; + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + +// ============================================================================ + +ExcelVbaProject::ExcelVbaProject( const Reference< XMultiServiceFactory >& rxGlobalFactory, const Reference< XSpreadsheetDocument >& rxDocument ) : + ::oox::ole::VbaProject( rxGlobalFactory, Reference< XModel >( rxDocument, UNO_QUERY ), CREATE_OUSTRING( "Calc" ) ), + mxDocument( rxDocument ) +{ +} + +void ExcelVbaProject::createMissingModules() +{ + /* !! HACK !! This function is called from old XLS filter only, must be + removed when this filter uses the OOX VBA import instead of the old SVX + VBA import. + */ + + // collect and register all sheets without codenames + prepareImport(); + // manually create the registered dummy modules + createDummyModules(); +} + +// protected ------------------------------------------------------------------ + +namespace { + +struct SheetCodeNameInfo +{ + PropertySet maSheetProps; /// Property set of the sheet without codename. + OUString maPrefix; /// Prefix for the codename to be generated. + + inline explicit SheetCodeNameInfo( PropertySet& rSheetProps, const OUString& rPrefix ) : + maSheetProps( rSheetProps ), maPrefix( rPrefix ) {} +}; + +typedef ::std::set< OUString > CodeNameSet; +typedef ::std::list< SheetCodeNameInfo > SheetCodeNameInfoList; + +} // namespace + +void ExcelVbaProject::prepareImport() +{ + /* Check if the sheets have imported codenames. Generate new unused + codenames if not. */ + if( mxDocument.is() ) try + { + // collect existing codenames (do not use them when creating new codenames) + CodeNameSet aUsedCodeNames; + + // collect sheets without codenames + SheetCodeNameInfoList aCodeNameInfos; + + // iterate over all imported sheets + Reference< XEnumerationAccess > xSheetsEA( mxDocument->getSheets(), UNO_QUERY_THROW ); + Reference< XEnumeration > xSheetsEnum( xSheetsEA->createEnumeration(), UNO_SET_THROW ); + // own try/catch for every sheet + while( xSheetsEnum->hasMoreElements() ) try + { + PropertySet aSheetProp( xSheetsEnum->nextElement() ); + OUString aCodeName; + aSheetProp.getProperty( aCodeName, PROP_CodeName ); + if( aCodeName.getLength() > 0 ) + { + aUsedCodeNames.insert( aCodeName ); + } + else + { + // TODO: once we have chart sheets we need a switch/case on sheet type ('SheetNNN' vs. 'ChartNNN') + aCodeNameInfos.push_back( SheetCodeNameInfo( aSheetProp, CREATE_OUSTRING( "Sheet" ) ) ); + } + } + catch( Exception& ) + { + } + + // create new codenames if sheets do not have one + for( SheetCodeNameInfoList::iterator aIt = aCodeNameInfos.begin(), aEnd = aCodeNameInfos.end(); aIt != aEnd; ++aIt ) + { + // search for an unused codename + sal_Int32 nCounter = 1; + OUString aCodeName; + do + { + aCodeName = OUStringBuffer( aIt->maPrefix ).append( nCounter++ ).makeStringAndClear(); + } + while( aUsedCodeNames.count( aCodeName ) > 0 ); + aUsedCodeNames.insert( aCodeName ); + + // set codename at sheet + aIt->maSheetProps.setProperty( PROP_CodeName, aCodeName ); + + // tell base class to create a dummy module + addDummyModule( aCodeName, ModuleType::DOCUMENT ); + } + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace xls +} // namespace oox diff --git a/oox/source/xls/makefile.mk b/oox/source/xls/makefile.mk index cdb2e18c262d..b5ede953bbfe 100644 --- a/oox/source/xls/makefile.mk +++ b/oox/source/xls/makefile.mk @@ -59,6 +59,7 @@ SLOFILES = \ $(SLO)$/excelchartconverter.obj \ $(SLO)$/excelfilter.obj \ $(SLO)$/excelhandlers.obj \ + $(SLO)$/excelvbaproject.obj \ $(SLO)$/externallinkbuffer.obj \ $(SLO)$/externallinkfragment.obj \ $(SLO)$/formulabase.obj \ diff --git a/oox/source/xls/workbookhelper.cxx b/oox/source/xls/workbookhelper.cxx index 5684fbd8ae75..ceba5690004c 100644 --- a/oox/source/xls/workbookhelper.cxx +++ b/oox/source/xls/workbookhelper.cxx @@ -43,7 +43,6 @@ #include "properties.hxx" #include "oox/helper/progressbar.hxx" #include "oox/helper/propertyset.hxx" -#include "oox/ole/vbaproject.hxx" #include "oox/drawingml/theme.hxx" #include "oox/xls/addressconverter.hxx" #include "oox/xls/biffinputstream.hxx" @@ -51,6 +50,7 @@ #include "oox/xls/defnamesbuffer.hxx" #include "oox/xls/excelchartconverter.hxx" #include "oox/xls/excelfilter.hxx" +#include "oox/xls/excelvbaproject.hxx" #include "oox/xls/externallinkbuffer.hxx" #include "oox/xls/formulaparser.hxx" #include "oox/xls/pagesettings.hxx" @@ -691,7 +691,7 @@ void WorkbookHelper::finalizeWorkbookImport() StorageRef xVbaPrjStrg = mrBookData.getVbaProjectStorage(); if( xVbaPrjStrg.get() && xVbaPrjStrg->isStorage() ) { - ::oox::ole::VbaProject aVbaProject( getGlobalFactory(), getBaseFilter().getModel(), CREATE_OUSTRING( "Calc" ) ); + ExcelVbaProject aVbaProject( getGlobalFactory(), getDocument() ); aVbaProject.importVbaProject( *xVbaPrjStrg, getBaseFilter().getGraphicHelper() ); } } diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx index 99c2d844f4b5..d2d42f2be369 100644 --- a/oox/source/xls/worksheethelper.cxx +++ b/oox/source/xls/worksheethelper.cxx @@ -404,7 +404,7 @@ public: Size getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const; /** Returns the address of the cell that contains the passed point in 1/100 mm. */ - CellAddress getCellAddressFromPosition( const Point& rPosition, const CellAddress* pStartAddr = 0 ) const; + CellAddress getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const; /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */ CellRangeAddress getCellRangeFromRectangle( const Rectangle& rRect ) const; @@ -795,41 +795,117 @@ Size WorksheetData::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const return aSize; } -CellAddress WorksheetData::getCellAddressFromPosition( const Point& rPosition, const CellAddress* pStartAddr ) const +namespace { + +inline sal_Int32 lclGetMidAddr( sal_Int32 nBegAddr, sal_Int32 nEndAddr, sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos ) +{ + // use sal_Int64 to prevent integer overflow + return nBegAddr + 1 + static_cast< sal_Int32 >( static_cast< sal_Int64 >( nEndAddr - nBegAddr - 2 ) * (nSearchPos - nBegPos) / (nEndPos - nBegPos) ); +} + +bool lclPrepareInterval( sal_Int32 nBegAddr, sal_Int32& rnMidAddr, sal_Int32 nEndAddr, + sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos ) { - // prepare start address for search loop - sal_Int32 nCol = pStartAddr ? ::std::min< sal_Int32 >( pStartAddr->Column + 1, mrMaxApiPos.Column ) : 1; - sal_Int32 nRow = pStartAddr ? ::std::min< sal_Int32 >( pStartAddr->Row + 1, mrMaxApiPos.Row ) : 1; + // searched position before nBegPos -> use nBegAddr + if( nSearchPos <= nBegPos ) + { + rnMidAddr = nBegAddr; + return false; + } + + // searched position after nEndPos, or begin next to end -> use nEndAddr + if( (nSearchPos >= nEndPos) || (nBegAddr + 1 >= nEndAddr) ) + { + rnMidAddr = nEndAddr; + return false; + } + + /* Otherwise find mid address according to position. lclGetMidAddr() will + return an address between nBegAddr and nEndAddr. */ + rnMidAddr = lclGetMidAddr( nBegAddr, nEndAddr, nBegPos, nEndPos, nSearchPos ); + return true; +} + +bool lclUpdateInterval( sal_Int32& rnBegAddr, sal_Int32& rnMidAddr, sal_Int32& rnEndAddr, + sal_Int32& rnBegPos, sal_Int32 nMidPos, sal_Int32& rnEndPos, sal_Int32 nSearchPos ) +{ + // nSearchPos < nMidPos: use the interval [begin,mid] in the next iteration + if( nSearchPos < nMidPos ) + { + // if rnBegAddr is next to rnMidAddr, the latter is the column/row in question + if( rnBegAddr + 1 >= rnMidAddr ) + return false; + // otherwise, set interval end to mid + rnEndPos = nMidPos; + rnEndAddr = rnMidAddr; + rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos ); + return true; + } + + // nSearchPos > nMidPos: use the interval [mid,end] in the next iteration + if( nSearchPos > nMidPos ) + { + // if rnMidAddr is next to rnEndAddr, the latter is the column/row in question + if( rnMidAddr + 1 >= rnEndAddr ) + { + rnMidAddr = rnEndAddr; + return false; + } + // otherwise, set interval start to mid + rnBegPos = nMidPos; + rnBegAddr = rnMidAddr; + rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos ); + return true; + } + + // nSearchPos == nMidPos: rnMidAddr is the column/row in question, do not loop anymore + return false; +} + +} // namespace + +CellAddress WorksheetData::getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const +{ + // starting cell address and its position in drawing layer (top-left edge) + sal_Int32 nBegCol = 0; + sal_Int32 nBegRow = 0; + Point aBegPos( 0, 0 ); + + // end cell address and its position in drawing layer (bottom-right edge) + sal_Int32 nEndCol = mrMaxApiPos.Column + 1; + sal_Int32 nEndRow = mrMaxApiPos.Row + 1; + Point aEndPos( rDrawPageSize.Width, rDrawPageSize.Height ); + + // starting point for interval search + sal_Int32 nMidCol, nMidRow; + bool bLoopCols = lclPrepareInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aEndPos.X, rPosition.X ); + bool bLoopRows = lclPrepareInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aEndPos.Y, rPosition.Y ); + Point aMidPos = getCellPosition( nMidCol, nMidRow ); /* The loop will find the column/row index of the cell right of/below the cell containing the passed point, unless the point is located at the top or left border of the containing cell. */ - bool bNextCol = true; - bool bNextRow = true; - Point aCellPos; - do + while( bLoopCols || bLoopRows ) { - aCellPos = getCellPosition( nCol, nRow ); - if( bNextCol && ((bNextCol = (aCellPos.X < rPosition.X) && (nCol < mrMaxApiPos.Column)) == true) ) - ++nCol; - if( bNextRow && ((bNextRow = (aCellPos.Y < rPosition.Y) && (nRow < mrMaxApiPos.Row)) == true) ) - ++nRow; + bLoopCols = bLoopCols && lclUpdateInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aMidPos.X, aEndPos.X, rPosition.X ); + bLoopRows = bLoopRows && lclUpdateInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aMidPos.Y, aEndPos.Y, rPosition.Y ); + aMidPos = getCellPosition( nMidCol, nMidRow ); } - while( bNextCol || bNextRow ); /* The cell left of/above the current search position contains the passed point, unless the point is located on the top/left border of the cell, or the last column/row of the sheet has been reached. */ - if( aCellPos.X > rPosition.X ) --nCol; - if( aCellPos.Y > rPosition.Y ) --nRow; - return CellAddress( getSheetIndex(), nCol, nRow ); + if( aMidPos.X > rPosition.X ) --nMidCol; + if( aMidPos.Y > rPosition.Y ) --nMidRow; + return CellAddress( getSheetIndex(), nMidCol, nMidRow ); } CellRangeAddress WorksheetData::getCellRangeFromRectangle( const Rectangle& rRect ) const { - CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ) ); + Size aPageSize = getDrawPageSize(); + CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ), aPageSize ); Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height ); - CellAddress aEndAddr = getCellAddressFromPosition( aBotRight ); + CellAddress aEndAddr = getCellAddressFromPosition( aBotRight, aPageSize ); bool bMultiCols = aStartAddr.Column < aEndAddr.Column; bool bMultiRows = aStartAddr.Row < aEndAddr.Row; if( bMultiCols || bMultiRows ) @@ -945,17 +1021,25 @@ void WorksheetData::extendUsedArea( const CellRangeAddress& rRange ) void WorksheetData::extendShapeBoundingBox( const Rectangle& rShapeRect ) { + // scale EMUs to 1/100 mm + const UnitConverter& rUnitConv = getUnitConverter(); + Rectangle aShapeRectHmm( + rUnitConv.scaleToMm100( rShapeRect.X, UNIT_EMU ), + rUnitConv.scaleToMm100( rShapeRect.Y, UNIT_EMU ), + rUnitConv.scaleToMm100( rShapeRect.Width, UNIT_EMU ), + rUnitConv.scaleToMm100( rShapeRect.Height, UNIT_EMU ) ); + if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) ) { // width and height of maShapeBoundingBox are assumed to be zero on first cell - maShapeBoundingBox = rShapeRect; + maShapeBoundingBox = aShapeRectHmm; } else { - sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, rShapeRect.X + rShapeRect.Width ); - sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, rShapeRect.Y + rShapeRect.Height ); - maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, rShapeRect.X ); - maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, rShapeRect.Y ); + sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, aShapeRectHmm.X + aShapeRectHmm.Width ); + sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, aShapeRectHmm.Y + aShapeRectHmm.Height ); + maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, aShapeRectHmm.X ); + maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, aShapeRectHmm.Y ); maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X; maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y; } |