nss: upgrade to release 3.73
[LibreOffice.git] / vcl / win / dtrans / FmtFilter.cxx
blobe9c4b42f8b68653e57caae1d8fd8afbb4f1da928
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"
24 #include <o3tl/safeint.hxx>
25 #include <osl/diagnose.h>
27 #include <shobjidl.h>
28 #include <shlguid.h>
29 #include <objidl.h>
30 #include <shellapi.h>
32 #include <string>
33 #include <sstream>
34 #include <vector>
35 #include <iomanip>
37 #include <systools/win32/comtools.hxx>
39 using namespace com::sun::star::uno;
41 namespace {
43 #pragma pack(2)
44 struct METAFILEHEADER
46 DWORD key;
47 short hmf;
48 SMALL_RECT bbox;
49 WORD inch;
50 DWORD reserved;
51 WORD checksum;
53 #pragma pack()
57 // convert a windows metafile picture to a LibreOffice metafile picture
59 Sequence< sal_Int8 > WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict )
61 OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) );
63 Sequence< sal_Int8 > mfpictStream;
64 METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) );
65 HMETAFILE hMf = pMFPict->hMF;
66 sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, nullptr );
68 if ( nCount > 0 )
70 mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) );
72 METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) );
73 SMALL_RECT aRect = { 0,
75 static_cast< short >( pMFPict->xExt ),
76 static_cast< short >( pMFPict->yExt ) };
77 USHORT nInch;
79 switch( pMFPict->mm )
81 case MM_TEXT:
82 nInch = 72;
83 break;
85 case MM_LOMETRIC:
86 nInch = 100;
87 break;
89 case MM_HIMETRIC:
90 nInch = 1000;
91 break;
93 case MM_LOENGLISH:
94 nInch = 254;
95 break;
97 case MM_HIENGLISH:
98 case MM_ISOTROPIC:
99 case MM_ANISOTROPIC:
100 nInch = 2540;
101 break;
103 case MM_TWIPS:
104 nInch = 1440;
105 break;
107 default:
108 nInch = 576;
111 pMFHeader->key = 0x9AC6CDD7L;
112 pMFHeader->hmf = 0;
113 pMFHeader->bbox = aRect;
114 pMFHeader->inch = nInch;
115 pMFHeader->reserved = 0;
116 pMFHeader->checksum = 0;
118 char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) );
120 nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) );
121 OSL_ASSERT( nCount > 0 );
124 return mfpictStream;
127 // convert a windows enhanced metafile to a LibreOffice metafile
129 Sequence< sal_Int8 > WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile )
131 Sequence< sal_Int8 > aRet;
132 UINT nSize = 0;
134 if( hEnhMetaFile &&
135 ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, nullptr ) ) != 0 ) )
137 aRet.realloc( nSize );
139 if( GetEnhMetaFileBits( hEnhMetaFile, nSize, reinterpret_cast<unsigned char*>(aRet.getArray()) ) != nSize )
140 aRet.realloc( 0 );
143 return aRet;
146 // convert a LibreOffice metafile picture to a windows metafile picture
148 HMETAFILEPICT OOMFPictToWinMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict )
150 HMETAFILEPICT hPict = nullptr;
151 HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict.getConstArray()) );
153 if( hMtf )
155 METAFILEPICT* pPict = static_cast<METAFILEPICT*>(GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) ));
157 pPict->mm = 8;
158 pPict->xExt = 0;
159 pPict->yExt = 0;
160 pPict->hMF = hMtf;
162 GlobalUnlock( hPict );
165 return hPict;
168 // convert a LibreOffice metafile picture to a windows enhanced metafile picture
170 HENHMETAFILE OOMFPictToWinENHMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict )
172 HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict.getConstArray()) );
174 return hEnhMtf;
177 // convert a windows device independent bitmap into a LibreOffice bitmap
179 Sequence< sal_Int8 > WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB )
181 OSL_ENSURE(o3tl::make_unsigned(aWinDIB.getLength()) > sizeof(BITMAPINFOHEADER), "CF_DIBV5/CF_DIB too small (!)");
182 Sequence< sal_Int8 > ooBmpStream;
184 ooBmpStream.realloc(aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER));
185 const BITMAPINFOHEADER* pBmpInfoHdr = reinterpret_cast< const BITMAPINFOHEADER* >(aWinDIB.getConstArray());
186 BITMAPFILEHEADER* pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >(ooBmpStream.getArray());
187 const DWORD nSizeInfoOrV5(pBmpInfoHdr->biSize > sizeof(BITMAPINFOHEADER) ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER));
188 DWORD nOffset(sizeof(BITMAPFILEHEADER) + nSizeInfoOrV5);
190 memcpy(pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength());
192 if(pBmpInfoHdr->biBitCount <= 8)
194 nOffset += (pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : (1 << pBmpInfoHdr->biBitCount)) << 2;
196 else if((BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ((16 == pBmpInfoHdr->biBitCount ) || (32 == pBmpInfoHdr->biBitCount )))
198 nOffset += 12;
201 pBmpFileHdr->bfType = ('M' << 8) | 'B';
202 pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
203 pBmpFileHdr->bfReserved1 = 0;
204 pBmpFileHdr->bfReserved2 = 0;
205 pBmpFileHdr->bfOffBits = nOffset;
207 return ooBmpStream;
210 // convert a LibreOffice bitmap into a windows device independent bitmap
212 Sequence< sal_Int8 > OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp )
214 Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
216 memcpy( winDIBStream.getArray( ),
217 aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ),
218 aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
220 return winDIBStream;
223 static std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment)
225 std::ostringstream htmlHeader;
226 htmlHeader << "Version:1.0" << '\r' << '\n';
227 htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n';
228 htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n';
229 htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n';
230 htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n';
231 return htmlHeader.str();
234 // the case of these tags has to match what we output in our filters
235 // both tags don't allow parameters
236 const std::string TAG_HTML("<html>");
237 const std::string TAG_END_HTML("</html>");
239 // The body tag may have parameters so we need to search for the
240 // closing '>' manually e.g. <body param> #92840#
241 const std::string TAG_BODY("<body");
242 const std::string TAG_END_BODY("</body");
244 Sequence<sal_Int8> TextHtmlToHTMLFormat(Sequence<sal_Int8> const & aTextHtml)
246 OSL_ASSERT(aTextHtml.getLength() > 0);
248 if (aTextHtml.getLength() <= 0)
249 return Sequence<sal_Int8>();
251 // fill the buffer with dummy values to calc the exact length
252 std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
253 size_t lHtmlFormatHeader = dummyHtmlHeader.length();
255 std::string textHtml(
256 reinterpret_cast<const char*>(aTextHtml.getConstArray()),
257 reinterpret_cast<const char*>(aTextHtml.getConstArray()) + aTextHtml.getLength());
259 std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so
260 std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
262 // The body tag may have parameters so we need to search for the
263 // closing '>' manually e.g. <BODY param> #92840#
264 std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
265 std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
267 std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
268 htmlFormat += textHtml;
270 Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
271 memset(byteSequence.getArray(), 0, byteSequence.getLength());
273 memcpy(
274 static_cast<void*>(byteSequence.getArray()),
275 static_cast<const void*>(htmlFormat.c_str()),
276 htmlFormat.length());
278 return byteSequence;
281 static std::wstring getFileExtension(const std::wstring& aFilename)
283 std::wstring::size_type idx = aFilename.rfind(L".");
284 if (idx != std::wstring::npos)
286 return std::wstring(aFilename, idx);
288 return std::wstring();
291 const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk";
293 static bool isShellLink(const std::wstring& aFilename)
295 std::wstring ext = getFileExtension(aFilename);
296 return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0);
299 /** Resolve a Windows Shell Link (lnk) file. If a resolution
300 is not possible simply return the provided name of the
301 lnk file. */
302 static std::wstring getShellLinkTarget(const std::wstring& aLnkFile)
304 OSL_ASSERT(isShellLink(aLnkFile));
306 std::wstring target = aLnkFile;
310 sal::systools::COMReference<IShellLinkW> pIShellLink;
311 HRESULT hr = CoCreateInstance(
312 CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, reinterpret_cast<LPVOID*>(&pIShellLink));
313 if (FAILED(hr))
314 return target;
316 sal::systools::COMReference<IPersistFile> pIPersistFile =
317 pIShellLink.QueryInterface<IPersistFile>(IID_IPersistFile);
319 hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ);
320 if (FAILED(hr))
321 return target;
323 hr = pIShellLink->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI);
324 if (FAILED(hr))
325 return target;
327 wchar_t pathW[MAX_PATH];
328 WIN32_FIND_DATAW wfd;
329 hr = pIShellLink->GetPath(pathW, MAX_PATH, &wfd, SLGP_RAWPATH);
330 if (FAILED(hr))
331 return target;
333 target = pathW;
335 catch(sal::systools::ComError& ex)
337 OSL_FAIL(ex.what());
339 return target;
342 typedef Sequence<sal_Int8> ByteSequence_t;
344 /* Calculate the size required for turning a string list into
345 a double '\0' terminated string buffer */
346 static size_t CalcSizeForStringListBuffer(const std::vector<std::wstring>& fileList)
348 if ( fileList.empty() )
349 return 0;
351 size_t size = 1; // one for the very final '\0'
352 for (auto const& elem : fileList)
354 size += elem.length() + 1; // length including terminating '\0'
356 return (size * sizeof(std::vector<std::wstring>::value_type::value_type));
359 static ByteSequence_t FileListToByteSequence(const std::vector<std::wstring>& fileList)
361 ByteSequence_t bseq;
362 size_t size = CalcSizeForStringListBuffer(fileList);
364 if (size > 0)
366 bseq.realloc(size);
367 wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray());
368 ZeroMemory(p, size);
370 for (auto const& elem : fileList)
372 wcsncpy(p, elem.c_str(), elem.length());
373 p += (elem.length() + 1);
376 return bseq;
379 css::uno::Sequence<sal_Int8> CF_HDROPToFileList(HGLOBAL hGlobal)
381 UINT nFiles = DragQueryFileW(static_cast<HDROP>(hGlobal), 0xFFFFFFFF, nullptr, 0);
382 std::vector<std::wstring> files;
384 for (UINT i = 0; i < nFiles; i++)
386 wchar_t buff[MAX_PATH];
387 /*UINT size =*/ DragQueryFileW(static_cast<HDROP>(hGlobal), i, buff, MAX_PATH);
388 std::wstring filename = buff;
389 if (isShellLink(filename))
390 filename = getShellLinkTarget(filename);
391 files.push_back(filename);
393 return FileListToByteSequence(files);
396 // convert a windows bitmap handle into a LibreOffice bitmap
398 Sequence< sal_Int8 > WinBITMAPToOOBMP( HBITMAP aHBMP )
400 Sequence< sal_Int8 > ooBmpStream;
402 SIZE aBmpSize;
403 if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) )
405 // fill bitmap info header
406 size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy;
407 Sequence< sal_Int8 > aBitmapStream(
408 sizeof(BITMAPINFO) +
409 nDataBytes
411 PBITMAPINFOHEADER pBmp = reinterpret_cast<PBITMAPINFOHEADER>(aBitmapStream.getArray());
412 pBmp->biSize = sizeof( BITMAPINFOHEADER );
413 pBmp->biWidth = aBmpSize.cx;
414 pBmp->biHeight = aBmpSize.cy;
415 pBmp->biPlanes = 1;
416 pBmp->biBitCount = 32;
417 pBmp->biCompression = BI_RGB;
418 pBmp->biSizeImage = static_cast<DWORD>(nDataBytes);
419 pBmp->biXPelsPerMeter = 1000;
420 pBmp->biYPelsPerMeter = 1000;
421 pBmp->biClrUsed = 0;
422 pBmp->biClrImportant = 0;
423 if( GetDIBits( nullptr, // DC, 0 is a default GC, basically that of the desktop
424 aHBMP,
425 0, aBmpSize.cy,
426 aBitmapStream.getArray() + sizeof(BITMAPINFO),
427 reinterpret_cast<LPBITMAPINFO>(pBmp),
428 DIB_RGB_COLORS ) )
430 ooBmpStream = WinDIBToOOBMP( aBitmapStream );
434 return ooBmpStream;
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */