diff options
author | Daniel Rentz [dr] <daniel.rentz@oracle.com> | 2010-12-27 12:33:29 +0100 |
---|---|---|
committer | Daniel Rentz [dr] <daniel.rentz@oracle.com> | 2010-12-27 12:33:29 +0100 |
commit | 87eded87d9f064715da13cf09a19e0a91f180625 (patch) | |
tree | f0b5bff661dc9b1f95c4b15be49acc25f5edbe7a /oox | |
parent | 5cefe89a5870b07017db265a074908a6009efbf5 (diff) | |
parent | 220821e1f4c3cb86a891e5864b665cadcfaed0c6 (diff) |
dr77: rebase to DEV300m96
Diffstat (limited to 'oox')
-rw-r--r-- | oox/inc/oox/core/binarycodec.hxx | 50 | ||||
-rw-r--r-- | oox/inc/oox/core/filterbase.hxx | 8 | ||||
-rw-r--r-- | oox/inc/oox/dump/dumperbase.hxx | 4 | ||||
-rw-r--r-- | oox/inc/oox/xls/biffcodec.hxx | 21 | ||||
-rw-r--r-- | oox/prj/build.lst | 2 | ||||
-rw-r--r-- | oox/source/core/binarycodec.cxx | 111 | ||||
-rw-r--r-- | oox/source/core/filterbase.cxx | 2 | ||||
-rw-r--r-- | oox/source/core/filterdetect.cxx | 107 | ||||
-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 | 14 | ||||
-rw-r--r-- | oox/source/ole/vbaproject.cxx | 15 | ||||
-rw-r--r-- | oox/source/xls/biffcodec.cxx | 88 | ||||
-rw-r--r-- | oox/source/xls/worksheethelper.cxx | 134 |
15 files changed, 447 insertions, 163 deletions
diff --git a/oox/inc/oox/core/binarycodec.hxx b/oox/inc/oox/core/binarycodec.hxx index 1e9dba07c388..ced63250f3e1 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 c3b82af62f5d..80dc233491d4 100644 --- a/oox/inc/oox/core/filterbase.hxx +++ b/oox/inc/oox/core/filterbase.hxx @@ -29,6 +29,7 @@ #define OOX_CORE_FILTERBASE_HXX #include <memory> +#include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/document/XExporter.hpp> #include <com/sun/star/document/XFilter.hpp> #include <com/sun/star/document/XImporter.hpp> @@ -209,9 +210,10 @@ public: /** Returns the VBA project manager. */ ::oox::ole::VbaProject& getVbaProject() 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/xls/biffcodec.hxx b/oox/inc/oox/xls/biffcodec.hxx index 438eb7e359be..9b9157c7e494 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/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/source/core/binarycodec.cxx b/oox/source/core/binarycodec.cxx index b2c117a12d90..3f406ba1af08 100644 --- a/oox/source/core/binarycodec.cxx +++ b/oox/source/core/binarycodec.cxx @@ -31,6 +31,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 { @@ -177,6 +182,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); @@ -231,11 +267,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() @@ -247,56 +278,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 9eaf5fb29a14..b215150acb88 100644 --- a/oox/source/core/filterbase.cxx +++ b/oox/source/core/filterbase.cxx @@ -414,7 +414,7 @@ VbaProject& FilterBase::getVbaProject() const return *mxImpl->mxVbaProject; } -OUString FilterBase::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) const +Sequence< 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 4f8bd8ef2463..cdab111e9898 100644 --- a/oox/source/core/filterdetect.cxx +++ b/oox/source/core/filterdetect.cxx @@ -351,7 +351,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; +} + +// ---------------------------------------------------------------------------- + +Sequence< 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 ]; @@ -390,30 +432,18 @@ 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 ); - - 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 ); + Sequence< NamedValue > aResult; + if( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) ) + { + SequenceAsHashMap aEncryptionData; + aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionKey" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen ); + aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionSalt" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize ); + aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifier" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) ); + aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifierHash" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) ); + aResult = aEncryptionData.getAsConstNamedValueList(); + } - return memcmp( pnSha1Hash, pnVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0; + return aResult; } // the password verifier ------------------------------------------------------ @@ -424,7 +454,9 @@ public: explicit PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ); virtual ::comphelper::DocPasswordVerifierResult - verifyPassword( const OUString& rPassword ); + verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData ); + virtual ::comphelper::DocPasswordVerifierResult + verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ); inline const sal_uInt8* getKey() const { return &maKey.front(); } @@ -439,11 +471,26 @@ PasswordVerifier::PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ) { } -::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword ) +::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData ) { // verifies the password and writes the related decryption key into maKey - return lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() ) ? - ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; + o_rEncryptionData = lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() ); + return o_rEncryptionData.hasElements() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; +} + +::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) +{ + SequenceAsHashMap aHashData( rEncryptionData ); + Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionKey" ), Sequence< sal_Int8 >() ); + Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifier" ), Sequence< sal_Int8 >() ); + Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifierHash" ), Sequence< sal_Int8 >() ); + + bool bResult = 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() ); + + return bResult ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; } } // namespace @@ -506,10 +553,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( + Sequence< 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 c55751ba25f6..61333535c38f 100644 --- a/oox/source/drawingml/textcharacterproperties.cxx +++ b/oox/source/drawingml/textcharacterproperties.cxx @@ -95,7 +95,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 944e17691c56..1e435defaa2d 100644 --- a/oox/source/drawingml/textrun.cxx +++ b/oox/source/drawingml/textrun.cxx @@ -77,7 +77,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 2f362af6ad2d..4e9156b5cc03 100644 --- a/oox/source/dump/biffdumper.cxx +++ b/oox/source/dump/biffdumper.cxx @@ -2422,7 +2422,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 5c1cf3398fc9..32278e425664 100644 --- a/oox/source/dump/dumperbase.cxx +++ b/oox/source/dump/dumperbase.cxx @@ -1583,18 +1583,18 @@ NameListRef SharedConfigData::getNameList( const OUString& rListName ) const return xList; } -OUString SharedConfigData::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) +Sequence< NamedValue > SharedConfigData::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) { - OUString aPassword; + Sequence< 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.hasElements(); } - return aPassword; + return aEncryptionData; } bool SharedConfigData::implIsValid() const @@ -1766,9 +1766,9 @@ NameListRef Config::getNameList( const String& rListName ) const return implGetNameList( rListName ); } -OUString Config::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) +Sequence< NamedValue > Config::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) { - return mxCfgData->requestPassword( rVerifier ); + return mxCfgData->requestEncryptionData( rVerifier ); } bool Config::isPasswordCancelled() const diff --git a/oox/source/ole/vbaproject.cxx b/oox/source/ole/vbaproject.cxx index f51193fe30ba..35e6b7911012 100644 --- a/oox/source/ole/vbaproject.cxx +++ b/oox/source/ole/vbaproject.cxx @@ -427,7 +427,9 @@ void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGrap 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 ); @@ -436,15 +438,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 @@ -481,7 +474,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 diff --git a/oox/source/xls/biffcodec.cxx b/oox/source/xls/biffcodec.cxx index 774760b7a9c5..89b39ef4fc94 100644 --- a/oox/source/xls/biffcodec.cxx +++ b/oox/source/xls/biffcodec.cxx @@ -53,9 +53,16 @@ BiffDecoderBase::~BiffDecoderBase() { } -::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword ) +::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData ) { - mbValid = implVerify( rPassword ); + o_rEncryptionData = implVerifyPassword( rPassword ); + mbValid = o_rEncryptionData.hasElements(); + return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; +} + +::comphelper::DocPasswordVerifierResult BiffDecoderBase::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) +{ + mbValid = implVerifyEncryptionData( rEncryptionData ); return mbValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD; } @@ -74,7 +81,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 ) { @@ -83,12 +89,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() @@ -96,24 +102,40 @@ BiffDecoder_XOR* BiffDecoder_XOR::implClone() return new BiffDecoder_XOR( *this ); } -bool BiffDecoder_XOR::implVerify( const OUString& rPassword ) +Sequence< NamedValue > BiffDecoder_XOR::implVerifyPassword( const 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( reinterpret_cast< const sal_uInt8* >( aBytePassword.getStr() ) ); + if( maCodec.verifyKey( mnKey, mnHash ) ) + maEncryptionData = maCodec.getEncryptionData(); + } + + return maEncryptionData; +} + +bool BiffDecoder_XOR::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) +{ + maEncryptionData.realloc( 0 ); + + if( rEncryptionData.hasElements() ) + { // 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.hasElements(); } void BiffDecoder_XOR::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) @@ -144,7 +166,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 ) @@ -153,13 +174,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() @@ -167,25 +188,44 @@ BiffDecoder_RCF* BiffDecoder_RCF::implClone() return new BiffDecoder_RCF( *this ); } -bool BiffDecoder_RCF::implVerify( const OUString& rPassword ) +Sequence< NamedValue > BiffDecoder_RCF::implVerifyPassword( const 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 false; + + return maEncryptionData; +} + +bool BiffDecoder_RCF::implVerifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) +{ + maEncryptionData.realloc( 0 ); + + if( rEncryptionData.hasElements() ) + { + // init codec + maCodec.initCodec( rEncryptionData ); + + if( maCodec.verifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) + maEncryptionData = rEncryptionData; + } + + return maEncryptionData.hasElements(); } void BiffDecoder_RCF::implDecode( sal_uInt8* pnDestData, const sal_uInt8* pnSrcData, sal_Int64 nStreamPos, sal_uInt16 nBytes ) @@ -319,7 +359,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/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx index b4f8a4459234..2bd8deeeae57 100644 --- a/oox/source/xls/worksheethelper.cxx +++ b/oox/source/xls/worksheethelper.cxx @@ -376,7 +376,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; @@ -771,41 +771,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 ) @@ -921,17 +997,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; } |