update credits
[LibreOffice.git] / dtrans / source / win32 / dtobj / FmtFilter.cxx
blobf9327d8e82df25c55219e296510a6f10d440fafd
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>
24 #include <comphelper/sequence.hxx>
26 #if defined _MSC_VER
27 #pragma warning(push,1)
28 #pragma warning(disable:4917)
29 #endif
30 #include <shobjidl.h>
31 #include <shlguid.h>
32 #include <objidl.h>
33 #include <shellapi.h>
34 #if defined _MSC_VER
35 #pragma warning(pop)
36 #endif
38 #include <string>
39 #include <sstream>
40 #include <vector>
41 #include <iomanip>
43 #include <systools/win32/comtools.hxx>
45 using namespace com::sun::star::uno;
47 #pragma pack(2)
48 struct METAFILEHEADER
50 DWORD key;
51 short hmf;
52 SMALL_RECT bbox;
53 WORD inch;
54 DWORD reserved;
55 WORD checksum;
57 #pragma pack()
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 );
72 if ( nCount > 0 )
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 ) };
81 USHORT nInch;
83 switch( pMFPict->mm )
85 case MM_TEXT:
86 nInch = 72;
87 break;
89 case MM_LOMETRIC:
90 nInch = 100;
91 break;
93 case MM_HIMETRIC:
94 nInch = 1000;
95 break;
97 case MM_LOENGLISH:
98 nInch = 254;
99 break;
101 case MM_HIENGLISH:
102 case MM_ISOTROPIC:
103 case MM_ANISOTROPIC:
104 nInch = 2540;
105 break;
107 case MM_TWIPS:
108 nInch = 1440;
109 break;
111 default:
112 nInch = 576;
115 pMFHeader->key = 0x9AC6CDD7L;
116 pMFHeader->hmf = 0;
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 );
128 return mfpictStream;
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;
138 UINT nSize = 0;
140 if( hEnhMetaFile &&
141 ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, NULL ) ) != 0 ) )
143 aRet.realloc( nSize );
145 if( GetEnhMetaFileBits( hEnhMetaFile, nSize, (sal_uChar*) aRet.getArray() ) != nSize )
146 aRet.realloc( 0 );
149 return aRet;
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() );
161 if( hMtf )
163 METAFILEPICT* pPict = (METAFILEPICT*) GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) );
165 pPict->mm = 8;
166 pPict->xExt = 0;
167 pPict->yExt = 0;
168 pPict->hMF = hMtf;
170 GlobalUnlock( hPict );
173 return 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() );
184 return hEnhMtf;
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 ) ) )
208 nOffset += 12;
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;
216 return ooBmpStream;
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 ) );
234 return winDIBStream;
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
259 // text
260 //------------------------------------------------------------------------------
262 Sequence< sal_Int8 > SAL_CALL TextHtmlToHTMLFormat( Sequence< sal_Int8 >& aTextHtml )
264 OSL_ASSERT( aTextHtml.getLength( ) > 0 );
266 // check parameter
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
277 // exact length
279 wsprintf(
280 aHTMLFmtHdr,
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
287 // without spaces
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
294 // e.g. <BODY param>
295 // #92840#
296 OString startBodyTag( "<BODY" );
297 OString endBodyTag( "</BODY" );
299 OString textHtml(
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 ) );
322 wsprintf(
323 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
332 memcpy(
333 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) ),
334 static_cast< LPVOID >( aHTMLFmtHdr ), lHTMLFmtHdr );
336 // concat the text/html
337 memcpy(
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());
397 memcpy(
398 static_cast<void*>(byteSequence.getArray()),
399 static_cast<const void*>(htmlFormat.c_str()),
400 htmlFormat.length());
402 return byteSequence;
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
425 lnk file. */
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));
437 if (FAILED(hr))
438 return target;
440 sal::systools::COMReference<IPersistFile> pIPersistFile =
441 pIShellLink.QueryInterface<IPersistFile>(IID_IPersistFile);
443 hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ);
444 if (FAILED(hr))
445 return target;
447 hr = pIShellLink->Resolve(NULL, SLR_UPDATE | SLR_NO_UI);
448 if (FAILED(hr))
449 return target;
451 char pathA[MAX_PATH];
452 WIN32_FIND_DATA wfd;
453 hr = pIShellLink->GetPath(pathA, MAX_PATH, &wfd, SLGP_RAWPATH);
454 if (FAILED(hr))
455 return target;
457 wchar_t pathW[MAX_PATH];
458 MultiByteToWideChar(CP_ACP, 0, pathA, -1, pathW, MAX_PATH);
459 target = pathW;
461 catch(sal::systools::ComError& ex)
463 OSL_FAIL(ex.what());
464 ex = ex;
466 return target;
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() )
478 return 0;
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)
491 ByteSequence_t bseq;
492 size_t size = CalcSizeForStringListBuffer(fileList);
494 if (size > 0)
496 bseq.realloc(size);
497 wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray());
498 ZeroMemory(p, size);
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);
508 return bseq;
511 ByteSequence_t CF_HDROPToFileList(HGLOBAL hGlobal)
513 UINT nFiles = DragQueryFileW((HDROP)hGlobal, 0xFFFFFFFF, NULL, 0);
514 FileList_t files;
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;
536 SIZE aBmpSize;
537 if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) )
539 // fill bitmap info header
540 size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy;
541 Sequence< sal_Int8 > aBitmapStream(
542 sizeof(BITMAPINFO) +
543 nDataBytes
545 PBITMAPINFOHEADER pBmp = (PBITMAPINFOHEADER)aBitmapStream.getArray();
546 pBmp->biSize = sizeof( BITMAPINFOHEADER );
547 pBmp->biWidth = aBmpSize.cx;
548 pBmp->biHeight = aBmpSize.cy;
549 pBmp->biPlanes = 1;
550 pBmp->biBitCount = 32;
551 pBmp->biCompression = BI_RGB;
552 pBmp->biSizeImage = (DWORD)nDataBytes;
553 pBmp->biXPelsPerMeter = 1000;
554 pBmp->biYPelsPerMeter = 1000;
555 pBmp->biClrUsed = 0;
556 pBmp->biClrImportant = 0;
557 if( GetDIBits( 0, // DC, 0 is a default GC, basically that of the desktop
558 aHBMP,
559 0, aBmpSize.cy,
560 aBitmapStream.getArray() + sizeof(BITMAPINFO),
561 (LPBITMAPINFO)pBmp,
562 DIB_RGB_COLORS ) )
564 ooBmpStream = WinDIBToOOBMP( aBitmapStream );
568 return ooBmpStream;
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */