diff options
Diffstat (limited to 'dtrans/source/win32/dtobj/FmtFilter.cxx')
-rw-r--r-- | dtrans/source/win32/dtobj/FmtFilter.cxx | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/dtrans/source/win32/dtobj/FmtFilter.cxx b/dtrans/source/win32/dtobj/FmtFilter.cxx new file mode 100644 index 000000000000..c8a8743647a9 --- /dev/null +++ b/dtrans/source/win32/dtobj/FmtFilter.cxx @@ -0,0 +1,536 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_dtrans.hxx" +#include "FmtFilter.hxx" +#include <osl/diagnose.h> +#include <comphelper/sequence.hxx> + +#if defined _MSC_VER +#pragma warning(push,1) +#pragma warning(disable:4917) +#endif +#include <Shobjidl.h> +#include <shlguid.h> +#include <ObjIdl.h> +#include <shellapi.h> +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include <string> +#include <sstream> +#include <vector> +#include <iomanip> + +#include <systools/win32/comtools.hxx> + +using namespace com::sun::star::uno; +using rtl::OString; + +#pragma pack(2) +struct METAFILEHEADER +{ + DWORD key; + short hmf; + SMALL_RECT bbox; + WORD inch; + DWORD reserved; + WORD checksum; +}; +#pragma pack() + +//------------------------------------------------------------------------ +// convert a windows metafile picture to a openoffice metafile picture +//------------------------------------------------------------------------ + +Sequence< sal_Int8 > SAL_CALL WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict ) +{ + OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) ); + + Sequence< sal_Int8 > mfpictStream; + METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) ); + HMETAFILE hMf = pMFPict->hMF; + sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, NULL ); + + if ( nCount > 0 ) + { + mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) ); + + METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) ); + SMALL_RECT aRect = { 0, + 0, + static_cast< short >( pMFPict->xExt ), + static_cast< short >( pMFPict->yExt ) }; + USHORT nInch; + + switch( pMFPict->mm ) + { + case MM_TEXT: + nInch = 72; + break; + + case MM_LOMETRIC: + nInch = 100; + break; + + case MM_HIMETRIC: + nInch = 1000; + break; + + case MM_LOENGLISH: + nInch = 254; + break; + + case MM_HIENGLISH: + case MM_ISOTROPIC: + case MM_ANISOTROPIC: + nInch = 2540; + break; + + case MM_TWIPS: + nInch = 1440; + break; + + default: + nInch = 576; + } + + pMFHeader->key = 0x9AC6CDD7L; + pMFHeader->hmf = 0; + pMFHeader->bbox = aRect; + pMFHeader->inch = nInch; + pMFHeader->reserved = 0; + pMFHeader->checksum = 0; + + char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) ); + + nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) ); + OSL_ASSERT( nCount > 0 ); + } + + return mfpictStream; +} + +//------------------------------------------------------------- +// convert a windows enhanced metafile to a openoffice metafile +//------------------------------------------------------------- + +Sequence< sal_Int8 > SAL_CALL WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile ) +{ + Sequence< sal_Int8 > aRet; + UINT nSize = 0; + + if( hEnhMetaFile && + ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, NULL ) ) != 0 ) ) + { + aRet.realloc( nSize ); + + if( GetEnhMetaFileBits( hEnhMetaFile, nSize, (sal_uChar*) aRet.getArray() ) != nSize ) + aRet.realloc( 0 ); + } + + return aRet; +} + +//------------------------------------------------------------------------ +// convert a openoffice metafile picture to a windows metafile picture +//------------------------------------------------------------------------ + +HMETAFILEPICT SAL_CALL OOMFPictToWinMFPict( Sequence< sal_Int8 >& aOOMetaFilePict ) +{ + HMETAFILEPICT hPict = NULL; + HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), (sal_uChar*) aOOMetaFilePict.getConstArray() ); + + if( hMtf ) + { + METAFILEPICT* pPict = (METAFILEPICT*) GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) ); + + pPict->mm = 8; + pPict->xExt = 0; + pPict->yExt = 0; + pPict->hMF = hMtf; + + GlobalUnlock( hPict ); + } + + return hPict; +} + +//----------------------------------------------------------------------------- +// convert a openoffice metafile picture to a windows enhanced metafile picture +//----------------------------------------------------------------------------- + +HENHMETAFILE SAL_CALL OOMFPictToWinENHMFPict( Sequence< sal_Int8 >& aOOMetaFilePict ) +{ + HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), (sal_uChar*) aOOMetaFilePict.getConstArray() ); + + return hEnhMtf; +} + +//------------------------------------------------------------------------ +// convert a windows device independent bitmap into a openoffice bitmap +//------------------------------------------------------------------------ + +Sequence< sal_Int8 > SAL_CALL WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB ) +{ + OSL_ASSERT( aWinDIB.getLength( ) > sizeof( BITMAPINFOHEADER ) ); + + Sequence< sal_Int8 > ooBmpStream; + + ooBmpStream.realloc( aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER) ); + + const BITMAPINFOHEADER *pBmpInfoHdr = (const BITMAPINFOHEADER*)aWinDIB.getConstArray(); + BITMAPFILEHEADER *pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >( ooBmpStream.getArray() ); + DWORD nOffset = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ); + + rtl_copyMemory( pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength( ) ); + + if( pBmpInfoHdr->biBitCount <= 8 ) + nOffset += ( pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : ( 1 << pBmpInfoHdr->biBitCount ) ) << 2; + else if( ( BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ( ( 16 == pBmpInfoHdr->biBitCount ) || ( 32 == pBmpInfoHdr->biBitCount ) ) ) + nOffset += 12; + + pBmpFileHdr->bfType = 'MB'; + pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER) + pBmpFileHdr->bfReserved1 = 0; + pBmpFileHdr->bfReserved2 = 0; + pBmpFileHdr->bfOffBits = nOffset; + + return ooBmpStream; +} + +//------------------------------------------------------------------------ +// convert a openoffice bitmap into a windows device independent bitmap +//------------------------------------------------------------------------ + +Sequence< sal_Int8 > SAL_CALL OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp ) +{ + OSL_ASSERT( aOOBmp.getLength( ) > + ( sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) ) ); + + Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) ); + + rtl_copyMemory( winDIBStream.getArray( ), + aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ), + aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) ); + + return winDIBStream; +} + +//------------------------------------------------------------------------------ +// converts the openoffice text/html clipboard format to the HTML Format +// well known under MS Windows +// the MS HTML Format has a header before the real html data +// +// Version:1.0 Version number of the clipboard. Staring is 0.9 +// StartHTML: Byte count from the beginning of the clipboard to the start +// of the context, or -1 if no context +// EndHTML: Byte count from the beginning of the clipboard to the end +// of the context, or -1 if no context +// StartFragment: Byte count from the beginning of the clipboard to the +// start of the fragment +// EndFragment: Byte count from the beginning of the clipboard to the +// end of the fragment +// StartSelection: Byte count from the beginning of the clipboard to the +// start of the selection +// EndSelection: Byte count from the beginning of the clipboard to the +// end of the selection +// +// StartSelection and EndSelection are optional +// The fragment should be preceded and followed by the HTML comments +// <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the +// text +//------------------------------------------------------------------------------ +/* +Sequence< sal_Int8 > SAL_CALL TextHtmlToHTMLFormat( Sequence< sal_Int8 >& aTextHtml ) +{ + OSL_ASSERT( aTextHtml.getLength( ) > 0 ); + + // check parameter + if ( !(aTextHtml.getLength( ) > 0) ) + return Sequence< sal_Int8 >( ); + + // we create a buffer with the approximated size of + // the HTML Format header + char aHTMLFmtHdr[120]; + + rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) ); + + // fill the buffer with dummy values to calc the + // exact length + + wsprintf( + aHTMLFmtHdr, + "Version:1.0\nStartHTML:%010d\r\nnEndHTML:%010d\r\nStartFragment:%010\r\nnEndFragment:%010d\r\n", 0, 0, 0, 0 ); + + sal_uInt32 lHTMLFmtHdr = rtl_str_getLength( aHTMLFmtHdr ); + + // the office allways writes the start + // and end html tag in upper cases and + // without spaces + // both tags don't allow parameters + OString startHtmlTag( "<HTML>" ); + OString endHtmlTag( "</HTML>" ); + + // we don't include '>' into the search + // because the body tag allows parameters + // e.g. <BODY param> + // #92840# + OString startBodyTag( "<BODY" ); + OString endBodyTag( "</BODY" ); + + OString textHtml( + reinterpret_cast< const sal_Char* >( aTextHtml.getConstArray( ) ), + aTextHtml.getLength( ) ); + + sal_Int32 nStartHtml = textHtml.indexOf( startHtmlTag ); + sal_Int32 nEndHtml = textHtml.indexOf( endHtmlTag ); + sal_Int32 nStartFrgmt = textHtml.indexOf( startBodyTag ); + sal_Int32 nEndFrgmt = textHtml.indexOf( endBodyTag ); + + OSL_ASSERT( (nStartHtml >= 0) && (nEndHtml > nStartHtml) && (nStartFrgmt > nStartHtml) && (nEndFrgmt > nStartFrgmt) ); + + Sequence< sal_Int8 > aHTMLFmtSequence; + + if ( (nStartHtml > -1) && (nEndHtml > -1) && (nStartFrgmt > -1) && (nEndFrgmt > -1) ) + { + nStartHtml = nStartHtml + lHTMLFmtHdr - 1; // we start one before <HTML> Word 2000 does also so + nEndHtml = nEndHtml + lHTMLFmtHdr + endHtmlTag.getLength( ) + 1; // our SOffice 5.2 wants 2 behind </HTML>? + nStartFrgmt = nStartFrgmt + startBodyTag.getLength( ) + lHTMLFmtHdr; // after the <BODY> tag + nEndFrgmt = nEndFrgmt + lHTMLFmtHdr; + + // fill the html header + rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) ); + + wsprintf( + aHTMLFmtHdr, + "Version:1.0\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n", + nStartHtml, nEndHtml, nStartFrgmt, nEndFrgmt ); + + // we add space for a trailing \0 + aHTMLFmtSequence.realloc( lHTMLFmtHdr + aTextHtml.getLength( ) + 1 ); + rtl_zeroMemory( aHTMLFmtSequence.getArray( ), aHTMLFmtSequence.getLength( ) ); + + // copy the HTML Format header + rtl_copyMemory( + static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) ), + static_cast< LPVOID >( aHTMLFmtHdr ), lHTMLFmtHdr ); + + // concat the text/html + rtl_copyMemory( + static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) + lHTMLFmtHdr ), + static_cast< LPVOID >( aTextHtml.getArray( ) ), + aTextHtml.getLength( ) ); + } + + return aHTMLFmtSequence; +} +*/ + +std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment) +{ + std::ostringstream htmlHeader; + htmlHeader << "Version:1.0" << '\r' << '\n'; + htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n'; + htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n'; + htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n'; + htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n'; + return htmlHeader.str(); +} + +// the office allways writes the start and end html tag in upper cases and +// without spaces both tags don't allow parameters +const std::string TAG_HTML = std::string("<HTML>"); +const std::string TAG_END_HTML = std::string("</HTML>"); + +// The body tag may have parameters so we need to search for the +// closing '>' manually e.g. <BODY param> #92840# +const std::string TAG_BODY = std::string("<BODY"); +const std::string TAG_END_BODY = std::string("</BODY"); + +Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8>& aTextHtml) +{ + OSL_ASSERT(aTextHtml.getLength() > 0); + + if (!(aTextHtml.getLength() > 0)) + return Sequence<sal_Int8>(); + + // fill the buffer with dummy values to calc the exact length + std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0); + size_t lHtmlFormatHeader = dummyHtmlHeader.length(); + + std::string textHtml( + reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()), + reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()) + aTextHtml.getLength()); + + std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so + std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>? + + // The body tag may have parameters so we need to search for the + // closing '>' manually e.g. <BODY param> #92840# + std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1; + std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader; + + std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment); + htmlFormat += textHtml; + + Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0' + rtl_zeroMemory(byteSequence.getArray(), byteSequence.getLength()); + + rtl_copyMemory( + static_cast<void*>(byteSequence.getArray()), + static_cast<const void*>(htmlFormat.c_str()), + htmlFormat.length()); + + return byteSequence; +} + +std::wstring getFileExtension(const std::wstring& aFilename) +{ + std::wstring::size_type idx = aFilename.rfind(L"."); + if ((idx != std::wstring::npos)) + { + return std::wstring(aFilename, idx); + } + return std::wstring(); +} + +const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk"; + +bool isShellLink(const std::wstring& aFilename) +{ + std::wstring ext = getFileExtension(aFilename); + return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0); +} + +/** Resolve a Windows Shell Link (lnk) file. If a resolution + is not possible simply return the provided name of the + lnk file. */ +std::wstring getShellLinkTarget(const std::wstring& aLnkFile) +{ + OSL_ASSERT(isShellLink(aLnkFile)); + + std::wstring target = aLnkFile; + + try + { + sal::systools::COMReference<IShellLinkA> pIShellLink; + HRESULT hr = CoCreateInstance( + CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<LPVOID*>(&pIShellLink)); + if (FAILED(hr)) + return target; + + sal::systools::COMReference<IPersistFile> pIPersistFile = + pIShellLink.QueryInterface<IPersistFile>(IID_IPersistFile); + + hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ); + if (FAILED(hr)) + return target; + + hr = pIShellLink->Resolve(NULL, SLR_UPDATE | SLR_NO_UI); + if (FAILED(hr)) + return target; + + char pathA[MAX_PATH]; + WIN32_FIND_DATA wfd; + hr = pIShellLink->GetPath(pathA, MAX_PATH, &wfd, SLGP_RAWPATH); + if (FAILED(hr)) + return target; + + wchar_t pathW[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, pathA, -1, pathW, MAX_PATH); + target = pathW; + } + catch(sal::systools::ComError& ex) + { + OSL_ENSURE(false, ex.what()); + ex = ex; + } + return target; +} + +typedef std::vector<std::wstring> FileList_t; +typedef FileList_t::value_type FileList_ValueType_t; +typedef Sequence<sal_Int8> ByteSequence_t; + +/* Calculate the size required for turning a string list into + a double '\0' terminated string buffer */ +size_t CalcSizeForStringListBuffer(const FileList_t& fileList) +{ + if (fileList.size() == 0) + return 0; + + size_t size = 1; // one for the very final '\0' + FileList_t::const_iterator iter_end = fileList.end(); + for (FileList_t::const_iterator iter = fileList.begin(); iter != iter_end; ++iter) + { + size += iter->length() + 1; // length including terminating '\0' + } + return (size * sizeof(FileList_ValueType_t::value_type)); +} + +ByteSequence_t FileListToByteSequence(const FileList_t& fileList) +{ + ByteSequence_t bseq; + size_t size = CalcSizeForStringListBuffer(fileList); + + if (size > 0) + { + bseq.realloc(size); + wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray()); + ZeroMemory(p, size); + + FileList_t::const_iterator iter; + FileList_t::const_iterator iter_end = fileList.end(); + for (iter = fileList.begin(); iter != iter_end; ++iter) + { + wcsncpy(p, iter->c_str(), iter->length()); + p += (iter->length() + 1); + } + } + return bseq; +} + +ByteSequence_t CF_HDROPToFileList(HGLOBAL hGlobal) +{ + UINT nFiles = DragQueryFileW((HDROP)hGlobal, 0xFFFFFFFF, NULL, 0); + FileList_t files; + + for (UINT i = 0; i < nFiles; i++) + { + wchar_t buff[MAX_PATH]; + /*UINT size =*/ DragQueryFileW((HDROP)hGlobal, i, buff, MAX_PATH); + std::wstring filename = buff; + if (isShellLink(filename)) + filename = getShellLinkTarget(filename); + files.push_back(filename); + } + return FileListToByteSequence(files); +} + |