1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "FmtFilter.hxx"
23 #include <osl/diagnose.h>
24 #include <comphelper/sequence.hxx>
27 #pragma warning(push,1)
28 #pragma warning(disable:4917)
43 #include <systools/win32/comtools.hxx>
45 using namespace com::sun::star::uno
;
59 //------------------------------------------------------------------------
60 // convert a windows metafile picture to a openoffice metafile picture
61 //------------------------------------------------------------------------
63 Sequence
< sal_Int8
> SAL_CALL
WinMFPictToOOMFPict( Sequence
< sal_Int8
>& aMetaFilePict
)
65 OSL_ASSERT( aMetaFilePict
.getLength( ) == sizeof( METAFILEPICT
) );
67 Sequence
< sal_Int8
> mfpictStream
;
68 METAFILEPICT
* pMFPict
= reinterpret_cast< METAFILEPICT
* >( aMetaFilePict
.getArray( ) );
69 HMETAFILE hMf
= pMFPict
->hMF
;
70 sal_uInt32 nCount
= GetMetaFileBitsEx( hMf
, 0, NULL
);
74 mfpictStream
.realloc( nCount
+ sizeof( METAFILEHEADER
) );
76 METAFILEHEADER
* pMFHeader
= reinterpret_cast< METAFILEHEADER
* >( mfpictStream
.getArray( ) );
77 SMALL_RECT aRect
= { 0,
79 static_cast< short >( pMFPict
->xExt
),
80 static_cast< short >( pMFPict
->yExt
) };
115 pMFHeader
->key
= 0x9AC6CDD7L
;
117 pMFHeader
->bbox
= aRect
;
118 pMFHeader
->inch
= nInch
;
119 pMFHeader
->reserved
= 0;
120 pMFHeader
->checksum
= 0;
122 char* pMFBuff
= reinterpret_cast< char* >( mfpictStream
.getArray( ) );
124 nCount
= GetMetaFileBitsEx( pMFPict
->hMF
, nCount
, pMFBuff
+ sizeof( METAFILEHEADER
) );
125 OSL_ASSERT( nCount
> 0 );
131 //-------------------------------------------------------------
132 // convert a windows enhanced metafile to a openoffice metafile
133 //-------------------------------------------------------------
135 Sequence
< sal_Int8
> SAL_CALL
WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile
)
137 Sequence
< sal_Int8
> aRet
;
141 ( ( nSize
= GetEnhMetaFileBits( hEnhMetaFile
, 0, NULL
) ) != 0 ) )
143 aRet
.realloc( nSize
);
145 if( GetEnhMetaFileBits( hEnhMetaFile
, nSize
, (sal_uChar
*) aRet
.getArray() ) != nSize
)
152 //------------------------------------------------------------------------
153 // convert a openoffice metafile picture to a windows metafile picture
154 //------------------------------------------------------------------------
156 HMETAFILEPICT SAL_CALL
OOMFPictToWinMFPict( Sequence
< sal_Int8
>& aOOMetaFilePict
)
158 HMETAFILEPICT hPict
= NULL
;
159 HMETAFILE hMtf
= SetMetaFileBitsEx( aOOMetaFilePict
.getLength(), (sal_uChar
*) aOOMetaFilePict
.getConstArray() );
163 METAFILEPICT
* pPict
= (METAFILEPICT
*) GlobalLock( hPict
= GlobalAlloc( GHND
, sizeof( METAFILEPICT
) ) );
170 GlobalUnlock( hPict
);
176 //-----------------------------------------------------------------------------
177 // convert a openoffice metafile picture to a windows enhanced metafile picture
178 //-----------------------------------------------------------------------------
180 HENHMETAFILE SAL_CALL
OOMFPictToWinENHMFPict( Sequence
< sal_Int8
>& aOOMetaFilePict
)
182 HENHMETAFILE hEnhMtf
= SetEnhMetaFileBits( aOOMetaFilePict
.getLength(), (sal_uChar
*) aOOMetaFilePict
.getConstArray() );
187 //------------------------------------------------------------------------
188 // convert a windows device independent bitmap into a openoffice bitmap
189 //------------------------------------------------------------------------
191 Sequence
< sal_Int8
> SAL_CALL
WinDIBToOOBMP( const Sequence
< sal_Int8
>& aWinDIB
)
193 OSL_ASSERT( aWinDIB
.getLength( ) > sizeof( BITMAPINFOHEADER
) );
195 Sequence
< sal_Int8
> ooBmpStream
;
197 ooBmpStream
.realloc( aWinDIB
.getLength( ) + sizeof(BITMAPFILEHEADER
) );
199 const BITMAPINFOHEADER
*pBmpInfoHdr
= (const BITMAPINFOHEADER
*)aWinDIB
.getConstArray();
200 BITMAPFILEHEADER
*pBmpFileHdr
= reinterpret_cast< BITMAPFILEHEADER
* >( ooBmpStream
.getArray() );
201 DWORD nOffset
= sizeof( BITMAPFILEHEADER
) + sizeof( BITMAPINFOHEADER
);
203 memcpy( pBmpFileHdr
+ 1, pBmpInfoHdr
, aWinDIB
.getLength( ) );
205 if( pBmpInfoHdr
->biBitCount
<= 8 )
206 nOffset
+= ( pBmpInfoHdr
->biClrUsed
? pBmpInfoHdr
->biClrUsed
: ( 1 << pBmpInfoHdr
->biBitCount
) ) << 2;
207 else if( ( BI_BITFIELDS
== pBmpInfoHdr
->biCompression
) && ( ( 16 == pBmpInfoHdr
->biBitCount
) || ( 32 == pBmpInfoHdr
->biBitCount
) ) )
210 pBmpFileHdr
->bfType
= ('M' << 8) | 'B';
211 pBmpFileHdr
->bfSize
= 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
212 pBmpFileHdr
->bfReserved1
= 0;
213 pBmpFileHdr
->bfReserved2
= 0;
214 pBmpFileHdr
->bfOffBits
= nOffset
;
219 //------------------------------------------------------------------------
220 // convert a openoffice bitmap into a windows device independent bitmap
221 //------------------------------------------------------------------------
223 Sequence
< sal_Int8
> SAL_CALL
OOBmpToWinDIB( Sequence
< sal_Int8
>& aOOBmp
)
225 OSL_ASSERT( aOOBmp
.getLength( ) >
226 ( sizeof( BITMAPFILEHEADER
) + sizeof( BITMAPINFOHEADER
) ) );
228 Sequence
< sal_Int8
> winDIBStream( aOOBmp
.getLength( ) - sizeof( BITMAPFILEHEADER
) );
230 memcpy( winDIBStream
.getArray( ),
231 aOOBmp
.getArray( ) + sizeof( BITMAPFILEHEADER
),
232 aOOBmp
.getLength( ) - sizeof( BITMAPFILEHEADER
) );
237 //------------------------------------------------------------------------------
238 // converts the openoffice text/html clipboard format to the HTML Format
239 // well known under MS Windows
240 // the MS HTML Format has a header before the real html data
242 // Version:1.0 Version number of the clipboard. Staring is 0.9
243 // StartHTML: Byte count from the beginning of the clipboard to the start
244 // of the context, or -1 if no context
245 // EndHTML: Byte count from the beginning of the clipboard to the end
246 // of the context, or -1 if no context
247 // StartFragment: Byte count from the beginning of the clipboard to the
248 // start of the fragment
249 // EndFragment: Byte count from the beginning of the clipboard to the
250 // end of the fragment
251 // StartSelection: Byte count from the beginning of the clipboard to the
252 // start of the selection
253 // EndSelection: Byte count from the beginning of the clipboard to the
254 // end of the selection
256 // StartSelection and EndSelection are optional
257 // The fragment should be preceded and followed by the HTML comments
258 // <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the
260 //------------------------------------------------------------------------------
262 Sequence< sal_Int8 > SAL_CALL TextHtmlToHTMLFormat( Sequence< sal_Int8 >& aTextHtml )
264 OSL_ASSERT( aTextHtml.getLength( ) > 0 );
267 if ( !(aTextHtml.getLength( ) > 0) )
268 return Sequence< sal_Int8 >( );
270 // we create a buffer with the approximated size of
271 // the HTML Format header
272 char aHTMLFmtHdr[120];
274 memset( aHTMLFmtHdr, 0, sizeof( aHTMLFmtHdr ) );
276 // fill the buffer with dummy values to calc the
281 "Version:1.0\nStartHTML:%010d\r\nnEndHTML:%010d\r\nStartFragment:%010\r\nnEndFragment:%010d\r\n", 0, 0, 0, 0 );
283 sal_uInt32 lHTMLFmtHdr = rtl_str_getLength( aHTMLFmtHdr );
285 // the office always writes the start
286 // and end html tag in upper cases and
288 // both tags don't allow parameters
289 OString startHtmlTag( "<HTML>" );
290 OString endHtmlTag( "</HTML>" );
292 // we don't include '>' into the search
293 // because the body tag allows parameters
296 OString startBodyTag( "<BODY" );
297 OString endBodyTag( "</BODY" );
300 reinterpret_cast< const sal_Char* >( aTextHtml.getConstArray( ) ),
301 aTextHtml.getLength( ) );
303 sal_Int32 nStartHtml = textHtml.indexOf( startHtmlTag );
304 sal_Int32 nEndHtml = textHtml.indexOf( endHtmlTag );
305 sal_Int32 nStartFrgmt = textHtml.indexOf( startBodyTag );
306 sal_Int32 nEndFrgmt = textHtml.indexOf( endBodyTag );
308 OSL_ASSERT( (nStartHtml >= 0) && (nEndHtml > nStartHtml) && (nStartFrgmt > nStartHtml) && (nEndFrgmt > nStartFrgmt) );
310 Sequence< sal_Int8 > aHTMLFmtSequence;
312 if ( (nStartHtml > -1) && (nEndHtml > -1) && (nStartFrgmt > -1) && (nEndFrgmt > -1) )
314 nStartHtml = nStartHtml + lHTMLFmtHdr - 1; // we start one before <HTML> Word 2000 does also so
315 nEndHtml = nEndHtml + lHTMLFmtHdr + endHtmlTag.getLength( ) + 1; // our SOffice 5.2 wants 2 behind </HTML>?
316 nStartFrgmt = nStartFrgmt + startBodyTag.getLength( ) + lHTMLFmtHdr; // after the <BODY> tag
317 nEndFrgmt = nEndFrgmt + lHTMLFmtHdr;
319 // fill the html header
320 memset( aHTMLFmtHdr, 0, sizeof( aHTMLFmtHdr ) );
324 "Version:1.0\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n",
325 nStartHtml, nEndHtml, nStartFrgmt, nEndFrgmt );
327 // we add space for a trailing \0
328 aHTMLFmtSequence.realloc( lHTMLFmtHdr + aTextHtml.getLength( ) + 1 );
329 memset( aHTMLFmtSequence.getArray( ), 0, aHTMLFmtSequence.getLength( ) );
331 // copy the HTML Format header
333 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) ),
334 static_cast< LPVOID >( aHTMLFmtHdr ), lHTMLFmtHdr );
336 // concat the text/html
338 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) + lHTMLFmtHdr ),
339 static_cast< LPVOID >( aTextHtml.getArray( ) ),
340 aTextHtml.getLength( ) );
343 return aHTMLFmtSequence;
347 std::string
GetHtmlFormatHeader(size_t startHtml
, size_t endHtml
, size_t startFragment
, size_t endFragment
)
349 std::ostringstream htmlHeader
;
350 htmlHeader
<< "Version:1.0" << '\r' << '\n';
351 htmlHeader
<< "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec
<< startHtml
<< '\r' << '\n';
352 htmlHeader
<< "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec
<< endHtml
<< '\r' << '\n';
353 htmlHeader
<< "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec
<< startFragment
<< '\r' << '\n';
354 htmlHeader
<< "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec
<< endFragment
<< '\r' << '\n';
355 return htmlHeader
.str();
358 // the office always writes the start and end html tag in upper cases and
359 // without spaces both tags don't allow parameters
360 const std::string TAG_HTML
= std::string("<HTML>");
361 const std::string TAG_END_HTML
= std::string("</HTML>");
363 // The body tag may have parameters so we need to search for the
364 // closing '>' manually e.g. <BODY param> #92840#
365 const std::string TAG_BODY
= std::string("<BODY");
366 const std::string TAG_END_BODY
= std::string("</BODY");
368 Sequence
<sal_Int8
> SAL_CALL
TextHtmlToHTMLFormat(Sequence
<sal_Int8
>& aTextHtml
)
370 OSL_ASSERT(aTextHtml
.getLength() > 0);
372 if (!(aTextHtml
.getLength() > 0))
373 return Sequence
<sal_Int8
>();
375 // fill the buffer with dummy values to calc the exact length
376 std::string dummyHtmlHeader
= GetHtmlFormatHeader(0, 0, 0, 0);
377 size_t lHtmlFormatHeader
= dummyHtmlHeader
.length();
379 std::string
textHtml(
380 reinterpret_cast<const sal_Char
*>(aTextHtml
.getConstArray()),
381 reinterpret_cast<const sal_Char
*>(aTextHtml
.getConstArray()) + aTextHtml
.getLength());
383 std::string::size_type nStartHtml
= textHtml
.find(TAG_HTML
) + lHtmlFormatHeader
- 1; // we start one before '<HTML>' Word 2000 does also so
384 std::string::size_type nEndHtml
= textHtml
.find(TAG_END_HTML
) + lHtmlFormatHeader
+ TAG_END_HTML
.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
386 // The body tag may have parameters so we need to search for the
387 // closing '>' manually e.g. <BODY param> #92840#
388 std::string::size_type nStartFragment
= textHtml
.find(">", textHtml
.find(TAG_BODY
)) + lHtmlFormatHeader
+ 1;
389 std::string::size_type nEndFragment
= textHtml
.find(TAG_END_BODY
) + lHtmlFormatHeader
;
391 std::string htmlFormat
= GetHtmlFormatHeader(nStartHtml
, nEndHtml
, nStartFragment
, nEndFragment
);
392 htmlFormat
+= textHtml
;
394 Sequence
<sal_Int8
> byteSequence(htmlFormat
.length() + 1); // space the trailing '\0'
395 memset(byteSequence
.getArray(), 0, byteSequence
.getLength());
398 static_cast<void*>(byteSequence
.getArray()),
399 static_cast<const void*>(htmlFormat
.c_str()),
400 htmlFormat
.length());
405 std::wstring
getFileExtension(const std::wstring
& aFilename
)
407 std::wstring::size_type idx
= aFilename
.rfind(L
".");
408 if ((idx
!= std::wstring::npos
))
410 return std::wstring(aFilename
, idx
);
412 return std::wstring();
415 const std::wstring SHELL_LINK_FILE_EXTENSION
= L
".lnk";
417 bool isShellLink(const std::wstring
& aFilename
)
419 std::wstring ext
= getFileExtension(aFilename
);
420 return (_wcsicmp(ext
.c_str(), SHELL_LINK_FILE_EXTENSION
.c_str()) == 0);
423 /** Resolve a Windows Shell Link (lnk) file. If a resolution
424 is not possible simply return the provided name of the
426 std::wstring
getShellLinkTarget(const std::wstring
& aLnkFile
)
428 OSL_ASSERT(isShellLink(aLnkFile
));
430 std::wstring target
= aLnkFile
;
434 sal::systools::COMReference
<IShellLinkA
> pIShellLink
;
435 HRESULT hr
= CoCreateInstance(
436 CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, IID_IShellLink
, reinterpret_cast<LPVOID
*>(&pIShellLink
));
440 sal::systools::COMReference
<IPersistFile
> pIPersistFile
=
441 pIShellLink
.QueryInterface
<IPersistFile
>(IID_IPersistFile
);
443 hr
= pIPersistFile
->Load(aLnkFile
.c_str(), STGM_READ
);
447 hr
= pIShellLink
->Resolve(NULL
, SLR_UPDATE
| SLR_NO_UI
);
451 char pathA
[MAX_PATH
];
453 hr
= pIShellLink
->GetPath(pathA
, MAX_PATH
, &wfd
, SLGP_RAWPATH
);
457 wchar_t pathW
[MAX_PATH
];
458 MultiByteToWideChar(CP_ACP
, 0, pathA
, -1, pathW
, MAX_PATH
);
461 catch(sal::systools::ComError
& ex
)
469 typedef std::vector
<std::wstring
> FileList_t
;
470 typedef FileList_t::value_type FileList_ValueType_t
;
471 typedef Sequence
<sal_Int8
> ByteSequence_t
;
473 /* Calculate the size required for turning a string list into
474 a double '\0' terminated string buffer */
475 size_t CalcSizeForStringListBuffer(const FileList_t
& fileList
)
477 if ( fileList
.empty() )
480 size_t size
= 1; // one for the very final '\0'
481 FileList_t::const_iterator iter_end
= fileList
.end();
482 for (FileList_t::const_iterator iter
= fileList
.begin(); iter
!= iter_end
; ++iter
)
484 size
+= iter
->length() + 1; // length including terminating '\0'
486 return (size
* sizeof(FileList_ValueType_t::value_type
));
489 ByteSequence_t
FileListToByteSequence(const FileList_t
& fileList
)
492 size_t size
= CalcSizeForStringListBuffer(fileList
);
497 wchar_t* p
= reinterpret_cast<wchar_t*>(bseq
.getArray());
500 FileList_t::const_iterator iter
;
501 FileList_t::const_iterator iter_end
= fileList
.end();
502 for (iter
= fileList
.begin(); iter
!= iter_end
; ++iter
)
504 wcsncpy(p
, iter
->c_str(), iter
->length());
505 p
+= (iter
->length() + 1);
511 ByteSequence_t
CF_HDROPToFileList(HGLOBAL hGlobal
)
513 UINT nFiles
= DragQueryFileW((HDROP
)hGlobal
, 0xFFFFFFFF, NULL
, 0);
516 for (UINT i
= 0; i
< nFiles
; i
++)
518 wchar_t buff
[MAX_PATH
];
519 /*UINT size =*/ DragQueryFileW((HDROP
)hGlobal
, i
, buff
, MAX_PATH
);
520 std::wstring filename
= buff
;
521 if (isShellLink(filename
))
522 filename
= getShellLinkTarget(filename
);
523 files
.push_back(filename
);
525 return FileListToByteSequence(files
);
528 //------------------------------------------------------------------------
529 // convert a windows bitmap handle into a openoffice bitmap
530 //------------------------------------------------------------------------
532 Sequence
< sal_Int8
> SAL_CALL
WinBITMAPToOOBMP( HBITMAP aHBMP
)
534 Sequence
< sal_Int8
> ooBmpStream
;
537 if( GetBitmapDimensionEx( aHBMP
, &aBmpSize
) )
539 // fill bitmap info header
540 size_t nDataBytes
= 4 * aBmpSize
.cy
* aBmpSize
.cy
;
541 Sequence
< sal_Int8
> aBitmapStream(
545 PBITMAPINFOHEADER pBmp
= (PBITMAPINFOHEADER
)aBitmapStream
.getArray();
546 pBmp
->biSize
= sizeof( BITMAPINFOHEADER
);
547 pBmp
->biWidth
= aBmpSize
.cx
;
548 pBmp
->biHeight
= aBmpSize
.cy
;
550 pBmp
->biBitCount
= 32;
551 pBmp
->biCompression
= BI_RGB
;
552 pBmp
->biSizeImage
= (DWORD
)nDataBytes
;
553 pBmp
->biXPelsPerMeter
= 1000;
554 pBmp
->biYPelsPerMeter
= 1000;
556 pBmp
->biClrImportant
= 0;
557 if( GetDIBits( 0, // DC, 0 is a default GC, basically that of the desktop
560 aBitmapStream
.getArray() + sizeof(BITMAPINFO
),
564 ooBmpStream
= WinDIBToOOBMP( aBitmapStream
);
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */