Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / dtrans / source / win32 / dtobj / FmtFilter.cxx
blob2130c42ba578cffb7cb15bad81d195edf576d412
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <string.h>
22 #include "FmtFilter.hxx"
23 #include <osl/diagnose.h>
25 #include <shobjidl.h>
26 #include <shlguid.h>
27 #include <objidl.h>
28 #include <shellapi.h>
30 #include <string>
31 #include <sstream>
32 #include <vector>
33 #include <iomanip>
35 #include <systools/win32/comtools.hxx>
37 using namespace com::sun::star::uno;
39 #pragma pack(2)
40 struct METAFILEHEADER
42 DWORD key;
43 short hmf;
44 SMALL_RECT bbox;
45 WORD inch;
46 DWORD reserved;
47 WORD checksum;
49 #pragma pack()
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 );
62 if ( nCount > 0 )
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 ) };
71 USHORT nInch;
73 switch( pMFPict->mm )
75 case MM_TEXT:
76 nInch = 72;
77 break;
79 case MM_LOMETRIC:
80 nInch = 100;
81 break;
83 case MM_HIMETRIC:
84 nInch = 1000;
85 break;
87 case MM_LOENGLISH:
88 nInch = 254;
89 break;
91 case MM_HIENGLISH:
92 case MM_ISOTROPIC:
93 case MM_ANISOTROPIC:
94 nInch = 2540;
95 break;
97 case MM_TWIPS:
98 nInch = 1440;
99 break;
101 default:
102 nInch = 576;
105 pMFHeader->key = 0x9AC6CDD7L;
106 pMFHeader->hmf = 0;
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 );
118 return mfpictStream;
121 // convert a windows enhanced metafile to a LibreOffice metafile
123 Sequence< sal_Int8 > WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile )
125 Sequence< sal_Int8 > aRet;
126 UINT nSize = 0;
128 if( hEnhMetaFile &&
129 ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, nullptr ) ) != 0 ) )
131 aRet.realloc( nSize );
133 if( GetEnhMetaFileBits( hEnhMetaFile, nSize, reinterpret_cast<unsigned char*>(aRet.getArray()) ) != nSize )
134 aRet.realloc( 0 );
137 return aRet;
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()) );
147 if( hMtf )
149 METAFILEPICT* pPict = static_cast<METAFILEPICT*>(GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) ));
151 pPict->mm = 8;
152 pPict->xExt = 0;
153 pPict->yExt = 0;
154 pPict->hMF = hMtf;
156 GlobalUnlock( hPict );
159 return 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()) );
168 return hEnhMtf;
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 )))
192 nOffset += 12;
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;
201 return ooBmpStream;
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 ) );
214 return winDIBStream;
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());
267 memcpy(
268 static_cast<void*>(byteSequence.getArray()),
269 static_cast<const void*>(htmlFormat.c_str()),
270 htmlFormat.length());
272 return byteSequence;
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
295 lnk file. */
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));
307 if (FAILED(hr))
308 return target;
310 sal::systools::COMReference<IPersistFile> pIPersistFile =
311 pIShellLink.QueryInterface<IPersistFile>(IID_IPersistFile);
313 hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ);
314 if (FAILED(hr))
315 return target;
317 hr = pIShellLink->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI);
318 if (FAILED(hr))
319 return target;
321 wchar_t pathW[MAX_PATH];
322 WIN32_FIND_DATAW wfd;
323 hr = pIShellLink->GetPath(pathW, MAX_PATH, &wfd, SLGP_RAWPATH);
324 if (FAILED(hr))
325 return target;
327 target = pathW;
329 catch(sal::systools::ComError& ex)
331 OSL_FAIL(ex.what());
333 return target;
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() )
343 return 0;
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)
355 ByteSequence_t bseq;
356 size_t size = CalcSizeForStringListBuffer(fileList);
358 if (size > 0)
360 bseq.realloc(size);
361 wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray());
362 ZeroMemory(p, size);
364 for (auto const& elem : fileList)
366 wcsncpy(p, elem.c_str(), elem.length());
367 p += (elem.length() + 1);
370 return bseq;
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;
396 SIZE aBmpSize;
397 if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) )
399 // fill bitmap info header
400 size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy;
401 Sequence< sal_Int8 > aBitmapStream(
402 sizeof(BITMAPINFO) +
403 nDataBytes
405 PBITMAPINFOHEADER pBmp = reinterpret_cast<PBITMAPINFOHEADER>(aBitmapStream.getArray());
406 pBmp->biSize = sizeof( BITMAPINFOHEADER );
407 pBmp->biWidth = aBmpSize.cx;
408 pBmp->biHeight = aBmpSize.cy;
409 pBmp->biPlanes = 1;
410 pBmp->biBitCount = 32;
411 pBmp->biCompression = BI_RGB;
412 pBmp->biSizeImage = static_cast<DWORD>(nDataBytes);
413 pBmp->biXPelsPerMeter = 1000;
414 pBmp->biYPelsPerMeter = 1000;
415 pBmp->biClrUsed = 0;
416 pBmp->biClrImportant = 0;
417 if( GetDIBits( nullptr, // DC, 0 is a default GC, basically that of the desktop
418 aHBMP,
419 0, aBmpSize.cy,
420 aBitmapStream.getArray() + sizeof(BITMAPINFO),
421 reinterpret_cast<LPBITMAPINFO>(pBmp),
422 DIB_RGB_COLORS ) )
424 ooBmpStream = WinDIBToOOBMP( aBitmapStream );
428 return ooBmpStream;
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */