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>
35 #include <systools/win32/comtools.hxx>
37 using namespace com::sun::star::uno
;
51 // convert a windows metafile picture to a LibreOffice metafile picture
53 Sequence
< sal_Int8
> WinMFPictToOOMFPict( Sequence
< sal_Int8
>& aMetaFilePict
)
55 OSL_ASSERT( aMetaFilePict
.getLength( ) == sizeof( METAFILEPICT
) );
57 Sequence
< sal_Int8
> mfpictStream
;
58 METAFILEPICT
* pMFPict
= reinterpret_cast< METAFILEPICT
* >( aMetaFilePict
.getArray( ) );
59 HMETAFILE hMf
= pMFPict
->hMF
;
60 sal_uInt32 nCount
= GetMetaFileBitsEx( hMf
, 0, nullptr );
64 mfpictStream
.realloc( nCount
+ sizeof( METAFILEHEADER
) );
66 METAFILEHEADER
* pMFHeader
= reinterpret_cast< METAFILEHEADER
* >( mfpictStream
.getArray( ) );
67 SMALL_RECT aRect
= { 0,
69 static_cast< short >( pMFPict
->xExt
),
70 static_cast< short >( pMFPict
->yExt
) };
105 pMFHeader
->key
= 0x9AC6CDD7L
;
107 pMFHeader
->bbox
= aRect
;
108 pMFHeader
->inch
= nInch
;
109 pMFHeader
->reserved
= 0;
110 pMFHeader
->checksum
= 0;
112 char* pMFBuff
= reinterpret_cast< char* >( mfpictStream
.getArray( ) );
114 nCount
= GetMetaFileBitsEx( pMFPict
->hMF
, nCount
, pMFBuff
+ sizeof( METAFILEHEADER
) );
115 OSL_ASSERT( nCount
> 0 );
121 // convert a windows enhanced metafile to a LibreOffice metafile
123 Sequence
< sal_Int8
> WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile
)
125 Sequence
< sal_Int8
> aRet
;
129 ( ( nSize
= GetEnhMetaFileBits( hEnhMetaFile
, 0, nullptr ) ) != 0 ) )
131 aRet
.realloc( nSize
);
133 if( GetEnhMetaFileBits( hEnhMetaFile
, nSize
, reinterpret_cast<unsigned char*>(aRet
.getArray()) ) != nSize
)
140 // convert a LibreOffice metafile picture to a windows metafile picture
142 HMETAFILEPICT
OOMFPictToWinMFPict( Sequence
< sal_Int8
> const & aOOMetaFilePict
)
144 HMETAFILEPICT hPict
= nullptr;
145 HMETAFILE hMtf
= SetMetaFileBitsEx( aOOMetaFilePict
.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict
.getConstArray()) );
149 METAFILEPICT
* pPict
= static_cast<METAFILEPICT
*>(GlobalLock( hPict
= GlobalAlloc( GHND
, sizeof( METAFILEPICT
) ) ));
156 GlobalUnlock( hPict
);
162 // convert a LibreOffice metafile picture to a windows enhanced metafile picture
164 HENHMETAFILE
OOMFPictToWinENHMFPict( Sequence
< sal_Int8
> const & aOOMetaFilePict
)
166 HENHMETAFILE hEnhMtf
= SetEnhMetaFileBits( aOOMetaFilePict
.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict
.getConstArray()) );
171 // convert a windows device independent bitmap into a LibreOffice bitmap
173 Sequence
< sal_Int8
> WinDIBToOOBMP( const Sequence
< sal_Int8
>& aWinDIB
)
175 OSL_ENSURE(sal_uInt32(aWinDIB
.getLength()) > sizeof(BITMAPINFOHEADER
), "CF_DIBV5/CF_DIB too small (!)");
176 Sequence
< sal_Int8
> ooBmpStream
;
178 ooBmpStream
.realloc(aWinDIB
.getLength( ) + sizeof(BITMAPFILEHEADER
));
179 const BITMAPINFOHEADER
* pBmpInfoHdr
= reinterpret_cast< const BITMAPINFOHEADER
* >(aWinDIB
.getConstArray());
180 BITMAPFILEHEADER
* pBmpFileHdr
= reinterpret_cast< BITMAPFILEHEADER
* >(ooBmpStream
.getArray());
181 const DWORD
nSizeInfoOrV5(pBmpInfoHdr
->biSize
> sizeof(BITMAPINFOHEADER
) ? sizeof(BITMAPV5HEADER
) : sizeof(BITMAPINFOHEADER
));
182 DWORD
nOffset(sizeof(BITMAPFILEHEADER
) + nSizeInfoOrV5
);
184 memcpy(pBmpFileHdr
+ 1, pBmpInfoHdr
, aWinDIB
.getLength());
186 if(pBmpInfoHdr
->biBitCount
<= 8)
188 nOffset
+= (pBmpInfoHdr
->biClrUsed
? pBmpInfoHdr
->biClrUsed
: (1 << pBmpInfoHdr
->biBitCount
)) << 2;
190 else if((BI_BITFIELDS
== pBmpInfoHdr
->biCompression
) && ((16 == pBmpInfoHdr
->biBitCount
) || (32 == pBmpInfoHdr
->biBitCount
)))
195 pBmpFileHdr
->bfType
= ('M' << 8) | 'B';
196 pBmpFileHdr
->bfSize
= 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
197 pBmpFileHdr
->bfReserved1
= 0;
198 pBmpFileHdr
->bfReserved2
= 0;
199 pBmpFileHdr
->bfOffBits
= nOffset
;
204 // convert a LibreOffice bitmap into a windows device independent bitmap
206 Sequence
< sal_Int8
> OOBmpToWinDIB( Sequence
< sal_Int8
>& aOOBmp
)
208 Sequence
< sal_Int8
> winDIBStream( aOOBmp
.getLength( ) - sizeof( BITMAPFILEHEADER
) );
210 memcpy( winDIBStream
.getArray( ),
211 aOOBmp
.getArray( ) + sizeof( BITMAPFILEHEADER
),
212 aOOBmp
.getLength( ) - sizeof( BITMAPFILEHEADER
) );
217 static std::string
GetHtmlFormatHeader(size_t startHtml
, size_t endHtml
, size_t startFragment
, size_t endFragment
)
219 std::ostringstream htmlHeader
;
220 htmlHeader
<< "Version:1.0" << '\r' << '\n';
221 htmlHeader
<< "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec
<< startHtml
<< '\r' << '\n';
222 htmlHeader
<< "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec
<< endHtml
<< '\r' << '\n';
223 htmlHeader
<< "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec
<< startFragment
<< '\r' << '\n';
224 htmlHeader
<< "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec
<< endFragment
<< '\r' << '\n';
225 return htmlHeader
.str();
228 // the case of these tags has to match what we output in our filters
229 // both tags don't allow parameters
230 const std::string
TAG_HTML("<html>");
231 const std::string
TAG_END_HTML("</html>");
233 // The body tag may have parameters so we need to search for the
234 // closing '>' manually e.g. <body param> #92840#
235 const std::string
TAG_BODY("<body");
236 const std::string
TAG_END_BODY("</body");
238 Sequence
<sal_Int8
> TextHtmlToHTMLFormat(Sequence
<sal_Int8
> const & aTextHtml
)
240 OSL_ASSERT(aTextHtml
.getLength() > 0);
242 if (aTextHtml
.getLength() <= 0)
243 return Sequence
<sal_Int8
>();
245 // fill the buffer with dummy values to calc the exact length
246 std::string dummyHtmlHeader
= GetHtmlFormatHeader(0, 0, 0, 0);
247 size_t lHtmlFormatHeader
= dummyHtmlHeader
.length();
249 std::string
textHtml(
250 reinterpret_cast<const sal_Char
*>(aTextHtml
.getConstArray()),
251 reinterpret_cast<const sal_Char
*>(aTextHtml
.getConstArray()) + aTextHtml
.getLength());
253 std::string::size_type nStartHtml
= textHtml
.find(TAG_HTML
) + lHtmlFormatHeader
- 1; // we start one before '<HTML>' Word 2000 does also so
254 std::string::size_type nEndHtml
= textHtml
.find(TAG_END_HTML
) + lHtmlFormatHeader
+ TAG_END_HTML
.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
256 // The body tag may have parameters so we need to search for the
257 // closing '>' manually e.g. <BODY param> #92840#
258 std::string::size_type nStartFragment
= textHtml
.find(">", textHtml
.find(TAG_BODY
)) + lHtmlFormatHeader
+ 1;
259 std::string::size_type nEndFragment
= textHtml
.find(TAG_END_BODY
) + lHtmlFormatHeader
;
261 std::string htmlFormat
= GetHtmlFormatHeader(nStartHtml
, nEndHtml
, nStartFragment
, nEndFragment
);
262 htmlFormat
+= textHtml
;
264 Sequence
<sal_Int8
> byteSequence(htmlFormat
.length() + 1); // space the trailing '\0'
265 memset(byteSequence
.getArray(), 0, byteSequence
.getLength());
268 static_cast<void*>(byteSequence
.getArray()),
269 static_cast<const void*>(htmlFormat
.c_str()),
270 htmlFormat
.length());
275 static std::wstring
getFileExtension(const std::wstring
& aFilename
)
277 std::wstring::size_type idx
= aFilename
.rfind(L
".");
278 if (idx
!= std::wstring::npos
)
280 return std::wstring(aFilename
, idx
);
282 return std::wstring();
285 const std::wstring SHELL_LINK_FILE_EXTENSION
= L
".lnk";
287 static bool isShellLink(const std::wstring
& aFilename
)
289 std::wstring ext
= getFileExtension(aFilename
);
290 return (_wcsicmp(ext
.c_str(), SHELL_LINK_FILE_EXTENSION
.c_str()) == 0);
293 /** Resolve a Windows Shell Link (lnk) file. If a resolution
294 is not possible simply return the provided name of the
296 static std::wstring
getShellLinkTarget(const std::wstring
& aLnkFile
)
298 OSL_ASSERT(isShellLink(aLnkFile
));
300 std::wstring target
= aLnkFile
;
304 sal::systools::COMReference
<IShellLinkW
> pIShellLink
;
305 HRESULT hr
= CoCreateInstance(
306 CLSID_ShellLink
, nullptr, CLSCTX_INPROC_SERVER
, IID_IShellLinkW
, reinterpret_cast<LPVOID
*>(&pIShellLink
));
310 sal::systools::COMReference
<IPersistFile
> pIPersistFile
=
311 pIShellLink
.QueryInterface
<IPersistFile
>(IID_IPersistFile
);
313 hr
= pIPersistFile
->Load(aLnkFile
.c_str(), STGM_READ
);
317 hr
= pIShellLink
->Resolve(nullptr, SLR_UPDATE
| SLR_NO_UI
);
321 wchar_t pathW
[MAX_PATH
];
322 WIN32_FIND_DATAW wfd
;
323 hr
= pIShellLink
->GetPath(pathW
, MAX_PATH
, &wfd
, SLGP_RAWPATH
);
329 catch(sal::systools::ComError
& ex
)
336 typedef Sequence
<sal_Int8
> ByteSequence_t
;
338 /* Calculate the size required for turning a string list into
339 a double '\0' terminated string buffer */
340 static size_t CalcSizeForStringListBuffer(const std::vector
<std::wstring
>& fileList
)
342 if ( fileList
.empty() )
345 size_t size
= 1; // one for the very final '\0'
346 for (auto const& elem
: fileList
)
348 size
+= elem
.length() + 1; // length including terminating '\0'
350 return (size
* sizeof(std::vector
<std::wstring
>::value_type::value_type
));
353 static ByteSequence_t
FileListToByteSequence(const std::vector
<std::wstring
>& fileList
)
356 size_t size
= CalcSizeForStringListBuffer(fileList
);
361 wchar_t* p
= reinterpret_cast<wchar_t*>(bseq
.getArray());
364 for (auto const& elem
: fileList
)
366 wcsncpy(p
, elem
.c_str(), elem
.length());
367 p
+= (elem
.length() + 1);
373 css::uno::Sequence
<sal_Int8
> CF_HDROPToFileList(HGLOBAL hGlobal
)
375 UINT nFiles
= DragQueryFileW(static_cast<HDROP
>(hGlobal
), 0xFFFFFFFF, nullptr, 0);
376 std::vector
<std::wstring
> files
;
378 for (UINT i
= 0; i
< nFiles
; i
++)
380 wchar_t buff
[MAX_PATH
];
381 /*UINT size =*/ DragQueryFileW(static_cast<HDROP
>(hGlobal
), i
, buff
, MAX_PATH
);
382 std::wstring filename
= buff
;
383 if (isShellLink(filename
))
384 filename
= getShellLinkTarget(filename
);
385 files
.push_back(filename
);
387 return FileListToByteSequence(files
);
390 // convert a windows bitmap handle into a LibreOffice bitmap
392 Sequence
< sal_Int8
> WinBITMAPToOOBMP( HBITMAP aHBMP
)
394 Sequence
< sal_Int8
> ooBmpStream
;
397 if( GetBitmapDimensionEx( aHBMP
, &aBmpSize
) )
399 // fill bitmap info header
400 size_t nDataBytes
= 4 * aBmpSize
.cy
* aBmpSize
.cy
;
401 Sequence
< sal_Int8
> aBitmapStream(
405 PBITMAPINFOHEADER pBmp
= reinterpret_cast<PBITMAPINFOHEADER
>(aBitmapStream
.getArray());
406 pBmp
->biSize
= sizeof( BITMAPINFOHEADER
);
407 pBmp
->biWidth
= aBmpSize
.cx
;
408 pBmp
->biHeight
= aBmpSize
.cy
;
410 pBmp
->biBitCount
= 32;
411 pBmp
->biCompression
= BI_RGB
;
412 pBmp
->biSizeImage
= static_cast<DWORD
>(nDataBytes
);
413 pBmp
->biXPelsPerMeter
= 1000;
414 pBmp
->biYPelsPerMeter
= 1000;
416 pBmp
->biClrImportant
= 0;
417 if( GetDIBits( nullptr, // DC, 0 is a default GC, basically that of the desktop
420 aBitmapStream
.getArray() + sizeof(BITMAPINFO
),
421 reinterpret_cast<LPBITMAPINFO
>(pBmp
),
424 ooBmpStream
= WinDIBToOOBMP( aBitmapStream
);
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */