bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / win / dtrans / FmtFilter.cxx
blob27d051f7e8a70532cb30f40fe3a0a27e1a9b1682
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 <o3tl/unit_conversion.hxx>
26 #include <osl/diagnose.h>
28 #include <shobjidl.h>
29 #include <shlguid.h>
30 #include <objidl.h>
31 #include <shellapi.h>
33 #include <string>
34 #include <sstream>
35 #include <vector>
36 #include <iomanip>
38 #include <systools/win32/comtools.hxx>
40 using namespace com::sun::star::uno;
42 namespace {
44 #pragma pack(2)
45 struct METAFILEHEADER
47 DWORD key;
48 short hmf;
49 SMALL_RECT bbox;
50 WORD inch;
51 DWORD reserved;
52 WORD checksum;
54 #pragma pack()
58 // convert a windows metafile picture to a LibreOffice metafile picture
60 Sequence< sal_Int8 > WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict )
62 OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) );
64 Sequence< sal_Int8 > mfpictStream;
65 METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) );
66 HMETAFILE hMf = pMFPict->hMF;
67 sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, nullptr );
69 if ( nCount > 0 )
71 mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) );
73 METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) );
74 SMALL_RECT aRect = { 0,
76 static_cast< short >( pMFPict->xExt ),
77 static_cast< short >( pMFPict->yExt ) };
78 USHORT nInch;
80 switch( pMFPict->mm )
82 case MM_TEXT:
83 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::pt);
84 break;
86 case MM_LOMETRIC:
87 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm10);
88 break;
90 case MM_HIMETRIC:
91 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100);
92 break;
94 case MM_LOENGLISH:
95 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::in100);
96 break;
98 case MM_HIENGLISH:
99 case MM_ISOTROPIC:
100 case MM_ANISOTROPIC:
101 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::in1000);
102 break;
104 case MM_TWIPS:
105 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::twip);
106 break;
108 default:
109 nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::master);
112 pMFHeader->key = 0x9AC6CDD7L;
113 pMFHeader->hmf = 0;
114 pMFHeader->bbox = aRect;
115 pMFHeader->inch = nInch;
116 pMFHeader->reserved = 0;
117 pMFHeader->checksum = 0;
119 char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) );
121 nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) );
122 OSL_ASSERT( nCount > 0 );
125 return mfpictStream;
128 // convert a windows enhanced metafile to a LibreOffice metafile
130 Sequence< sal_Int8 > WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile )
132 Sequence< sal_Int8 > aRet;
133 UINT nSize = 0;
135 if( hEnhMetaFile &&
136 ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, nullptr ) ) != 0 ) )
138 aRet.realloc( nSize );
140 if( GetEnhMetaFileBits( hEnhMetaFile, nSize, reinterpret_cast<unsigned char*>(aRet.getArray()) ) != nSize )
141 aRet.realloc( 0 );
144 return aRet;
147 // convert a LibreOffice metafile picture to a windows metafile picture
149 HMETAFILEPICT OOMFPictToWinMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict )
151 HMETAFILEPICT hPict = nullptr;
152 HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict.getConstArray()) );
154 if( hMtf )
156 METAFILEPICT* pPict = static_cast<METAFILEPICT*>(GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) ));
158 pPict->mm = 8;
159 pPict->xExt = 0;
160 pPict->yExt = 0;
161 pPict->hMF = hMtf;
163 GlobalUnlock( hPict );
166 return hPict;
169 // convert a LibreOffice metafile picture to a windows enhanced metafile picture
171 HENHMETAFILE OOMFPictToWinENHMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict )
173 HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), reinterpret_cast<unsigned char const *>(aOOMetaFilePict.getConstArray()) );
175 return hEnhMtf;
178 // convert a windows device independent bitmap into a LibreOffice bitmap
180 Sequence< sal_Int8 > WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB )
182 OSL_ENSURE(o3tl::make_unsigned(aWinDIB.getLength()) > sizeof(BITMAPINFOHEADER), "CF_DIBV5/CF_DIB too small (!)");
183 Sequence< sal_Int8 > ooBmpStream;
185 ooBmpStream.realloc(aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER));
186 const BITMAPINFOHEADER* pBmpInfoHdr = reinterpret_cast< const BITMAPINFOHEADER* >(aWinDIB.getConstArray());
187 BITMAPFILEHEADER* pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >(ooBmpStream.getArray());
188 const DWORD nSizeInfoOrV5(pBmpInfoHdr->biSize > sizeof(BITMAPINFOHEADER) ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER));
189 DWORD nOffset(sizeof(BITMAPFILEHEADER) + nSizeInfoOrV5);
191 memcpy(pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength());
193 if(pBmpInfoHdr->biBitCount <= 8)
195 nOffset += (pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : (1 << pBmpInfoHdr->biBitCount)) << 2;
197 else if((BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ((16 == pBmpInfoHdr->biBitCount ) || (32 == pBmpInfoHdr->biBitCount )))
199 nOffset += 12;
202 pBmpFileHdr->bfType = ('M' << 8) | 'B';
203 pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
204 pBmpFileHdr->bfReserved1 = 0;
205 pBmpFileHdr->bfReserved2 = 0;
206 pBmpFileHdr->bfOffBits = nOffset;
208 return ooBmpStream;
211 // convert a LibreOffice bitmap into a windows device independent bitmap
213 Sequence< sal_Int8 > OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp )
215 Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
217 memcpy( winDIBStream.getArray( ),
218 aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ),
219 aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
221 return winDIBStream;
224 static std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment)
226 std::ostringstream htmlHeader;
227 htmlHeader << "Version:1.0" << '\r' << '\n';
228 htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n';
229 htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n';
230 htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n';
231 htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n';
232 return htmlHeader.str();
235 // the case of these tags has to match what we output in our filters
236 // both tags don't allow parameters
237 const std::string TAG_HTML("<html>");
238 const std::string TAG_END_HTML("</html>");
240 // The body tag may have parameters so we need to search for the
241 // closing '>' manually e.g. <body param> #92840#
242 const std::string TAG_BODY("<body");
243 const std::string TAG_END_BODY("</body");
245 Sequence<sal_Int8> TextHtmlToHTMLFormat(Sequence<sal_Int8> const & aTextHtml)
247 OSL_ASSERT(aTextHtml.getLength() > 0);
249 if (aTextHtml.getLength() <= 0)
250 return Sequence<sal_Int8>();
252 // fill the buffer with dummy values to calc the exact length
253 std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
254 size_t lHtmlFormatHeader = dummyHtmlHeader.length();
256 std::string textHtml(
257 reinterpret_cast<const char*>(aTextHtml.getConstArray()),
258 reinterpret_cast<const char*>(aTextHtml.getConstArray()) + aTextHtml.getLength());
260 std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so
261 std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
263 // The body tag may have parameters so we need to search for the
264 // closing '>' manually e.g. <BODY param> #92840#
265 std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
266 std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
268 std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
269 htmlFormat += textHtml;
271 Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
272 memset(byteSequence.getArray(), 0, byteSequence.getLength());
274 memcpy(
275 static_cast<void*>(byteSequence.getArray()),
276 static_cast<const void*>(htmlFormat.c_str()),
277 htmlFormat.length());
279 return byteSequence;
282 static std::wstring getFileExtension(const std::wstring& aFilename)
284 std::wstring::size_type idx = aFilename.rfind(L".");
285 if (idx != std::wstring::npos)
287 return std::wstring(aFilename, idx);
289 return std::wstring();
292 const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk";
294 static bool isShellLink(const std::wstring& aFilename)
296 std::wstring ext = getFileExtension(aFilename);
297 return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0);
300 /** Resolve a Windows Shell Link (lnk) file. If a resolution
301 is not possible simply return the provided name of the
302 lnk file. */
303 static std::wstring getShellLinkTarget(const std::wstring& aLnkFile)
305 OSL_ASSERT(isShellLink(aLnkFile));
307 std::wstring target = aLnkFile;
311 sal::systools::COMReference<IShellLinkW> pIShellLink;
312 pIShellLink.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
314 sal::systools::COMReference<IPersistFile> pIPersistFile(pIShellLink,
315 sal::systools::COM_QUERY_THROW);
317 HRESULT hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ);
318 if (FAILED(hr))
319 return target;
321 hr = pIShellLink->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI);
322 if (FAILED(hr))
323 return target;
325 wchar_t pathW[MAX_PATH];
326 WIN32_FIND_DATAW wfd;
327 hr = pIShellLink->GetPath(pathW, MAX_PATH, &wfd, SLGP_RAWPATH);
328 if (FAILED(hr))
329 return target;
331 target = pathW;
333 catch(sal::systools::ComError& ex)
335 OSL_FAIL(ex.what());
337 return target;
340 typedef Sequence<sal_Int8> ByteSequence_t;
342 /* Calculate the size required for turning a string list into
343 a double '\0' terminated string buffer */
344 static size_t CalcSizeForStringListBuffer(const std::vector<std::wstring>& fileList)
346 if ( fileList.empty() )
347 return 0;
349 size_t size = 1; // one for the very final '\0'
350 for (auto const& elem : fileList)
352 size += elem.length() + 1; // length including terminating '\0'
354 return (size * sizeof(std::vector<std::wstring>::value_type::value_type));
357 static ByteSequence_t FileListToByteSequence(const std::vector<std::wstring>& fileList)
359 ByteSequence_t bseq;
360 size_t size = CalcSizeForStringListBuffer(fileList);
362 if (size > 0)
364 bseq.realloc(size);
365 wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray());
366 ZeroMemory(p, size);
368 for (auto const& elem : fileList)
370 wcsncpy(p, elem.c_str(), elem.length());
371 p += (elem.length() + 1);
374 return bseq;
377 css::uno::Sequence<sal_Int8> CF_HDROPToFileList(HGLOBAL hGlobal)
379 UINT nFiles = DragQueryFileW(static_cast<HDROP>(hGlobal), 0xFFFFFFFF, nullptr, 0);
380 std::vector<std::wstring> files;
382 for (UINT i = 0; i < nFiles; i++)
384 wchar_t buff[MAX_PATH];
385 /*UINT size =*/ DragQueryFileW(static_cast<HDROP>(hGlobal), i, buff, MAX_PATH);
386 std::wstring filename = buff;
387 if (isShellLink(filename))
388 filename = getShellLinkTarget(filename);
389 files.push_back(filename);
391 return FileListToByteSequence(files);
394 // convert a windows bitmap handle into a LibreOffice bitmap
396 Sequence< sal_Int8 > WinBITMAPToOOBMP( HBITMAP aHBMP )
398 Sequence< sal_Int8 > ooBmpStream;
400 SIZE aBmpSize;
401 if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) )
403 // fill bitmap info header
404 size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy;
405 Sequence< sal_Int8 > aBitmapStream(
406 sizeof(BITMAPINFO) +
407 nDataBytes
409 PBITMAPINFOHEADER pBmp = reinterpret_cast<PBITMAPINFOHEADER>(aBitmapStream.getArray());
410 pBmp->biSize = sizeof( BITMAPINFOHEADER );
411 pBmp->biWidth = aBmpSize.cx;
412 pBmp->biHeight = aBmpSize.cy;
413 pBmp->biPlanes = 1;
414 pBmp->biBitCount = 32;
415 pBmp->biCompression = BI_RGB;
416 pBmp->biSizeImage = static_cast<DWORD>(nDataBytes);
417 pBmp->biXPelsPerMeter = 1000;
418 pBmp->biYPelsPerMeter = 1000;
419 pBmp->biClrUsed = 0;
420 pBmp->biClrImportant = 0;
421 if( GetDIBits( nullptr, // DC, 0 is a default GC, basically that of the desktop
422 aHBMP,
423 0, aBmpSize.cy,
424 aBitmapStream.getArray() + sizeof(BITMAPINFO),
425 reinterpret_cast<LPBITMAPINFO>(pBmp),
426 DIB_RGB_COLORS ) )
428 ooBmpStream = WinDIBToOOBMP( aBitmapStream );
432 return ooBmpStream;
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */