update dev300-m58
[ooovba.git] / dtrans / source / win32 / dtobj / FmtFilter.cxx
blob9c610cab17cd67c5097c085dbf00467dca51b672
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: FmtFilter.cxx,v $
10 * $Revision: 1.16 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dtrans.hxx"
33 #include "FmtFilter.hxx"
34 #include <osl/diagnose.h>
35 #include <comphelper/sequence.hxx>
37 #if defined _MSC_VER
38 #pragma warning(push,1)
39 #pragma warning(disable:4917)
40 #endif
41 #include <Shobjidl.h>
42 #include <shlguid.h>
43 #include <ObjIdl.h>
44 #include <shellapi.h>
45 #if defined _MSC_VER
46 #pragma warning(pop)
47 #endif
49 #include <string>
50 #include <sstream>
51 #include <vector>
52 #include <iomanip>
54 #include <systools/win32/comtools.hxx>
56 using namespace com::sun::star::uno;
57 using rtl::OString;
59 #pragma pack(2)
60 struct METAFILEHEADER
62 DWORD key;
63 short hmf;
64 SMALL_RECT bbox;
65 WORD inch;
66 DWORD reserved;
67 WORD checksum;
69 #pragma pack()
71 //------------------------------------------------------------------------
72 // convert a windows metafile picture to a openoffice metafile picture
73 //------------------------------------------------------------------------
75 Sequence< sal_Int8 > SAL_CALL WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict )
77 OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) );
79 Sequence< sal_Int8 > mfpictStream;
80 METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) );
81 HMETAFILE hMf = pMFPict->hMF;
82 sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, NULL );
84 if ( nCount > 0 )
86 mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) );
88 METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) );
89 SMALL_RECT aRect = { 0,
90 0,
91 static_cast< short >( pMFPict->xExt ),
92 static_cast< short >( pMFPict->yExt ) };
93 USHORT nInch;
95 switch( pMFPict->mm )
97 case MM_TEXT:
98 nInch = 72;
99 break;
101 case MM_LOMETRIC:
102 nInch = 100;
103 break;
105 case MM_HIMETRIC:
106 nInch = 1000;
107 break;
109 case MM_LOENGLISH:
110 nInch = 254;
111 break;
113 case MM_HIENGLISH:
114 case MM_ISOTROPIC:
115 case MM_ANISOTROPIC:
116 nInch = 2540;
117 break;
119 case MM_TWIPS:
120 nInch = 1440;
121 break;
123 default:
124 nInch = 576;
127 pMFHeader->key = 0x9AC6CDD7L;
128 pMFHeader->hmf = 0;
129 pMFHeader->bbox = aRect;
130 pMFHeader->inch = nInch;
131 pMFHeader->reserved = 0;
132 pMFHeader->checksum = 0;
134 char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) );
136 nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) );
137 OSL_ASSERT( nCount > 0 );
140 return mfpictStream;
143 //-------------------------------------------------------------
144 // convert a windows enhanced metafile to a openoffice metafile
145 //-------------------------------------------------------------
147 Sequence< sal_Int8 > SAL_CALL WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile )
149 Sequence< sal_Int8 > aRet;
150 UINT nSize = 0;
152 if( hEnhMetaFile &&
153 ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, NULL ) ) != 0 ) )
155 aRet.realloc( nSize );
157 if( GetEnhMetaFileBits( hEnhMetaFile, nSize, (sal_uChar*) aRet.getArray() ) != nSize )
158 aRet.realloc( 0 );
161 return aRet;
164 //------------------------------------------------------------------------
165 // convert a openoffice metafile picture to a windows metafile picture
166 //------------------------------------------------------------------------
168 HMETAFILEPICT SAL_CALL OOMFPictToWinMFPict( Sequence< sal_Int8 >& aOOMetaFilePict )
170 HMETAFILEPICT hPict = NULL;
171 HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), (sal_uChar*) aOOMetaFilePict.getConstArray() );
173 if( hMtf )
175 METAFILEPICT* pPict = (METAFILEPICT*) GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) );
177 pPict->mm = 8;
178 pPict->xExt = 0;
179 pPict->yExt = 0;
180 pPict->hMF = hMtf;
182 GlobalUnlock( hPict );
185 return hPict;
188 //-----------------------------------------------------------------------------
189 // convert a openoffice metafile picture to a windows enhanced metafile picture
190 //-----------------------------------------------------------------------------
192 HENHMETAFILE SAL_CALL OOMFPictToWinENHMFPict( Sequence< sal_Int8 >& aOOMetaFilePict )
194 HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), (sal_uChar*) aOOMetaFilePict.getConstArray() );
196 return hEnhMtf;
199 //------------------------------------------------------------------------
200 // convert a windows device independent bitmap into a openoffice bitmap
201 //------------------------------------------------------------------------
203 Sequence< sal_Int8 > SAL_CALL WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB )
205 OSL_ASSERT( aWinDIB.getLength( ) > sizeof( BITMAPINFOHEADER ) );
207 Sequence< sal_Int8 > ooBmpStream;
209 ooBmpStream.realloc( aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER) );
211 const BITMAPINFOHEADER *pBmpInfoHdr = (const BITMAPINFOHEADER*)aWinDIB.getConstArray();
212 BITMAPFILEHEADER *pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >( ooBmpStream.getArray() );
213 DWORD nOffset = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
215 rtl_copyMemory( pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength( ) );
217 if( pBmpInfoHdr->biBitCount <= 8 )
218 nOffset += ( pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : ( 1 << pBmpInfoHdr->biBitCount ) ) << 2;
219 else if( ( BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ( ( 16 == pBmpInfoHdr->biBitCount ) || ( 32 == pBmpInfoHdr->biBitCount ) ) )
220 nOffset += 12;
222 pBmpFileHdr->bfType = 'MB';
223 pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER)
224 pBmpFileHdr->bfReserved1 = 0;
225 pBmpFileHdr->bfReserved2 = 0;
226 pBmpFileHdr->bfOffBits = nOffset;
228 return ooBmpStream;
231 //------------------------------------------------------------------------
232 // convert a openoffice bitmap into a windows device independent bitmap
233 //------------------------------------------------------------------------
235 Sequence< sal_Int8 > SAL_CALL OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp )
237 OSL_ASSERT( aOOBmp.getLength( ) >
238 ( sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) ) );
240 Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
242 rtl_copyMemory( winDIBStream.getArray( ),
243 aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ),
244 aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) );
246 return winDIBStream;
249 //------------------------------------------------------------------------------
250 // converts the openoffice text/html clipboard format to the HTML Format
251 // well known under MS Windows
252 // the MS HTML Format has a header before the real html data
254 // Version:1.0 Version number of the clipboard. Staring is 0.9
255 // StartHTML: Byte count from the beginning of the clipboard to the start
256 // of the context, or -1 if no context
257 // EndHTML: Byte count from the beginning of the clipboard to the end
258 // of the context, or -1 if no context
259 // StartFragment: Byte count from the beginning of the clipboard to the
260 // start of the fragment
261 // EndFragment: Byte count from the beginning of the clipboard to the
262 // end of the fragment
263 // StartSelection: Byte count from the beginning of the clipboard to the
264 // start of the selection
265 // EndSelection: Byte count from the beginning of the clipboard to the
266 // end of the selection
268 // StartSelection and EndSelection are optional
269 // The fragment should be preceded and followed by the HTML comments
270 // <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the
271 // text
272 //------------------------------------------------------------------------------
274 Sequence< sal_Int8 > SAL_CALL TextHtmlToHTMLFormat( Sequence< sal_Int8 >& aTextHtml )
276 OSL_ASSERT( aTextHtml.getLength( ) > 0 );
278 // check parameter
279 if ( !(aTextHtml.getLength( ) > 0) )
280 return Sequence< sal_Int8 >( );
282 // we create a buffer with the approximated size of
283 // the HTML Format header
284 char aHTMLFmtHdr[120];
286 rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) );
288 // fill the buffer with dummy values to calc the
289 // exact length
291 wsprintf(
292 aHTMLFmtHdr,
293 "Version:1.0\nStartHTML:%010d\r\nnEndHTML:%010d\r\nStartFragment:%010\r\nnEndFragment:%010d\r\n", 0, 0, 0, 0 );
295 sal_uInt32 lHTMLFmtHdr = rtl_str_getLength( aHTMLFmtHdr );
297 // the office allways writes the start
298 // and end html tag in upper cases and
299 // without spaces
300 // both tags don't allow parameters
301 OString startHtmlTag( "<HTML>" );
302 OString endHtmlTag( "</HTML>" );
304 // we don't include '>' into the search
305 // because the body tag allows parameters
306 // e.g. <BODY param>
307 // #92840#
308 OString startBodyTag( "<BODY" );
309 OString endBodyTag( "</BODY" );
311 OString textHtml(
312 reinterpret_cast< const sal_Char* >( aTextHtml.getConstArray( ) ),
313 aTextHtml.getLength( ) );
315 sal_Int32 nStartHtml = textHtml.indexOf( startHtmlTag );
316 sal_Int32 nEndHtml = textHtml.indexOf( endHtmlTag );
317 sal_Int32 nStartFrgmt = textHtml.indexOf( startBodyTag );
318 sal_Int32 nEndFrgmt = textHtml.indexOf( endBodyTag );
320 OSL_ASSERT( (nStartHtml >= 0) && (nEndHtml > nStartHtml) && (nStartFrgmt > nStartHtml) && (nEndFrgmt > nStartFrgmt) );
322 Sequence< sal_Int8 > aHTMLFmtSequence;
324 if ( (nStartHtml > -1) && (nEndHtml > -1) && (nStartFrgmt > -1) && (nEndFrgmt > -1) )
326 nStartHtml = nStartHtml + lHTMLFmtHdr - 1; // we start one before <HTML> Word 2000 does also so
327 nEndHtml = nEndHtml + lHTMLFmtHdr + endHtmlTag.getLength( ) + 1; // our SOffice 5.2 wants 2 behind </HTML>?
328 nStartFrgmt = nStartFrgmt + startBodyTag.getLength( ) + lHTMLFmtHdr; // after the <BODY> tag
329 nEndFrgmt = nEndFrgmt + lHTMLFmtHdr;
331 // fill the html header
332 rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) );
334 wsprintf(
335 aHTMLFmtHdr,
336 "Version:1.0\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n",
337 nStartHtml, nEndHtml, nStartFrgmt, nEndFrgmt );
339 // we add space for a trailing \0
340 aHTMLFmtSequence.realloc( lHTMLFmtHdr + aTextHtml.getLength( ) + 1 );
341 rtl_zeroMemory( aHTMLFmtSequence.getArray( ), aHTMLFmtSequence.getLength( ) );
343 // copy the HTML Format header
344 rtl_copyMemory(
345 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) ),
346 static_cast< LPVOID >( aHTMLFmtHdr ), lHTMLFmtHdr );
348 // concat the text/html
349 rtl_copyMemory(
350 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) + lHTMLFmtHdr ),
351 static_cast< LPVOID >( aTextHtml.getArray( ) ),
352 aTextHtml.getLength( ) );
355 return aHTMLFmtSequence;
359 std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment)
361 std::ostringstream htmlHeader;
362 htmlHeader << "Version:1.0" << '\r' << '\n';
363 htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n';
364 htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n';
365 htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n';
366 htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n';
367 return htmlHeader.str();
370 // the office allways writes the start and end html tag in upper cases and
371 // without spaces both tags don't allow parameters
372 const std::string TAG_HTML = std::string("<HTML>");
373 const std::string TAG_END_HTML = std::string("</HTML>");
375 // The body tag may have parameters so we need to search for the
376 // closing '>' manually e.g. <BODY param> #92840#
377 const std::string TAG_BODY = std::string("<BODY");
378 const std::string TAG_END_BODY = std::string("</BODY");
380 Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8>& aTextHtml)
382 OSL_ASSERT(aTextHtml.getLength() > 0);
384 if (!(aTextHtml.getLength() > 0))
385 return Sequence<sal_Int8>();
387 // fill the buffer with dummy values to calc the exact length
388 std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
389 size_t lHtmlFormatHeader = dummyHtmlHeader.length();
391 std::string textHtml(
392 reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()),
393 reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()) + aTextHtml.getLength());
395 std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so
396 std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
398 // The body tag may have parameters so we need to search for the
399 // closing '>' manually e.g. <BODY param> #92840#
400 std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
401 std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
403 std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
404 htmlFormat += textHtml;
406 Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
407 rtl_zeroMemory(byteSequence.getArray(), byteSequence.getLength());
409 rtl_copyMemory(
410 static_cast<void*>(byteSequence.getArray()),
411 static_cast<const void*>(htmlFormat.c_str()),
412 htmlFormat.length());
414 return byteSequence;
417 std::wstring getFileExtension(const std::wstring& aFilename)
419 std::wstring::size_type idx = aFilename.rfind(L".");
420 if ((idx != std::wstring::npos))
422 return std::wstring(aFilename, idx);
424 return std::wstring();
427 const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk";
429 bool isShellLink(const std::wstring& aFilename)
431 std::wstring ext = getFileExtension(aFilename);
432 return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0);
435 /** Resolve a Windows Shell Link (lnk) file. If a resolution
436 is not possible simply return the provided name of the
437 lnk file. */
438 std::wstring getShellLinkTarget(const std::wstring& aLnkFile)
440 OSL_ASSERT(isShellLink(aLnkFile));
442 std::wstring target = aLnkFile;
446 sal::systools::COMReference<IShellLinkA> pIShellLink;
447 HRESULT hr = CoCreateInstance(
448 CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<LPVOID*>(&pIShellLink));
449 if (FAILED(hr))
450 return target;
452 sal::systools::COMReference<IPersistFile> pIPersistFile =
453 pIShellLink.QueryInterface<IPersistFile>(IID_IPersistFile);
455 hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ);
456 if (FAILED(hr))
457 return target;
459 hr = pIShellLink->Resolve(NULL, SLR_UPDATE | SLR_NO_UI);
460 if (FAILED(hr))
461 return target;
463 char pathA[MAX_PATH];
464 WIN32_FIND_DATA wfd;
465 hr = pIShellLink->GetPath(pathA, MAX_PATH, &wfd, SLGP_RAWPATH);
466 if (FAILED(hr))
467 return target;
469 wchar_t pathW[MAX_PATH];
470 MultiByteToWideChar(CP_ACP, 0, pathA, -1, pathW, MAX_PATH);
471 target = pathW;
473 catch(sal::systools::ComError& ex)
475 OSL_ENSURE(false, ex.what());
476 ex = ex;
478 return target;
481 typedef std::vector<std::wstring> FileList_t;
482 typedef FileList_t::value_type FileList_ValueType_t;
483 typedef Sequence<sal_Int8> ByteSequence_t;
485 /* Calculate the size required for turning a string list into
486 a double '\0' terminated string buffer */
487 size_t CalcSizeForStringListBuffer(const FileList_t& fileList)
489 if (fileList.size() == 0)
490 return 0;
492 size_t size = 1; // one for the very final '\0'
493 FileList_t::const_iterator iter_end = fileList.end();
494 for (FileList_t::const_iterator iter = fileList.begin(); iter != iter_end; ++iter)
496 size += iter->length() + 1; // length including terminating '\0'
498 return (size * sizeof(FileList_ValueType_t::value_type));
501 ByteSequence_t FileListToByteSequence(const FileList_t& fileList)
503 ByteSequence_t bseq;
504 size_t size = CalcSizeForStringListBuffer(fileList);
506 if (size > 0)
508 bseq.realloc(size);
509 wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray());
510 ZeroMemory(p, size);
512 FileList_t::const_iterator iter;
513 FileList_t::const_iterator iter_end = fileList.end();
514 for (iter = fileList.begin(); iter != iter_end; ++iter)
516 wcsncpy(p, iter->c_str(), iter->length());
517 p += (iter->length() + 1);
520 return bseq;
523 ByteSequence_t CF_HDROPToFileList(HGLOBAL hGlobal)
525 UINT nFiles = DragQueryFileW((HDROP)hGlobal, 0xFFFFFFFF, NULL, 0);
526 FileList_t files;
528 for (UINT i = 0; i < nFiles; i++)
530 wchar_t buff[MAX_PATH];
531 /*UINT size =*/ DragQueryFileW((HDROP)hGlobal, i, buff, MAX_PATH);
532 std::wstring filename = buff;
533 if (isShellLink(filename))
534 filename = getShellLinkTarget(filename);
535 files.push_back(filename);
537 return FileListToByteSequence(files);