1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: FmtFilter.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dtrans.hxx"
33 #include "FmtFilter.hxx"
34 #include <osl/diagnose.h>
35 #include <comphelper/sequence.hxx>
38 #pragma warning(push,1)
39 #pragma warning(disable:4917)
54 #include <systools/win32/comtools.hxx>
56 using namespace com::sun::star::uno
;
71 //------------------------------------------------------------------------
72 // convert a windows metafile picture to a openoffice metafile picture
73 //------------------------------------------------------------------------
75 Sequence
< sal_Int8
> SAL_CALL
WinMFPictToOOMFPict( Sequence
< sal_Int8
>& aMetaFilePict
)
77 OSL_ASSERT( aMetaFilePict
.getLength( ) == sizeof( METAFILEPICT
) );
79 Sequence
< sal_Int8
> mfpictStream
;
80 METAFILEPICT
* pMFPict
= reinterpret_cast< METAFILEPICT
* >( aMetaFilePict
.getArray( ) );
81 HMETAFILE hMf
= pMFPict
->hMF
;
82 sal_uInt32 nCount
= GetMetaFileBitsEx( hMf
, 0, NULL
);
86 mfpictStream
.realloc( nCount
+ sizeof( METAFILEHEADER
) );
88 METAFILEHEADER
* pMFHeader
= reinterpret_cast< METAFILEHEADER
* >( mfpictStream
.getArray( ) );
89 SMALL_RECT aRect
= { 0,
91 static_cast< short >( pMFPict
->xExt
),
92 static_cast< short >( pMFPict
->yExt
) };
127 pMFHeader
->key
= 0x9AC6CDD7L
;
129 pMFHeader
->bbox
= aRect
;
130 pMFHeader
->inch
= nInch
;
131 pMFHeader
->reserved
= 0;
132 pMFHeader
->checksum
= 0;
134 char* pMFBuff
= reinterpret_cast< char* >( mfpictStream
.getArray( ) );
136 nCount
= GetMetaFileBitsEx( pMFPict
->hMF
, nCount
, pMFBuff
+ sizeof( METAFILEHEADER
) );
137 OSL_ASSERT( nCount
> 0 );
143 //-------------------------------------------------------------
144 // convert a windows enhanced metafile to a openoffice metafile
145 //-------------------------------------------------------------
147 Sequence
< sal_Int8
> SAL_CALL
WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile
)
149 Sequence
< sal_Int8
> aRet
;
153 ( ( nSize
= GetEnhMetaFileBits( hEnhMetaFile
, 0, NULL
) ) != 0 ) )
155 aRet
.realloc( nSize
);
157 if( GetEnhMetaFileBits( hEnhMetaFile
, nSize
, (sal_uChar
*) aRet
.getArray() ) != nSize
)
164 //------------------------------------------------------------------------
165 // convert a openoffice metafile picture to a windows metafile picture
166 //------------------------------------------------------------------------
168 HMETAFILEPICT SAL_CALL
OOMFPictToWinMFPict( Sequence
< sal_Int8
>& aOOMetaFilePict
)
170 HMETAFILEPICT hPict
= NULL
;
171 HMETAFILE hMtf
= SetMetaFileBitsEx( aOOMetaFilePict
.getLength(), (sal_uChar
*) aOOMetaFilePict
.getConstArray() );
175 METAFILEPICT
* pPict
= (METAFILEPICT
*) GlobalLock( hPict
= GlobalAlloc( GHND
, sizeof( METAFILEPICT
) ) );
182 GlobalUnlock( hPict
);
188 //-----------------------------------------------------------------------------
189 // convert a openoffice metafile picture to a windows enhanced metafile picture
190 //-----------------------------------------------------------------------------
192 HENHMETAFILE SAL_CALL
OOMFPictToWinENHMFPict( Sequence
< sal_Int8
>& aOOMetaFilePict
)
194 HENHMETAFILE hEnhMtf
= SetEnhMetaFileBits( aOOMetaFilePict
.getLength(), (sal_uChar
*) aOOMetaFilePict
.getConstArray() );
199 //------------------------------------------------------------------------
200 // convert a windows device independent bitmap into a openoffice bitmap
201 //------------------------------------------------------------------------
203 Sequence
< sal_Int8
> SAL_CALL
WinDIBToOOBMP( const Sequence
< sal_Int8
>& aWinDIB
)
205 OSL_ASSERT( aWinDIB
.getLength( ) > sizeof( BITMAPINFOHEADER
) );
207 Sequence
< sal_Int8
> ooBmpStream
;
209 ooBmpStream
.realloc( aWinDIB
.getLength( ) + sizeof(BITMAPFILEHEADER
) );
211 const BITMAPINFOHEADER
*pBmpInfoHdr
= (const BITMAPINFOHEADER
*)aWinDIB
.getConstArray();
212 BITMAPFILEHEADER
*pBmpFileHdr
= reinterpret_cast< BITMAPFILEHEADER
* >( ooBmpStream
.getArray() );
213 DWORD nOffset
= sizeof( BITMAPFILEHEADER
) + sizeof( BITMAPINFOHEADER
);
215 rtl_copyMemory( pBmpFileHdr
+ 1, pBmpInfoHdr
, aWinDIB
.getLength( ) );
217 if( pBmpInfoHdr
->biBitCount
<= 8 )
218 nOffset
+= ( pBmpInfoHdr
->biClrUsed
? pBmpInfoHdr
->biClrUsed
: ( 1 << pBmpInfoHdr
->biBitCount
) ) << 2;
219 else if( ( BI_BITFIELDS
== pBmpInfoHdr
->biCompression
) && ( ( 16 == pBmpInfoHdr
->biBitCount
) || ( 32 == pBmpInfoHdr
->biBitCount
) ) )
222 pBmpFileHdr
->bfType
= 'MB';
223 pBmpFileHdr
->bfSize
= 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
224 pBmpFileHdr
->bfReserved1
= 0;
225 pBmpFileHdr
->bfReserved2
= 0;
226 pBmpFileHdr
->bfOffBits
= nOffset
;
231 //------------------------------------------------------------------------
232 // convert a openoffice bitmap into a windows device independent bitmap
233 //------------------------------------------------------------------------
235 Sequence
< sal_Int8
> SAL_CALL
OOBmpToWinDIB( Sequence
< sal_Int8
>& aOOBmp
)
237 OSL_ASSERT( aOOBmp
.getLength( ) >
238 ( sizeof( BITMAPFILEHEADER
) + sizeof( BITMAPINFOHEADER
) ) );
240 Sequence
< sal_Int8
> winDIBStream( aOOBmp
.getLength( ) - sizeof( BITMAPFILEHEADER
) );
242 rtl_copyMemory( winDIBStream
.getArray( ),
243 aOOBmp
.getArray( ) + sizeof( BITMAPFILEHEADER
),
244 aOOBmp
.getLength( ) - sizeof( BITMAPFILEHEADER
) );
249 //------------------------------------------------------------------------------
250 // converts the openoffice text/html clipboard format to the HTML Format
251 // well known under MS Windows
252 // the MS HTML Format has a header before the real html data
254 // Version:1.0 Version number of the clipboard. Staring is 0.9
255 // StartHTML: Byte count from the beginning of the clipboard to the start
256 // of the context, or -1 if no context
257 // EndHTML: Byte count from the beginning of the clipboard to the end
258 // of the context, or -1 if no context
259 // StartFragment: Byte count from the beginning of the clipboard to the
260 // start of the fragment
261 // EndFragment: Byte count from the beginning of the clipboard to the
262 // end of the fragment
263 // StartSelection: Byte count from the beginning of the clipboard to the
264 // start of the selection
265 // EndSelection: Byte count from the beginning of the clipboard to the
266 // end of the selection
268 // StartSelection and EndSelection are optional
269 // The fragment should be preceded and followed by the HTML comments
270 // <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the
272 //------------------------------------------------------------------------------
274 Sequence< sal_Int8 > SAL_CALL TextHtmlToHTMLFormat( Sequence< sal_Int8 >& aTextHtml )
276 OSL_ASSERT( aTextHtml.getLength( ) > 0 );
279 if ( !(aTextHtml.getLength( ) > 0) )
280 return Sequence< sal_Int8 >( );
282 // we create a buffer with the approximated size of
283 // the HTML Format header
284 char aHTMLFmtHdr[120];
286 rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) );
288 // fill the buffer with dummy values to calc the
293 "Version:1.0\nStartHTML:%010d\r\nnEndHTML:%010d\r\nStartFragment:%010\r\nnEndFragment:%010d\r\n", 0, 0, 0, 0 );
295 sal_uInt32 lHTMLFmtHdr = rtl_str_getLength( aHTMLFmtHdr );
297 // the office allways writes the start
298 // and end html tag in upper cases and
300 // both tags don't allow parameters
301 OString startHtmlTag( "<HTML>" );
302 OString endHtmlTag( "</HTML>" );
304 // we don't include '>' into the search
305 // because the body tag allows parameters
308 OString startBodyTag( "<BODY" );
309 OString endBodyTag( "</BODY" );
312 reinterpret_cast< const sal_Char* >( aTextHtml.getConstArray( ) ),
313 aTextHtml.getLength( ) );
315 sal_Int32 nStartHtml = textHtml.indexOf( startHtmlTag );
316 sal_Int32 nEndHtml = textHtml.indexOf( endHtmlTag );
317 sal_Int32 nStartFrgmt = textHtml.indexOf( startBodyTag );
318 sal_Int32 nEndFrgmt = textHtml.indexOf( endBodyTag );
320 OSL_ASSERT( (nStartHtml >= 0) && (nEndHtml > nStartHtml) && (nStartFrgmt > nStartHtml) && (nEndFrgmt > nStartFrgmt) );
322 Sequence< sal_Int8 > aHTMLFmtSequence;
324 if ( (nStartHtml > -1) && (nEndHtml > -1) && (nStartFrgmt > -1) && (nEndFrgmt > -1) )
326 nStartHtml = nStartHtml + lHTMLFmtHdr - 1; // we start one before <HTML> Word 2000 does also so
327 nEndHtml = nEndHtml + lHTMLFmtHdr + endHtmlTag.getLength( ) + 1; // our SOffice 5.2 wants 2 behind </HTML>?
328 nStartFrgmt = nStartFrgmt + startBodyTag.getLength( ) + lHTMLFmtHdr; // after the <BODY> tag
329 nEndFrgmt = nEndFrgmt + lHTMLFmtHdr;
331 // fill the html header
332 rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) );
336 "Version:1.0\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n",
337 nStartHtml, nEndHtml, nStartFrgmt, nEndFrgmt );
339 // we add space for a trailing \0
340 aHTMLFmtSequence.realloc( lHTMLFmtHdr + aTextHtml.getLength( ) + 1 );
341 rtl_zeroMemory( aHTMLFmtSequence.getArray( ), aHTMLFmtSequence.getLength( ) );
343 // copy the HTML Format header
345 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) ),
346 static_cast< LPVOID >( aHTMLFmtHdr ), lHTMLFmtHdr );
348 // concat the text/html
350 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) + lHTMLFmtHdr ),
351 static_cast< LPVOID >( aTextHtml.getArray( ) ),
352 aTextHtml.getLength( ) );
355 return aHTMLFmtSequence;
359 std::string
GetHtmlFormatHeader(size_t startHtml
, size_t endHtml
, size_t startFragment
, size_t endFragment
)
361 std::ostringstream htmlHeader
;
362 htmlHeader
<< "Version:1.0" << '\r' << '\n';
363 htmlHeader
<< "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec
<< startHtml
<< '\r' << '\n';
364 htmlHeader
<< "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec
<< endHtml
<< '\r' << '\n';
365 htmlHeader
<< "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec
<< startFragment
<< '\r' << '\n';
366 htmlHeader
<< "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec
<< endFragment
<< '\r' << '\n';
367 return htmlHeader
.str();
370 // the office allways writes the start and end html tag in upper cases and
371 // without spaces both tags don't allow parameters
372 const std::string TAG_HTML
= std::string("<HTML>");
373 const std::string TAG_END_HTML
= std::string("</HTML>");
375 // The body tag may have parameters so we need to search for the
376 // closing '>' manually e.g. <BODY param> #92840#
377 const std::string TAG_BODY
= std::string("<BODY");
378 const std::string TAG_END_BODY
= std::string("</BODY");
380 Sequence
<sal_Int8
> SAL_CALL
TextHtmlToHTMLFormat(Sequence
<sal_Int8
>& aTextHtml
)
382 OSL_ASSERT(aTextHtml
.getLength() > 0);
384 if (!(aTextHtml
.getLength() > 0))
385 return Sequence
<sal_Int8
>();
387 // fill the buffer with dummy values to calc the exact length
388 std::string dummyHtmlHeader
= GetHtmlFormatHeader(0, 0, 0, 0);
389 size_t lHtmlFormatHeader
= dummyHtmlHeader
.length();
391 std::string
textHtml(
392 reinterpret_cast<const sal_Char
*>(aTextHtml
.getConstArray()),
393 reinterpret_cast<const sal_Char
*>(aTextHtml
.getConstArray()) + aTextHtml
.getLength());
395 std::string::size_type nStartHtml
= textHtml
.find(TAG_HTML
) + lHtmlFormatHeader
- 1; // we start one before '<HTML>' Word 2000 does also so
396 std::string::size_type nEndHtml
= textHtml
.find(TAG_END_HTML
) + lHtmlFormatHeader
+ TAG_END_HTML
.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
398 // The body tag may have parameters so we need to search for the
399 // closing '>' manually e.g. <BODY param> #92840#
400 std::string::size_type nStartFragment
= textHtml
.find(">", textHtml
.find(TAG_BODY
)) + lHtmlFormatHeader
+ 1;
401 std::string::size_type nEndFragment
= textHtml
.find(TAG_END_BODY
) + lHtmlFormatHeader
;
403 std::string htmlFormat
= GetHtmlFormatHeader(nStartHtml
, nEndHtml
, nStartFragment
, nEndFragment
);
404 htmlFormat
+= textHtml
;
406 Sequence
<sal_Int8
> byteSequence(htmlFormat
.length() + 1); // space the trailing '\0'
407 rtl_zeroMemory(byteSequence
.getArray(), byteSequence
.getLength());
410 static_cast<void*>(byteSequence
.getArray()),
411 static_cast<const void*>(htmlFormat
.c_str()),
412 htmlFormat
.length());
417 std::wstring
getFileExtension(const std::wstring
& aFilename
)
419 std::wstring::size_type idx
= aFilename
.rfind(L
".");
420 if ((idx
!= std::wstring::npos
))
422 return std::wstring(aFilename
, idx
);
424 return std::wstring();
427 const std::wstring SHELL_LINK_FILE_EXTENSION
= L
".lnk";
429 bool isShellLink(const std::wstring
& aFilename
)
431 std::wstring ext
= getFileExtension(aFilename
);
432 return (_wcsicmp(ext
.c_str(), SHELL_LINK_FILE_EXTENSION
.c_str()) == 0);
435 /** Resolve a Windows Shell Link (lnk) file. If a resolution
436 is not possible simply return the provided name of the
438 std::wstring
getShellLinkTarget(const std::wstring
& aLnkFile
)
440 OSL_ASSERT(isShellLink(aLnkFile
));
442 std::wstring target
= aLnkFile
;
446 sal::systools::COMReference
<IShellLinkA
> pIShellLink
;
447 HRESULT hr
= CoCreateInstance(
448 CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, IID_IShellLink
, reinterpret_cast<LPVOID
*>(&pIShellLink
));
452 sal::systools::COMReference
<IPersistFile
> pIPersistFile
=
453 pIShellLink
.QueryInterface
<IPersistFile
>(IID_IPersistFile
);
455 hr
= pIPersistFile
->Load(aLnkFile
.c_str(), STGM_READ
);
459 hr
= pIShellLink
->Resolve(NULL
, SLR_UPDATE
| SLR_NO_UI
);
463 char pathA
[MAX_PATH
];
465 hr
= pIShellLink
->GetPath(pathA
, MAX_PATH
, &wfd
, SLGP_RAWPATH
);
469 wchar_t pathW
[MAX_PATH
];
470 MultiByteToWideChar(CP_ACP
, 0, pathA
, -1, pathW
, MAX_PATH
);
473 catch(sal::systools::ComError
& ex
)
475 OSL_ENSURE(false, ex
.what());
481 typedef std::vector
<std::wstring
> FileList_t
;
482 typedef FileList_t::value_type FileList_ValueType_t
;
483 typedef Sequence
<sal_Int8
> ByteSequence_t
;
485 /* Calculate the size required for turning a string list into
486 a double '\0' terminated string buffer */
487 size_t CalcSizeForStringListBuffer(const FileList_t
& fileList
)
489 if (fileList
.size() == 0)
492 size_t size
= 1; // one for the very final '\0'
493 FileList_t::const_iterator iter_end
= fileList
.end();
494 for (FileList_t::const_iterator iter
= fileList
.begin(); iter
!= iter_end
; ++iter
)
496 size
+= iter
->length() + 1; // length including terminating '\0'
498 return (size
* sizeof(FileList_ValueType_t::value_type
));
501 ByteSequence_t
FileListToByteSequence(const FileList_t
& fileList
)
504 size_t size
= CalcSizeForStringListBuffer(fileList
);
509 wchar_t* p
= reinterpret_cast<wchar_t*>(bseq
.getArray());
512 FileList_t::const_iterator iter
;
513 FileList_t::const_iterator iter_end
= fileList
.end();
514 for (iter
= fileList
.begin(); iter
!= iter_end
; ++iter
)
516 wcsncpy(p
, iter
->c_str(), iter
->length());
517 p
+= (iter
->length() + 1);
523 ByteSequence_t
CF_HDROPToFileList(HGLOBAL hGlobal
)
525 UINT nFiles
= DragQueryFileW((HDROP
)hGlobal
, 0xFFFFFFFF, NULL
, 0);
528 for (UINT i
= 0; i
< nFiles
; i
++)
530 wchar_t buff
[MAX_PATH
];
531 /*UINT size =*/ DragQueryFileW((HDROP
)hGlobal
, i
, buff
, MAX_PATH
);
532 std::wstring filename
= buff
;
533 if (isShellLink(filename
))
534 filename
= getShellLinkTarget(filename
);
535 files
.push_back(filename
);
537 return FileListToByteSequence(files
);